Repository: open-telemetry/opentelemetry-php (php)

Issue:
OTLP Exporter crashing the app when getting `Export failure: Unauthorized`
**Describe your environment**

When trying out PHP OTel and Wordpress in a Docker container, while sending traces to Dynatrace, when my token was invalid, the whole wordpress container crashed.

As an OpenTelemetry user I expected the exporter to fail to export as it happens in other languages, but not crash the application.

Below is my development box and dependencies:

```
PHP 8.2.4 (cli) (built: Mar 27 2023 22:42:00) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.4, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.4, Copyright (c), by Zend Technologies
```

```php
"require": {
        "open-telemetry/api": "1.0.0beta5",
        "open-telemetry/sdk": "1.0.0beta6",
        "open-telemetry/exporter-otlp": "1.0.0beta5",
        "open-telemetry/opentelemetry-auto-wordpress": "0.0.4",
        "open-telemetry/opentelemetry-instrumentation-installer": "0.0.2",
        "guzzlehttp/guzzle": "7.4.5",
        "php-http/guzzle7-adapter": "1.0.0"
}
```

**Additional context**
Issue discussed in here: https://cloud-native.slack.com/archives/C01NFPCV44V/p1681301122955069


Pull request description:
relax default logging levels
without a psr-3 logger, we use trigger_error. Using this with E_USER_ERROR is fatal, which is not what we want.

Fixes #968 

Patch:
diff --git a/examples/logs/features/monolog-otel-integration.php b/examples/logs/features/monolog-otel-integration.php
index 33b3e9fe..5852e155 100644
--- a/examples/logs/features/monolog-otel-integration.php
+++ b/examples/logs/features/monolog-otel-integration.php
@@ -45,7 +45,7 @@ $otelHandler = new class(LogLevel::INFO) extends AbstractProcessingHandler {
 
     protected function write(array $record): void
     {
-        $this->logger->logRecord($this->convert($record));
+        $this->logger->emit($this->convert($record));
     }
 
     private function convert(array $record): LogRecord
diff --git a/src/API/Behavior/LogsMessagesTrait.php b/src/API/Behavior/LogsMessagesTrait.php
index adeb9603..21d22345 100644
--- a/src/API/Behavior/LogsMessagesTrait.php
+++ b/src/API/Behavior/LogsMessagesTrait.php
@@ -18,11 +18,10 @@ trait LogsMessagesTrait
     {
         switch ($level) {
             case LogLevel::WARNING:
-                return E_USER_WARNING;
             case LogLevel::ERROR:
             case LogLevel::CRITICAL:
             case LogLevel::EMERGENCY:
-                return E_USER_ERROR;
+                return E_USER_WARNING;
             default:
                 return E_USER_NOTICE;
         }
diff --git a/src/API/Common/Instrumentation/CachedInstrumentation.php b/src/API/Common/Instrumentation/CachedInstrumentation.php
index 6cba1a4b..c7969511 100644
--- a/src/API/Common/Instrumentation/CachedInstrumentation.php
+++ b/src/API/Common/Instrumentation/CachedInstrumentation.php
@@ -88,10 +88,9 @@ final class CachedInstrumentation
         $loggerProvider = Globals::loggerProvider();
 
         if ($this->loggers === null) {
-            //@todo configurable includeTraceContext?
-            return $loggerProvider->getLogger($this->name, $this->version, $this->schemaUrl, true, $this->attributes);
+            return $loggerProvider->getLogger($this->name, $this->version, $this->schemaUrl, $this->attributes);
         }
 
-        return $this->loggers[$loggerProvider] ??= $loggerProvider->getLogger($this->name, $this->version, $this->schemaUrl, true, $this->attributes);
+        return $this->loggers[$loggerProvider] ??= $loggerProvider->getLogger($this->name, $this->version, $this->schemaUrl, $this->attributes);
     }
 }
