From d3facad7b50c6d936f3b4ca03267cccd485c6ced Mon Sep 17 00:00:00 2001 From: Timo Michna Date: Sun, 17 Jul 2022 12:46:05 +0200 Subject: [PATCH] Add Span InMemoryExporter (#775) * Add InMemoryExporter --- .../traces/features/exporters/in_memory.php | 43 +++++++++++ src/SDK/Trace/ExporterFactory.php | 3 +- .../Trace/SpanExporter/InMemoryExporter.php | 45 ++++++++++++ tests/Unit/SDK/Trace/ExporterFactoryTest.php | 2 + .../SpanExporter/InMemoryExporterTest.php | 71 +++++++++++++++++++ 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 examples/traces/features/exporters/in_memory.php create mode 100644 src/SDK/Trace/SpanExporter/InMemoryExporter.php create mode 100644 tests/Unit/SDK/Trace/SpanExporter/InMemoryExporterTest.php diff --git a/examples/traces/features/exporters/in_memory.php b/examples/traces/features/exporters/in_memory.php new file mode 100644 index 000000000..e8d247a20 --- /dev/null +++ b/examples/traces/features/exporters/in_memory.php @@ -0,0 +1,43 @@ +getTracer('io.opentelemetry.contrib.php'); + +// This creates a span and sets it as the current parent (and root) span +$rootSpan = $tracer->spanBuilder('foo')->startSpan(); +$rootScope = $rootSpan->activate(); + +// This creates child spans +$childSpan1 = $tracer->spanBuilder('bar')->startSpan(); +$childSpan2 = $tracer->spanBuilder('bar')->startSpan(); + +// This closes all spans +$childSpan2->end(); +$childSpan1->end(); +$rootSpan->end(); + +/** @var SpanDataInterface $span */ +foreach ($storage as $span) { + echo PHP_EOL . sprintf( + 'TRACE: "%s", SPAN: "%s", PARENT: "%s"', + $span->getTraceId(), + $span->getSpanId(), + $span->getParentSpanId() + ); +} +echo PHP_EOL; diff --git a/src/SDK/Trace/ExporterFactory.php b/src/SDK/Trace/ExporterFactory.php index 02da58ce4..882c0e628 100644 --- a/src/SDK/Trace/ExporterFactory.php +++ b/src/SDK/Trace/ExporterFactory.php @@ -18,6 +18,7 @@ class ExporterFactory private const KNOWN_EXPORTERS = [ 'console' => '\OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporter', + 'memory' => '\OpenTelemetry\SDK\Trace\SpanExporter\InMemoryExporter', 'logger+file' => '\OpenTelemetry\SDK\Trace\SpanExporter\LoggerExporter', 'jaeger+http' => '\OpenTelemetry\Contrib\Jaeger\Exporter', 'zipkin+http' => '\OpenTelemetry\Contrib\Zipkin\Exporter', @@ -47,7 +48,7 @@ public function __construct(string $serviceName = self::DEFAULT_SERVICE_NAME) */ public function fromConnectionString(string $connectionString): SpanExporterInterface { - if (in_array($connectionString, ['console', 'otlp+http'])) { + if (in_array($connectionString, ['console', 'memory', 'otlp+http'])) { return self::buildExporter($connectionString); } diff --git a/src/SDK/Trace/SpanExporter/InMemoryExporter.php b/src/SDK/Trace/SpanExporter/InMemoryExporter.php new file mode 100644 index 000000000..c9874a439 --- /dev/null +++ b/src/SDK/Trace/SpanExporter/InMemoryExporter.php @@ -0,0 +1,45 @@ +storage = $storage ?? new ArrayObject(); + } + + public static function fromConnectionString(string $endpointUrl = null, string $name = null, $args = null) + { + return new self(); + } + + protected function doExport(iterable $spans): int + { + foreach ($spans as $span) { + $this->storage[] = $span; + } + + return SpanExporterInterface::STATUS_SUCCESS; + } + + public function getSpans(): array + { + return (array) $this->storage; + } + + public function getStorage(): ArrayObject + { + return $this->storage; + } +} diff --git a/tests/Unit/SDK/Trace/ExporterFactoryTest.php b/tests/Unit/SDK/Trace/ExporterFactoryTest.php index 4ca430cce..1d153c810 100644 --- a/tests/Unit/SDK/Trace/ExporterFactoryTest.php +++ b/tests/Unit/SDK/Trace/ExporterFactoryTest.php @@ -11,6 +11,7 @@ use OpenTelemetry\Contrib; use OpenTelemetry\SDK\Trace\ExporterFactory; use OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporter; +use OpenTelemetry\SDK\Trace\SpanExporter\InMemoryExporter; use PHPUnit\Framework\TestCase; /** @@ -50,6 +51,7 @@ public function endpointProvider(): array 'otlp+grpc' => ['test.otlpgrpc', 'otlp+grpc://otlp:4317', Contrib\OtlpGrpc\Exporter::class], 'zipkintonewrelic' => ['test.zipkintonewrelic', 'zipkintonewrelic+https://trace-api.newrelic.com/trace/v1?licenseKey=abc23423423', Contrib\ZipkinToNewrelic\Exporter::class], 'console' => ['test.console', 'console', ConsoleSpanExporter::class], + 'memory' => ['test.memory', 'memory', InMemoryExporter::class], ]; } diff --git a/tests/Unit/SDK/Trace/SpanExporter/InMemoryExporterTest.php b/tests/Unit/SDK/Trace/SpanExporter/InMemoryExporterTest.php new file mode 100644 index 000000000..94abbab10 --- /dev/null +++ b/tests/Unit/SDK/Trace/SpanExporter/InMemoryExporterTest.php @@ -0,0 +1,71 @@ +export($spans); + + $this->assertSame( + $spans, + $instance->getSpans() + ); + } + + public function test_from_connection_string(): void + { + $this->assertInstanceOf( + InMemoryExporter::class, + InMemoryExporter::fromConnectionString() + ); + } + + public function test_get_storage(): void + { + $storage = new ArrayObject(); + + $this->assertSame( + $storage, + (new InMemoryExporter($storage))->getStorage() + ); + } + + public function test_get_spans(): void + { + $storage = new ArrayObject(); + + $this->assertSame( + (array) $storage, + (new InMemoryExporter($storage))->getSpans() + ); + } + + public function provideSpans(): Generator + { + $spans = []; + + for ($x = 0; $x < 3; $x++) { + $spans[] = $this->createMock(SpanDataInterface::class); + + yield $x => [$spans]; + } + } +}