diff --git a/examples/autoload_sdk.php b/examples/autoload_sdk.php index dd5091359..9043bca29 100644 --- a/examples/autoload_sdk.php +++ b/examples/autoload_sdk.php @@ -4,9 +4,6 @@ namespace OpenTelemetry\Example; -use OpenTelemetry\API\Logs\EventLogger; -use OpenTelemetry\API\Logs\LogRecord; - putenv('OTEL_PHP_AUTOLOAD_ENABLED=true'); putenv('OTEL_TRACES_EXPORTER=otlp'); putenv('OTEL_METRICS_EXPORTER=otlp'); @@ -24,8 +21,6 @@ $instrumentation->tracer()->spanBuilder('root')->startSpan()->end(); $instrumentation->meter()->createCounter('cnt')->add(1); - -$eventLogger = new EventLogger($instrumentation->logger(), 'my-domain'); -$eventLogger->logEvent('foo', new LogRecord('hello, otel')); +$instrumentation->eventLogger()->emit('foo', 'hello, otel'); echo 'Finished!' . PHP_EOL; diff --git a/examples/load_config.php b/examples/load_config.php index 591f3f583..874159bc3 100644 --- a/examples/load_config.php +++ b/examples/load_config.php @@ -2,8 +2,6 @@ declare(strict_types=1); -use OpenTelemetry\API\Logs\EventLogger; -use OpenTelemetry\API\Logs\LogRecord; use OpenTelemetry\Config\SDK\Configuration; require __DIR__ . '/../vendor/autoload.php'; @@ -18,12 +16,14 @@ $tracer = $sdk->getTracerProvider()->getTracer('demo'); $meter = $sdk->getMeterProvider()->getMeter('demo'); -$logger = $sdk->getLoggerProvider()->getLogger('demo'); +$eventLogger = $sdk->getEventLoggerProvider()->getEventLogger('demo'); -$tracer->spanBuilder('root')->startSpan()->end(); +$span = $tracer->spanBuilder('root')->startSpan(); +$scope = $span->activate(); $meter->createCounter('cnt')->add(1); -$eventLogger = new EventLogger($logger, 'my-domain'); -$eventLogger->logEvent('foo', new LogRecord('hello, otel')); +$eventLogger->emit('foo', 'hello, otel'); +$scope->detach(); +$span->end(); echo 'Finished!' . PHP_EOL; diff --git a/examples/load_config_env.php b/examples/load_config_env.php index 6fa447949..1c90d2683 100644 --- a/examples/load_config_env.php +++ b/examples/load_config_env.php @@ -2,8 +2,6 @@ declare(strict_types=1); -use OpenTelemetry\API\Logs\EventLogger; -use OpenTelemetry\API\Logs\LogRecord; use OpenTelemetry\Config\SDK\Configuration; require __DIR__ . '/../vendor/autoload.php'; @@ -23,12 +21,10 @@ $tracer = $sdk->getTracerProvider()->getTracer('demo'); $meter = $sdk->getMeterProvider()->getMeter('demo'); -$logger = $sdk->getLoggerProvider()->getLogger('demo'); +$eventLogger = $sdk->getEventLoggerProvider()->getEventLogger('demo'); $tracer->spanBuilder('root')->startSpan()->end(); $meter->createCounter('cnt')->add(1); - -$eventLogger = new EventLogger($logger, 'my-domain'); -$eventLogger->logEvent('foo', new LogRecord('hello, otel')); +$eventLogger->emit('foo', 'hello, otel'); echo 'Finished!' . PHP_EOL; diff --git a/examples/logs/exporters/otlp_grpc.php b/examples/logs/exporters/otlp_grpc.php index 93f76c885..26d787b14 100644 --- a/examples/logs/exporters/otlp_grpc.php +++ b/examples/logs/exporters/otlp_grpc.php @@ -5,14 +5,13 @@ namespace OpenTelemetry\Example; use OpenTelemetry\API\Common\Time\Clock; -use OpenTelemetry\API\Logs\EventLogger; -use OpenTelemetry\API\Logs\LogRecord; +use OpenTelemetry\API\Logs\Severity; use OpenTelemetry\API\Signals; use OpenTelemetry\Contrib\Grpc\GrpcTransportFactory; use OpenTelemetry\Contrib\Otlp\LogsExporter; use OpenTelemetry\Contrib\Otlp\OtlpUtil; -use Opentelemetry\Proto\Logs\V1\SeverityNumber; use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Logs\EventLoggerProvider; use OpenTelemetry\SDK\Logs\LoggerProvider; use OpenTelemetry\SDK\Logs\LogRecordLimitsBuilder; use OpenTelemetry\SDK\Logs\Processor\BatchLogRecordProcessor; @@ -30,19 +29,18 @@ (new LogRecordLimitsBuilder())->build()->getAttributeFactory() ) ); -$logger = $loggerProvider->getLogger('demo', '1.0', 'http://schema.url', ['foo' => 'bar']); -$eventLogger = new EventLogger($logger, 'my-domain'); - -$eventLogger->logEvent( - 'foo', - (new LogRecord(['foo' => 'bar', 'baz' => 'bat', 'msg' => 'hello world'])) - ->setSeverityText('INFO') - ->setSeverityNumber(SeverityNumber::SEVERITY_NUMBER_INFO) +$eventLoggerProvider = new EventLoggerProvider($loggerProvider); +$eventLogger = $eventLoggerProvider->getEventLogger('demo', '1.0', 'http://schema.url', ['foo' => 'bar']); + +$eventLogger->emit( + name: 'foo', + payload: ['foo' => 'bar', 'baz' => 'bat', 'msg' => 'hello world'], + severityNumber: Severity::INFO ); -$eventLogger->logEvent( - 'foo', - new LogRecord('otel is great') +$eventLogger->emit( + 'bar', + 'otel is great' ); $loggerProvider->shutdown(); diff --git a/examples/logs/exporters/otlp_http.php b/examples/logs/exporters/otlp_http.php index 42f41040c..e575ce233 100644 --- a/examples/logs/exporters/otlp_http.php +++ b/examples/logs/exporters/otlp_http.php @@ -4,12 +4,12 @@ namespace OpenTelemetry\Example; -use OpenTelemetry\API\Logs\EventLogger; use OpenTelemetry\API\Logs\LogRecord; +use OpenTelemetry\API\Logs\Severity; use OpenTelemetry\Contrib\Otlp\LogsExporter; use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory; -use Opentelemetry\Proto\Logs\V1\SeverityNumber; use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Logs\EventLoggerProvider; use OpenTelemetry\SDK\Logs\LoggerProvider; use OpenTelemetry\SDK\Logs\LogRecordLimitsBuilder; use OpenTelemetry\SDK\Logs\Processor\SimpleLogRecordProcessor; @@ -27,12 +27,12 @@ (new LogRecordLimitsBuilder())->build()->getAttributeFactory() ) ); -$logger = $loggerProvider->getLogger('demo', '1.0', 'https://opentelemetry.io/schemas/1.7.1', ['foo' => 'bar']); -$eventLogger = new EventLogger($logger, 'my-domain'); - -$record = (new LogRecord(['foo' => 'bar', 'baz' => 'bat', 'msg' => 'hello world'])) - ->setSeverityText('INFO') - ->setTimestamp((new \DateTime())->getTimestamp() * LogRecord::NANOS_PER_SECOND) - ->setSeverityNumber(SeverityNumber::SEVERITY_NUMBER_INFO); - -$eventLogger->logEvent('foo', $record); +$eventLoggerProvider = new EventLoggerProvider($loggerProvider); +$eventLogger = $eventLoggerProvider->getEventLogger('demo', '1.0', 'https://opentelemetry.io/schemas/1.7.1', ['foo' => 'bar']); + +$eventLogger->emit( + name: 'foo', + payload: ['foo' => 'bar', 'baz' => 'bat', 'msg' => 'hello world'], + timestamp: (new \DateTime())->getTimestamp() * LogRecord::NANOS_PER_SECOND, + severityNumber: Severity::INFO, +); diff --git a/examples/logs/features/batch_exporting.php b/examples/logs/features/batch_exporting.php index 831c628d0..46a6c30e6 100644 --- a/examples/logs/features/batch_exporting.php +++ b/examples/logs/features/batch_exporting.php @@ -5,10 +5,11 @@ namespace OpenTelemetry\Example; use OpenTelemetry\API\Common\Time\Clock; -use OpenTelemetry\API\Logs\EventLogger; -use OpenTelemetry\API\Logs\LogRecord; +use OpenTelemetry\API\Logs\Severity; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Logs\EventLogger; +use OpenTelemetry\SDK\Logs\EventLoggerProvider; use OpenTelemetry\SDK\Logs\Exporter\ConsoleExporterFactory; use OpenTelemetry\SDK\Logs\LoggerProvider; use OpenTelemetry\SDK\Logs\Processor\BatchLogRecordProcessor; @@ -22,19 +23,16 @@ ), new InstrumentationScopeFactory(Attributes::factory()) ); +$eventLoggerProvider = new EventLoggerProvider($loggerProvider); //get a logger, and emit a log record from an EventLogger. -$loggerOne = $loggerProvider->getLogger('demo', '1.0'); -$loggerTwo = $loggerProvider->getLogger('demo', '2.0'); -$eventLoggerOne = new EventLogger($loggerOne, 'my-domain'); -$eventLoggerTwo = new EventLogger($loggerTwo, 'my-domain'); - -$record = (new LogRecord(['foo' => 'bar', 'baz' => 'bat', 'msg' => 'hello world'])) - ->setSeverityText('INFO') - ->setSeverityNumber(9); - -$eventLoggerOne->logEvent('foo', $record); -$eventLoggerOne->logEvent('bar', (new LogRecord('hello world'))); -$eventLoggerTwo->logEvent('foo', $record); +$eventLoggerOne = $eventLoggerProvider->getEventLogger('demo', '1.0'); +$eventLoggerTwo = $eventLoggerProvider->getEventLogger('demo', '2.0'); + +$payload = ['foo' => 'bar', 'baz' => 'bat', 'msg' => 'hello world']; + +$eventLoggerOne->emit(name: 'foo', payload: $payload, severityNumber: Severity::INFO); +$eventLoggerOne->emit('bar', 'hello world'); +$eventLoggerTwo->emit(name: 'foo', payload: $payload, severityNumber: Severity::INFO); //shut down logger provider $loggerProvider->shutdown(); diff --git a/examples/logs/getting_started.php b/examples/logs/getting_started.php index b6033a502..b929cfaa0 100644 --- a/examples/logs/getting_started.php +++ b/examples/logs/getting_started.php @@ -2,10 +2,10 @@ declare(strict_types=1); -use OpenTelemetry\API\Logs\EventLogger; -use OpenTelemetry\API\Logs\LogRecord; +use OpenTelemetry\API\Logs\Severity; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Logs\EventLoggerProvider; use OpenTelemetry\SDK\Logs\Exporter\ConsoleExporterFactory; use OpenTelemetry\SDK\Logs\LoggerProvider; use OpenTelemetry\SDK\Logs\Processor\SimpleLogRecordProcessor; @@ -26,6 +26,7 @@ ), new InstrumentationScopeFactory(Attributes::factory()) ); +$eventLoggerProvider = new EventLoggerProvider($loggerProvider); $tracerProvider = new TracerProvider(); $tracer = $tracerProvider->getTracer('demo-tracer'); @@ -35,16 +36,12 @@ echo 'Trace id: ' . $span->getContext()->getTraceId() . PHP_EOL; echo 'Span id: ' . $span->getContext()->getSpanId() . PHP_EOL; -//get a logger, and emit a log record from an EventLogger. The active context (trace id + span id) will be +//get an event logger, and emit an event. The active context (trace id + span id) will be //attached to the log record -$logger = $loggerProvider->getLogger('demo', '1.0', 'http://schema.url', ['foo' => 'bar']); -$eventLogger = new EventLogger($logger, 'my-domain'); +$eventLogger = $eventLoggerProvider->getEventLogger('demo', '1.0', 'http://schema.url', ['foo' => 'bar']); +$payload = ['foo' => 'bar', 'baz' => 'bat', 'msg' => 'hello world']; -$record = (new LogRecord(['foo' => 'bar', 'baz' => 'bat', 'msg' => 'hello world'])) - ->setSeverityText('INFO') - ->setSeverityNumber(9); - -$eventLogger->logEvent('foo', $record); +$eventLogger->emit(name: 'foo', payload: $payload, severityNumber: Severity::INFO); //end span $span->end(); diff --git a/examples/logs/logger_builder.php b/examples/logs/logger_builder.php index 6b0b0cfaa..0c368e35e 100644 --- a/examples/logs/logger_builder.php +++ b/examples/logs/logger_builder.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use OpenTelemetry\API\Logs\EventLogger; use OpenTelemetry\API\Logs\LogRecord; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Logs\Exporter\ConsoleExporterFactory; @@ -22,11 +21,14 @@ ->build(); $logger = $loggerProvider->getLogger('demo', '1.0', 'http://schema.url', ['foo' => 'bar']); -$eventLogger = new EventLogger($logger, 'my-domain'); $record = (new LogRecord(['foo' => 'bar', 'baz' => 'bat', 'msg' => 'hello world'])) ->setSeverityText('INFO') ->setSeverityNumber(9); -$eventLogger->logEvent('foo', $record); +/** + * Note that Loggers should only be used directly by a log appender. + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.32.0/specification/logs/bridge-api.md#logs-bridge-api + */ +$logger->emit($record); $loggerProvider->shutdown(); diff --git a/src/API/Globals.php b/src/API/Globals.php index 51fe8edbf..7d296f4fc 100644 --- a/src/API/Globals.php +++ b/src/API/Globals.php @@ -9,6 +9,7 @@ use const E_USER_WARNING; use OpenTelemetry\API\Instrumentation\Configurator; use OpenTelemetry\API\Instrumentation\ContextKeys; +use OpenTelemetry\API\Logs\EventLoggerProviderInterface; use OpenTelemetry\API\Logs\LoggerProviderInterface; use OpenTelemetry\API\Metrics\MeterProviderInterface; use OpenTelemetry\API\Trace\TracerProviderInterface; @@ -31,6 +32,7 @@ public function __construct( private readonly TracerProviderInterface $tracerProvider, private readonly MeterProviderInterface $meterProvider, private readonly LoggerProviderInterface $loggerProvider, + private readonly EventLoggerProviderInterface $eventLoggerProvider, private readonly TextMapPropagatorInterface $propagator, ) { } @@ -55,6 +57,11 @@ public static function loggerProvider(): LoggerProviderInterface return Context::getCurrent()->get(ContextKeys::loggerProvider()) ?? self::globals()->loggerProvider; } + public static function eventLoggerProvider(): EventLoggerProviderInterface + { + return Context::getCurrent()->get(ContextKeys::eventLoggerProvider()) ?? self::globals()->eventLoggerProvider; + } + /** * @param Closure(Configurator): Configurator $initializer * @@ -95,10 +102,11 @@ private static function globals(): self $meterProvider = $context->get(ContextKeys::meterProvider()); $propagator = $context->get(ContextKeys::propagator()); $loggerProvider = $context->get(ContextKeys::loggerProvider()); + $eventLoggerProvider = $context->get(ContextKeys::eventLoggerProvider()); - assert(isset($tracerProvider, $meterProvider, $loggerProvider, $propagator)); + assert(isset($tracerProvider, $meterProvider, $loggerProvider, $eventLoggerProvider, $propagator)); - return self::$globals = new self($tracerProvider, $meterProvider, $loggerProvider, $propagator); + return self::$globals = new self($tracerProvider, $meterProvider, $loggerProvider, $eventLoggerProvider, $propagator); } /** diff --git a/src/API/Instrumentation/CachedInstrumentation.php b/src/API/Instrumentation/CachedInstrumentation.php index deb0f58f2..20749c0c5 100644 --- a/src/API/Instrumentation/CachedInstrumentation.php +++ b/src/API/Instrumentation/CachedInstrumentation.php @@ -5,6 +5,8 @@ namespace OpenTelemetry\API\Instrumentation; use OpenTelemetry\API\Globals; +use OpenTelemetry\API\Logs\EventLoggerInterface; +use OpenTelemetry\API\Logs\EventLoggerProviderInterface; use OpenTelemetry\API\Logs\LoggerInterface; use OpenTelemetry\API\Logs\LoggerProviderInterface; use OpenTelemetry\API\Metrics\MeterInterface; @@ -29,6 +31,8 @@ final class CachedInstrumentation private WeakMap $meters; /** @var WeakMap */ private WeakMap $loggers; + /** @var WeakMap */ + private WeakMap $eventLoggers; /** * @psalm-suppress PropertyTypeCoercion @@ -42,6 +46,7 @@ public function __construct( $this->tracers = new \WeakMap(); $this->meters = new \WeakMap(); $this->loggers = new \WeakMap(); + $this->eventLoggers = new \WeakMap(); } public function tracer(): TracerInterface @@ -63,4 +68,10 @@ public function logger(): LoggerInterface return $this->loggers[$loggerProvider] ??= $loggerProvider->getLogger($this->name, $this->version, $this->schemaUrl, $this->attributes); } + public function eventLogger(): EventLoggerInterface + { + $eventLoggerProvider = Globals::eventLoggerProvider(); + + return $this->eventLoggers[$eventLoggerProvider] ??= $eventLoggerProvider->getEventLogger($this->name, $this->version, $this->schemaUrl, $this->attributes); + } } diff --git a/src/API/Instrumentation/Configurator.php b/src/API/Instrumentation/Configurator.php index 71d301363..d8912ec2d 100644 --- a/src/API/Instrumentation/Configurator.php +++ b/src/API/Instrumentation/Configurator.php @@ -4,7 +4,9 @@ namespace OpenTelemetry\API\Instrumentation; +use OpenTelemetry\API\Logs\EventLoggerProviderInterface; use OpenTelemetry\API\Logs\LoggerProviderInterface; +use OpenTelemetry\API\Logs\NoopEventLoggerProvider; use OpenTelemetry\API\Logs\NoopLoggerProvider; use OpenTelemetry\API\Metrics\MeterProviderInterface; use OpenTelemetry\API\Metrics\Noop\NoopMeterProvider; @@ -28,6 +30,7 @@ final class Configurator implements ImplicitContextKeyedInterface private ?MeterProviderInterface $meterProvider = null; private ?TextMapPropagatorInterface $propagator = null; private ?LoggerProviderInterface $loggerProvider = null; + private ?EventLoggerProviderInterface $eventLoggerProvider = null; private function __construct() { @@ -50,7 +53,8 @@ public static function createNoop(): Configurator ->withTracerProvider(new NoopTracerProvider()) ->withMeterProvider(new NoopMeterProvider()) ->withPropagator(new NoopTextMapPropagator()) - ->withLoggerProvider(new NoopLoggerProvider()) + ->withLoggerProvider(NoopLoggerProvider::getInstance()) + ->withEventLoggerProvider(new NoopEventLoggerProvider()) ; } @@ -75,6 +79,9 @@ public function storeInContext(?ContextInterface $context = null): ContextInterf if ($this->loggerProvider !== null) { $context = $context->with(ContextKeys::loggerProvider(), $this->loggerProvider); } + if ($this->eventLoggerProvider !== null) { + $context = $context->with(ContextKeys::eventLoggerProvider(), $this->eventLoggerProvider); + } return $context; } @@ -110,4 +117,12 @@ public function withLoggerProvider(?LoggerProviderInterface $loggerProvider): Co return $self; } + + public function withEventLoggerProvider(?EventLoggerProviderInterface $eventLoggerProvider): Configurator + { + $self = clone $this; + $self->eventLoggerProvider = $eventLoggerProvider; + + return $self; + } } diff --git a/src/API/Instrumentation/ContextKeys.php b/src/API/Instrumentation/ContextKeys.php index ea1a66416..9f53e5b86 100644 --- a/src/API/Instrumentation/ContextKeys.php +++ b/src/API/Instrumentation/ContextKeys.php @@ -4,6 +4,7 @@ namespace OpenTelemetry\API\Instrumentation; +use OpenTelemetry\API\Logs\EventLoggerProviderInterface; use OpenTelemetry\API\Logs\LoggerProviderInterface; use OpenTelemetry\API\Metrics\MeterProviderInterface; use OpenTelemetry\API\Trace\TracerProviderInterface; @@ -55,4 +56,14 @@ public static function loggerProvider(): ContextKeyInterface return $instance ??= Context::createKey(LoggerProviderInterface::class); } + + /** + * @return ContextKeyInterface + */ + public static function eventLoggerProvider(): ContextKeyInterface + { + static $instance; + + return $instance ??= Context::createKey(EventLoggerProviderInterface::class); + } } diff --git a/src/API/Logs/EventLogger.php b/src/API/Logs/EventLogger.php deleted file mode 100644 index abbe54b97..000000000 --- a/src/API/Logs/EventLogger.php +++ /dev/null @@ -1,23 +0,0 @@ -setAttributes([ - 'event.name' => $eventName, - 'event.domain' => $this->domain, - ]); - $this->logger->emit($logRecord); - } -} diff --git a/src/API/Logs/EventLoggerInterface.php b/src/API/Logs/EventLoggerInterface.php index a2096b9b7..73d19808e 100644 --- a/src/API/Logs/EventLoggerInterface.php +++ b/src/API/Logs/EventLoggerInterface.php @@ -4,10 +4,19 @@ namespace OpenTelemetry\API\Logs; +use OpenTelemetry\Context\ContextInterface; + /** * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/event-api.md#events-api-interface */ interface EventLoggerInterface { - public function logEvent(string $eventName, LogRecord $logRecord): void; + public function emit( + string $name, + mixed $payload = null, + ?int $timestamp = null, + ?ContextInterface $context = null, + Severity $severityNumber = null, + iterable $attributes = [], + ): void; } diff --git a/src/API/Logs/EventLoggerProviderInterface.php b/src/API/Logs/EventLoggerProviderInterface.php new file mode 100644 index 000000000..957a19654 --- /dev/null +++ b/src/API/Logs/EventLoggerProviderInterface.php @@ -0,0 +1,18 @@ +severityNumber = $severityNumber; + $this->severityNumber = ($severityNumber instanceof Severity) ? $severityNumber->value : $severityNumber; return $this; } diff --git a/src/API/Logs/LoggerInterface.php b/src/API/Logs/LoggerInterface.php index 89477c8d2..4e1bc3931 100644 --- a/src/API/Logs/LoggerInterface.php +++ b/src/API/Logs/LoggerInterface.php @@ -6,5 +6,9 @@ interface LoggerInterface { + /** + * This method should only be used when implementing a `log appender` + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.32.0/specification/logs/bridge-api.md#artifact-naming + */ public function emit(LogRecord $logRecord): void; } diff --git a/src/API/Logs/Map/Psr3.php b/src/API/Logs/Map/Psr3.php index 63a00e7b9..c2e21c973 100644 --- a/src/API/Logs/Map/Psr3.php +++ b/src/API/Logs/Map/Psr3.php @@ -4,28 +4,17 @@ namespace OpenTelemetry\API\Logs\Map; -use Psr\Log\LogLevel; +use OpenTelemetry\API\Logs\Severity; class Psr3 { /** - * Maps PSR-3 severity level (string) to the appropriate opentelemetry severity number + * Maps PSR-3 severity level (string) to the appropriate opentelemetry severity * - * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model-appendix.md#appendix-b-severitynumber-example-mappings - * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-severitynumber + * @deprecated Use Severity::fromPsr3 */ - public static function severityNumber(string $level): int + public static function severityNumber(string $level): Severity { - return match (strtolower($level)) { - LogLevel::DEBUG => 5, - LogLevel::INFO => 9, - LogLevel::NOTICE => 10, - LogLevel::WARNING => 13, - LogLevel::ERROR => 17, - LogLevel::CRITICAL => 18, - LogLevel::ALERT => 19, - LogLevel::EMERGENCY => 21, - default => 0, - }; + return Severity::fromPsr3($level); } } diff --git a/src/API/Logs/NoopEventLogger.php b/src/API/Logs/NoopEventLogger.php new file mode 100644 index 000000000..73c1459e2 --- /dev/null +++ b/src/API/Logs/NoopEventLogger.php @@ -0,0 +1,22 @@ + Severity::DEBUG, + LogLevel::INFO => Severity::INFO, + LogLevel::NOTICE => Severity::INFO2, + LogLevel::WARNING => Severity::WARN, + LogLevel::ERROR => Severity::ERROR, + LogLevel::CRITICAL => Severity::ERROR2, + LogLevel::ALERT => Severity::ERROR3, + LogLevel::EMERGENCY => Severity::FATAL, + default => throw new ValueError('Unknown severity: ' . $level), + }; + } +} diff --git a/src/API/Trace/LocalRootSpan.php b/src/API/Trace/LocalRootSpan.php new file mode 100644 index 000000000..474f9d127 --- /dev/null +++ b/src/API/Trace/LocalRootSpan.php @@ -0,0 +1,37 @@ +get(ContextKeys::localRootSpan()) ?? Span::getInvalid(); + } + + public static function store(ContextInterface $context, SpanInterface $span): ContextInterface + { + return $context->with(ContextKeys::localRootSpan(), $span); + } + + /** + * @internal + */ + public static function isLocalRoot(ContextInterface $parentContext): bool + { + $spanContext = Span::fromContext($parentContext)->getContext(); + + return !$spanContext->isValid() || $spanContext->isRemote(); + } +} diff --git a/src/API/Trace/Span.php b/src/API/Trace/Span.php index 88360e6cd..af7491389 100644 --- a/src/API/Trace/Span.php +++ b/src/API/Trace/Span.php @@ -48,12 +48,21 @@ final public static function wrap(SpanContextInterface $spanContext): SpanInterf /** @inheritDoc */ final public function activate(): ScopeInterface { - return Context::getCurrent()->withContextValue($this)->activate(); + $context = Context::getCurrent(); + if (LocalRootSpan::isLocalRoot($context)) { + $context = LocalRootSpan::store($context, $this); + } + + return $context->withContextValue($this)->activate(); } /** @inheritDoc */ final public function storeInContext(ContextInterface $context): ContextInterface { + if (LocalRootSpan::isLocalRoot($context)) { + $context = LocalRootSpan::store($context, $this); + } + return $context->with(ContextKeys::span(), $this); } } diff --git a/src/Config/SDK/ComponentProvider/OpenTelemetrySdk.php b/src/Config/SDK/ComponentProvider/OpenTelemetrySdk.php index 45e35aed2..730164e6c 100644 --- a/src/Config/SDK/ComponentProvider/OpenTelemetrySdk.php +++ b/src/Config/SDK/ComponentProvider/OpenTelemetrySdk.php @@ -14,6 +14,7 @@ use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; use OpenTelemetry\SDK\Common\Attribute\Attributes; use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory; +use OpenTelemetry\SDK\Logs\EventLoggerProvider; use OpenTelemetry\SDK\Logs\LoggerProvider; use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface; use OpenTelemetry\SDK\Logs\Processor\MultiLogRecordProcessor; @@ -239,12 +240,14 @@ public function createPlugin(array $properties, Context $context): SdkBuilder instrumentationScopeFactory: new InstrumentationScopeFactory(Attributes::factory()), resource: $resource, ); + $eventLoggerProvider = new EventLoggerProvider($loggerProvider); // $sdkBuilder->setTracerProvider($tracerProvider); $sdkBuilder->setMeterProvider($meterProvider); $sdkBuilder->setLoggerProvider($loggerProvider); + $sdkBuilder->setEventLoggerProvider($eventLoggerProvider); return $sdkBuilder; } diff --git a/src/Context/ContextKeys.php b/src/Context/ContextKeys.php index bc1022568..f90e7fb69 100644 --- a/src/Context/ContextKeys.php +++ b/src/Context/ContextKeys.php @@ -16,6 +16,13 @@ public static function span(): ContextKeyInterface return $instance ??= Context::createKey('opentelemetry-trace-span-key'); } + public static function localRootSpan(): ContextKeyInterface + { + static $instance; + + return $instance ??= Context::createKey('opentelemetry-trace-local-root-span-key'); + } + public static function baggage(): ContextKeyInterface { static $instance; diff --git a/src/SDK/Logs/EventLogger.php b/src/SDK/Logs/EventLogger.php new file mode 100644 index 000000000..c4f0fb62d --- /dev/null +++ b/src/SDK/Logs/EventLogger.php @@ -0,0 +1,48 @@ +setAttribute('event.name', $name); + $logRecord->setAttributes($attributes); + $logRecord->setAttribute('event.name', $name); + $logRecord->setBody($payload); + $logRecord->setTimestamp($timestamp ?? $this->clock->now()); + $logRecord->setContext($context ?? Context::getCurrent()); + $logRecord->setSeverityNumber($severityNumber ?? Severity::INFO); + + $this->logger->emit($logRecord); + } +} diff --git a/src/SDK/Logs/EventLoggerProvider.php b/src/SDK/Logs/EventLoggerProvider.php new file mode 100644 index 000000000..53233a53c --- /dev/null +++ b/src/SDK/Logs/EventLoggerProvider.php @@ -0,0 +1,25 @@ +loggerProvider->getLogger($name, $version, $schemaUrl, $attributes), + Clock::getDefault(), + ); + } +} diff --git a/src/SDK/Logs/EventLoggerProviderFactory.php b/src/SDK/Logs/EventLoggerProviderFactory.php new file mode 100644 index 000000000..89d8cd814 --- /dev/null +++ b/src/SDK/Logs/EventLoggerProviderFactory.php @@ -0,0 +1,21 @@ +loggerProvider; } + public function getEventLoggerProvider(): EventLoggerProviderInterface + { + return $this->eventLoggerProvider; + } + public function getPropagator(): TextMapPropagatorInterface { return $this->propagator; diff --git a/src/SDK/SdkAutoloader.php b/src/SDK/SdkAutoloader.php index b1d5edca9..f204d8540 100644 --- a/src/SDK/SdkAutoloader.php +++ b/src/SDK/SdkAutoloader.php @@ -10,6 +10,7 @@ use OpenTelemetry\SDK\Common\Configuration\Configuration; use OpenTelemetry\SDK\Common\Configuration\Variables; use OpenTelemetry\SDK\Common\Util\ShutdownHandler; +use OpenTelemetry\SDK\Logs\EventLoggerProviderFactory; use OpenTelemetry\SDK\Logs\LoggerProviderFactory; use OpenTelemetry\SDK\Metrics\MeterProviderFactory; use OpenTelemetry\SDK\Propagation\PropagatorFactory; @@ -48,6 +49,7 @@ public static function autoload(): bool ->build(); $loggerProvider = (new LoggerProviderFactory())->create($emitMetrics ? $meterProvider : null, $resource); + $eventLoggerProvider = (new EventLoggerProviderFactory())->create($loggerProvider); ShutdownHandler::register($tracerProvider->shutdown(...)); ShutdownHandler::register($meterProvider->shutdown(...)); @@ -57,6 +59,7 @@ public static function autoload(): bool ->withTracerProvider($tracerProvider) ->withMeterProvider($meterProvider) ->withLoggerProvider($loggerProvider) + ->withEventLoggerProvider($eventLoggerProvider) ->withPropagator($propagator) ; }); diff --git a/src/SDK/SdkBuilder.php b/src/SDK/SdkBuilder.php index 22664b417..403713e0b 100644 --- a/src/SDK/SdkBuilder.php +++ b/src/SDK/SdkBuilder.php @@ -5,6 +5,8 @@ namespace OpenTelemetry\SDK; use OpenTelemetry\API\Instrumentation\Configurator; +use OpenTelemetry\API\Logs\EventLoggerProviderInterface; +use OpenTelemetry\API\Logs\NoopEventLoggerProvider; use OpenTelemetry\Context\Context; use OpenTelemetry\Context\Propagation\NoopTextMapPropagator; use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; @@ -22,6 +24,7 @@ class SdkBuilder private ?TracerProviderInterface $tracerProvider = null; private ?MeterProviderInterface $meterProvider = null; private ?LoggerProviderInterface $loggerProvider = null; + private ?EventLoggerProviderInterface $eventLoggerProvider = null; private ?TextMapPropagatorInterface $propagator = null; private bool $autoShutdown = false; @@ -56,6 +59,13 @@ public function setLoggerProvider(LoggerProviderInterface $loggerProvider): self return $this; } + public function setEventLoggerProvider(EventLoggerProviderInterface $eventLoggerProvider): self + { + $this->eventLoggerProvider = $eventLoggerProvider; + + return $this; + } + public function setPropagator(TextMapPropagatorInterface $propagator): self { $this->propagator = $propagator; @@ -68,6 +78,7 @@ public function build(): Sdk $tracerProvider = $this->tracerProvider ?? new NoopTracerProvider(); $meterProvider = $this->meterProvider ?? new NoopMeterProvider(); $loggerProvider = $this->loggerProvider ?? new NoopLoggerProvider(); + $eventLoggerProvider = $this->eventLoggerProvider ?? new NoopEventLoggerProvider(); if ($this->autoShutdown) { // rector rule disabled in config, because ShutdownHandler::register() does not keep a strong reference to $this ShutdownHandler::register($tracerProvider->shutdown(...)); @@ -79,6 +90,7 @@ public function build(): Sdk $tracerProvider, $meterProvider, $loggerProvider, + $eventLoggerProvider, $this->propagator ?? NoopTextMapPropagator::getInstance(), ); } @@ -91,6 +103,7 @@ public function buildAndRegisterGlobal(): ScopeInterface ->withTracerProvider($sdk->getTracerProvider()) ->withMeterProvider($sdk->getMeterProvider()) ->withLoggerProvider($sdk->getLoggerProvider()) + ->withEventLoggerProvider($sdk->getEventLoggerProvider()) ->storeInContext(); return Context::storage()->attach($context); diff --git a/tests/Integration/SDK/LocalRootSpanTest.php b/tests/Integration/SDK/LocalRootSpanTest.php new file mode 100644 index 000000000..7e2a2b16e --- /dev/null +++ b/tests/Integration/SDK/LocalRootSpanTest.php @@ -0,0 +1,49 @@ +span = $tracerProvider->getTracer('test')->spanBuilder('my-local-root-span')->startSpan(); + } + + public function test_active_root_span_is_local_root(): void + { + $scope = $this->span->activate(); + + try { + $this->assertSame($this->span, LocalRootSpan::current()); + } finally { + $scope->detach(); + } + $this->assertSame(Span::getInvalid(), LocalRootSpan::current(), 'root span ended, a local root span does not exist'); + } + + public function test_root_span_stored_in_context_is_local_root(): void + { + $root = Context::getRoot(); + Context::storage()->attach($this->span->storeInContext($root)); + $this->assertSame($this->span, LocalRootSpan::current()); + $scope = Context::storage()->scope(); + $this->assertNotNull($scope); + $this->assertSame($this->span, Span::fromContext($scope->context())); + $scope->detach(); + $this->assertSame(Span::getInvalid(), LocalRootSpan::current(), 'root span ended, a local root span does not exist'); + } +} diff --git a/tests/Unit/API/Instrumentation/InstrumentationTest.php b/tests/Unit/API/Instrumentation/InstrumentationTest.php index ce96727b5..90e61f310 100644 --- a/tests/Unit/API/Instrumentation/InstrumentationTest.php +++ b/tests/Unit/API/Instrumentation/InstrumentationTest.php @@ -7,8 +7,11 @@ use OpenTelemetry\API\Globals; use OpenTelemetry\API\Instrumentation\CachedInstrumentation; use OpenTelemetry\API\Instrumentation\Configurator; +use OpenTelemetry\API\Logs\EventLoggerInterface; +use OpenTelemetry\API\Logs\EventLoggerProviderInterface; use OpenTelemetry\API\Logs\LoggerInterface; use OpenTelemetry\API\Logs\LoggerProviderInterface; +use OpenTelemetry\API\Logs\NoopEventLoggerProvider; use OpenTelemetry\API\Logs\NoopLoggerProvider; use OpenTelemetry\API\Metrics\MeterInterface; use OpenTelemetry\API\Metrics\MeterProviderInterface; @@ -41,6 +44,7 @@ public function test_globals_not_configured_returns_noop_instances(): void $this->assertInstanceOf(NoopMeterProvider::class, Globals::meterProvider()); $this->assertInstanceOf(NoopTextMapPropagator::class, Globals::propagator()); $this->assertInstanceOf(NoopLoggerProvider::class, Globals::loggerProvider()); + $this->assertInstanceOf(NoopEventLoggerProvider::class, Globals::eventLoggerProvider()); } public function test_globals_returns_configured_instances(): void @@ -49,12 +53,14 @@ public function test_globals_returns_configured_instances(): void $meterProvider = $this->createMock(MeterProviderInterface::class); $propagator = $this->createMock(TextMapPropagatorInterface::class); $loggerProvider = $this->createMock(LoggerProviderInterface::class); + $eventLoggerProvider = $this->createMock(EventLoggerProviderInterface::class); $scope = Configurator::create() ->withTracerProvider($tracerProvider) ->withMeterProvider($meterProvider) ->withPropagator($propagator) ->withLoggerProvider($loggerProvider) + ->withEventLoggerProvider($eventLoggerProvider) ->activate(); try { @@ -62,6 +68,7 @@ public function test_globals_returns_configured_instances(): void $this->assertSame($meterProvider, Globals::meterProvider()); $this->assertSame($propagator, Globals::propagator()); $this->assertSame($loggerProvider, Globals::loggerProvider()); + $this->assertSame($eventLoggerProvider, Globals::eventLoggerProvider()); } finally { $scope->detach(); } @@ -88,12 +95,16 @@ public function test_instrumentation_returns_configured_instances(): void $logger = $this->createMock(LoggerInterface::class); $loggerProvider = $this->createMock(LoggerProviderInterface::class); $loggerProvider->method('getLogger')->willReturn($logger); + $eventLogger = $this->createMock(EventLoggerInterface::class); + $eventLoggerProvider = $this->createMock(EventLoggerProviderInterface::class); + $eventLoggerProvider->method('getEventLogger')->willReturn($eventLogger); $propagator = $this->createMock(TextMapPropagatorInterface::class); $scope = Configurator::create() ->withTracerProvider($tracerProvider) ->withMeterProvider($meterProvider) ->withLoggerProvider($loggerProvider) + ->withEventLoggerProvider($eventLoggerProvider) ->withPropagator($propagator) ->activate(); @@ -101,6 +112,7 @@ public function test_instrumentation_returns_configured_instances(): void $this->assertSame($tracer, $instrumentation->tracer()); $this->assertSame($meter, $instrumentation->meter()); $this->assertSame($logger, $instrumentation->logger()); + $this->assertSame($eventLogger, $instrumentation->eventLogger()); } finally { $scope->detach(); } diff --git a/tests/Unit/API/Logs/EventLoggerTest.php b/tests/Unit/API/Logs/EventLoggerTest.php deleted file mode 100644 index f06625fc2..000000000 --- a/tests/Unit/API/Logs/EventLoggerTest.php +++ /dev/null @@ -1,28 +0,0 @@ -createMock(LoggerInterface::class); - $domain = 'some.domain'; - $logRecord = $this->createMock(LogRecord::class); - $eventLogger = new EventLogger($logger, $domain); - $logRecord->expects($this->once())->method('setAttributes'); - $logger->expects($this->once())->method('emit')->with($this->equalTo($logRecord)); - - $eventLogger->logEvent('some.event', $logRecord); - } -} diff --git a/tests/Unit/API/Logs/LogRecordTest.php b/tests/Unit/API/Logs/LogRecordTest.php index 949898b30..525cbbda5 100644 --- a/tests/Unit/API/Logs/LogRecordTest.php +++ b/tests/Unit/API/Logs/LogRecordTest.php @@ -5,6 +5,7 @@ namespace OpenTelemetry\Tests\Unit\API\Logs; use OpenTelemetry\API\Logs\LogRecord; +use OpenTelemetry\API\Logs\Severity; use OpenTelemetry\Context\Context; use PHPUnit\Framework\TestCase; @@ -16,7 +17,7 @@ class LogRecordTest extends TestCase /** * @dataProvider settersProvider */ - public function test_setters(string $method, string $propertyName, $value): void + public function test_setters(string $method, string $propertyName, mixed $value, mixed $expected = null): void { $record = new LogRecord(); $record->{$method}($value); @@ -24,7 +25,7 @@ public function test_setters(string $method, string $propertyName, $value): void $reflection = new \ReflectionClass($record); $property = $reflection->getProperty($propertyName); $property->setAccessible(true); - $this->assertSame($value, $property->getValue($record)); + $this->assertSame($expected ?? $value, $property->getValue($record)); } public static function settersProvider(): array @@ -33,6 +34,7 @@ public static function settersProvider(): array ['setBody', 'body', 'foo'], ['setAttributes', 'attributes', ['foo' => 'bar']], ['setSeverityNumber', 'severityNumber', 5], + ['setSeverityNumber', 'severityNumber', Severity::ERROR, Severity::ERROR->value], ['setSeverityText', 'severityText', 'info'], ['setObservedTimestamp', 'observedTimestamp', 999], ['setTimestamp', 'timestamp', 888], diff --git a/tests/Unit/API/Logs/Map/Psr3Test.php b/tests/Unit/API/Logs/Map/Psr3Test.php index bdef1235c..38b1320a6 100644 --- a/tests/Unit/API/Logs/Map/Psr3Test.php +++ b/tests/Unit/API/Logs/Map/Psr3Test.php @@ -32,7 +32,6 @@ public static function levelProvider(): array [LogLevel::NOTICE], [LogLevel::INFO], [LogLevel::DEBUG], - ['unknown'], ]; } } diff --git a/tests/Unit/API/Logs/SeverityTest.php b/tests/Unit/API/Logs/SeverityTest.php new file mode 100644 index 000000000..9cd048d53 --- /dev/null +++ b/tests/Unit/API/Logs/SeverityTest.php @@ -0,0 +1,44 @@ +expectException(ValueError::class); + Severity::fromPsr3('unknown'); + } + + /** + * @dataProvider levelProvider + */ + public function test_severity_number(string $level): void + { + $this->assertNotNull(Severity::fromPsr3($level)); + } + + public static function levelProvider(): array + { + return [ + [LogLevel::EMERGENCY], + [LogLevel::ALERT], + [LogLevel::CRITICAL], + [LogLevel::ERROR], + [LogLevel::WARNING], + [LogLevel::NOTICE], + [LogLevel::INFO], + [LogLevel::DEBUG], + ]; + } +} diff --git a/tests/Unit/API/Trace/LocalRootSpanTest.php b/tests/Unit/API/Trace/LocalRootSpanTest.php new file mode 100644 index 000000000..7cf78fbe1 --- /dev/null +++ b/tests/Unit/API/Trace/LocalRootSpanTest.php @@ -0,0 +1,59 @@ +with( + ContextKeys::localRootSpan(), + Span::wrap( + SpanContext::createFromRemoteParent( + '00000000000000000000000000000001', + '0000000000000002', + ) + ) + ); + $this->assertTrue(LocalRootSpan::isLocalRoot($context)); + } + + public function test_get_local_root_span(): void + { + $span = Span::getInvalid(); + $context = LocalRootSpan::store(Context::getCurrent(), $span); + $scope = $context->activate(); + + try { + $this->assertSame($span, LocalRootSpan::fromContext($context)); + $this->assertSame($span, LocalRootSpan::current()); + } finally { + $scope->detach(); + } + } + + public function test_get_local_root_span_when_not_set(): void + { + $context = Context::getRoot(); + $scope = $context->activate(); + + try { + $this->assertFalse(LocalRootSpan::fromContext($context)->getContext()->isValid()); + $this->assertFalse(LocalRootSpan::current()->getContext()->isValid()); + $this->assertSame(Span::getInvalid(), LocalRootSpan::current()); + } finally { + $scope->detach(); + } + } +} diff --git a/tests/Unit/Context/ContextKeysTest.php b/tests/Unit/Context/ContextKeysTest.php index ac0ce3967..6a931b98b 100644 --- a/tests/Unit/Context/ContextKeysTest.php +++ b/tests/Unit/Context/ContextKeysTest.php @@ -17,6 +17,11 @@ public function test_span_context_key(): void $this->assertSame(ContextKeys::span(), ContextKeys::span()); } + public function test_local_root_span_context_key(): void + { + $this->assertSame(ContextKeys::localRootSpan(), ContextKeys::localRootSpan()); + } + public function test_baggage_context_key(): void { $this->assertSame(ContextKeys::baggage(), ContextKeys::baggage()); diff --git a/tests/Unit/SDK/Logs/EventLoggerProviderFactoryTest.php b/tests/Unit/SDK/Logs/EventLoggerProviderFactoryTest.php new file mode 100644 index 000000000..dc7ae94bb --- /dev/null +++ b/tests/Unit/SDK/Logs/EventLoggerProviderFactoryTest.php @@ -0,0 +1,53 @@ +restoreEnvironmentVariables(); + } + + /** + * @dataProvider createProvider + * @psalm-suppress ArgumentTypeCoercion + */ + public function test_create(string $disabled, string $expected): void + { + $this->setEnvironmentVariable(Variables::OTEL_SDK_DISABLED, $disabled); + $loggerProvider = $this->createMock(LoggerProviderInterface::class); + $factory = new EventLoggerProviderFactory(); + $eventLoggerProvider = $factory->create($loggerProvider); + $this->assertInstanceOf($expected, $eventLoggerProvider); + } + + public static function createProvider(): array + { + return [ + 'sdk disabled' => [ + 'true', + NoopEventLoggerProvider::class, + ], + 'sdk enabled' => [ + 'false', + EventLoggerProvider::class, + ], + ]; + } +} diff --git a/tests/Unit/SDK/Logs/EventLoggerProviderTest.php b/tests/Unit/SDK/Logs/EventLoggerProviderTest.php new file mode 100644 index 000000000..a63b7e368 --- /dev/null +++ b/tests/Unit/SDK/Logs/EventLoggerProviderTest.php @@ -0,0 +1,26 @@ +createMock(LoggerProviderInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $loggerProvider->expects($this->once())->method('getLogger')->willReturn($logger); + $eventLoggerProvider = new EventLoggerProvider($loggerProvider); + + $eventLoggerProvider->getEventLogger('event.logger', '1.0', 'https://example.org/schema', ['foo' => 'foo']); + } +} diff --git a/tests/Unit/SDK/Logs/EventLoggerTest.php b/tests/Unit/SDK/Logs/EventLoggerTest.php new file mode 100644 index 000000000..ea9dbac77 --- /dev/null +++ b/tests/Unit/SDK/Logs/EventLoggerTest.php @@ -0,0 +1,103 @@ +clock = new TestClock(); + Clock::setDefault($this->clock); + $this->logger = $this->createMock(LoggerInterface::class); + $loggerProvider = $this->createMock(LoggerProviderInterface::class); + $loggerProvider->method('getLogger')->willReturn($this->logger); + $this->eventLoggerProvider = new EventLoggerProvider($loggerProvider); + } + + public function tearDown(): void + { + Clock::reset(); + } + + public function test_emit(): void + { + $this->logger->expects($this->once())->method('emit')->with($this->callback(function (LogRecord $logRecord) { + $expected = (new LogRecord('some.payload')) + ->setSeverityNumber(Severity::ERROR) + ->setTimestamp(123456) + ->setContext(Context::getCurrent()) + ->setAttributes([ + 'event.name' => 'my.event', + 'bar' => 'bar', + ]); + $this->assertEquals($expected, $logRecord); + + return true; + })); + + $eventLogger = $this->eventLoggerProvider->getEventLogger('event.logger', '1.0', 'https://example.org/schema', ['foo' => 'foo']); + $eventLogger->emit('my.event', 'some.payload', 123456, severityNumber: Severity::ERROR, attributes: ['bar' => 'bar']); + } + + public function test_default_values(): void + { + $this->logger->expects($this->once())->method('emit')->with($this->callback(function (LogRecord $logRecord) { + $expected = (new LogRecord()) + ->setSeverityNumber(Severity::INFO) + ->setTimestamp($this->clock->now()) + ->setContext(Context::getCurrent()) + ->setAttributes([ + 'event.name' => 'my.event', + ]); + $this->assertEquals($expected, $logRecord); + + return true; + })); + + $eventLogger = $this->eventLoggerProvider->getEventLogger('event.logger'); + $eventLogger->emit('my.event'); + } + + /** + * "The user provided Attributes MUST not take over the event.name attribute" + * @see https://github.com/open-telemetry/opentelemetry-specification/blob/v1.32.0/specification/logs/event-sdk.md#emit-event + */ + public function test_event_name_attribute_is_ignored(): void + { + $this->logger->expects($this->once())->method('emit')->with($this->callback(function (LogRecord $logRecord) { + $expected = (new LogRecord()) + ->setSeverityNumber(Severity::INFO) + ->setTimestamp($this->clock->now()) + ->setContext(Context::getCurrent()) + ->setAttributes([ + 'event.name' => 'my.event', + ]); + $this->assertEquals($expected, $logRecord); + + return true; + })); + + $eventLogger = $this->eventLoggerProvider->getEventLogger('event.logger'); + $eventLogger->emit('my.event', attributes: ['event.name' => 'not.my.event']); + } +} diff --git a/tests/Unit/SDK/SdkAutoloaderTest.php b/tests/Unit/SDK/SdkAutoloaderTest.php index e053cc0f5..e3e4df742 100644 --- a/tests/Unit/SDK/SdkAutoloaderTest.php +++ b/tests/Unit/SDK/SdkAutoloaderTest.php @@ -7,6 +7,7 @@ use AssertWell\PHPUnitGlobalState\EnvironmentVariables; use OpenTelemetry\API\Globals; use OpenTelemetry\API\LoggerHolder; +use OpenTelemetry\API\Logs\NoopEventLoggerProvider; use OpenTelemetry\API\Logs\NoopLoggerProvider; use OpenTelemetry\API\Metrics\Noop\NoopMeterProvider; use OpenTelemetry\API\Trace\NoopTracerProvider; @@ -64,6 +65,7 @@ public function test_noop_if_disabled(): void $this->assertInstanceOf(NoopMeterProvider::class, Globals::meterProvider()); $this->assertInstanceOf(NoopTracerProvider::class, Globals::tracerProvider()); $this->assertInstanceOf(NoopLoggerProvider::class, Globals::loggerProvider()); + $this->assertInstanceOf(NoopEventLoggerProvider::class, Globals::eventLoggerProvider()); $this->assertInstanceOf(NoopTextMapPropagator::class, Globals::propagator(), 'propagator not initialized by disabled autoloader'); } diff --git a/tests/Unit/SDK/SdkBuilderTest.php b/tests/Unit/SDK/SdkBuilderTest.php index 0d05cd123..48baabaae 100644 --- a/tests/Unit/SDK/SdkBuilderTest.php +++ b/tests/Unit/SDK/SdkBuilderTest.php @@ -5,6 +5,7 @@ namespace OpenTelemetry\Tests\Unit\SDK; use OpenTelemetry\API\Globals; +use OpenTelemetry\API\Logs\EventLoggerProviderInterface; use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; use OpenTelemetry\SDK\Logs\LoggerProviderInterface; use OpenTelemetry\SDK\Metrics\MeterProviderInterface; @@ -21,6 +22,7 @@ class SdkBuilderTest extends TestCase private TracerProviderInterface $tracerProvider; private MeterProviderInterface $meterProvider; private LoggerProviderInterface $loggerProvider; + private EventLoggerProviderInterface $eventLoggerProvider; private SdkBuilder $builder; public function setUp(): void @@ -29,9 +31,11 @@ public function setUp(): void $this->tracerProvider = $this->createMock(TracerProviderInterface::class); $this->meterProvider = $this->createMock(MeterProviderInterface::class); $this->loggerProvider = $this->createMock(LoggerProviderInterface::class); + $this->eventLoggerProvider = $this->createMock(EventLoggerProviderInterface::class); $this->builder = (new SdkBuilder()) ->setMeterProvider($this->meterProvider) ->setLoggerProvider($this->loggerProvider) + ->setEventLoggerProvider($this->eventLoggerProvider) ->setPropagator($this->propagator) ->setTracerProvider($this->tracerProvider) ->setAutoShutdown(true); @@ -44,6 +48,7 @@ public function test_build(): void $this->assertSame($this->propagator, $sdk->getPropagator()); $this->assertSame($this->tracerProvider, $sdk->getTracerProvider()); $this->assertSame($this->loggerProvider, $sdk->getLoggerProvider()); + $this->assertSame($this->eventLoggerProvider, $sdk->getEventLoggerProvider()); } public function test_build_and_register_global(): void @@ -53,6 +58,7 @@ public function test_build_and_register_global(): void $this->assertSame($this->propagator, Globals::propagator()); $this->assertSame($this->tracerProvider, Globals::tracerProvider()); $this->assertSame($this->loggerProvider, Globals::loggerProvider()); + $this->assertSame($this->eventLoggerProvider, Globals::eventLoggerProvider()); $scope->detach(); } } diff --git a/tests/Unit/SDK/SdkTest.php b/tests/Unit/SDK/SdkTest.php index 4eff6943f..be35ab3bb 100644 --- a/tests/Unit/SDK/SdkTest.php +++ b/tests/Unit/SDK/SdkTest.php @@ -5,6 +5,7 @@ namespace OpenTelemetry\Tests\Unit\SDK; use AssertWell\PHPUnitGlobalState\EnvironmentVariables; +use OpenTelemetry\API\Logs\EventLoggerProviderInterface; use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface; use OpenTelemetry\SDK\Common\Configuration\Variables; use OpenTelemetry\SDK\Logs\LoggerProviderInterface; @@ -82,10 +83,12 @@ public function test_getters(): void $meterProvider = $this->createMock(MeterProviderInterface::class); $tracerProvider = $this->createMock(TracerProviderInterface::class); $loggerProvider = $this->createMock(LoggerProviderInterface::class); - $sdk = new Sdk($tracerProvider, $meterProvider, $loggerProvider, $propagator); + $eventLoggerProvider = $this->createMock(EventLoggerProviderInterface::class); + $sdk = new Sdk($tracerProvider, $meterProvider, $loggerProvider, $eventLoggerProvider, $propagator); $this->assertSame($propagator, $sdk->getPropagator()); $this->assertSame($meterProvider, $sdk->getMeterProvider()); $this->assertSame($tracerProvider, $sdk->getTracerProvider()); $this->assertSame($loggerProvider, $sdk->getLoggerProvider()); + $this->assertSame($eventLoggerProvider, $sdk->getEventLoggerProvider()); } } diff --git a/tests/coverage/html/.gitkeep b/tests/coverage/html/.gitkeep deleted file mode 100644 index e69de29bb..000000000