Skip to content

Commit c1595bd

Browse files
committed
feat: Add support for Dynamic Sampling
1 parent 6935650 commit c1595bd

File tree

9 files changed

+124
-2
lines changed

9 files changed

+124
-2
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"jean85/pretty-package-versions": "^1.5 || ^2.0",
2828
"php-http/discovery": "^1.11",
2929
"sentry/sdk": "^3.2",
30+
"sentry/sentry": "^3.9",
3031
"symfony/cache-contracts": "^1.1||^2.4||^3.0",
3132
"symfony/config": "^4.4.20||^5.0.11||^6.0",
3233
"symfony/console": "^4.4.20||^5.0.11||^6.0",

src/EventListener/TracingConsoleListener.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Sentry\Tracing\SpanContext;
1010
use Sentry\Tracing\Transaction;
1111
use Sentry\Tracing\TransactionContext;
12+
use Sentry\Tracing\TransactionSource;
1213
use Symfony\Component\Console\Command\Command;
1314
use Symfony\Component\Console\Event\ConsoleCommandEvent;
1415
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
@@ -61,6 +62,7 @@ public function handleConsoleCommandEvent(ConsoleCommandEvent $event): void
6162
$transactionContext = new TransactionContext();
6263
$transactionContext->setOp('console.command');
6364
$transactionContext->setName($this->getSpanName($command));
65+
$transactionContext->setSource(TransactionSource::task());
6466

6567
$span = $this->hub->startTransaction($transactionContext);
6668
} else {

src/EventListener/TracingRequestListener.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Sentry\Tracing\Transaction;
88
use Sentry\Tracing\TransactionContext;
9+
use Sentry\Tracing\TransactionSource;
910
use Symfony\Component\HttpFoundation\Request;
1011
use Symfony\Component\HttpKernel\Event\RequestEvent;
1112
use Symfony\Component\HttpKernel\Event\TerminateEvent;
@@ -36,9 +37,13 @@ public function handleKernelRequestEvent(RequestEvent $event): void
3637
/** @var float $requestStartTime */
3738
$requestStartTime = $request->server->get('REQUEST_TIME_FLOAT', microtime(true));
3839

39-
$context = TransactionContext::fromSentryTrace($request->headers->get('sentry-trace', ''));
40+
$context = TransactionContext::fromHeaders(
41+
$request->headers->get('sentry-trace', ''),
42+
$request->headers->get('baggage', '')
43+
);
4044
$context->setOp('http.server');
4145
$context->setName(sprintf('%s %s%s%s', $request->getMethod(), $request->getSchemeAndHttpHost(), $request->getBaseUrl(), $request->getPathInfo()));
46+
$context->setSource(TransactionSource::route());
4247
$context->setStartTimestamp($requestStartTime);
4348
$context->setTags($this->getTags($request));
4449

src/Tracing/HttpClient/AbstractTraceableHttpClient.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public function request(string $method, string $url, array $options = []): Respo
4949
if (null !== $parent) {
5050
$headers = $options['headers'] ?? [];
5151
$headers['sentry-trace'] = $parent->toTraceparent();
52+
$headers['baggage'] = $parent->toBaggage();
5253
$options['headers'] = $headers;
5354

5455
$context = new SpanContext();

src/Twig/SentryExtension.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function getFunctions(): array
3030
{
3131
return [
3232
new TwigFunction('sentry_trace_meta', [$this, 'getTraceMeta'], ['is_safe' => ['html']]),
33+
new TwigFunction('sentry_baggage_meta', [$this, 'getBaggageMeta'], ['is_safe' => ['html']]),
3334
];
3435
}
3536

@@ -42,4 +43,14 @@ public function getTraceMeta(): string
4243

4344
return sprintf('<meta name="sentry-trace" content="%s" />', null !== $span ? $span->toTraceparent() : '');
4445
}
46+
47+
/**
48+
* Returns an HTML meta tag named `baggage`.
49+
*/
50+
public function getBaggageMeta(): string
51+
{
52+
$span = $this->hub->getSpan();
53+
54+
return sprintf('<meta name="baggage" content="%s" />', null !== $span ? $span->toBaggage() : '');
55+
}
4556
}

