Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ private function serializeEvents(array $events) : array
foreach ($events as $event) {
$result[] = [
'name' => $event->name(),
'timeUnixNano' => (string) $event->timestamp(),
'timeUnixNano' => $this->toNanoseconds($event->timestamp()),
'attributes' => $this->serializeAttributes($event->attributes()),
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ private function createSpanEvent(SpanEvent $event) : Event
{
$protoEvent = new Event();
$protoEvent->setName($event->name());
$protoEvent->setTimeUnixNano($event->timestamp());
$protoEvent->setTimeUnixNano($this->toNanoseconds($event->timestamp()));
$protoEvent->setAttributes($this->createKeyValues($event->attributes())); // @phpstan-ignore argument.type

return $protoEvent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private function serializeEvents(array $events) : array
foreach ($events as $event) {
$result[] = [
'name' => $event->name(),
'timeUnixNano' => (string) $event->timestamp(),
'timeUnixNano' => $this->toNanoseconds($event->timestamp()),
'attributes' => $this->attributeSerializer->serialize($event->attributesObject()),
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ public function test_exports_span_with_events(TransportConfiguration $config) :
$tracer = $telemetry->tracer('test-component');

$span = $tracer->span('event-test');
$span->recordEvent(GenericEvent::now('cache.hit', ['cache.key' => 'user:123']));
$span->recordEvent(GenericEvent::now('db.query', ['db.statement' => 'SELECT * FROM users']));
$span->recordEvent(GenericEvent::create('cache.hit', new \DateTimeImmutable(), ['cache.key' => 'user:123']));
$span->recordEvent(GenericEvent::create('db.query', new \DateTimeImmutable(), ['db.statement' => 'SELECT * FROM users']));
$tracer->complete($span);

$telemetry->shutdown();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ public function test_serialize_spans_with_events() : void
$context = SpanContext::create(TraceId::generate(), SpanId::generate());

$span = new Span('test-span', $context, SpanKind::INTERNAL, new \DateTimeImmutable(), $resource, $scope);
$span->recordEvent(GenericEvent::now('cache.hit', ['key' => 'user:123']));
$span->recordEvent(GenericEvent::create('cache.hit', new \DateTimeImmutable(), ['key' => 'user:123']));

$json = $this->serializer->serializeSpans([$span]);
/** @var array<string, mixed> $data */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function test_serialize_span_with_error_status() : void
public function test_serialize_span_with_events() : void
{
$span = $this->createSpan();
$span->recordEvent(GenericEvent::now('cache.hit', ['key' => 'user:123']));
$span->recordEvent(GenericEvent::create('cache.hit', new \DateTimeImmutable(), ['key' => 'user:123']));

$result = $this->serializer->serialize($span);

Expand Down
7 changes: 4 additions & 3 deletions src/lib/telemetry/src/Flow/Telemetry/DSL/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,16 @@ function span_context(TraceId $traceId, SpanId $spanId, ?SpanId $parentSpanId =
}

/**
* Create a SpanEvent (GenericEvent) with the current timestamp.
* Create a SpanEvent (GenericEvent) with an explicit timestamp.
*
* @param string $name Event name
* @param \DateTimeImmutable $timestamp Event timestamp
* @param array<string, array<bool|float|int|string>|bool|float|int|string> $attributes Event attributes
*/
#[DocumentationDSL(module: Module::TELEMETRY, type: DSLType::TYPE)]
function span_event(string $name, array $attributes = []) : GenericEvent
function span_event(string $name, \DateTimeImmutable $timestamp, array $attributes = []) : GenericEvent
{
return GenericEvent::now($name, $attributes);
return GenericEvent::create($name, $timestamp, $attributes);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,6 @@ public function get(string $key) : ?string
return null;
}

public function keys() : array
{
return \array_keys($this->data);
}

public function set(string $key, string $value) : void
{
$this->data[$key] = $value;
Expand Down
11 changes: 0 additions & 11 deletions src/lib/telemetry/src/Flow/Telemetry/Propagation/Carrier.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@
* $this->request = $this->request->withHeader($key, $value);
* }
*
* public function keys(): array
* {
* return array_keys($this->request->getHeaders());
* }
* }
* ```
*/
Expand All @@ -48,13 +44,6 @@ interface Carrier
*/
public function get(string $key) : ?string;

/**
* Get all available keys.
*
* @return array<string> List of keys in the carrier
*/
public function keys() : array;

/**
* Set a value.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,40 +60,6 @@ public function get(string $key) : ?string
return null;
}

/**
* @return array<string>
*/
public function keys() : array
{
$keys = [];

foreach (\array_keys($_SERVER) as $key) {
if (\is_string($key) && \str_starts_with($key, 'HTTP_')) {
$keys[] = \str_replace('_', '-', \strtolower(\substr($key, 5)));
}
}

foreach (\array_keys($_GET) as $key) {
if (\is_string($key)) {
$keys[] = $key;
}
}

foreach (\array_keys($_POST) as $key) {
if (\is_string($key)) {
$keys[] = $key;
}
}

foreach (\array_keys($_COOKIE) as $key) {
if (\is_string($key)) {
$keys[] = $key;
}
}

return \array_unique($keys);
}

public function set(string $key, string $value) : void
{
throw new RuntimeException('SuperglobalCarrier is read-only');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private function buildEventLines(Span $span) : array
$lines[] = $this->output->bold('Events (' . \count($events) . '):');

foreach ($events as $event) {
$timestamp = $this->formatNanosTimestamp($event->timestamp());
$timestamp = $this->formatTimestamp($event->timestamp());
$attrs = $event->attributes();
$attrStr = \count($attrs) > 0 ? ' ' . $this->output->dim($this->output->formatValue($attrs)) : '';
$lines[] = ' ' . $this->output->gray($timestamp) . ' ' . $event->name() . $attrStr;
Expand Down Expand Up @@ -162,20 +162,6 @@ private function calculateWidth(array $lines) : int
return \max(self::MIN_WIDTH, $maxLength + 4);
}

private function formatNanosTimestamp(int $nanos) : string
{
$seconds = (int) ($nanos / 1_000_000_000);
$micros = (int) (($nanos % 1_000_000_000) / 1000);

try {
$dt = (new \DateTimeImmutable())->setTimestamp($seconds);

return $dt->format('H:i:s') . '.' . \str_pad((string) $micros, 6, '0', STR_PAD_LEFT);
} catch (\Exception) {
return (string) $nanos;
}
}

private function formatResource(TelemetryResource $resource) : string
{
$parts = [];
Expand Down Expand Up @@ -209,6 +195,11 @@ private function formatStatusIcon(Span $span) : string
};
}

private function formatTimestamp(\DateTimeImmutable $timestamp) : string
{
return $timestamp->format('H:i:s.u');
}

private function printSpan(Span $span) : void
{
$headerLines = $this->buildSpanLines($span);
Expand Down
32 changes: 10 additions & 22 deletions src/lib/telemetry/src/Flow/Telemetry/Tracer/GenericEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,19 @@
* Default implementation of SpanEvent.
*
* GenericEvent provides a simple, immutable implementation for recording
* events within a span. Events can be created with explicit timestamps
* or automatically use the current time.
* events within a span. Events are created with explicit timestamps.
*
* Example usage:
* ```php
* $event = GenericEvent::now('user.login', ['user.id' => '12345']);
* $event = GenericEvent::create('user.login', $clock->now(), ['user.id' => '12345']);
* echo $event->name(); // "user.login"
* ```
*/
final readonly class GenericEvent implements SpanEvent
{
public function __construct(
private string $name,
private int $timestamp,
private \DateTimeImmutable $timestamp,
private Attributes $attributesObject = new Attributes(),
) {
}
Expand All @@ -32,39 +31,28 @@ public function __construct(
* Create an event with an explicit timestamp.
*
* @param string $name Event name
* @param int $timestamp Timestamp in nanoseconds since Unix epoch
* @param \DateTimeImmutable $timestamp Event timestamp
* @param array<string, array<bool|\DateTimeInterface|float|int|string|\Throwable>|bool|\DateTimeInterface|float|int|string|\Throwable> $attributes Event attributes
*/
public static function create(string $name, int $timestamp, array $attributes = []) : self
public static function create(string $name, \DateTimeImmutable $timestamp, array $attributes = []) : self
{
return new self($name, $timestamp, Attributes::create($attributes));
}

/**
* Create a GenericEvent from a normalized array representation.
*
* @param array{name: string, timestamp: int, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>} $data Normalized event data
* @param array{name: string, timestamp: string, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>} $data Normalized event data
*/
public static function fromArray(array $data) : self
{
return new self(
$data['name'],
$data['timestamp'],
new \DateTimeImmutable($data['timestamp']),
Attributes::fromArray($data['attributes']),
);
}

/**
* Create an event with the current timestamp.
*
* @param string $name Event name
* @param array<string, array<bool|\DateTimeInterface|float|int|string|\Throwable>|bool|\DateTimeInterface|float|int|string|\Throwable> $attributes Event attributes
*/
public static function now(string $name, array $attributes = []) : self
{
return new self($name, \hrtime(true), Attributes::create($attributes));
}

/**
* @return array<string, array<bool|float|int|string>|bool|float|int|string>
*/
Expand All @@ -86,18 +74,18 @@ public function name() : string
/**
* Normalize the GenericEvent to an array representation for serialization.
*
* @return array{name: string, timestamp: int, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}
* @return array{name: string, timestamp: string, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}
*/
public function normalize() : array
{
return [
'name' => $this->name,
'timestamp' => $this->timestamp,
'timestamp' => $this->timestamp->format('c'),
'attributes' => $this->attributesObject->normalize(),
];
}

public function timestamp() : int
public function timestamp() : \DateTimeImmutable
{
return $this->timestamp;
}
Expand Down
11 changes: 6 additions & 5 deletions src/lib/telemetry/src/Flow/Telemetry/Tracer/Span.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* ```php
* $span = new Span('process-order', $context, SpanKind::INTERNAL, new \DateTimeImmutable());
* $span->setAttribute('order.id', '12345')
* ->recordEvent(GenericEvent::now('validation.passed'))
* ->recordEvent(GenericEvent::create('validation.passed', new \DateTimeImmutable()))
* ->setStatus(SpanStatus::ok())
* ->end();
* ```
Expand Down Expand Up @@ -69,7 +69,7 @@ public function __construct(
* resource: array{attributes: array<string, array<bool|float|int|string>|bool|float|int|string>},
* scope: array{name: string, version: string, schemaUrl: null|string, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>},
* attributes: array<string, array<bool|float|int|string>|bool|float|int|string>,
* events: array<array{name: string, timestamp: int, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}>,
* events: array<array{name: string, timestamp: string, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}>,
* links: array<array{context: array{traceId: array{hex: string}, spanId: array{hex: string}, parentSpanId: null|array{hex: string}, isRemote: bool}, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}>,
* status: null|array{code: int, description: null|string},
* isRecording: bool
Expand Down Expand Up @@ -255,7 +255,7 @@ public function name() : string
* resource: array{attributes: array<string, array<bool|float|int|string>|bool|float|int|string>},
* scope: array{name: string, version: string, schemaUrl: null|string, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>},
* attributes: array<string, array<bool|float|int|string>|bool|float|int|string>,
* events: array<array{name: string, timestamp: int, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}>,
* events: array<array{name: string, timestamp: string, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}>,
* links: array<array{context: array{traceId: array{hex: string}, spanId: array{hex: string}, parentSpanId: null|array{hex: string}, isRemote: bool}, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}>,
* status: null|array{code: int, description: null|string},
* isRecording: bool
Expand Down Expand Up @@ -309,19 +309,20 @@ public function recordEvent(SpanEvent $event) : self
* Creates an event with OpenTelemetry semantic conventions for exceptions.
*
* @param \Throwable $exception The exception to record
* @param \DateTimeImmutable $timestamp The timestamp when the exception occurred
* @param array<string, array<bool|float|int|string>|bool|float|int|string> $attributes Additional attributes
*
* @return $this
*/
public function recordException(\Throwable $exception, array $attributes = []) : self
public function recordException(\Throwable $exception, \DateTimeImmutable $timestamp, array $attributes = []) : self
{
$eventAttributes = \array_merge([
'exception.type' => $exception::class,
'exception.message' => $exception->getMessage(),
'exception.stacktrace' => $exception->getTraceAsString(),
], $attributes);

$this->events[] = GenericEvent::now('exception', $eventAttributes);
$this->events[] = GenericEvent::create('exception', $timestamp, $eventAttributes);

return $this;
}
Expand Down
8 changes: 4 additions & 4 deletions src/lib/telemetry/src/Flow/Telemetry/Tracer/SpanEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface SpanEvent
/**
* Create a SpanEvent from a normalized array representation.
*
* @param array{name: string, timestamp: int, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>} $data Normalized event data
* @param array{name: string, timestamp: string, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>} $data Normalized event data
*/
public static function fromArray(array $data) : self;

Expand All @@ -41,12 +41,12 @@ public function name() : string;
/**
* Normalize the event to an array representation for serialization.
*
* @return array{name: string, timestamp: int, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}
* @return array{name: string, timestamp: string, attributes: array<string, array<bool|float|int|string>|bool|float|int|string>}
*/
public function normalize() : array;

/**
* Get the event timestamp in nanoseconds since Unix epoch.
* Get the event timestamp.
*/
public function timestamp() : int;
public function timestamp() : \DateTimeImmutable;
}
2 changes: 1 addition & 1 deletion src/lib/telemetry/src/Flow/Telemetry/Tracer/Tracer.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public function trace(string $name, callable $callback, SpanKind $kind = SpanKin

return $result;
} catch (\Throwable $e) {
$span->recordException($e);
$span->recordException($e, $this->clock->now());
$span->setStatus(SpanStatus::error($e->getMessage()));

throw $e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,19 @@ public function test_span_context_with_parent() : void

public function test_span_event_creates_event() : void
{
$event = span_event('test.event');
$timestamp = new \DateTimeImmutable();
$event = span_event('test.event', $timestamp);

self::assertInstanceOf(GenericEvent::class, $event);
self::assertSame('test.event', $event->name());
self::assertSame($timestamp, $event->timestamp());
self::assertSame([], $event->attributes());
}

public function test_span_event_with_attributes() : void
{
$event = span_event('test.event', ['key' => 'value']);
$timestamp = new \DateTimeImmutable();
$event = span_event('test.event', $timestamp, ['key' => 'value']);

self::assertSame(['key' => 'value'], $event->attributes());
}
Expand Down
Loading
Loading