Move and refactor clock components (#633)

* Move Clock classes to SDK\Common\Time namespace

* Move conversion methods to Util class

* Implement StopWatch

* Implement ClockFactory

* Fix StopwatchInterface

* Finalize ClockFactory

* Implement StopWatchFactory

* Deprecate AbstractClock

* Add BC alias

* Add initial start time to StopWatch

* Unify and optimize SystemClock methods

* Use ClockFactory in Span

* Use ClockFactory in BatchSpanProcessor

* Use ClockInterface in BatchSpanProcessorTest

* Use ClockFactory in SpanData

* Use ClockFactory in examples

* Add millisToNanos Util method

* Use StopWatch in BatchSpanProcessor

* Make Phan happy

* Make Psalm happy

* Make PHPUnit happy

* Remove sllh/composer-versions-check from allowed composer plugins

* Use correct assertion

* Use correct assertion

* Assert difference
This commit is contained in:
Timo Michna 2022-03-25 23:26:39 +01:00 committed by GitHub
parent 2b72c92fcb
commit 8e1e912c92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 902 additions and 183 deletions

View File

@ -55,7 +55,10 @@
"Jaeger\\Thrift\\": "thrift/jaeger/"
},
"files": [
"src/Context/fiber/initialize_fiber_handler.php"
"src/Context/fiber/initialize_fiber_handler.php",
"src/SDK/Common/Time/ClockInterface.php",
"src/SDK/Common/Time/AbstractClock.php",
"src/SDK/Common/Time/SystemClock.php"
]
},
"autoload-dev": {

View File

@ -97,7 +97,6 @@ $kernel->terminate($request, $response);
```php
use OpenTelemetry\Contrib\Jaeger\Exporter as JaegerExporter;
use OpenTelemetry\Contrib\Zipkin\Exporter as ZipkinExporter;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;

View File

@ -113,7 +113,6 @@ To use open-telemetry specific classes we have to import them at the top of our
use App\Kernel;
use OpenTelemetry\Contrib\Jaeger\Exporter as JaegerExporter;
use OpenTelemetry\Contrib\Zipkin\Exporter as ZipkinExporter;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;

View File

@ -5,8 +5,8 @@ require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOffSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
use OpenTelemetry\SDK\Trace\TracerProvider;
@ -28,7 +28,7 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
$span->setAttribute('remote_ip', '1.2.3.4');
$span->setAttribute('country', 'USA');
$timestamp = AbstractClock::getDefault()->timestamp();
$timestamp = ClockFactory::getDefault()->timestamp();
$span->addEvent('found_login', new Attributes([
'id' => 12345,
'username' => 'otuser',

View File

@ -8,8 +8,8 @@ use GuzzleHttp\Psr7\HttpFactory;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\Newrelic\Exporter as NewrelicExporter;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
@ -67,7 +67,7 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
for ($i = 0; $i < 5; $i++) {
// start a span, register some events
$timestamp = AbstractClock::getDefault()->timestamp();
$timestamp = ClockFactory::getDefault()->now();
$span = $tracer->startAndActivateSpan('session.generate.span.' . microtime(true));
$spanParent = $span->getParentContext();

View File

@ -6,8 +6,8 @@ require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\OtlpGrpc\Exporter as OTLPExporter;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
@ -31,7 +31,7 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
for ($i = 0; $i < 5; $i++) {
// start a span, register some events
$timestamp = AbstractClock::getDefault()->timestamp();
$timestamp = ClockFactory::getDefault()->now();
$span = $tracer->startAndActivateSpan('session.generate.span' . microtime(true));
//startAndActivateSpan('session.generate.span.' . microtime(true));

View File

@ -6,8 +6,8 @@ require __DIR__ . '/../vendor/autoload.php';
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\OtlpGrpc\Exporter as OTLPExporter;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
@ -35,7 +35,7 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
$rootSpan->setAttribute('remote_ip', '1.2.3.4')
->setAttribute('country', 'USA');
$timestamp = AbstractClock::getDefault()->timestamp();
$timestamp = ClockFactory::getDefault()->now();
$rootSpan->addEvent('found_login', new Attributes([
'id' => 1,
'username' => 'otuser',

View File

@ -8,8 +8,8 @@ use GuzzleHttp\Psr7\HttpFactory;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\ZipkinToNewrelic\Exporter as ZipkinToNewrelicExporter;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
@ -67,7 +67,7 @@ if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
for ($i = 0; $i < 5; $i++) {
// start a span, register some events
$timestamp = AbstractClock::getDefault()->timestamp();
$timestamp = ClockFactory::getDefault()->now();
$span = $tracer->startAndActivateSpan('session.generate.span.' . microtime(true));
$spanParent = $span->getParentContext();

View File

@ -15,7 +15,7 @@ echo sprintf('Sending batches every %dms and on shutdown', $delayMillis) . PHP_E
$tracerProvider = new TracerProvider(
new BatchSpanProcessor(
new ConsoleSpanExporter(),
\OpenTelemetry\SDK\SystemClock::getDefault(),
\OpenTelemetry\SDK\Common\Time\SystemClock::getDefault(),
2048, //max spans to queue before sending to exporter
$delayMillis, //batch delay milliseconds
)

View File

@ -17,7 +17,6 @@ require __DIR__ . '/../vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use OpenTelemetry\Contrib\Jaeger\Exporter as JaegerExporter;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Logs\SimplePsrFileLogger;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SpanExporter\LoggerDecorator;
@ -59,7 +58,7 @@ $decorator = new LoggerDecorator(
* Create the Tracer
*/
$tracerProvider = new TracerProvider(
new BatchSpanProcessor($decorator, AbstractClock::getDefault()),
new BatchSpanProcessor($decorator),
new AlwaysOnSampler()
);
$tracer = $tracerProvider->getTracer();

View File

@ -12,7 +12,7 @@ use Jaeger\Thrift\Tag;
use Jaeger\Thrift\TagType;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\API\Trace\StatusCode;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Time\Util as TimeUtil;
use OpenTelemetry\SDK\Trace\EventInterface;
use OpenTelemetry\SDK\Trace\LinkInterface;
use OpenTelemetry\SDK\Trace\SpanConverterInterface;
@ -69,8 +69,8 @@ class SpanConverter implements SpanConverterInterface
'parentSpanId' => $parentSpanId,
] = self::convertOtelToJaegerIds($span);
$startTime = AbstractClock::nanosToMicro($span->getStartEpochNanos());
$duration = AbstractClock::nanosToMicro($span->getEndEpochNanos() - $span->getStartEpochNanos());
$startTime = TimeUtil::nanosToMicros($span->getStartEpochNanos());
$duration = TimeUtil::nanosToMicros($span->getEndEpochNanos() - $span->getStartEpochNanos());
$tags = self::convertOtelSpanDataToJaegerTags($span);
@ -292,7 +292,7 @@ class SpanConverter implements SpanConverterInterface
private static function convertSingleOtelEventToJaegerLog(EventInterface $event): Log
{
$timestamp = AbstractClock::nanosToMicro($event->getEpochNanos());
$timestamp = TimeUtil::nanosToMicros($event->getEpochNanos());
$eventValue = $event->getAttributes()->get(self::EVENT_ATTRIBUTE_KEY_NAMED_EVENT) ?? $event->getName();
$attributes = $event->getAttributes()->toArray();

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace OpenTelemetry\Contrib\Newrelic;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Time\Util as TimeUtil;
use OpenTelemetry\SDK\Trace\SpanConverterInterface;
use OpenTelemetry\SDK\Trace\SpanDataInterface;
@ -37,8 +37,8 @@ class SpanConverter implements SpanConverterInterface
{
$spanParent = $span->getParentContext();
$startTimestamp = AbstractClock::nanosToMilli($span->getStartEpochNanos());
$endTimestamp = AbstractClock::nanosToMilli($span->getEndEpochNanos());
$startTimestamp = TimeUtil::nanosToMillis($span->getStartEpochNanos());
$endTimestamp = TimeUtil::nanosToMillis($span->getEndEpochNanos());
$row = [
'id' => $span->getSpanId(),

View File

@ -8,7 +8,7 @@ use function max;
use OpenTelemetry\API\Trace\SpanKind;
use OpenTelemetry\API\Trace\StatusCode;
use OpenTelemetry\Contrib\Zipkin\SpanKind as ZipkinSpanKind;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Time\Util as TimeUtil;
use OpenTelemetry\SDK\Trace\EventInterface;
use OpenTelemetry\SDK\Trace\SpanConverterInterface;
use OpenTelemetry\SDK\Trace\SpanDataInterface;
@ -75,8 +75,8 @@ class SpanConverter implements SpanConverterInterface
{
$spanParent = $span->getParentContext();
$startTimestamp = AbstractClock::nanosToMicro($span->getStartEpochNanos());
$endTimestamp = AbstractClock::nanosToMicro($span->getEndEpochNanos());
$startTimestamp = TimeUtil::nanosToMicros($span->getStartEpochNanos());
$endTimestamp = TimeUtil::nanosToMicros($span->getEndEpochNanos());
$row = [
'id' => $span->getSpanId(),
@ -167,7 +167,7 @@ class SpanConverter implements SpanConverterInterface
$value = ($attributesAsJson !== null) ? sprintf('"%s": %s', $eventName, $attributesAsJson) : sprintf('"%s"', $eventName);
$annotation = [
'timestamp' => AbstractClock::nanosToMicro($event->getEpochNanos()),
'timestamp' => TimeUtil::nanosToMicros($event->getEpochNanos()),
'value' => $value,
];

View File

@ -5,7 +5,7 @@ declare(strict_types=1);
namespace OpenTelemetry\Contrib\ZipkinToNewrelic;
use function max;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Time\Util as TimeUtil;
use OpenTelemetry\SDK\Trace\SpanConverterInterface;
use OpenTelemetry\SDK\Trace\SpanDataInterface;
@ -56,8 +56,8 @@ class SpanConverter implements SpanConverterInterface
{
$spanParent = $span->getParentContext();
$startTimestamp = AbstractClock::nanosToMicro($span->getStartEpochNanos());
$endTimestamp = AbstractClock::nanosToMicro($span->getEndEpochNanos());
$startTimestamp = TimeUtil::nanosToMicros($span->getStartEpochNanos());
$endTimestamp = TimeUtil::nanosToMicros($span->getEndEpochNanos());
$row = [
'id' => $span->getSpanId(),
@ -88,7 +88,7 @@ class SpanConverter implements SpanConverterInterface
$row['annotations'] = [];
}
$row['annotations'][] = [
'timestamp' => AbstractClock::nanosToMicro($event->getEpochNanos()),
'timestamp' => TimeUtil::nanosToMicros($event->getEpochNanos()),
'value' => $event->getName(),
];
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK;
interface ClockInterface
{
public const NANOS_PER_SECOND = 1000000000;
public const NANOS_PER_MILLISECOND = 1000000;
/**
* Returns the current epoch wall-clock timestamp in nanoseconds.
* This timestamp should _ONLY_ be used to compute a current time.
* Use {@see \OpenTelemetry\SDK\AbstractClock::nanoTime} for calculating
* durations.
*/
public function now(): int;
/**
* Returns a high resolution timestamp that should _ONLY_ be used to calculate elapsed time.
*/
public function nanoTime(): int;
}

View File

@ -2,17 +2,19 @@
declare(strict_types=1);
namespace OpenTelemetry\SDK;
use function intdiv;
namespace OpenTelemetry\SDK\Common\Time;
/**
* @deprecated
* Use {@see \OpenTelemetry\SDK\Common\Time\ClockFactory} and {@see \OpenTelemetry\SDK\Common\Time\Util} instead.
*/
abstract class AbstractClock implements ClockInterface
{
private static ?ClockInterface $testClock;
public static function getDefault(): ClockInterface
{
return self::$testClock ?? SystemClock::getInstance();
return self::$testClock ?? SystemClock::create();
}
/**
@ -42,3 +44,9 @@ abstract class AbstractClock implements ClockInterface
return $seconds * self::NANOS_PER_SECOND;
}
}
/**
* BC class alias
* @todo: remove in future release. Also in composer.json autoload/files.
*/
class_alias(AbstractClock::class, 'OpenTelemetry\SDK\AbstractClock');

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Time;
final class ClockFactory implements ClockFactoryInterface
{
private static ?ClockInterface $default;
public static function create(): self
{
return new self();
}
public function build(): ClockInterface
{
return new SystemClock();
}
public static function getDefault(): ClockInterface
{
return self::$default ?? self::$default = self::create()->build();
}
public static function setDefault(?ClockInterface $clock): void
{
self::$default = $clock;
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Time;
interface ClockFactoryInterface
{
public static function create(): self;
public function build(): ClockInterface;
public static function getDefault(): ClockInterface;
public static function setDefault(?ClockInterface $clock): void;
}

View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Time;
interface ClockInterface
{
public const MILLIS_PER_SECOND = 1_000;
public const MICROS_PER_SECOND = 1_000_000;
public const NANOS_PER_SECOND = 1_000_000_000;
public const NANOS_PER_MILLISECOND = 1_000_000;
public const NANOS_PER_MICROSECOND = 1_000;
/**
* Returns the current epoch wall-clock timestamp in nanoseconds
*/
public function now(): int;
/**
* @deprecated
*/
public function nanoTime(): int;
}
/**
* BC class alias
* @todo: remove in future release. Also in composer.json autoload/files.
*/
class_alias(ClockInterface::class, 'OpenTelemetry\SDK\ClockInterface');

View File

@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Time;
final class StopWatch implements StopWatchInterface
{
private const INITIAL_ELAPSED_TIME = 0;
private ClockInterface $clock;
private bool $running = false;
private ?int $initialStartTime;
private ?int $startTime = null;
private ?int $stopTime = null;
public function __construct(ClockInterface $clock, ?int $initialStartTime = null)
{
$this->clock = $clock;
$this->initialStartTime = $initialStartTime;
}
public function isRunning(): bool
{
return $this->running;
}
public function start(): void
{
// resolve start time as early as possible
$startTime = $this->time();
if ($this->isRunning()) {
return;
}
$this->startTime = $startTime;
if (!$this->hasBeenStarted()) {
$this->initialStartTime = $startTime;
}
$this->running = true;
}
public function stop(): void
{
if (!$this->isRunning()) {
return;
}
$this->stopTime = $this->time();
$this->running = false;
}
public function reset(): void
{
$this->startTime = $this->initialStartTime = $this->isRunning() ? $this->time() : null;
}
public function getElapsedTime(): int
{
if (!$this->hasBeenStarted()) {
return self::INITIAL_ELAPSED_TIME;
}
return $this->calculateElapsedTime();
}
public function getLastElapsedTime(): int
{
if (!$this->hasBeenStarted()) {
return self::INITIAL_ELAPSED_TIME;
}
return $this->calculateLastElapsedTime();
}
private function time(): int
{
return $this->clock->now();
}
private function hasBeenStarted(): bool
{
return $this->initialStartTime !== null;
}
private function calculateElapsedTime(): int
{
$referenceTime = $this->isRunning()
? $this->time()
: $this->getStopTime();
return $referenceTime - $this->getInitialStartTime();
}
private function calculateLastElapsedTime(): int
{
$referenceTime = $this->isRunning()
? $this->time()
: $this->getStopTime();
return $referenceTime - $this->getStartTime();
}
private function getInitialStartTime(): ?int
{
return $this->initialStartTime;
}
private function getStartTime(): ?int
{
return $this->startTime;
}
private function getStopTime(): ?int
{
return $this->stopTime;
}
}

View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Time;
final class StopWatchFactory implements StopWatchFactoryInterface
{
private static ?StopWatchInterface $default;
private ClockInterface $clock;
private ?int $initialStartTime;
public function __construct(?ClockInterface $clock = null, ?int $initialStartTime = null)
{
$this->clock = $clock ?? ClockFactory::getDefault();
$this->initialStartTime = $initialStartTime;
}
public static function create(?ClockInterface $clock = null, ?int $initialStartTime = null): self
{
return new self($clock, $initialStartTime);
}
public static function fromClockFactory(ClockFactoryInterface $factory, ?int $initialStartTime = null): self
{
return self::create($factory->build(), $initialStartTime);
}
public function build(): StopWatch
{
return new StopWatch($this->clock, $this->initialStartTime);
}
public static function getDefault(): StopWatchInterface
{
return self::$default ?? self::$default = self::create()->build();
}
public static function setDefault(?StopWatchInterface $default): void
{
self::$default = $default;
}
}

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Time;
interface StopWatchFactoryInterface
{
public static function create(?ClockInterface $clock = null, ?int $initialStartTime = null): self;
public static function fromClockFactory(ClockFactoryInterface $factory, ?int $initialStartTime = null): self;
public function build(): StopWatchInterface;
public static function getDefault(): StopWatchInterface;
public static function setDefault(?StopWatchInterface $default): void;
}

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Time;
interface StopWatchInterface
{
public function isRunning(): bool;
public function start(): void;
public function stop(): void;
public function reset(): void;
public function getElapsedTime(): int;
public function getLastElapsedTime(): int;
}

View File

@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Time;
use function hrtime;
use function microtime;
final class SystemClock implements ClockInterface
{
private static ?self $instance = null;
private static int $referenceTime = 0;
public function __construct()
{
self::init();
}
/**
* @deprecated
*/
public static function getInstance(): self
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public static function create(): self
{
return new self();
}
/** @inheritDoc */
public function now(): int
{
return self::$referenceTime + hrtime(true);
}
/**
* @deprecated
*/
public function nanoTime(): int
{
return $this->now();
}
private static function init(): void
{
if (self::$referenceTime > 0) {
return;
}
self::$referenceTime = self::calculateReferenceTime(
microtime(true),
hrtime(true)
);
}
/**
* Calculates the reference time which is later used to calculate the current wall clock time in nanoseconds by adding the current uptime.
*/
private static function calculateReferenceTime(float $wallClockMicroTime, int $upTime): int
{
return ((int) ($wallClockMicroTime * ClockInterface::NANOS_PER_SECOND)) - $upTime;
}
}
/**
* BC class alias
* @todo: remove in future release. Also in composer.json autoload/files.
*/
class_alias(SystemClock::class, 'OpenTelemetry\SDK\SystemClock');

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK\Common\Time;
class Util
{
/** @psalm-pure */
public static function nanosToMicros(int $nanoseconds): int
{
return intdiv($nanoseconds, ClockInterface::NANOS_PER_MICROSECOND);
}
/** @psalm-pure */
public static function nanosToMillis(int $nanoseconds): int
{
return intdiv($nanoseconds, ClockInterface::NANOS_PER_MILLISECOND);
}
/** @psalm-pure */
public static function secondsToNanos(int $seconds): int
{
return $seconds * ClockInterface::NANOS_PER_SECOND;
}
/** @psalm-pure */
public static function millisToNanos(int $milliSeconds): int
{
return $milliSeconds * ClockInterface::NANOS_PER_MILLISECOND;
}
}

View File

@ -1,38 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\SDK;
use function hrtime;
use function microtime;
final class SystemClock extends AbstractClock
{
private static ?self $instance = null;
public static function getInstance(): self
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/** @inheritDoc */
public function now(): int
{
/**
* `microtime` returns a unix timestamp _WITH_ microseconds, not _IN_ microseconds.
* E.g. `1633052992.330921` so we must multiply it by {@see \OpenTelemetry\API\ClockInterface::NANOS_PER_SECOND} to get a value _IN_ nanoseconds.
*/
return (int) (microtime(true) * ClockInterface::NANOS_PER_SECOND);
}
/** @inheritDoc */
public function nanoTime(): int
{
return hrtime(true);
}
}

View File

@ -13,11 +13,11 @@ use function get_class;
use function in_array;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Attribute\AttributeLimits;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationLibraryInterface;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use function sprintf;
use function str_replace;
@ -129,14 +129,8 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
?AttributesInterface $attributes,
array $links,
int $totalRecordedLinks,
int $userStartEpochNanos
int $startEpochNanos
): self {
if (0 !== $userStartEpochNanos) {
$startEpochNanos = $userStartEpochNanos;
} else {
$startEpochNanos = AbstractClock::getDefault()->now();
}
$span = new self(
$name,
$context,
@ -149,7 +143,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
$attributes,
$links,
$totalRecordedLinks,
$startEpochNanos
$startEpochNanos !== 0 ? $startEpochNanos : ClockFactory::getDefault()->now()
);
// Call onStart here to ensure the span is fully initialized.
@ -264,7 +258,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
if (count($this->events) < $this->spanLimits->getEventCountLimit()) {
$this->events[] = new Event(
$name,
$timestamp ?? AbstractClock::getDefault()->now(),
$timestamp ?? ClockFactory::getDefault()->now(),
Attributes::withLimits(
$attributes,
new AttributeLimits(
@ -283,7 +277,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
/** @inheritDoc */
public function recordException(Throwable $exception, iterable $attributes = []): self
{
$timestamp = AbstractClock::getDefault()->now();
$timestamp = ClockFactory::getDefault()->now();
$eventAttributes = new Attributes([
'exception.type' => get_class($exception),
'exception.message' => $exception->getMessage(),
@ -327,7 +321,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
return;
}
$this->endEpochNanos = $endEpochNanos ?? AbstractClock::getDefault()->now();
$this->endEpochNanos = $endEpochNanos ?? ClockFactory::getDefault()->now();
$this->hasEnded = true;
$this->spanProcessor->onEnd($this);
@ -373,7 +367,7 @@ final class Span extends API\AbstractSpan implements ReadWriteSpanInterface
/** @inheritDoc */
public function getDuration(): int
{
return ($this->hasEnded ? $this->endEpochNanos : AbstractClock::getDefault()->now()) - $this->startEpochNanos;
return ($this->hasEnded ? $this->endEpochNanos : ClockFactory::getDefault()->now()) - $this->startEpochNanos;
}
/** @inheritDoc */

View File

@ -6,10 +6,13 @@ namespace OpenTelemetry\SDK\Trace\SpanProcessor;
use InvalidArgumentException;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\ClockInterface;
use OpenTelemetry\SDK\Common\Environment\EnvironmentVariablesTrait;
use OpenTelemetry\SDK\Common\Environment\Variables as Env;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Common\Time\ClockInterface;
use OpenTelemetry\SDK\Common\Time\StopWatch;
use OpenTelemetry\SDK\Common\Time\StopWatchFactory;
use OpenTelemetry\SDK\Common\Time\Util as TimeUtil;
use OpenTelemetry\SDK\Trace\ReadableSpanInterface;
use OpenTelemetry\SDK\Trace\ReadWriteSpanInterface;
use OpenTelemetry\SDK\Trace\SpanDataInterface;
@ -32,9 +35,8 @@ class BatchSpanProcessor implements SpanProcessorInterface
/** @phpstan-ignore-next-line */
private ?int $exporterTimeoutMillis;
private ?int $maxExportBatchSize;
private ?int $lastExportTimestamp = null;
private ClockInterface $clock;
private bool $running = true;
private StopWatch $stopwatch;
/** @var list<SpanDataInterface> */
private array $queue = [];
@ -47,11 +49,10 @@ class BatchSpanProcessor implements SpanProcessorInterface
int $exporterTimeoutMillis = null,
int $maxExportBatchSize = null
) {
if (null === $clock) {
$clock = AbstractClock::getDefault();
}
$this->exporter = $exporter;
$this->clock = $clock;
// @todo make the stopwatch a dependency rather than using the factory?
$this->stopwatch = StopWatchFactory::create($clock ?? ClockFactory::getDefault())->build();
$this->stopwatch->start();
$this->maxQueueSize = $maxQueueSize
?: $this->getIntFromEnvironment(Env::OTEL_BSP_MAX_QUEUE_SIZE, self::DEFAULT_MAX_QUEUE_SIZE);
$this->scheduledDelayMillis = $scheduledDelayMillis
@ -99,16 +100,14 @@ class BatchSpanProcessor implements SpanProcessorInterface
/** @inheritDoc */
public function forceFlush(): bool
{
if (!$this->running) {
if (!$this->running || $this->exporter === null) {
return true;
}
if (null !== $this->exporter) {
$this->exporter->export($this->queue);
$this->queue = [];
$this->lastExportTimestamp = $this->clock->nanoTime();
$this->exporter->forceFlush();
}
$this->exporter->export($this->queue);
$this->queue = [];
$this->stopwatch->reset();
$this->exporter->forceFlush();
return true;
}
@ -140,15 +139,6 @@ class BatchSpanProcessor implements SpanProcessorInterface
protected function enoughTimeHasPassed(): bool
{
$now = $this->clock->nanoTime();
// if lastExport never occurred let it start from now on
if (null === $this->lastExportTimestamp) {
$this->lastExportTimestamp = $now;
return false;
}
return ($this->scheduledDelayMillis * ClockInterface::NANOS_PER_MILLISECOND) < ($now - $this->lastExportTimestamp);
return TimeUtil::millisToNanos((int) $this->scheduledDelayMillis) < $this->stopwatch->getLastElapsedTime();
}
}

View File

@ -7,7 +7,7 @@ use App\Kernel;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\Context\Context;
use OpenTelemetry\Contrib\Jaeger\Exporter as JaegerExporter;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplingResult;
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;
@ -32,7 +32,7 @@ $exporter = new JaegerExporter(
if (SamplingResult::RECORD_AND_SAMPLE === $samplingResult->getDecision()) {
$tracer = (new TracerProvider())
->addSpanProcessor(new BatchSpanProcessor($exporter, AbstractClock::getDefault()))
->addSpanProcessor(new BatchSpanProcessor($exporter, ClockFactory::getDefault()))
->getTracer('io.opentelemetry.contrib.php');
$request = Request::createFromGlobals();

View File

@ -2,15 +2,15 @@
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK;
namespace OpenTelemetry\Tests\Unit\SDK\Common\Time;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\ClockInterface;
use OpenTelemetry\SDK\SystemClock;
use OpenTelemetry\SDK\Common\Time\AbstractClock;
use OpenTelemetry\SDK\Common\Time\ClockInterface;
use OpenTelemetry\SDK\Common\Time\SystemClock;
use PHPUnit\Framework\TestCase;
/**
* @covers OpenTelemetry\SDK\AbstractClock
* @covers \OpenTelemetry\SDK\Common\Time\AbstractClock
*/
class AbstractClockTest extends TestCase
{

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Common\Time;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Common\Time\ClockInterface;
use OpenTelemetry\SDK\Common\Time\SystemClock;
use PHPUnit\Framework\TestCase;
/**
* @covers \OpenTelemetry\SDK\Common\Time\ClockFactory
*/
class ClockFactoryTest extends TestCase
{
public function test_build(): void
{
$this->assertInstanceOf(SystemClock::class, ClockFactory::create()->build());
}
public function test_default_is_system_clock(): void
{
$this->assertInstanceOf(SystemClock::class, ClockFactory::getDefault());
}
public function test_default_is_settable(): void
{
$clock = $this->createMock(ClockInterface::class);
ClockFactory::setDefault($clock);
$this->assertSame($clock, ClockFactory::getDefault());
}
public function test_default_is_resettable(): void
{
$clock = $this->createMock(ClockInterface::class);
ClockFactory::setDefault(
$clock
);
ClockFactory::setDefault(null);
$this->assertNotSame($clock, ClockFactory::getDefault());
}
}

View File

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Common\Time;
use OpenTelemetry\SDK\Common\Time\ClockFactoryInterface;
use OpenTelemetry\SDK\Common\Time\StopWatch;
use OpenTelemetry\SDK\Common\Time\StopWatchFactory;
use OpenTelemetry\SDK\Common\Time\StopWatchInterface;
use PHPUnit\Framework\TestCase;
/**
* @covers \OpenTelemetry\SDK\Common\Time\StopWatchFactory
*/
class StopWatchFactoryTest extends TestCase
{
public function test_from_clock_factory(): void
{
$clockFactory = $this->createMock(ClockFactoryInterface::class);
$clockFactory->expects($this->once())->method('build');
StopWatchFactory::fromClockFactory($clockFactory);
}
public function test_default_is_system_clock(): void
{
$this->assertInstanceOf(StopWatch::class, StopWatchFactory::getDefault());
}
public function test_default_is_settable(): void
{
$stopwatch = $this->createMock(StopWatchInterface::class);
StopWatchFactory::setDefault($stopwatch);
$this->assertSame($stopwatch, StopWatchFactory::getDefault());
}
public function test_default_is_resettable(): void
{
StopWatchFactory::setDefault(
$this->createMock(StopWatchInterface::class)
);
StopWatchFactory::setDefault(null);
$this->assertInstanceOf(StopWatch::class, StopWatchFactory::getDefault());
}
}

View File

@ -0,0 +1,231 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Common\Time;
use OpenTelemetry\SDK\Common\Time\StopWatch;
use OpenTelemetry\Tests\Unit\SDK\Util\TestClock;
use PHPUnit\Framework\TestCase;
/**
* @covers \OpenTelemetry\SDK\Common\Time\StopWatch
*/
class StopWatchTest extends TestCase
{
private StopWatch $stopwatch;
private TestClock $testClock;
public function setUp(): void
{
$this->init();
}
private function init(?int $initialStartTime = null): void
{
$this->stopwatch = new StopWatch(
$this->testClock = new TestClock(),
$initialStartTime
);
}
public function test_is_not_running_initially(): void
{
$this->assertFalse($this->stopwatch->isRunning());
}
public function test_start(): void
{
$this->stopwatch->start();
$this->assertTrue($this->stopwatch->isRunning());
}
public function test_restart(): void
{
$this->stopwatch->start();
$this->stopwatch->stop();
$this->stopwatch->start();
$this->assertTrue($this->stopwatch->isRunning());
}
public function test_stop(): void
{
$this->stopwatch->start();
$this->stopwatch->stop();
$this->assertFalse($this->stopwatch->isRunning());
}
public function test_stop_without_start(): void
{
$this->stopwatch->stop();
$this->assertFalse($this->stopwatch->isRunning());
}
public function test_get_elapsed_time_initially(): void
{
$this->assertSame(0, $this->stopwatch->getElapsedTime());
}
public function test_get_elapsed_time_started(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->assertSame($elapsed, $this->stopwatch->getElapsedTime());
}
public function test_get_elapsed_time_started_twice(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->assertSame($elapsed * 2, $this->stopwatch->getElapsedTime());
}
public function test_get_elapsed_time_stopped(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->stopwatch->stop();
$this->testClock->advance($elapsed);
$this->assertSame($elapsed, $this->stopwatch->getElapsedTime());
}
public function test_get_elapsed_time_stopped_twice(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->stopwatch->stop();
$this->testClock->advance($elapsed);
$this->stopwatch->stop();
$this->assertSame($elapsed, $this->stopwatch->getElapsedTime());
}
public function test_get_elapsed_time_with_initial_start_time(): void
{
$elapsed = 500;
$this->init(TestClock::DEFAULT_START_EPOCH - $elapsed);
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->assertSame($elapsed * 2, $this->stopwatch->getElapsedTime());
}
public function test_get_last_elapsed_time_initially(): void
{
$this->assertSame(0, $this->stopwatch->getLastElapsedTime());
}
public function test_get_last_elapsed_time_started(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->assertSame($elapsed, $this->stopwatch->getLastElapsedTime());
}
public function test_get_last_elapsed_time_started_twice(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->assertSame($elapsed * 2, $this->stopwatch->getLastElapsedTime());
}
public function test_get_last_elapsed_time_restarted(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->stopwatch->stop();
$this->testClock->advance($elapsed);
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->assertSame($elapsed, $this->stopwatch->getLastElapsedTime());
}
public function test_get_last_elapsed_time_stopped(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->stopwatch->stop();
$this->testClock->advance($elapsed);
$this->assertSame($elapsed, $this->stopwatch->getLastElapsedTime());
}
public function test_get_last_elapsed_time_stopped_twice(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->stopwatch->stop();
$this->testClock->advance($elapsed);
$this->stopwatch->stop();
$this->assertSame($elapsed, $this->stopwatch->getLastElapsedTime());
}
public function test_reset_initially(): void
{
$this->stopwatch->reset();
$this->testClock->advance(500);
$this->assertSame(0, $this->stopwatch->getElapsedTime());
$this->assertSame(0, $this->stopwatch->getLastElapsedTime());
}
public function test_reset_started(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->stopwatch->reset();
$this->testClock->advance($elapsed);
$this->assertSame($elapsed, $this->stopwatch->getElapsedTime());
$this->assertSame($elapsed, $this->stopwatch->getLastElapsedTime());
}
public function test_reset_stopped(): void
{
$elapsed = 500;
$this->stopwatch->start();
$this->testClock->advance($elapsed);
$this->stopwatch->stop();
$this->stopwatch->reset();
$this->testClock->advance($elapsed);
$this->assertSame(0, $this->stopwatch->getElapsedTime());
$this->assertSame(0, $this->stopwatch->getLastElapsedTime());
}
}

View File

@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Common\Time;
use DateTime;
use OpenTelemetry\SDK\Common\Time\SystemClock;
use PHPUnit\Framework\TestCase;
/**
* @covers \OpenTelemetry\SDK\Common\Time\SystemClock
*/
class SystemClockTest extends TestCase
{
private const NANOS_PER_SECOND = 1_000_000_000;
public function test_get_instance_always_returns_same_clock(): void
{
$this->assertSame(SystemClock::getInstance(), SystemClock::getInstance());
}
public function test_now_is_chronological(): void
{
$time1 = SystemClock::create()->now();
usleep(1);
$time2 = SystemClock::create()->now();
$this->assertGreaterThan($time1, $time2);
}
public function test_now_returns_nanoseconds(): void
{
$this->assertNanoSecondsWallClock(
SystemClock::create()->now(),
new DateTime()
);
}
public function test_nano_time_is_chronological(): void
{
$time1 = SystemClock::create()->nanoTime();
usleep(1);
$time2 = SystemClock::create()->nanoTime();
$this->assertGreaterThan($time1, $time2);
}
public function test_nano_time_returns_nanoseconds(): void
{
$this->assertNanoSecondsWallClock(
SystemClock::create()->nanoTime(),
new DateTime()
);
}
private function assertNanoSecondsWallClock(int $value, DateTime $reference): void
{
$this->assertGreaterThan(self::NANOS_PER_SECOND, $value);
$tested = (new DateTime())->setTimestamp((int) ($value / self::NANOS_PER_SECOND));
$interval = $tested->diff($reference);
// Make sure to avoid edge cases, so check for difference of 0 OR 1
$this->assertTrue($interval->days === 0 || $interval->days === 1);
$this->assertTrue($interval->h === 0 || $interval->h === 1);
$this->assertTrue($interval->m === 0 || $interval->m === 1);
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Common\Time;
use OpenTelemetry\SDK\Common\Time\Util;
use PHPUnit\Framework\TestCase;
/**
* @covers \OpenTelemetry\SDK\Common\Time\Util
*/
class UtilTest extends TestCase
{
public function test_nanos_to_micro(): void
{
$this->assertEquals(1, Util::nanosToMicros((int) 1e3));
}
public function test_nanos_to_milli(): void
{
$this->assertEquals(1, Util::nanosToMillis((int) 1e6));
}
public function test_seconds_to_nanos(): void
{
$this->assertEquals((int) 1e9, Util::secondsToNanos(1));
}
public function test_millis_to_nanos(): void
{
$this->assertEquals((int) 1e6, Util::millisToNanos(1));
}
}

View File

@ -1,24 +0,0 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK;
use OpenTelemetry\SDK\SystemClock;
use PHPUnit\Framework\TestCase;
/**
* @covers OpenTelemetry\SDK\SystemClock
*/
class SystemClockTest extends TestCase
{
/**
* @runInSeparateProcess
* @preserveGlobalState false
*/
public function test_get_instance_always_returns_same_clock(): void
{
$clock = SystemClock::getInstance();
$this->assertSame($clock, SystemClock::getInstance());
}
}

View File

@ -9,7 +9,8 @@ use Exception;
use Mockery;
use Mockery\Adapter\Phpunit\MockeryTestCase;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Common\Time\ClockInterface;
use OpenTelemetry\SDK\Trace\ReadWriteSpanInterface;
use OpenTelemetry\SDK\Trace\SpanDataInterface;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
@ -30,12 +31,12 @@ class BatchSpanProcessorTest extends MockeryTestCase
{
$this->testClock = new TestClock();
AbstractClock::setTestClock($this->testClock);
ClockFactory::setDefault($this->testClock);
}
protected function tearDown(): void
{
AbstractClock::setTestClock();
ClockFactory::setDefault(null);
$this->restoreEnvironmentVariables();
}
@ -140,9 +141,9 @@ class BatchSpanProcessorTest extends MockeryTestCase
{
return [
'no clock advance' => [1000, 0, false],
'clock advance less than threshold' => [1000, 999 * AbstractClock::NANOS_PER_MILLISECOND, false],
'clock advance equals threshold' => [1000, 1000 * AbstractClock::NANOS_PER_MILLISECOND, false],
'clock advance exceeds threshold' => [1000, 1001 * AbstractClock::NANOS_PER_MILLISECOND, true],
'clock advance less than threshold' => [1000, 999 * ClockInterface::NANOS_PER_MILLISECOND, false],
'clock advance equals threshold' => [1000, 1000 * ClockInterface::NANOS_PER_MILLISECOND, false],
'clock advance exceeds threshold' => [1000, 1001 * ClockInterface::NANOS_PER_MILLISECOND, true],
];
}
@ -230,7 +231,7 @@ class BatchSpanProcessorTest extends MockeryTestCase
$exporter->expects($this->once())->method('export');
$exporter->expects($this->once())->method('shutdown');
$proc = new BatchSpanProcessor($exporter, $this->createMock(AbstractClock::class));
$proc = new BatchSpanProcessor($exporter, $this->createMock(ClockInterface::class));
for ($i = 0; $i < $batchSize - 1; $i++) {
$mock_span = $this->createSampledSpanMock();
@ -245,7 +246,7 @@ class BatchSpanProcessorTest extends MockeryTestCase
$exporter = $this->createMock(SpanExporterInterface::class);
$exporter->expects($this->atLeastOnce())->method('shutdown');
$proc = new BatchSpanProcessor($exporter, $this->createMock(AbstractClock::class));
$proc = new BatchSpanProcessor($exporter, $this->createMock(ClockInterface::class));
$proc->shutdown();
$span = $this->createSampledSpanMock();

View File

@ -13,11 +13,12 @@ use OpenTelemetry\API\Trace as API;
use OpenTelemetry\API\Trace\NonRecordingSpan;
use OpenTelemetry\API\Trace\SpanContext;
use OpenTelemetry\Context\Context;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\ClockInterface;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationLibrary;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Common\Time\ClockInterface;
use OpenTelemetry\SDK\Common\Time\Util as TimeUtil;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SDK\Trace\Event;
@ -90,12 +91,12 @@ class SpanTest extends MockeryTestCase
)
);
AbstractClock::setTestClock($this->testClock);
ClockFactory::setDefault($this->testClock);
}
protected function tearDown(): void
{
AbstractClock::setTestClock();
ClockFactory::setDefault(null);
}
// region API
@ -465,7 +466,7 @@ class SpanTest extends MockeryTestCase
$span = $this->createTestRootSpan();
$span->addEvent('event1');
$span->addEvent('event2', new Attributes(['key1' => 1]));
$span->addEvent('event3', [], AbstractClock::secondsToNanos(10));
$span->addEvent('event3', [], TimeUtil::secondsToNanos(10));
$span->end();
@ -475,7 +476,7 @@ class SpanTest extends MockeryTestCase
$this->assertEvent($events[$idx++], 'event1', new Attributes(), self::START_EPOCH);
$this->assertEvent($events[$idx++], 'event2', new Attributes(['key1' => 1]), self::START_EPOCH);
$this->assertEvent($events[$idx], 'event3', new Attributes(), AbstractClock::secondsToNanos(10));
$this->assertEvent($events[$idx], 'event3', new Attributes(), TimeUtil::secondsToNanos(10));
}
public function test_add_event_attribute_length(): void

View File

@ -7,10 +7,10 @@ namespace OpenTelemetry\Tests\Unit\SDK\Util;
use function count;
use function max;
use OpenTelemetry\API\Trace as API;
use OpenTelemetry\SDK\AbstractClock;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationLibrary;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SDK\Trace as SDK;
@ -105,7 +105,7 @@ class SpanData implements SDK\SpanDataInterface
public function addEvent(string $name, ?AttributesInterface $attributes, int $timestamp = null): self
{
$this->events[] = new SDK\Event($name, $timestamp ?? AbstractClock::getDefault()->now(), $attributes);
$this->events[] = new SDK\Event($name, $timestamp ?? ClockFactory::getDefault()->now(), $attributes);
return $this;
}

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace OpenTelemetry\Tests\Unit\SDK\Util;
use OpenTelemetry\SDK\ClockInterface;
use OpenTelemetry\SDK\Common\Time\ClockInterface;
final class TestClock implements ClockInterface
{