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:
parent
2b72c92fcb
commit
8e1e912c92
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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');
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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');
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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');
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue