Skip to content

Commit 5295efc

Browse files
Laravel: tracing Queues (+ hook refactoring) (#250)
* Laravel: start of QueueWatcher. * Laravel: PR feedback. * Laravel: moved additional attributes from event into span. * Laravel: moved propagation to root of message. Refs: https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/#context-propagation https://w3c.github.io/trace-context-mqtt/#json-payload * Laravel: experimenting with hooking \Illuminate\Contracts\Queue\Queue. * Laravel: added queue context propagation via hook. * Update src/Instrumentation/Laravel/src/Hooks/Queue.php * Laravel: fix post-hook return. Thanks @brettmc * Laravel: message processing on the consumer side. * Laravel: refining queue hooks. * Laravel: removed the QueueWatcher in favour of hook. * Laravel: hook restructuring. * Laravel: moved ServeCommand hook. * Laravel: hook SyncQueue. * Laravel: moved main Application hook. * Laravel: queue cleanup. * Laravel: test queue tracing. * Laravel: SyncQueue hook linting. * Laravel: rebuilt docker image and newer otel-instrumentation fixed this. * Laravel: update QueueTest. * Laravel: hook Queue bulk & later. * Laravel: added estimate delivery_timestamp when passed to Queue->later(). * Laravel: fixing psalm errors. * Laravel: fixing phpstan errors. * Laravel: refactoring QueueTest. * Laravel: added Queue->later tests. * Laravel: fix Queue->later tests. * Laravel: added beanstalk message system detection. * Laravel: added bulk message dispatch test. * Laravel: added redis connection test. * Laravel: record a span if a job is received from the queue. * Laravel: PR feedback to address closing incorrect span. * Laravel: PR feedback - change confusing ClockInterface mock. * Laravel: prefer stable dependencies with lowest package compat. * Laravel: fix dependencies for use with prefer-lowest. * Laravel: fix lowest dependencies. * Laravel: fix watcher PhanTypeArraySuspicious warnings. * Laravel: removed ClockInterface usage to avoid dependency on SDK. * Laravel: more fixes for phan. * Laravel: remove erroneous Context destroy usage. * Laravel: added interface LaravelHook. * Laravel: suppress psalm warning. * Laravel: moved Console/Kernel/Command hooks. * Laravel: export-ignore /.phan. * Laravel: explicitly list support for Laravel versions 6 to 11. * Laravel: moved Http Kernel hooks. * Laravel: consistent test naming. * Laravel: test dropped empty queue receives.
1 parent a0817cf commit 5295efc

30 files changed

+1004
-232
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
/.gitattributes export-ignore
77
/.gitignore export-ignore
8+
/.phan export-ignore
89
/.php-cs-fixer.php export-ignore
910
/phpstan.neon.dist export-ignore
1011
/phpunit.xml.dist export-ignore

.php-cs-fixer.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,3 @@
4040
])
4141
->setRiskyAllowed(true)
4242
->setFinder($finder);
43-

