diff options
author | Andrew Dolgov <[email protected]> | 2023-04-09 20:50:33 +0300 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2023-04-09 20:50:33 +0300 |
commit | 8f3646a9c93a06f76f6abb31020fdb74b4b1fc59 (patch) | |
tree | 4e6c9f39e0623ef70bedfee014f1bd20603f89ad /vendor/jonahgeorge/jaeger-client-php/src/Jaeger/Span.php | |
parent | a37eab2610a0a2bcb655258781c1c7e925dc94c0 (diff) |
exp: jaeger tracing
Diffstat (limited to 'vendor/jonahgeorge/jaeger-client-php/src/Jaeger/Span.php')
-rw-r--r-- | vendor/jonahgeorge/jaeger-client-php/src/Jaeger/Span.php | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/vendor/jonahgeorge/jaeger-client-php/src/Jaeger/Span.php b/vendor/jonahgeorge/jaeger-client-php/src/Jaeger/Span.php new file mode 100644 index 000000000..abcb07c89 --- /dev/null +++ b/vendor/jonahgeorge/jaeger-client-php/src/Jaeger/Span.php @@ -0,0 +1,476 @@ +<?php + +namespace Jaeger; + +use Jaeger\Thrift\Agent\Zipkin\AnnotationType; +use Jaeger\Thrift\Agent\Zipkin\BinaryAnnotation; +use OpenTracing\Span as OTSpan; +use DateTime; +use DateTimeInterface; +use OpenTracing\SpanContext as OTSpanContext; +use const OpenTracing\Tags\COMPONENT; +use const OpenTracing\Tags\PEER_HOST_IPV4; +use const OpenTracing\Tags\PEER_PORT; +use const OpenTracing\Tags\PEER_SERVICE; +use const OpenTracing\Tags\SPAN_KIND; +use const OpenTracing\Tags\SPAN_KIND_MESSAGE_BUS_CONSUMER; +use const OpenTracing\Tags\SPAN_KIND_MESSAGE_BUS_PRODUCER; +use const OpenTracing\Tags\SPAN_KIND_RPC_CLIENT; +use const OpenTracing\Tags\SPAN_KIND_RPC_SERVER; + +class Span implements OTSpan +{ + /** + * @var Tracer + */ + private $tracer; + + /** + * @var SpanContext + */ + private $context; + + /** + * @var string + */ + private $operationName; + + /** + * @var int|float|DateTime|null + */ + private $startTime; + + /** + * @var int|float|DateTime|null + */ + private $endTime; + + /** + * SPAN_RPC_CLIENT + * @var null|string + */ + private $kind; + + /** + * @var array|null + */ + public $peer; + + /** + * @var string|null + */ + private $component; + + /** + * @var array + */ + private $logs = []; + + /** + * @var BinaryAnnotation[] + */ + public $tags = []; + + /** + * @var bool + */ + private $debug = false; + + /** + * Span constructor. + * @param SpanContext $context + * @param Tracer $tracer + * @param string $operationName + * @param array $tags + * @param int|float|DateTime|null $startTime + */ + public function __construct( + SpanContext $context, + Tracer $tracer, + string $operationName, + array $tags = [], + $startTime = null + ) { + $this->context = $context; + $this->tracer = $tracer; + + $this->operationName = $operationName; + $this->startTime = $this->microTime($startTime); + $this->endTime = null; + $this->kind = null; + $this->peer = null; + $this->component = null; + + foreach ($tags as $key => $value) { + $this->setTag($key, $value); + } + } + + /** + * Converts time to microtime int + * - int represents microseconds + * - float represents seconds + * + * @param int|float|DateTime|null $time + * @return int + */ + protected function microTime($time): int + { + if ($time === null) { + return $this->timestampMicro(); + } + + if ($time instanceof \DateTimeInterface) { + return (int)round($time->format('U.u') * 1000000, 0); + } + + if (is_int($time)) { + return $time; + } + + if (is_float($time)) { + return (int)round($time * 1000000, 0); + } + + throw new \InvalidArgumentException(sprintf( + 'Time should be one of the types int|float|DateTime|null, got %s.', + gettype($time) + )); + } + + /** + * @return Tracer + */ + public function getTracer(): Tracer + { + return $this->tracer; + } + + /** + * @return bool + */ + public function isDebug(): bool + { + return $this->debug; + } + + /** + * @return int + */ + public function getStartTime(): int + { + return $this->startTime; + } + + /** + * @return int|null + */ + public function getEndTime() + { + return $this->endTime; + } + + /** + * @return string + */ + public function getOperationName(): string + { + return $this->operationName; + } + + /** + * @return mixed + */ + public function getComponent() + { + // TODO + return $this->component; + } + + /** + * {@inheritdoc} + * + * @return SpanContext + */ + public function getContext(): OTSpanContext + { + return $this->context; + } + + /** + * {@inheritdoc} + */ + public function finish($finishTime = null, array $logRecords = []): void + { + if (!$this->isSampled()) { + return; + } + + foreach ($logRecords as $logRecord) { + $this->log($logRecord); + } + + $this->endTime = $this->microTime($finishTime); + $this->tracer->reportSpan($this); + } + + /** + * Returns true if the trace should be measured. + * + * @return bool + */ + public function isSampled(): bool + { + $context = $this->getContext(); + + return ($context->getFlags() & SAMPLED_FLAG) == SAMPLED_FLAG; + } + + /** + * {@inheritdoc} + */ + public function overwriteOperationName(string $newOperationName): void + { + // TODO log warning + $this->operationName = $newOperationName; + } + + /** + * {@inheritdoc} + * + * @param array $tags + * @return void + */ + public function setTags($tags) + { + foreach ($tags as $key => $value) { + $this->setTag($key, $value); + } + } + + /** + * {@inheritdoc} + */ + public function setTag(string $key, $value): void + { + if ($this->isSampled()) { + $special = self::SPECIAL_TAGS[$key] ?? null; + $handled = false; + + if ($special !== null && is_callable([$this, $special])) { + $handled = $this->$special($value); + } + + if (!$handled) { + $tag = $this->makeTag($key, $value); + $this->tags[$key] = $tag; + } + } + } + + const SPECIAL_TAGS = [ + PEER_SERVICE => 'setPeerService', + PEER_HOST_IPV4 => 'setPeerHostIpv4', + PEER_PORT => 'setPeerPort', + SPAN_KIND => 'setSpanKind', + COMPONENT => 'setComponent', + ]; + + /** + * Sets a low-cardinality identifier of the module, library, + * or package that is generating a span. + * + * @see Span::setTag() + * + * @param string $value + * @return bool + */ + private function setComponent($value): bool + { + $this->component = $value; + return true; + } + + /** + * @return bool + */ + private function setSpanKind($value): bool + { + $validSpanKinds = [ + SPAN_KIND_RPC_CLIENT, + SPAN_KIND_RPC_SERVER, + SPAN_KIND_MESSAGE_BUS_CONSUMER, + SPAN_KIND_MESSAGE_BUS_PRODUCER, + ]; + + if ($value === null || in_array($value, $validSpanKinds, true)) { + $this->kind = $value; + return true; + } + return false; + } + + /** + * @return string|null + */ + public function getKind(): ?string + { + return $this->kind; + } + + /** + * @return bool + */ + private function setPeerPort($value): bool + { + if ($this->peer === null) { + $this->peer = ['port' => $value]; + } else { + $this->peer['port'] = $value; + } + return true; + } + + /** + * @return bool + */ + private function setPeerHostIpv4($value): bool + { + if ($this->peer === null) { + $this->peer = ['ipv4' => $value]; + } else { + $this->peer['ipv4'] = $value; + } + return true; + } + + /** + * @return bool + */ + private function setPeerService($value): bool + { + if ($this->peer === null) { + $this->peer = ['service_name' => $value]; + } else { + $this->peer['service_name'] = $value; + } + return true; + } + + /** + * @return bool + */ + public function isRpc(): bool + { + return $this->kind == SPAN_KIND_RPC_CLIENT || $this->kind == SPAN_KIND_RPC_SERVER; + } + + /** + * @return bool + */ + public function isRpcClient(): bool + { + return $this->kind == SPAN_KIND_RPC_CLIENT; + } + + /** + * {@inheritdoc} + */ + public function log(array $fields = [], $timestamp = null): void + { + $timestamp = $this->microTime($timestamp); + if ($timestamp < $this->getStartTime()) { + $timestamp = $this->timestampMicro(); + } + + $this->logs[] = [ + 'fields' => $fields, + 'timestamp' => $timestamp, + ]; + } + + /** + * Returns the logs. + * + * [ + * [ + * 'timestamp' => timestamp in microsecond, + * 'fields' => [ + * 'error' => 'message', + * ] + * ] + * ] + * + * @return array + */ + public function getLogs(): array + { + return $this->logs; + } + + /** + * {@inheritdoc} + */ + public function addBaggageItem(string $key, string $value): void + { + $this->context = $this->context->withBaggageItem($key, $value); + } + + /** + * {@inheritdoc} + */ + public function getBaggageItem(string $key): ?string + { + return $this->context->getBaggageItem($key); + } + + /** + * @return array + */ + public function getTags(): array + { + return $this->tags; + } + + /** + * @return int + */ + private function timestampMicro(): int + { + return round(microtime(true) * 1000000); + } + + /** + * @param string $key + * @param mixed $value + * @return BinaryAnnotation + */ + private function makeTag(string $key, $value): BinaryAnnotation + { + $valueType = gettype($value); + $annotationType = null; + switch ($valueType) { + case "boolean": + $annotationType = AnnotationType::BOOL; + break; + case "integer": + $annotationType = AnnotationType::I64; + break; + case "double": + $annotationType = AnnotationType::DOUBLE; + break; + default: + $annotationType = AnnotationType::STRING; + $value = (string)$value; + if (strlen($value) > 1024) { + $value = substr($value, 0, 1024); + } + } + + return new BinaryAnnotation([ + 'key' => $key, + 'value' => $value, + 'annotation_type' => $annotationType, + ]); + } +} |