diff --git a/README.md b/README.md index 775890a..3c8b368 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ - [Flushing Spans](#flushing-spans) - [Logging Integration](#logging-integration) - [Middleware](#middleware) + - [Console Commands](#console-commands) - [Context Propagation](#context-propagation) - [Custom Drivers](#custom-drivers) - [Writing New Driver](#writing-new-driver) @@ -245,6 +246,21 @@ You can override the default name of the span in the controller: Trace::getRootSpan()->setName('Create Order') ``` +### Console Commands + +If you want to trace select console commands, make them implement `Vinelab\Tracing\Contracts\ShouldBeTraced` interface, indicating that we should start spans for the command. + +The trace will include the following **tags** on a root span: + +- `type` (cli) +- `argv` + +You can override the default name of the span in the command itself: + +```php +Trace::getRootSpan()->setName('Mark Orders Expired') +``` + ### Context Propagation As we talked about previously, the tracer understands how to inject and extract trace context across different applications (services). diff --git a/composer.json b/composer.json index 84ed662..cc91e9e 100644 --- a/composer.json +++ b/composer.json @@ -12,9 +12,10 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", - "illuminate/http": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", - "illuminate/support": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", + "illuminate/console": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", + "illuminate/contracts": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", + "illuminate/http": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", + "illuminate/support": "~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0", "openzipkin/zipkin": "~1.0", "psr/http-message": "~1.0", "ramsey/uuid": "~3.0" diff --git a/src/Contracts/ShouldBeTraced.php b/src/Contracts/ShouldBeTraced.php new file mode 100644 index 0000000..d9e61f0 --- /dev/null +++ b/src/Contracts/ShouldBeTraced.php @@ -0,0 +1,8 @@ +tracer = $tracer; + $this->artisan = $artisan; + } + + /** + * Handle the event. + * + * @param CommandStarting $event + * @return void + */ + public function handle(CommandStarting $event) + { + if ($this->shouldTraceCommand($event->command)) { + $span = $this->tracer->startSpan('Console Command'); + + $span->tag('type', 'cli'); + $span->tag('argv', implode(PHP_EOL, $_SERVER['argv'])); + } + } + + /** + * @param string $command + * @return bool + */ + protected function shouldTraceCommand(string $command): bool + { + /** @var Command $command */ + $command = Arr::get($this->artisan->all(), $command); + + $interfaces = class_implements($command); + + return isset($interfaces[ShouldBeTraced::class]); + } +} diff --git a/src/TracingServiceProvider.php b/src/TracingServiceProvider.php index 4d2764a..a63ffe0 100644 --- a/src/TracingServiceProvider.php +++ b/src/TracingServiceProvider.php @@ -2,9 +2,11 @@ namespace Vinelab\Tracing; +use Illuminate\Console\Events\CommandStarting; use Illuminate\Support\ServiceProvider; use Vinelab\Tracing\Contracts\Tracer; use Vinelab\Tracing\Facades\Trace; +use Vinelab\Tracing\Listeners\TraceCommand; class TracingServiceProvider extends ServiceProvider { @@ -21,6 +23,8 @@ public function boot() ]); } + $this->app['events']->listen(CommandStarting::class, TraceCommand::class); + $this->app->terminating(function () { $rootSpan = Trace::getRootSpan(); diff --git a/tests/Fixtures/ExampleCommand.php b/tests/Fixtures/ExampleCommand.php new file mode 100644 index 0000000..b962658 --- /dev/null +++ b/tests/Fixtures/ExampleCommand.php @@ -0,0 +1,10 @@ +createTracer($reporter); + + $artisan = Mockery::mock(Kernel::class); + $artisan->shouldReceive('all')->andReturn([ + 'example' => new ExampleCommand(), + ]); + + $listener = new TraceCommand($tracer, $artisan); + $listener->handle(new CommandStarting('example', new ArrayInput(['test']), new DummyOutput())); + + $tracer->flush(); + + $reporter->shouldHaveReceived('report')->with(Mockery::on(function ($spans) { + $span = $this->shiftSpan($spans); + + $this->assertEquals('Console Command', Arr::get($span, 'name')); + $this->assertEquals('cli', Arr::get($span, 'tags.type')); + $this->assertContains('phpunit', Arr::get($span, 'tags.argv')); + + return true; + })); + } +} diff --git a/tests/Zipkin/MiddlewareTest.php b/tests/Zipkin/TraceRequestsTest.php similarity index 98% rename from tests/Zipkin/MiddlewareTest.php rename to tests/Zipkin/TraceRequestsTest.php index 60fc1b4..291357d 100644 --- a/tests/Zipkin/MiddlewareTest.php +++ b/tests/Zipkin/TraceRequestsTest.php @@ -11,7 +11,7 @@ use Vinelab\Tracing\Middleware\TraceRequests; use Vinelab\Tracing\Tests\Fixtures\NoopReporter; -class MiddlewareTest extends TestCase +class TraceRequestsTest extends TestCase { use InteractsWithZipkin;