tests/EventListener/TracingConsoleListenerTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Sentry\Tracing\Span;
1313
use Sentry\Tracing\Transaction;
1414
use Sentry\Tracing\TransactionContext;
15+
use Sentry\Tracing\TransactionSource;
1516
use Symfony\Component\Console\Command\Command;
1617
use Symfony\Component\Console\Event\ConsoleCommandEvent;
1718
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
@@ -71,6 +72,7 @@ public function handleConsoleCommandEventStartsTransactionIfNoSpanIsSetOnHubData
7172
$transactionContext = new TransactionContext();
7273
$transactionContext->setOp('console.command');
7374
$transactionContext->setName('<unnamed command>');
75+
$transactionContext->setSource(TransactionSource::task());
7476

7577
yield [
7678
new Command(),
@@ -80,6 +82,7 @@ public function handleConsoleCommandEventStartsTransactionIfNoSpanIsSetOnHubData
8082
$transactionContext = new TransactionContext();
8183
$transactionContext->setOp('console.command');
8284
$transactionContext->setName('app:command');
85+
$transactionContext->setSource(TransactionSource::task());
8386

8487
yield [
8588
new Command('app:command'),

tests/EventListener/TracingRequestListenerTest.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
use Sentry\Options;
1111
use Sentry\SentryBundle\EventListener\TracingRequestListener;
1212
use Sentry\State\HubInterface;
13+
use Sentry\Tracing\DynamicSamplingContext;
1314
use Sentry\Tracing\SpanId;
1415
use Sentry\Tracing\SpanStatus;
1516
use Sentry\Tracing\TraceId;
1617
use Sentry\Tracing\Transaction;
1718
use Sentry\Tracing\TransactionContext;
19+
use Sentry\Tracing\TransactionSource;
1820
use Symfony\Bridge\PhpUnit\ClockMock;
1921
use Symfony\Component\HttpFoundation\Request;
2022
use Symfony\Component\HttpFoundation\Response;
@@ -85,11 +87,15 @@ public function testHandleKernelRequestEvent(Options $options, Request $request,
8587
*/
8688
public function handleKernelRequestEventDataProvider(): \Generator
8789
{
90+
$samplingContext = DynamicSamplingContext::fromHeader('');
91+
$samplingContext->freeze();
92+
8893
$transactionContext = new TransactionContext();
8994
$transactionContext->setTraceId(new TraceId('566e3688a61d4bc888951642d6f14a19'));
9095
$transactionContext->setParentSpanId(new SpanId('566e3688a61d4bc8'));
9196
$transactionContext->setParentSampled(true);
9297
$transactionContext->setName('GET http://www.example.com/');
98+
$transactionContext->setSource(TransactionSource::route());
9399
$transactionContext->setOp('http.server');
94100
$transactionContext->setStartTimestamp(1613493597.010275);
95101
$transactionContext->setTags([
@@ -100,6 +106,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
100106
'route' => '<unknown>',
101107
'net.host.name' => 'www.example.com',
102108
]);
109+
$transactionContext->getMetadata()->setDynamicSamplingContext($samplingContext);
103110

104111
yield 'request.headers.sentry-trace EXISTS' => [
105112
new Options(),
@@ -117,8 +124,47 @@ public function handleKernelRequestEventDataProvider(): \Generator
117124
$transactionContext,
118125
];
119126

127+
$samplingContext = DynamicSamplingContext::fromHeader('sentry-trace_id=566e3688a61d4bc888951642d6f14a19,sentry-public_key=public,sentry-sample_rate=1');
128+
$samplingContext->freeze();
129+
130+
$transactionContext = new TransactionContext();
131+
$transactionContext->setTraceId(new TraceId('566e3688a61d4bc888951642d6f14a19'));
132+
$transactionContext->setParentSpanId(new SpanId('566e3688a61d4bc8'));
133+
$transactionContext->setParentSampled(true);
134+
$transactionContext->setName('GET http://www.example.com/');
135+
$transactionContext->setSource(TransactionSource::route());
136+
$transactionContext->setOp('http.server');
137+
$transactionContext->setStartTimestamp(1613493597.010275);
138+
$transactionContext->setTags([
139+
'net.host.port' => '80',
140+
'http.method' => 'GET',
141+
'http.url' => 'http://www.example.com/',
142+
'http.flavor' => '1.1',
143+
'route' => '<unknown>',
144+
'net.host.name' => 'www.example.com',
145+
]);
146+
$transactionContext->getMetadata()->setDynamicSamplingContext($samplingContext);
147+
148+
yield 'request.headers.sentry-trace and headers.baggage EXISTS' => [
149+
new Options(),
150+
Request::create(
151+
'http://www.example.com',
152+
'GET',
153+
[],
154+
[],
155+
[],
156+
[
157+
'REQUEST_TIME_FLOAT' => 1613493597.010275,
158+
'HTTP_sentry-trace' => '566e3688a61d4bc888951642d6f14a19-566e3688a61d4bc8-1',
159+
'HTTP_baggage' => 'sentry-trace_id=566e3688a61d4bc888951642d6f14a19,sentry-public_key=public,sentry-sample_rate=1',
160+
]
161+
),
162+
$transactionContext,
163+
];
164+
120165
$transactionContext = new TransactionContext();
121166
$transactionContext->setName('GET http://www.example.com/');
167+
$transactionContext->setSource(TransactionSource::route());
122168
$transactionContext->setOp('http.server');
123169
$transactionContext->setStartTimestamp(1613493597.010275);
124170
$transactionContext->setTags([
@@ -141,6 +187,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
141187

142188
$transactionContext = new TransactionContext();
143189
$transactionContext->setName('GET http://127.0.0.1/');
190+
$transactionContext->setSource(TransactionSource::route());
144191
$transactionContext->setOp('http.server');
145192
$transactionContext->setStartTimestamp(1613493597.010275);
146193
$transactionContext->setTags([
@@ -171,6 +218,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
171218

172219
$transactionContext = new TransactionContext();
173220
$transactionContext->setName('GET http://www.example.com/path');
221+
$transactionContext->setSource(TransactionSource::route());
174222
$transactionContext->setOp('http.server');
175223
$transactionContext->setStartTimestamp(1613493597.010275);
176224
$transactionContext->setTags([
@@ -194,6 +242,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
194242

195243
$transactionContext = new TransactionContext();
196244
$transactionContext->setName('GET http://www.example.com/path');
245+
$transactionContext->setSource(TransactionSource::route());
197246
$transactionContext->setOp('http.server');
198247
$transactionContext->setStartTimestamp(1613493597.010275);
199248
$transactionContext->setTags([
@@ -217,6 +266,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
217266

218267
$transactionContext = new TransactionContext();
219268
$transactionContext->setName('GET http://www.example.com/');
269+
$transactionContext->setSource(TransactionSource::route());
220270
$transactionContext->setOp('http.server');
221271
$transactionContext->setStartTimestamp(1613493597.010275);
222272
$transactionContext->setTags([
@@ -240,6 +290,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
240290

241291
$transactionContext = new TransactionContext();
242292
$transactionContext->setName('GET http://www.example.com/');
293+
$transactionContext->setSource(TransactionSource::route());
243294
$transactionContext->setOp('http.server');
244295
$transactionContext->setStartTimestamp(1613493597.010275);
245296
$transactionContext->setTags([
@@ -263,6 +314,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
263314

264315
$transactionContext = new TransactionContext();
265316
$transactionContext->setName('GET http://www.example.com/');
317+
$transactionContext->setSource(TransactionSource::route());
266318
$transactionContext->setOp('http.server');
267319
$transactionContext->setStartTimestamp(1613493597.010275);
268320
$transactionContext->setTags([
@@ -286,6 +338,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
286338

287339
$transactionContext = new TransactionContext();
288340
$transactionContext->setName('GET http://www.example.com/');
341+
$transactionContext->setSource(TransactionSource::route());
289342
$transactionContext->setOp('http.server');
290343
$transactionContext->setStartTimestamp(1613493597.010275);
291344
$transactionContext->setTags([
@@ -309,6 +362,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
309362

310363
$transactionContext = new TransactionContext();
311364
$transactionContext->setName('GET http://www.example.com/');
365+
$transactionContext->setSource(TransactionSource::route());
312366
$transactionContext->setOp('http.server');
313367
$transactionContext->setStartTimestamp(1613493597.010275);
314368
$transactionContext->setTags([
@@ -332,6 +386,7 @@ public function handleKernelRequestEventDataProvider(): \Generator
332386

333387
$transactionContext = new TransactionContext();
334388
$transactionContext->setName('GET http://:/');
389+
$transactionContext->setSource(TransactionSource::route());
335390
$transactionContext->setOp('http.server');
336391
$transactionContext->setStartTimestamp(1613493597.010275);
337392
$transactionContext->setTags([

tests/Tracing/HttpClient/TraceableHttpClientTest.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Sentry\SentryBundle\Tracing\HttpClient\AbstractTraceableResponse;
1212
use Sentry\SentryBundle\Tracing\HttpClient\TraceableHttpClient;
1313
use Sentry\State\HubInterface;
14+
use Sentry\Tracing\DynamicSamplingContext;
1415
use Sentry\Tracing\Transaction;
1516
use Sentry\Tracing\TransactionContext;
1617
use Symfony\Component\HttpClient\MockHttpClient;
@@ -51,7 +52,12 @@ protected function setUp(): void
5152

5253
public function testRequest(): void
5354
{
54-
$transaction = new Transaction(new TransactionContext());
55+
$samplingContext = DynamicSamplingContext::fromHeader('sentry-trace_id=566e3688a61d4bc888951642d6f14a19,sentry-public_key=public,sentry-sample_rate=1');
56+
57+
$transactionContext = new TransactionContext();
58+
$transactionContext->getMetadata()->setDynamicSamplingContext($samplingContext);
59+
60+
$transaction = new Transaction($transactionContext);
5561
$transaction->initSpanRecorder();
5662

5763
$this->hub->expects($this->once())
@@ -68,6 +74,7 @@ public function testRequest(): void
6874
$this->assertSame('GET', $response->getInfo('http_method'));
6975
$this->assertSame('https://www.example.com/test-page', $response->getInfo('url'));
7076
$this->assertSame(['sentry-trace: ' . $transaction->toTraceparent()], $mockResponse->getRequestOptions()['normalized_headers']['sentry-trace']);
77+
$this->assertSame(['baggage: ' . $transaction->toBaggage()], $mockResponse->getRequestOptions()['normalized_headers']['baggage']);
7178
$this->assertNotNull($transaction->getSpanRecorder());
7279

7380
$spans = $transaction->getSpanRecorder()->getSpans();

tests/Twig/SentryExtensionTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPUnit\Framework\TestCase;
99
use Sentry\SentryBundle\Twig\SentryExtension;
1010
use Sentry\State\HubInterface;
11+
use Sentry\Tracing\DynamicSamplingContext;
1112
use Sentry\Tracing\Span;
1213
use Sentry\Tracing\SpanId;
1314
use Sentry\Tracing\TraceId;
@@ -71,6 +72,42 @@ public function traceMetaFunctionDataProvider(): \Generator
7172
];
7273
}
7374

75+
/**
76+
* @dataProvider baggageMetaFunctionDataProvider
77+
*/
78+
public function testBaggageMetaFunction(?Span $span, string $expectedTemplate): void
79+
{
80+
$this->hub->expects($this->once())
81+
->method('getSpan')
82+
->willReturn($span);
83+
84+
$environment = new Environment(new ArrayLoader(['foo.twig' => '{{ sentry_baggage_meta() }}']));
85+
$environment->addExtension(new SentryExtension($this->hub));
86+
87+
$this->assertSame($expectedTemplate, $environment->render('foo.twig'));
88+
}
89+
90+
/**
91+
* @return \Generator<mixed>
92+
*/
93+
public function baggageMetaFunctionDataProvider(): \Generator
94+
{
95+
yield [
96+
null,
97+
'<meta name="baggage" content="" />',
98+
];
99+
100+
$samplingContext = DynamicSamplingContext::fromHeader('sentry-trace_id=566e3688a61d4bc888951642d6f14a19,sentry-public_key=public,sentry-sample_rate=1');
101+
$transactionContext = new TransactionContext();
102+
$transactionContext->getMetadata()->setDynamicSamplingContext($samplingContext);
103+
$transaction = new Transaction($transactionContext);
104+
105+
yield [
106+
$transaction,
107+
'<meta name="baggage" content="sentry-trace_id=566e3688a61d4bc888951642d6f14a19,sentry-public_key=public,sentry-sample_rate=1" />',
108+
];
109+
}
110+
74111
private static function isTwigBundlePackageInstalled(): bool
75112
{
76113
return class_exists(TwigBundle::class);

0 commit comments

Comments
 (0)