diff --git a/src/API/Logs/EventLogger.php b/src/API/Logs/EventLogger.php
index 75bc6ed4..68deb865 100644
--- a/src/API/Logs/EventLogger.php
+++ b/src/API/Logs/EventLogger.php
@@ -21,6 +21,6 @@ class EventLogger implements EventLoggerInterface
             'event.name' => $eventName,
             'event.domain' => $this->domain,
         ]);
-        $this->logger->logRecord($logRecord);
+        $this->logger->emit($logRecord);
     }
 }
diff --git a/src/API/Logs/LoggerInterface.php b/src/API/Logs/LoggerInterface.php
index ab89a8ce..89477c8d 100644
--- a/src/API/Logs/LoggerInterface.php
+++ b/src/API/Logs/LoggerInterface.php
@@ -6,5 +6,5 @@ namespace OpenTelemetry\API\Logs;
 
 interface LoggerInterface
 {
-    public function logRecord(LogRecord $logRecord): void;
+    public function emit(LogRecord $logRecord): void;
 }
diff --git a/src/API/Logs/LoggerProviderInterface.php b/src/API/Logs/LoggerProviderInterface.php
index 2222a900..e60353de 100644
--- a/src/API/Logs/LoggerProviderInterface.php
+++ b/src/API/Logs/LoggerProviderInterface.php
@@ -13,7 +13,6 @@ interface LoggerProviderInterface
         string $name,
         ?string $version = null,
         ?string $schemaUrl = null,
-        bool $includeTraceContext = true,
         iterable $attributes = [] //instrumentation scope attributes
     ): LoggerInterface;
 }
diff --git a/src/API/Logs/NoopLogger.php b/src/API/Logs/NoopLogger.php
index 0062a588..faacd5e1 100644
--- a/src/API/Logs/NoopLogger.php
+++ b/src/API/Logs/NoopLogger.php
@@ -20,7 +20,7 @@ class NoopLogger implements LoggerInterface
     /**
      * @codeCoverageIgnore
      */
-    public function logRecord(LogRecord $logRecord): void
+    public function emit(LogRecord $logRecord): void
     {
     }
 
diff --git a/src/API/Logs/NoopLoggerProvider.php b/src/API/Logs/NoopLoggerProvider.php
index bb0c5c6d..8b00b663 100644
--- a/src/API/Logs/NoopLoggerProvider.php
+++ b/src/API/Logs/NoopLoggerProvider.php
@@ -13,7 +13,7 @@ class NoopLoggerProvider implements LoggerProviderInterface
         return $instance ??= new self();
     }
 
-    public function getLogger(string $name, ?string $version = null, ?string $schemaUrl = null, bool $includeTraceContext = true, iterable $attributes = []): LoggerInterface
+    public function getLogger(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = []): LoggerInterface
     {
         return NoopLogger::getInstance();
     }