composer.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@
77
"readme": "./README.md",
88
"license": "Apache-2.0",
99
"minimum-stability": "dev",
10+
"prefer-stable": true,
1011
"require": {
1112
"php": "^8.0",
1213
"ext-json": "*",
1314
"ext-opentelemetry": "*",
14-
"laravel/framework": ">=6.0",
15+
"laravel/framework": "^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0",
1516
"open-telemetry/api": "^1.0",
16-
"open-telemetry/sem-conv": "^1.23"
17+
"open-telemetry/sem-conv": "^1.24"
1718
},
1819
"require-dev": {
19-
"friendsofphp/php-cs-fixer": "^3",
20+
"friendsofphp/php-cs-fixer": "^3.50",
2021
"guzzlehttp/guzzle": "*",
21-
"laravel/tinker": "*",
2222
"nunomaduro/collision": "*",
2323
"open-telemetry/sdk": "^1.0",
24-
"orchestra/testbench": ">=4.0",
24+
"orchestra/testbench": ">=7.41.3",
2525
"phan/phan": "^5.0",
2626
"php-http/mock-client": "*",
2727
"phpstan/phpstan": "^1.1",

src/ConsoleInstrumentation.php

Lines changed: 0 additions & 119 deletions
This file was deleted.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\Illuminate\Console;
6+
7+
use Illuminate\Console\Command as IlluminateCommand;
8+
use OpenTelemetry\API\Trace\Span;
9+
use OpenTelemetry\Context\Context;
10+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHook;
11+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHookTrait;
12+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\PostHookTrait;
13+
use function OpenTelemetry\Instrumentation\hook;
14+
use OpenTelemetry\SemConv\TraceAttributes;
15+
use Throwable;
16+
17+
class Command implements LaravelHook
18+
{
19+
use LaravelHookTrait;
20+
use PostHookTrait;
21+
22+
public function instrument(): void
23+
{
24+
$this->hookExecute();
25+
}
26+
27+
protected function hookExecute(): bool
28+
{
29+
return hook(
30+
IlluminateCommand::class,
31+
'execute',
32+
pre: function (IlluminateCommand $command, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
33+
/** @psalm-suppress ArgumentTypeCoercion */
34+
$builder = $this->instrumentation
35+
->tracer()
36+
->spanBuilder(sprintf('Command %s', $command->getName() ?: 'unknown'))
37+
->setAttribute(TraceAttributes::CODE_FUNCTION, $function)
38+
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
39+
->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
40+
->setAttribute(TraceAttributes::CODE_LINENO, $lineno);
41+
42+
$parent = Context::getCurrent();
43+
$span = $builder->startSpan();
44+
Context::storage()->attach($span->storeInContext($parent));
45+
46+
return $params;
47+
},
48+
post: function (IlluminateCommand $command, array $params, ?int $exitCode, ?Throwable $exception) {
49+
$scope = Context::storage()->scope();
50+
if (!$scope) {
51+
return;
52+
}
53+
54+
$span = Span::fromContext($scope->context());
55+
$span->addEvent('command finished', [
56+
'exit-code' => $exitCode,
57+
]);
58+
59+
$this->endSpan($exception);
60+
}
61+
);
62+
}
63+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\Illuminate\Contracts\Console;
6+
7+
use Illuminate\Console\Command;
8+
use Illuminate\Contracts\Console\Kernel as KernelContract;
9+
use OpenTelemetry\API\Trace\Span;
10+
use OpenTelemetry\API\Trace\SpanKind;
11+
use OpenTelemetry\API\Trace\StatusCode;
12+
use OpenTelemetry\Context\Context;
13+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\Illuminate\Queue\AttributesBuilder;
14+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHook;
15+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\LaravelHookTrait;
16+
use OpenTelemetry\Contrib\Instrumentation\Laravel\Hooks\PostHookTrait;
17+
use OpenTelemetry\Contrib\Instrumentation\Laravel\LaravelInstrumentation;
18+
use function OpenTelemetry\Instrumentation\hook;
19+
use OpenTelemetry\SemConv\TraceAttributes;
20+
use Throwable;
21+
22+
class Kernel implements LaravelHook
23+
{
24+
use AttributesBuilder;
25+
use LaravelHookTrait;
26+
use PostHookTrait;
27+
28+
public function instrument(): void
29+
{
30+
if (LaravelInstrumentation::shouldTraceCli()) {
31+
$this->hookHandle();
32+
}
33+
}
34+
35+
private function hookHandle(): bool
36+
{
37+
return hook(
38+
KernelContract::class,
39+
'handle',
40+
pre: function (KernelContract $kernel, array $params, string $class, string $function, ?string $filename, ?int $lineno) {
41+
/** @psalm-suppress ArgumentTypeCoercion */
42+
$builder = $this->instrumentation
43+
->tracer()
44+
->spanBuilder('Artisan handler')
45+
->setSpanKind(SpanKind::KIND_PRODUCER)
46+
->setAttribute(TraceAttributes::CODE_FUNCTION, $function)
47+
->setAttribute(TraceAttributes::CODE_NAMESPACE, $class)
48+
->setAttribute(TraceAttributes::CODE_FILEPATH, $filename)
49+
->setAttribute(TraceAttributes::CODE_LINENO, $lineno);
50+
51+
$parent = Context::getCurrent();
52+
$span = $builder->startSpan();
53+
Context::storage()->attach($span->storeInContext($parent));
54+
55+
return $params;
56+
},
57+
post: function (KernelContract $kernel, array $params, ?int $exitCode, ?Throwable $exception) {
58+
$scope = Context::storage()->scope();
59+
if (!$scope) {
60+
return;
61+
}
62+
63+
$span = Span::fromContext($scope->context());
64+
65+
if ($exitCode !== Command::SUCCESS) {
66+
$span->setStatus(StatusCode::STATUS_ERROR);
67+
}
68+
69+
$this->endSpan($exception);
70+
}
71+
);
72+
}
73+
}

0 commit comments

Comments
 (0)