2 namespace Wikimedia\Tests\Telemetry
;
5 use GuzzleHttp\Handler\MockHandler
;
6 use GuzzleHttp\Psr7\Response
;
7 use MediaWiki\MainConfigNames
;
8 use MediaWikiIntegrationTestCase
;
9 use Wikimedia\Telemetry\Clock
;
10 use Wikimedia\Telemetry\NoopTracer
;
11 use Wikimedia\Telemetry\SpanInterface
;
12 use Wikimedia\Telemetry\Tracer
;
13 use Wikimedia\Telemetry\TracerState
;
16 * @covers \Wikimedia\Telemetry\Tracer
17 * @covers \Wikimedia\Telemetry\OtlpHttpExporter
19 class TelemetryIntegrationTest
extends MediaWikiIntegrationTestCase
{
20 private const EXAMPLE_TRACING_CONFIG
= [
21 'serviceName' => 'test-service',
22 'samplingProbability' => 100,
23 'endpoint' => 'http://198.51.100.42:4318/v1/traces'
26 private const EXAMPLE_TRACING_CONFIG_NO_SAMPLING
= [
27 'serviceName' => 'test-service',
28 'samplingProbability' => 0,
29 'endpoint' => 'http://198.51.100.42:4318/v1/traces'
32 private MockHandler
$handler;
34 protected function setUp(): void
{
37 $this->handler
= new MockHandler();
38 $this->setService( '_TracerHTTPClient', new Client( [
39 'handler' => $this->handler
,
40 'http_errors' => false
44 protected function tearDown(): void
{
46 Clock
::setMockTime( null );
47 TracerState
::destroyInstance();
50 public function testShouldDoNothingWhenTracingDisabled(): void
{
51 $this->overrideConfigValue( MainConfigNames
::OpenTelemetryConfig
, null );
53 $tracer = $this->getServiceContainer()->getTracer();
54 $span = $tracer->createSpan( 'test' )
61 $this->assertInstanceOf( NoopTracer
::class, $tracer );
62 $this->assertNull( $this->handler
->getLastRequest() );
65 public function testShouldDoNothingWhenNotSampled(): void
{
66 $this->overrideConfigValue(
67 MainConfigNames
::OpenTelemetryConfig
,
68 self
::EXAMPLE_TRACING_CONFIG_NO_SAMPLING
71 $tracer = $this->getServiceContainer()->getTracer();
72 $span = $tracer->createRootSpan( 'test' )
76 $child = $tracer->createSpan( 'child' )
85 $this->assertInstanceOf( Tracer
::class, $tracer );
86 $this->assertNull( $this->handler
->getLastRequest() );
89 public function testShouldNotExportDataWhenNoSpansWereCreated(): void
{
90 $this->overrideConfigValue( MainConfigNames
::OpenTelemetryConfig
, self
::EXAMPLE_TRACING_CONFIG
);
92 $tracer = $this->getServiceContainer()->getTracer();
96 $this->assertInstanceOf( Tracer
::class, $tracer );
97 $this->assertNull( $this->handler
->getLastRequest() );
100 public function testShouldNotExportDataWhenTracerWasNotExplicitlyShutdown(): void
{
101 $this->overrideConfigValue( MainConfigNames
::OpenTelemetryConfig
, self
::EXAMPLE_TRACING_CONFIG
);
103 $tracer = $this->getServiceContainer()->getTracer();
104 $span = $tracer->createRootSpan( 'test' )
109 $this->assertInstanceOf( Tracer
::class, $tracer );
110 $this->assertNull( $this->handler
->getLastRequest() );
113 public function testShouldExportDataOnShutdownWhenTracingEnabled(): void
{
114 $this->overrideConfigValue( MainConfigNames
::OpenTelemetryConfig
, self
::EXAMPLE_TRACING_CONFIG
);
115 $this->handler
->append( new Response( 200 ) );
117 $mockTime = 5481675965496;
118 Clock
::setMockTime( $mockTime );
120 $tracer = $this->getServiceContainer()->getTracer();
121 $span = $tracer->createRootSpan( 'test' )
122 ->setSpanKind( SpanInterface
::SPAN_KIND_SERVER
)
128 Clock
::setMockTime( $mockTime );
130 $childSpan = $tracer->createSpan( 'child' )
131 ->setAttributes( [ 'some-key' => 'test', 'ignored' => new \
stdClass() ] )
135 Clock
::setMockTime( $mockTime );
140 Clock
::setMockTime( $mockTime );
142 $span->setSpanStatus( SpanInterface
::SPAN_STATUS_ERROR
);
146 $this->handler
->getLastRequest(),
147 'Exporting trace data should be deferred until the tracer is explicitly shut down'
152 $request = $this->handler
->getLastRequest();
154 $this->assertInstanceOf( Tracer
::class, $tracer );
155 $this->assertSame( 'http://198.51.100.42:4318/v1/traces', (string)$request->getUri() );
156 $this->assertSame( 'application/json', $request->getHeaderLine( 'Content-Type' ) );
158 $expected = file_get_contents( __DIR__
. '/expected-trace-data.json' );
160 $expected = strtr( $expected, [
161 '<TRACE-ID>' => $span->getContext()->getTraceId(),
162 '<SPAN-1-ID>' => $span->getContext()->getSpanId(),
163 '<SPAN-2-ID>' => $childSpan->getContext()->getSpanId(),
164 '<HOST-NAME>' => wfHostname()
167 $this->assertJsonStringEqualsJsonString(
169 (string)$request->getBody()