diff --git a/src/Contrib/Otlp/LogsConverter.php b/src/Contrib/Otlp/LogsConverter.php
index df980cb3..07888769 100644
--- a/src/Contrib/Otlp/LogsConverter.php
+++ b/src/Contrib/Otlp/LogsConverter.php
@@ -18,6 +18,13 @@ use OpenTelemetry\SDK\Resource\ResourceInfo;
 
 class LogsConverter
 {
+    private ProtobufSerializer $serializer;
+
+    public function __construct(?ProtobufSerializer $serializer = null)
+    {
+        $this->serializer = $serializer ?? ProtobufSerializer::getDefault();
+    }
+
     /**
      * @param iterable<ReadableLogRecord> $logs
      * @psalm-suppress InvalidArgument
@@ -76,8 +83,8 @@ class LogsConverter
         $pLogRecord->setObservedTimeUnixNano($record->getObservedTimestamp() ?? 0);
         $spanContext = $record->getSpanContext();
         if ($spanContext !== null && $spanContext->isValid()) {
-            $pLogRecord->setTraceId($spanContext->getTraceIdBinary());
-            $pLogRecord->setSpanId($spanContext->getSpanIdBinary());
+            $pLogRecord->setTraceId($this->serializer->serializeTraceId($spanContext->getTraceIdBinary()));
+            $pLogRecord->setSpanId($this->serializer->serializeSpanId($spanContext->getSpanIdBinary()));
             $pLogRecord->setFlags($spanContext->getTraceFlags());
         }
         $severityNumber = $record->getSeverityNumber();
diff --git a/src/Contrib/Otlp/LogsExporter.php b/src/Contrib/Otlp/LogsExporter.php
index 36855a4a..fb100391 100644
--- a/src/Contrib/Otlp/LogsExporter.php
+++ b/src/Contrib/Otlp/LogsExporter.php
@@ -42,7 +42,7 @@ class LogsExporter implements LogRecordExporterInterface
     public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface
     {
         return $this->transport
-            ->send($this->serializer->serialize((new LogsConverter())->convert($batch)), $cancellation)
+            ->send($this->serializer->serialize((new LogsConverter($this->serializer))->convert($batch)), $cancellation)
             ->map(function (?string $payload): bool {
                 if ($payload === null) {
                     return true;
diff --git a/src/Contrib/Otlp/MetricConverter.php b/src/Contrib/Otlp/MetricConverter.php
index 868276f5..584c4136 100644
--- a/src/Contrib/Otlp/MetricConverter.php
+++ b/src/Contrib/Otlp/MetricConverter.php
@@ -27,6 +27,13 @@ use function serialize;
 
 final class MetricConverter
 {
+    private ProtobufSerializer $serializer;
+
+    public function __construct(?ProtobufSerializer $serializer = null)
+    {
+        $this->serializer = $serializer ?? ProtobufSerializer::getDefault();
+    }
+
     /**
      * @param iterable<SDK\Metrics\Data\Metric> $batch
      */
@@ -218,8 +225,8 @@ final class MetricConverter
         $pExemplar = new Exemplar();
         $this->setFilteredAttributes($pExemplar, $exemplar->attributes);
         $pExemplar->setTimeUnixNano($exemplar->timestamp);
-        $pExemplar->setSpanId(hex2bin((string) $exemplar->spanId));
-        $pExemplar->setTraceId(hex2bin((string) $exemplar->traceId));
+        $pExemplar->setSpanId($this->serializer->serializeSpanId(hex2bin((string) $exemplar->spanId)));
+        $pExemplar->setTraceId($this->serializer->serializeTraceId(hex2bin((string) $exemplar->traceId)));
         if (is_int($exemplar->value)) {
             $pExemplar->setAsInt($exemplar->value);
         }
diff --git a/src/Contrib/Otlp/MetricExporter.php b/src/Contrib/Otlp/MetricExporter.php
index 2f5a2a39..d9f26fd5 100644
--- a/src/Contrib/Otlp/MetricExporter.php
+++ b/src/Contrib/Otlp/MetricExporter.php
@@ -52,7 +52,7 @@ final class MetricExporter implements MetricExporterInterface
     public function export(iterable $batch): bool
     {
         return $this->transport
-            ->send($this->serializer->serialize((new MetricConverter())->convert($batch)))
+            ->send($this->serializer->serialize((new MetricConverter($this->serializer))->convert($batch)))
             ->map(function (?string $payload): bool {
                 if ($payload === null) {
                     return true;
diff --git a/src/Contrib/Otlp/ProtobufSerializer.php b/src/Contrib/Otlp/ProtobufSerializer.php
index 076f643a..c244d006 100644
--- a/src/Contrib/Otlp/ProtobufSerializer.php
+++ b/src/Contrib/Otlp/ProtobufSerializer.php
@@ -5,6 +5,8 @@ declare(strict_types=1);
 namespace OpenTelemetry\Contrib\Otlp;
 
 use AssertionError;
+use function base64_decode;
+use function bin2hex;
 use Exception;
 use Google\Protobuf\Internal\Message;
 use InvalidArgumentException;
@@ -29,6 +31,11 @@ final class ProtobufSerializer
         $this->contentType = $contentType;
     }
 
+    public static function getDefault(): ProtobufSerializer
+    {
+        return new self(self::PROTOBUF);
+    }
+
     /**
      * @psalm-param TransportInterface<SUPPORTED_CONTENT_TYPES> $transport
      */
@@ -44,6 +51,32 @@ final class ProtobufSerializer
         }
     }
 
+    public function serializeTraceId(string $traceId): string
+    {
+        switch ($this->contentType) {
+            case self::PROTOBUF:
+                return $traceId;
+            case self::JSON:
+            case self::NDJSON:
+                return base64_decode(bin2hex($traceId));
+            default:
+                throw new AssertionError();
+        }
+    }
+
+    public function serializeSpanId(string $spanId): string
+    {
+        switch ($this->contentType) {
+            case self::PROTOBUF:
+                return $spanId;
+            case self::JSON:
+            case self::NDJSON:
+                return base64_decode(bin2hex($spanId));
+            default:
+                throw new AssertionError();
+        }
+    }
+
     public function serialize(Message $message): string
     {
         switch ($this->contentType) {
@@ -71,7 +104,8 @@ final class ProtobufSerializer
                 break;
             case self::JSON:
             case self::NDJSON:
-                $message->mergeFromJsonString($payload);
+                // @phan-suppress-next-line PhanParamTooManyInternal
+                $message->mergeFromJsonString($payload, true);
 
                 break;
             default:
diff --git a/src/Contrib/Otlp/SpanConverter.php b/src/Contrib/Otlp/SpanConverter.php
index 99fee406..1a8b4369 100644
--- a/src/Contrib/Otlp/SpanConverter.php
+++ b/src/Contrib/Otlp/SpanConverter.php
@@ -26,6 +26,13 @@ use function spl_object_id;
 
 final class SpanConverter
 {
+    private ProtobufSerializer $serializer;
+
+    public function __construct(?ProtobufSerializer $serializer = null)
+    {
+        $this->serializer = $serializer ?? ProtobufSerializer::getDefault();
+    }
+
     public function convert(iterable $spans): ExportTraceServiceRequest
     {
         $pExportTraceServiceRequest = new ExportTraceServiceRequest();
@@ -139,11 +146,11 @@ final class SpanConverter
     private function convertSpan(SpanDataInterface $span): Span
     {
         $pSpan = new Span();
-        $pSpan->setTraceId($span->getContext()->getTraceIdBinary());
-        $pSpan->setSpanId($span->getContext()->getSpanIdBinary());
+        $pSpan->setTraceId($this->serializer->serializeTraceId($span->getContext()->getTraceIdBinary()));
+        $pSpan->setSpanId($this->serializer->serializeSpanId($span->getContext()->getSpanIdBinary()));
         $pSpan->setTraceState((string) $span->getContext()->getTraceState());
         if ($span->getParentContext()->isValid()) {
-            $pSpan->setParentSpanId($span->getParentContext()->getSpanIdBinary());
+            $pSpan->setParentSpanId($this->serializer->serializeSpanId($span->getParentContext()->getSpanIdBinary()));
         }
         $pSpan->setName($span->getName());
         $pSpan->setKind($this->convertSpanKind($span->getKind()));
@@ -163,8 +170,8 @@ final class SpanConverter
         foreach ($span->getLinks() as $link) {
             /** @psalm-suppress InvalidArgument */
             $pSpan->getLinks()[] = $pLink = new Link();
-            $pLink->setTraceId($link->getSpanContext()->getTraceIdBinary());
-            $pLink->setSpanId($link->getSpanContext()->getSpanIdBinary());
+            $pLink->setTraceId($this->serializer->serializeTraceId($link->getSpanContext()->getTraceIdBinary()));
+            $pLink->setSpanId($this->serializer->serializeSpanId($link->getSpanContext()->getSpanIdBinary()));
             $pLink->setTraceState((string) $link->getSpanContext()->getTraceState());
             $this->setAttributes($pLink, $link->getAttributes());
         }
diff --git a/src/Contrib/Otlp/SpanExporter.php b/src/Contrib/Otlp/SpanExporter.php
index 5ef2e4c3..a496206f 100644
--- a/src/Contrib/Otlp/SpanExporter.php
+++ b/src/Contrib/Otlp/SpanExporter.php
@@ -38,7 +38,7 @@ final class SpanExporter implements SpanExporterInterface
     public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface
     {
         return $this->transport
-            ->send($this->serializer->serialize((new SpanConverter())->convert($batch)), $cancellation)
+            ->send($this->serializer->serialize((new SpanConverter($this->serializer))->convert($batch)), $cancellation)
             ->map(function (?string $payload): bool {
                 if ($payload === null) {
                     return true;
diff --git a/src/SDK/Logs/Logger.php b/src/SDK/Logs/Logger.php
index 9058a7f2..0b8db152 100644
--- a/src/SDK/Logs/Logger.php
+++ b/src/SDK/Logs/Logger.php
@@ -18,18 +18,16 @@ class Logger implements LoggerInterface
 {
     private InstrumentationScopeInterface $scope;
     private LoggerSharedState $loggerSharedState;
-    private bool $includeTraceContext;
 
-    public function __construct(LoggerSharedState $loggerSharedState, InstrumentationScopeInterface $scope, bool $includeTraceContext)
+    public function __construct(LoggerSharedState $loggerSharedState, InstrumentationScopeInterface $scope)
     {
         $this->loggerSharedState = $loggerSharedState;
         $this->scope = $scope;
-        $this->includeTraceContext = $includeTraceContext;
     }
 
-    public function logRecord(LogRecord $logRecord): void
+    public function emit(LogRecord $logRecord): void
     {
-        $readWriteLogRecord = new ReadWriteLogRecord($this->scope, $this->loggerSharedState, $logRecord, $this->includeTraceContext);
+        $readWriteLogRecord = new ReadWriteLogRecord($this->scope, $this->loggerSharedState, $logRecord);
         // @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md#onemit
         $this->loggerSharedState->getProcessor()->onEmit(
             $readWriteLogRecord,
diff --git a/src/SDK/Logs/LoggerProvider.php b/src/SDK/Logs/LoggerProvider.php
index a4c2023e..f0a8266c 100644
--- a/src/SDK/Logs/LoggerProvider.php
+++ b/src/SDK/Logs/LoggerProvider.php
@@ -29,14 +29,14 @@ class LoggerProvider implements LoggerProviderInterface
     /**
      * @see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/sdk.md#logger-creation
      */
-    public function getLogger(string $name, ?string $version = null, ?string $schemaUrl = null, bool $includeTraceContext = true, iterable $attributes = []): LoggerInterface
+    public function getLogger(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = []): LoggerInterface
     {
         if ($this->loggerSharedState->hasShutdown()) {
             return NoopLogger::getInstance();
         }
         $scope = $this->instrumentationScopeFactory->create($name, $version, $schemaUrl, $attributes);
 
-        return new Logger($this->loggerSharedState, $scope, $includeTraceContext);
+        return new Logger($this->loggerSharedState, $scope);
     }
 
     public function shutdown(CancellationInterface $cancellation = null): bool
diff --git a/src/SDK/Logs/NoopLoggerProvider.php b/src/SDK/Logs/NoopLoggerProvider.php
index 724b40bb..819e02ee 100644
--- a/src/SDK/Logs/NoopLoggerProvider.php
+++ b/src/SDK/Logs/NoopLoggerProvider.php
@@ -16,7 +16,7 @@ class NoopLoggerProvider implements LoggerProviderInterface
         return $instance ??= new self();
     }
 
-    public function getLogger(string $name, ?string $version = null, ?string $schemaUrl = null, bool $includeTraceContext = true, iterable $attributes = []): LoggerInterface
+    public function getLogger(string $name, ?string $version = null, ?string $schemaUrl = null, iterable $attributes = []): LoggerInterface
     {
         return NoopLogger::getInstance();
     }
diff --git a/src/SDK/Logs/ReadableLogRecord.php b/src/SDK/Logs/ReadableLogRecord.php
index 04e116be..74666b30 100644
--- a/src/SDK/Logs/ReadableLogRecord.php
+++ b/src/SDK/Logs/ReadableLogRecord.php
@@ -24,19 +24,18 @@ class ReadableLogRecord extends LogRecord
     protected AttributesInterface $convertedAttributes;
     protected SpanContextInterface $spanContext;
 
-    public function __construct(InstrumentationScopeInterface $scope, LoggerSharedState $loggerSharedState, LogRecord $logRecord, bool $includeTraceContext)
+    public function __construct(InstrumentationScopeInterface $scope, LoggerSharedState $loggerSharedState, LogRecord $logRecord)
     {
         $this->scope = $scope;
         $this->loggerSharedState = $loggerSharedState;
 
         parent::__construct($logRecord->body);
         $this->timestamp = $logRecord->timestamp;
-        $this->observedTimestamp = $logRecord->observedTimestamp;
+        $this->observedTimestamp = $logRecord->observedTimestamp
+            ?? (int) (microtime(true) * LogRecord::NANOS_PER_SECOND);
         $this->context = $logRecord->context;
-        if ($includeTraceContext) {
-            $context = $this->context ?? Context::getCurrent();
-            $this->spanContext = Span::fromContext($context)->getContext();
-        };
+        $context = $this->context ?? Context::getCurrent();
+        $this->spanContext = Span::fromContext($context)->getContext();
         $this->severityNumber = $logRecord->severityNumber;
         $this->severityText = $logRecord->severityText;
 


Test patch:
diff --git a/tests/Unit/API/Logs/EventLoggerTest.php b/tests/Unit/API/Logs/EventLoggerTest.php
index 9227b674..f06625fc 100644
--- a/tests/Unit/API/Logs/EventLoggerTest.php
+++ b/tests/Unit/API/Logs/EventLoggerTest.php
@@ -21,7 +21,7 @@ class EventLoggerTest extends TestCase
         $logRecord = $this->createMock(LogRecord::class);
         $eventLogger = new EventLogger($logger, $domain);
         $logRecord->expects($this->once())->method('setAttributes');
-        $logger->expects($this->once())->method('logRecord')->with($this->equalTo($logRecord));
+        $logger->expects($this->once())->method('emit')->with($this->equalTo($logRecord));
 
         $eventLogger->logEvent('some.event', $logRecord);
     }
diff --git a/tests/Unit/Contrib/Otlp/SpanExporterTest.php b/tests/Unit/Contrib/Otlp/SpanExporterTest.php
index f14db6d7..035d3fda 100644
--- a/tests/Unit/Contrib/Otlp/SpanExporterTest.php
+++ b/tests/Unit/Contrib/Otlp/SpanExporterTest.php
@@ -4,12 +4,17 @@ declare(strict_types=1);
 
 namespace OpenTelemetry\Tests\Unit\Contrib\Otlp;
 
+use function fseek;
+use OpenTelemetry\API\Trace\SpanContext;
 use OpenTelemetry\Contrib\Otlp\SpanExporter;
+use OpenTelemetry\SDK\Common\Export\Stream\StreamTransport;
 use OpenTelemetry\SDK\Common\Export\TransportInterface;
 use OpenTelemetry\SDK\Common\Future\CompletedFuture;
 use OpenTelemetry\SDK\Common\Future\ErrorFuture;
+use OpenTelemetry\Tests\Unit\SDK\Util\SpanData;
 use PHPUnit\Framework\MockObject\MockObject;
 use PHPUnit\Framework\TestCase;
+use function stream_get_contents;
 
 /**
  * @covers \OpenTelemetry\Contrib\Otlp\SpanExporter
@@ -61,4 +66,42 @@ class SpanExporterTest extends TestCase
         $this->transport->expects($this->once())->method('forceFlush');
         $this->exporter->forceFlush();
     }
+
+    public function test_json_span_and_trace_id_hex_format(): void
+    {
+        $stream = fopen('php://memory', 'a+b');
+        $transport = new StreamTransport($stream, 'application/json');
+        $exporter = new SpanExporter($transport);
+
+        $exporter->export([
+            (new SpanData())->setContext(SpanContext::create('0af7651916cd43dd8448eb211c80319c', 'b7ad6b7169203331')),
+        ]);
+
+        fseek($stream, 0);
+        $this->assertJsonStringEqualsJsonString(<<<TRACE
+            {
+                "resourceSpans": [
+                    {
+                        "resource": {},
+                        "scopeSpans": [
+                            {
+                                "scope": {},
+                                "spans": [
+                                    {
+                                        "traceId": "0af7651916cd43dd8448eb211c80319c",
+                                        "spanId": "b7ad6b7169203331",
+                                        "name": "test-span-data",
+                                        "kind": "SPAN_KIND_INTERNAL",
+                                        "startTimeUnixNano": "1505855794194009601",
+                                        "endTimeUnixNano": "1505855799465726528",
+                                        "status": {}
+                                    }
+                                ]
+                            }
+                        ]
+                    }
+                ]
+            }
+            TRACE, stream_get_contents($stream));
+    }
 }
diff --git a/tests/Unit/SDK/Logs/Exporter/ConsoleExporterTest.php b/tests/Unit/SDK/Logs/Exporter/ConsoleExporterTest.php
index c97913ff..0c580dc0 100644
--- a/tests/Unit/SDK/Logs/Exporter/ConsoleExporterTest.php
+++ b/tests/Unit/SDK/Logs/Exporter/ConsoleExporterTest.php
@@ -34,7 +34,6 @@ class ConsoleExporterTest extends TestCase
                 $this->createMock(InstrumentationScopeInterface::class),
                 $this->createMock(LoggerSharedState::class),
                 (new LogRecord('foo')),
-                true,
             )),
         ];
 
diff --git a/tests/Unit/SDK/Logs/LoggerTest.php b/tests/Unit/SDK/Logs/LoggerTest.php
index 08b57601..50be2f38 100644
--- a/tests/Unit/SDK/Logs/LoggerTest.php
+++ b/tests/Unit/SDK/Logs/LoggerTest.php
@@ -34,7 +34,7 @@ class LoggerTest extends TestCase
 
     public function test_log_record(): void
     {
-        $logger = new Logger($this->sharedState, $this->scope, true);
+        $logger = new Logger($this->sharedState, $this->scope);
         $record = (new LogRecord())->setContext($this->createMock(ContextInterface::class));
 
         $this->processor->expects($this->once())->method('onEmit')
@@ -43,6 +43,26 @@ class LoggerTest extends TestCase
                 $this->isInstanceOf(ContextInterface::class)
             );
 
-        $logger->logRecord($record);
+        $logger->emit($record);
+    }
+
+    public function test_sets_observed_timestamp_on_emit(): void
+    {
+        $logger = new Logger($this->sharedState, $this->scope);
+        $record = new LogRecord();
+        $time = microtime(true) * LogRecord::NANOS_PER_SECOND;
+
+        $this->processor->expects($this->once())->method('onEmit')
+            ->with(
+                $this->callback(function (ReadWriteLogRecord $record) use ($time) {
+                    $this->assertNotNull($record->getObservedTimestamp());
+                    $this->assertGreaterThan($time, $record->getObservedTimestamp());
+
+                    return true;
+                }),
+                $this->anything(),
+            );
+
+        $logger->emit($record);
     }
 }
diff --git a/tests/Unit/SDK/Logs/ReadableLogRecordTest.php b/tests/Unit/SDK/Logs/ReadableLogRecordTest.php
index e5c50873..ac409a37 100644
--- a/tests/Unit/SDK/Logs/ReadableLogRecordTest.php
+++ b/tests/Unit/SDK/Logs/ReadableLogRecordTest.php
@@ -37,7 +37,7 @@ class ReadableLogRecordTest extends TestCase
             ->setObservedTimestamp(22)
             ->setAttributes(['foo' => 'bar'])
             ->setContext($context);
-        $record = new ReadableLogRecord($scope, $sharedState, $logRecord, true);
+        $record = new ReadableLogRecord($scope, $sharedState, $logRecord);
 
         $this->assertSame($scope, $record->getInstrumentationScope());
         $this->assertSame($resource, $record->getResource());