Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --sentry-trace CLI option #976

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/Sentry/Laravel/Features/ConsoleIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@

namespace Sentry\Laravel\Features;

use Illuminate\Console\Application as ConsoleApplication;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Console\Events as ConsoleEvents;
use Sentry\Breadcrumb;
use Sentry\Laravel\Features\Concerns\TracksPushedScopesAndSpans;
use Sentry\Laravel\Integration;
use Sentry\SentrySdk;
use Sentry\State\Scope;
use Sentry\Tracing\SpanStatus;
use Sentry\Tracing\TransactionContext;
use Sentry\Tracing\TransactionSource;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;

class ConsoleIntegration extends Feature
{
use TracksPushedScopesAndSpans;

private const FEATURE_KEY = 'command_info';

public function isApplicable(): bool
Expand All @@ -21,6 +30,12 @@ public function isApplicable(): bool

public function onBoot(Dispatcher $events): void
{
ConsoleApplication::starting(static function (ConsoleApplication $console) {
$console->getDefinition()->addOption(
new InputOption('--sentry-trace', null, InputOption::VALUE_OPTIONAL, 'Trace the execution of this command using the Sentry SDK')
);
});

$events->listen(ConsoleEvents\CommandStarting::class, [$this, 'commandStarting']);
$events->listen(ConsoleEvents\CommandFinished::class, [$this, 'commandFinished']);
}
Expand All @@ -31,6 +46,23 @@ public function commandStarting(ConsoleEvents\CommandStarting $event): void
return;
}

$shouldTrace = $event->input->hasOption('sentry-trace') && $event->input->getParameterOption('--sentry-trace') !== false;

// If `--sentry-trace` is passed, we start a new transaction and optionally take the operation name from the option value
if ($shouldTrace) {
$sentryTraceOp = $event->input->getOption('sentry-trace');

$context = TransactionContext::make()
->setName($event->command)
->setSource(TransactionSource::task())
->setOp($sentryTraceOp ?? 'console.command')
->setStartTimestamp(microtime(true));

$transaction = SentrySdk::getCurrentHub()->startTransaction($context);

$this->pushSpan($transaction);
}

Integration::configureScope(static function (Scope $scope) use ($event): void {
$scope->setTag('command', $event->command);
});
Expand Down Expand Up @@ -63,6 +95,14 @@ public function commandFinished(ConsoleEvents\CommandFinished $event): void
));
}

$span = $this->maybePopSpan();

if ($span) {
$span->finish();

$span->setStatus($event->exitCode === 0 ? SpanStatus::ok() : SpanStatus::internalError());
}

// Flush any and all events that were possibly generated by the command
Integration::flushEvents();

Expand Down
25 changes: 23 additions & 2 deletions src/Sentry/Laravel/Features/ConsoleSchedulingIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Illuminate\Contracts\Cache\Factory as Cache;
use Illuminate\Contracts\Cache\Repository;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\ProcessUtils;
use Illuminate\Support\Str;
use RuntimeException;
use Sentry\CheckIn;
Expand Down Expand Up @@ -136,8 +137,28 @@ public function useCacheStore(?string $name): void

public function handleScheduledTaskStarting(ScheduledTaskStarting $event): void
{
// There is nothing for us to track if it's a background task since it will be handled by a separate process
if (!$event->task || $event->task->runInBackground) {
if (!$event->task) {
return;
}

// If the command is run in the background we need to add the trace argument to the command string
if ($event->task->command && $event->task->runInBackground) {
if (Str::contains($event->task->command, '--sentry-trace')) {
return;
}

$traceArgument = ProcessUtils::escapeArgument('console.command.scheduled');

$event->task->command = "{$event->task->command} --sentry-trace={$traceArgument}";

// We have modified the command string and at this point there is nothing for us to do
// The framework will create a child process and run the command in the background with the new command
// We will pick up the `--sentry-trace` option in the new process and start a new transaction from there
return;
}

// If the command is run in the background we don't want to start a transaction here since it will be useless because the actual work will take place in a different process
if ($event->task->runInBackground) {
return;
}

Expand Down
Loading