Skip to content

Commit

Permalink
Merge pull request #6 from 090809/feat-injecting-current-span-to-outg…
Browse files Browse the repository at this point in the history
…oing-requests

feat(http-client/injecting): adding 'withTrace' macro for Http Client
  • Loading branch information
freekmurze authored Jan 4, 2023
2 parents 4f8d4f2 + 1110cf7 commit dfe0d25
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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')
```

24 changes: 24 additions & 0 deletions src/Http/Client/Macro.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Spatie\OpenTelemetry\Http\Client;

use Illuminate\Http\Client\PendingRequest;
use Spatie\OpenTelemetry\Facades\Measure as MeasureFacade;
use Spatie\OpenTelemetry\Support\Injectors\TextInjector;

class Macro
{
public static function apply() {
PendingRequest::macro('withTrace', function () {
$headers = [];

if ($span = MeasureFacade::currentSpan()) {
$headers['traceparent'] = "";

TextInjector::Inject($headers['traceparent'], $span);
}

return PendingRequest::withHeaders($headers);
});
}
}
5 changes: 4 additions & 1 deletion src/OpenTelemetryServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
use Spatie\OpenTelemetry\Drivers\Driver;
use Spatie\OpenTelemetry\Drivers\MultiDriver;
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;
Expand Down Expand Up @@ -39,6 +40,8 @@ public function bootingPackage()

$action->execute();
}

HttpClientMacro::apply();
}

protected function getMultiDriver(): MultiDriver
Expand Down
19 changes: 19 additions & 0 deletions src/Support/Injectors/TextInjector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Spatie\OpenTelemetry\Support\Injectors;

use Spatie\OpenTelemetry\Support\Span;

class TextInjector
{
static public function Inject(string &$data, Span $span): void
{
$data = sprintf(
'%s-%s-%s-%02x',
'00',
$span->trace()->id(),
$span->id(),
$span->flags(),
);
}
}
5 changes: 5 additions & 0 deletions src/Support/Measure.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
19 changes: 19 additions & 0 deletions src/Support/Span.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Span

protected string $id;

protected int $flags;

/**
* @var array<string, mixed>
*/
Expand Down Expand Up @@ -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();
Expand Down
52 changes: 52 additions & 0 deletions tests/HttpInjectTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

use Spatie\OpenTelemetry\Facades\Measure;
use Spatie\OpenTelemetry\Support\Injectors\TextInjector;

it('injects current span context name to Laravel HTTP (outgoing) requests', function () {
Http::fake();

$parentSpan = Measure::start('parent');

$parentSpanTraceContextID = "";
TextInjector::Inject($parentSpanTraceContextID, $parentSpan);

Http::withTrace()->post('http://example.com/first');

Http::assertSent(function (\Illuminate\Http\Client\Request $request) use ($parentSpanTraceContextID) {
return $request
->hasHeader('traceparent', $parentSpanTraceContextID);
});

$childSpan = Measure::start('second');
$childSpanTraceContextID = "";
TextInjector::Inject($childSpanTraceContextID, $childSpan);

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');
});

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;
});
});
3 changes: 3 additions & 0 deletions tests/TestSupport/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -32,6 +33,8 @@ protected function setUp(): void

Measure::setDriver($this->memoryDriver);

HttpClientMacro::apply();

FakeIdGenerator::reset();
}

Expand Down

0 comments on commit dfe0d25

Please sign in to comment.