From 26e3fd51ead0511e14a7efb18a335fb869274013 Mon Sep 17 00:00:00 2001 From: pallam Date: Tue, 29 Nov 2022 04:45:40 +0300 Subject: [PATCH 1/4] feat(http-client/injecting): adding 'withTrace' macro for Http Client injection of current span context id --- ...> continuing-traces-with-other-systems.md} | 15 +++++++- src/Http/Client/Macro.php | 17 +++++++++ src/OpenTelemetryServiceProvider.php | 3 ++ src/Support/Measure.php | 5 +++ src/Support/Span.php | 11 ++++++ tests/HttpInjectTest.php | 36 +++++++++++++++++++ tests/TestSupport/TestCase.php | 3 ++ 7 files changed, 89 insertions(+), 1 deletion(-) rename docs/advanced-usage/{continuing-traces-from-other-sytems.md => continuing-traces-with-other-systems.md} (66%) create mode 100644 src/Http/Client/Macro.php create mode 100644 tests/HttpInjectTest.php diff --git a/docs/advanced-usage/continuing-traces-from-other-sytems.md b/docs/advanced-usage/continuing-traces-with-other-systems.md similarity index 66% rename from docs/advanced-usage/continuing-traces-from-other-sytems.md rename to docs/advanced-usage/continuing-traces-with-other-systems.md index 8903025..ccb669e 100644 --- a/docs/advanced-usage/continuing-traces-from-other-sytems.md +++ b/docs/advanced-usage/continuing-traces-with-other-systems.md @@ -1,8 +1,10 @@ --- -title: Continuing traces from other systems +title: Continuing tracing with other systems weight: 2 --- +## From other system + If your Laravel app is used in a bigger system, where one of the other apps started a trace, your Laravel app might get called by that other apps with [a `traceparent` header](https://uptrace.dev/opentelemetry/opentelemetry-traceparent.html). This header contains the id of trace that was started. To have all measurements you take use that trace id from the header, you can use the `ContinueTrace` middleware. This middleware will look for incoming requests that have a `traceparent` header and use the given trace id. @@ -24,4 +26,15 @@ class Kernel extends HttpKernel } ``` +## To other system + +In another case, if your Laravel app calls other systems, you can inject `traceparent` HTTP Header onto the outgoing request, by calling macro `withTrace` in HTTP Facade. + +It automatically adds current span context id to HTTP header for your outgoing request. + +```php +use Http; + +Http::withTrace()->post('https://example.com') +``` diff --git a/src/Http/Client/Macro.php b/src/Http/Client/Macro.php new file mode 100644 index 0000000..870abf7 --- /dev/null +++ b/src/Http/Client/Macro.php @@ -0,0 +1,17 @@ + MeasureFacade::currentSpan()->toTraceContextID(), + ]); + }); + } +} diff --git a/src/OpenTelemetryServiceProvider.php b/src/OpenTelemetryServiceProvider.php index 9e06741..30fb92d 100644 --- a/src/OpenTelemetryServiceProvider.php +++ b/src/OpenTelemetryServiceProvider.php @@ -6,6 +6,7 @@ use Spatie\LaravelPackageTools\PackageServiceProvider; use Spatie\OpenTelemetry\Drivers\Driver; use Spatie\OpenTelemetry\Drivers\Multidriver; +use Spatie\OpenTelemetry\Http\Client\Macro as HttpClientMacro; use Spatie\OpenTelemetry\Support\IdGenerator; use Spatie\OpenTelemetry\Support\Measure; use Spatie\OpenTelemetry\Support\Samplers\Sampler; @@ -39,6 +40,8 @@ public function bootingPackage() $action->execute(); } + + HttpClientMacro::apply(); } protected function getMultiDriver(): Multidriver diff --git a/src/Support/Measure.php b/src/Support/Measure.php index 1ebf7df..36eb615 100644 --- a/src/Support/Measure.php +++ b/src/Support/Measure.php @@ -107,6 +107,11 @@ public function getSpan(string $name): ?Span return $this->startedSpans[$name] ?? null; } + public function currentSpan(): ?Span + { + return $this->parentSpan; + } + public function startedSpanNames(): array { return array_keys($this->startedSpans); diff --git a/src/Support/Span.php b/src/Support/Span.php index cd3eb36..82c7064 100644 --- a/src/Support/Span.php +++ b/src/Support/Span.php @@ -69,6 +69,17 @@ public function getTags(): array ); } + public function toTraceContextID(): string + { + return sprintf( + '%s-%s-%s-%s', + '00', // version + $this->trace->id(), // trace id + $this->id, // span id + '01' // flags - https://www.w3.org/TR/trace-context/#trace-flags; 01 - Should be traced in next application + ); + } + public function toArray(): array { return [ diff --git a/tests/HttpInjectTest.php b/tests/HttpInjectTest.php new file mode 100644 index 0000000..0c32979 --- /dev/null +++ b/tests/HttpInjectTest.php @@ -0,0 +1,36 @@ +toTraceContextID(); + + Http::withTrace()->post('http://example.com/first'); + + Http::assertSent(function (\Illuminate\Http\Client\Request $request) use ($parentSpanTraceContextID) { + return $request + ->hasHeader('traceparent', $parentSpanTraceContextID); + }); + + $childSpanTraceContextID = Measure::start('second')->toTraceContextID(); + + Http::withTrace()->post('http://example.com/second'); + + Http::assertSent(function (\Illuminate\Http\Client\Request $request) use ($childSpanTraceContextID) { + return $request + ->hasHeader('traceparent', $childSpanTraceContextID); + }); + + Measure::stop('second'); + + Http::withTrace()->post('http://example.com/third'); + + Http::assertSent(function (\Illuminate\Http\Client\Request $request) use ($parentSpanTraceContextID) { + return $request + ->hasHeader('traceparent', $parentSpanTraceContextID); + }); + + Measure::stop('first'); +}); diff --git a/tests/TestSupport/TestCase.php b/tests/TestSupport/TestCase.php index c85ffb6..70b13d3 100644 --- a/tests/TestSupport/TestCase.php +++ b/tests/TestSupport/TestCase.php @@ -5,6 +5,7 @@ use Orchestra\Testbench\TestCase as Orchestra; use Spatie\OpenTelemetry\Drivers\MemoryDriver; use Spatie\OpenTelemetry\Facades\Measure; +use Spatie\OpenTelemetry\Http\Client\Macro as HttpClientMacro; use Spatie\OpenTelemetry\OpenTelemetryServiceProvider; use Spatie\OpenTelemetry\Support\IdGenerator; use Spatie\OpenTelemetry\Support\Samplers\AlwaysSampler; @@ -32,6 +33,8 @@ protected function setUp(): void Measure::setDriver($this->memoryDriver); + HttpClientMacro::apply(); + FakeIdGenerator::reset(); } From 7481a31651f0d64e7b1dec56c77a139c04bcc0ee Mon Sep 17 00:00:00 2001 From: pallam Date: Tue, 29 Nov 2022 05:05:01 +0300 Subject: [PATCH 2/4] fix(http-client/injecting): it must not fall if no spans present --- src/Http/Client/Macro.php | 10 +++++++--- tests/HttpInjectTest.php | 10 ++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Http/Client/Macro.php b/src/Http/Client/Macro.php index 870abf7..8fc5d0e 100644 --- a/src/Http/Client/Macro.php +++ b/src/Http/Client/Macro.php @@ -9,9 +9,13 @@ class Macro { public static function apply() { PendingRequest::macro('withTrace', function () { - return PendingRequest::withHeaders([ - 'traceparent' => MeasureFacade::currentSpan()->toTraceContextID(), - ]); + $headers = []; + + if ($traceContextID = MeasureFacade::currentSpan()?->toTraceContextID()) { + $headers['traceparent'] = $traceContextID; + } + + return PendingRequest::withHeaders($headers); }); } } diff --git a/tests/HttpInjectTest.php b/tests/HttpInjectTest.php index 0c32979..1fb6380 100644 --- a/tests/HttpInjectTest.php +++ b/tests/HttpInjectTest.php @@ -34,3 +34,13 @@ Measure::stop('first'); }); + +it('wil not fall, if no spans present', function () { + Http::fake(); + + Http::withTrace()->post('http://example.com/first'); + + Http::assertSent(function (\Illuminate\Http\Client\Request $request) { + return true; + }); +}); From 728e34e6a25381005e9f4a187a1b93613393f6d3 Mon Sep 17 00:00:00 2001 From: pallam Date: Sun, 1 Jan 2023 21:18:07 +0300 Subject: [PATCH 3/4] feat(injection): rewrite injection mechanism --- config/open-telemetry.php | 12 ++++++++ .../continuing-traces-with-other-systems.md | 16 ++++++++++ src/Http/Client/Macro.php | 5 ++-- src/Support/Injectors/ArrayInjector.php | 17 +++++++++++ src/Support/Injectors/TextInjector.php | 19 ++++++++++++ src/Support/Span.php | 30 ++++++++++++------- tests/HttpInjectTest.php | 10 +++++-- 7 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 src/Support/Injectors/ArrayInjector.php create mode 100644 src/Support/Injectors/TextInjector.php diff --git a/config/open-telemetry.php b/config/open-telemetry.php index 56c20a4..0cee8e2 100644 --- a/config/open-telemetry.php +++ b/config/open-telemetry.php @@ -94,4 +94,16 @@ * This class generates ids for both traces and spans. */ 'id_generator' => Spatie\OpenTelemetry\Support\IdGenerator::class, + + /* + * Injectors configure, how span will be injected into other structures + */ + 'injectors' => [ + /* + * Array Injector often be used for configuration of outgoing http requests. + */ + 'array' => [ + 'key' => 'traceparent' + ] + ] ]; diff --git a/docs/advanced-usage/continuing-traces-with-other-systems.md b/docs/advanced-usage/continuing-traces-with-other-systems.md index ccb669e..4ba3d89 100644 --- a/docs/advanced-usage/continuing-traces-with-other-systems.md +++ b/docs/advanced-usage/continuing-traces-with-other-systems.md @@ -38,3 +38,19 @@ use Http; Http::withTrace()->post('https://example.com') ``` +There has variants for header injection, with configuring config: + +```php +/* + * Injectors configure, how span will be injected into other structures + */ +'injectors' => [ + /* + * Array Injector often be used for configuration of outgoing http requests. + */ + 'array' => [ + 'key' => 'traceparent' + ] +] +``` + diff --git a/src/Http/Client/Macro.php b/src/Http/Client/Macro.php index 8fc5d0e..daaaf2c 100644 --- a/src/Http/Client/Macro.php +++ b/src/Http/Client/Macro.php @@ -4,6 +4,7 @@ use Illuminate\Http\Client\PendingRequest; use Spatie\OpenTelemetry\Facades\Measure as MeasureFacade; +use Spatie\OpenTelemetry\Support\Injectors\ArrayInjector; class Macro { @@ -11,8 +12,8 @@ public static function apply() { PendingRequest::macro('withTrace', function () { $headers = []; - if ($traceContextID = MeasureFacade::currentSpan()?->toTraceContextID()) { - $headers['traceparent'] = $traceContextID; + if ($span = MeasureFacade::currentSpan()) { + ArrayInjector::Inject($headers, $span); } return PendingRequest::withHeaders($headers); diff --git a/src/Support/Injectors/ArrayInjector.php b/src/Support/Injectors/ArrayInjector.php new file mode 100644 index 0000000..264e14f --- /dev/null +++ b/src/Support/Injectors/ArrayInjector.php @@ -0,0 +1,17 @@ +trace()->id(), + $span->id(), + $span->flags(), + ); + } +} diff --git a/src/Support/Span.php b/src/Support/Span.php index 82c7064..06cefce 100644 --- a/src/Support/Span.php +++ b/src/Support/Span.php @@ -10,6 +10,8 @@ class Span protected string $id; + protected int $flags; + /** * @var array */ @@ -47,6 +49,23 @@ public function parentSpan(): ?Span return $this->parentSpan; } + public function trace(): ?Trace + { + return $this->trace; + } + + public function flags(): int + { + /** + * TODO: flags MUST be propagated from Measure Lottery or Parent span when new span created. + * By design, all spans, that have 0x00 flag (DEFAULT) - running lottery for trace + * And all 0x01 flags (SPAN_TRACED) MUST be sampled, without any lottery, + * If not, it will be an useless traces with "clear windows" + * + */ + return 0x01; + } + public function stop(): self { $this->stopWatch->stop(); @@ -69,17 +88,6 @@ public function getTags(): array ); } - public function toTraceContextID(): string - { - return sprintf( - '%s-%s-%s-%s', - '00', // version - $this->trace->id(), // trace id - $this->id, // span id - '01' // flags - https://www.w3.org/TR/trace-context/#trace-flags; 01 - Should be traced in next application - ); - } - public function toArray(): array { return [ diff --git a/tests/HttpInjectTest.php b/tests/HttpInjectTest.php index 1fb6380..c1bd6ae 100644 --- a/tests/HttpInjectTest.php +++ b/tests/HttpInjectTest.php @@ -1,11 +1,15 @@ toTraceContextID(); + $parentSpan = Measure::start('parent'); + + $parentSpanTraceContextID = ""; + TextInjector::Inject($parentSpanTraceContextID, $parentSpan); Http::withTrace()->post('http://example.com/first'); @@ -14,7 +18,9 @@ ->hasHeader('traceparent', $parentSpanTraceContextID); }); - $childSpanTraceContextID = Measure::start('second')->toTraceContextID(); + $childSpan = Measure::start('second'); + $childSpanTraceContextID = ""; + TextInjector::Inject($childSpanTraceContextID, $childSpan); Http::withTrace()->post('http://example.com/second'); From 1110cf7cdb44f6bfd0be601f49c5f7688777449c Mon Sep 17 00:00:00 2001 From: pallam Date: Wed, 4 Jan 2023 12:34:32 +0300 Subject: [PATCH 4/4] fix(injection): simplified injection mechanism --- config/open-telemetry.php | 12 ------------ .../continuing-traces-with-other-systems.md | 16 ---------------- src/Http/Client/Macro.php | 6 ++++-- src/Support/Injectors/ArrayInjector.php | 17 ----------------- 4 files changed, 4 insertions(+), 47 deletions(-) delete mode 100644 src/Support/Injectors/ArrayInjector.php diff --git a/config/open-telemetry.php b/config/open-telemetry.php index 0cee8e2..56c20a4 100644 --- a/config/open-telemetry.php +++ b/config/open-telemetry.php @@ -94,16 +94,4 @@ * This class generates ids for both traces and spans. */ 'id_generator' => Spatie\OpenTelemetry\Support\IdGenerator::class, - - /* - * Injectors configure, how span will be injected into other structures - */ - 'injectors' => [ - /* - * Array Injector often be used for configuration of outgoing http requests. - */ - 'array' => [ - 'key' => 'traceparent' - ] - ] ]; diff --git a/docs/advanced-usage/continuing-traces-with-other-systems.md b/docs/advanced-usage/continuing-traces-with-other-systems.md index 4ba3d89..ccb669e 100644 --- a/docs/advanced-usage/continuing-traces-with-other-systems.md +++ b/docs/advanced-usage/continuing-traces-with-other-systems.md @@ -38,19 +38,3 @@ use Http; Http::withTrace()->post('https://example.com') ``` -There has variants for header injection, with configuring config: - -```php -/* - * Injectors configure, how span will be injected into other structures - */ -'injectors' => [ - /* - * Array Injector often be used for configuration of outgoing http requests. - */ - 'array' => [ - 'key' => 'traceparent' - ] -] -``` - diff --git a/src/Http/Client/Macro.php b/src/Http/Client/Macro.php index daaaf2c..7b605a2 100644 --- a/src/Http/Client/Macro.php +++ b/src/Http/Client/Macro.php @@ -4,7 +4,7 @@ use Illuminate\Http\Client\PendingRequest; use Spatie\OpenTelemetry\Facades\Measure as MeasureFacade; -use Spatie\OpenTelemetry\Support\Injectors\ArrayInjector; +use Spatie\OpenTelemetry\Support\Injectors\TextInjector; class Macro { @@ -13,7 +13,9 @@ public static function apply() { $headers = []; if ($span = MeasureFacade::currentSpan()) { - ArrayInjector::Inject($headers, $span); + $headers['traceparent'] = ""; + + TextInjector::Inject($headers['traceparent'], $span); } return PendingRequest::withHeaders($headers); diff --git a/src/Support/Injectors/ArrayInjector.php b/src/Support/Injectors/ArrayInjector.php deleted file mode 100644 index 264e14f..0000000 --- a/src/Support/Injectors/ArrayInjector.php +++ /dev/null @@ -1,17 +0,0 @@ -