From cdd7ad020e165fe680703b6d3319b908b682fb7a Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Fri, 20 Oct 2023 17:12:29 +0300 Subject: jaeger-client -> opentelemetry --- .../exporter-otlp/AttributesConverter.php | 62 +++++ .../open-telemetry/exporter-otlp/ContentTypes.php | 12 + .../exporter-otlp/HttpEndpointResolver.php | 145 +++++++++++ .../HttpEndpointResolverInterface.php | 28 +++ .../open-telemetry/exporter-otlp/LogsConverter.php | 142 +++++++++++ .../open-telemetry/exporter-otlp/LogsExporter.php | 85 +++++++ .../exporter-otlp/LogsExporterFactory.php | 85 +++++++ .../exporter-otlp/MetricConverter.php | 265 +++++++++++++++++++++ .../exporter-otlp/MetricExporter.php | 97 ++++++++ .../exporter-otlp/MetricExporterFactory.php | 110 +++++++++ .../exporter-otlp/OtlpHttpTransportFactory.php | 33 +++ vendor/open-telemetry/exporter-otlp/OtlpUtil.php | 45 ++++ .../exporter-otlp/ProtobufSerializer.php | 115 +++++++++ vendor/open-telemetry/exporter-otlp/Protocols.php | 36 +++ vendor/open-telemetry/exporter-otlp/README.md | 45 ++++ .../open-telemetry/exporter-otlp/SpanConverter.php | 187 +++++++++++++++ .../open-telemetry/exporter-otlp/SpanExporter.php | 81 +++++++ .../exporter-otlp/SpanExporterFactory.php | 96 ++++++++ vendor/open-telemetry/exporter-otlp/_register.php | 9 + vendor/open-telemetry/exporter-otlp/composer.json | 41 ++++ 20 files changed, 1719 insertions(+) create mode 100644 vendor/open-telemetry/exporter-otlp/AttributesConverter.php create mode 100644 vendor/open-telemetry/exporter-otlp/ContentTypes.php create mode 100644 vendor/open-telemetry/exporter-otlp/HttpEndpointResolver.php create mode 100644 vendor/open-telemetry/exporter-otlp/HttpEndpointResolverInterface.php create mode 100644 vendor/open-telemetry/exporter-otlp/LogsConverter.php create mode 100644 vendor/open-telemetry/exporter-otlp/LogsExporter.php create mode 100644 vendor/open-telemetry/exporter-otlp/LogsExporterFactory.php create mode 100644 vendor/open-telemetry/exporter-otlp/MetricConverter.php create mode 100644 vendor/open-telemetry/exporter-otlp/MetricExporter.php create mode 100644 vendor/open-telemetry/exporter-otlp/MetricExporterFactory.php create mode 100644 vendor/open-telemetry/exporter-otlp/OtlpHttpTransportFactory.php create mode 100644 vendor/open-telemetry/exporter-otlp/OtlpUtil.php create mode 100644 vendor/open-telemetry/exporter-otlp/ProtobufSerializer.php create mode 100644 vendor/open-telemetry/exporter-otlp/Protocols.php create mode 100644 vendor/open-telemetry/exporter-otlp/README.md create mode 100644 vendor/open-telemetry/exporter-otlp/SpanConverter.php create mode 100644 vendor/open-telemetry/exporter-otlp/SpanExporter.php create mode 100644 vendor/open-telemetry/exporter-otlp/SpanExporterFactory.php create mode 100644 vendor/open-telemetry/exporter-otlp/_register.php create mode 100644 vendor/open-telemetry/exporter-otlp/composer.json (limited to 'vendor/open-telemetry/exporter-otlp') diff --git a/vendor/open-telemetry/exporter-otlp/AttributesConverter.php b/vendor/open-telemetry/exporter-otlp/AttributesConverter.php new file mode 100644 index 000000000..4a349ab67 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/AttributesConverter.php @@ -0,0 +1,62 @@ +getValues()[] = self::convertAnyValue($element); + } + $result->setArrayValue($values); + } else { + $values = new KeyValueList(); + foreach ($value as $key => $element) { + /** @psalm-suppress InvalidArgument */ + $values->getValues()[] = new KeyValue(['key' => $key, 'value' => self::convertAnyValue($element)]); + } + $result->setKvlistValue($values); + } + } + if (is_int($value)) { + $result->setIntValue($value); + } + if (is_bool($value)) { + $result->setBoolValue($value); + } + if (is_float($value)) { + $result->setDoubleValue($value); + } + if (is_string($value)) { + $result->setStringValue($value); + } + + return $result; + } + + /** + * Test whether an array is simple (non-KeyValue) + */ + public static function isSimpleArray(array $value): bool + { + return $value === [] || array_key_first($value) === 0; + } +} diff --git a/vendor/open-telemetry/exporter-otlp/ContentTypes.php b/vendor/open-telemetry/exporter-otlp/ContentTypes.php new file mode 100644 index 000000000..8ac70d54a --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/ContentTypes.php @@ -0,0 +1,12 @@ +httpFactoryResolver = $httpFactoryResolver ?? MessageFactoryResolver::create(); + } + + public static function create(?FactoryResolverInterface $httpFactoryResolver = null): self + { + return new self($httpFactoryResolver); + } + + public function resolve(string $endpoint, string $signal): UriInterface + { + $components = self::parseEndpoint($endpoint); + + return self::addPort( + self::addUserInfo( + $this->createDefaultUri($components, $signal), + $components + ), + $components + ); + } + + public function resolveToString(string $endpoint, string $signal): string + { + return (string) $this->resolve($endpoint, $signal); + } + + private function createUri(): UriInterface + { + return $this->httpFactoryResolver->resolveUriFactory() + ->createUri(); + } + + private function createDefaultUri(array $components, string $signal): UriInterface + { + if (isset($components[self::SCHEME_ATTRIBUTE])) { + self::validateScheme($components[self::SCHEME_ATTRIBUTE]); + } + + return $this->createUri() + ->withScheme($components[self::SCHEME_ATTRIBUTE] ?? self::DEFAULT_SCHEME) + ->withPath(self::resolvePath($components[self::PATH_ATTRIBUTE] ?? self::ROOT_PATH, $signal)) + ->withHost($components[self::HOST_ATTRIBUTE]); + } + + private static function validateScheme(string $protocol): void + { + if (!in_array($protocol, HttpEndpointResolverInterface::VALID_SCHEMES, true)) { + throw new InvalidArgumentException(sprintf( + 'Expected protocol to be http or https, given: "%s"', + $protocol + )); + } + } + + private static function validateSignal(string $signal): void + { + if (!in_array($signal, Signals::SIGNALS)) { + throw new InvalidArgumentException(sprintf( + 'Signal must be one of "%s". Given "%s"', + implode(', ', Signals::SIGNALS), + $signal + )); + } + } + + private static function parseEndpoint(string $endpoint): array + { + $result = parse_url($endpoint); + + if (!is_array($result) || !isset($result[self::HOST_ATTRIBUTE])) { + throw new InvalidArgumentException(sprintf( + 'Failed to parse endpoint "%s"', + $endpoint + )); + } + + return $result; + } + + private static function addUserInfo(UriInterface $uri, array $components): UriInterface + { + if (isset($components[self::USER_ATTRIBUTE])) { + $uri = $uri->withUserInfo( + $components[self::USER_ATTRIBUTE], + $components[self::PASS_ATTRIBUTE] ?? null + ); + } + + return $uri; + } + + private static function addPort(UriInterface $uri, array $components): UriInterface + { + if (isset($components[self::PORT_ATTRIBUTE])) { + $uri = $uri->withPort( + $components[self::PORT_ATTRIBUTE] + ); + } + + return $uri; + } + + private static function resolvePath(string $path, string $signal): string + { + self::validateSignal($signal); + + return str_replace('//', '/', sprintf('%s/%s', $path, self::getDefaultPath($signal))); + } + + private static function getDefaultPath(string $signal): string + { + return HttpEndpointResolverInterface::DEFAULT_PATHS[$signal]; + } +} diff --git a/vendor/open-telemetry/exporter-otlp/HttpEndpointResolverInterface.php b/vendor/open-telemetry/exporter-otlp/HttpEndpointResolverInterface.php new file mode 100644 index 000000000..fe165bd8a --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/HttpEndpointResolverInterface.php @@ -0,0 +1,28 @@ + self::TRACE_DEFAULT_PATH, + Signals::METRICS => self::METRICS_DEFAULT_PATH, + Signals::LOGS => self::LOGS_DEFAULT_PATH, + ]; + public const VALID_SCHEMES = [ + 'http', + 'https', + ]; + + public function resolve(string $endpoint, string $signal): UriInterface; + + public function resolveToString(string $endpoint, string $signal): string; +} diff --git a/vendor/open-telemetry/exporter-otlp/LogsConverter.php b/vendor/open-telemetry/exporter-otlp/LogsConverter.php new file mode 100644 index 000000000..1da53ad1f --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/LogsConverter.php @@ -0,0 +1,142 @@ +serializer = $serializer ?? ProtobufSerializer::getDefault(); + } + + /** + * @param iterable $logs + * @psalm-suppress InvalidArgument + */ + public function convert(iterable $logs): ExportLogsServiceRequest + { + $pExportLogsServiceRequest = new ExportLogsServiceRequest(); + $scopeLogs = []; + $resourceLogs = []; + $resourceCache = []; + $scopeCache = []; + + foreach ($logs as $log) { + $resource = $log->getResource(); + $instrumentationScope = $log->getInstrumentationScope(); + + $resourceId = $resourceCache[spl_object_id($resource)] ??= serialize([ + $resource->getSchemaUrl(), + $resource->getAttributes()->toArray(), + $resource->getAttributes()->getDroppedAttributesCount(), + ]); + $instrumentationScopeId = $scopeCache[spl_object_id($instrumentationScope)] ??= serialize([ + $instrumentationScope->getName(), + $instrumentationScope->getVersion(), + $instrumentationScope->getSchemaUrl(), + $instrumentationScope->getAttributes()->toArray(), + $instrumentationScope->getAttributes()->getDroppedAttributesCount(), + ]); + + if (($pResourceLogs = $resourceLogs[$resourceId] ?? null) === null) { + /** @psalm-suppress InvalidArgument */ + $pExportLogsServiceRequest->getResourceLogs()[] + = $resourceLogs[$resourceId] + = $pResourceLogs + = $this->convertResourceLogs($resource); + } + + if (($pScopeLogs = $scopeLogs[$resourceId][$instrumentationScopeId] ?? null) === null) { + $pResourceLogs->getScopeLogs()[] + = $scopeLogs[$resourceId][$instrumentationScopeId] + = $pScopeLogs + = $this->convertInstrumentationScope($instrumentationScope); + } + + $pScopeLogs->getLogRecords()[] = $this->convertLogRecord($log); + } + + return $pExportLogsServiceRequest; + } + + private function convertLogRecord(ReadableLogRecord $record): LogRecord + { + $pLogRecord = new LogRecord(); + $pLogRecord->setBody(AttributesConverter::convertAnyValue($record->getBody())); + $pLogRecord->setTimeUnixNano($record->getTimestamp() ?? 0); + $pLogRecord->setObservedTimeUnixNano($record->getObservedTimestamp() ?? 0); + $spanContext = $record->getSpanContext(); + if ($spanContext !== null && $spanContext->isValid()) { + $pLogRecord->setTraceId($this->serializer->serializeTraceId($spanContext->getTraceIdBinary())); + $pLogRecord->setSpanId($this->serializer->serializeSpanId($spanContext->getSpanIdBinary())); + $pLogRecord->setFlags($spanContext->getTraceFlags()); + } + $severityNumber = $record->getSeverityNumber(); + if ($severityNumber !== null) { + $pLogRecord->setSeverityNumber($severityNumber); + } + $severityText = $record->getSeverityText(); + if ($severityText !== null) { + $pLogRecord->setSeverityText($severityText); + } + $this->setAttributes($pLogRecord, $record->getAttributes()); + $pLogRecord->setDroppedAttributesCount($record->getAttributes()->getDroppedAttributesCount()); + + return $pLogRecord; + } + + private function convertInstrumentationScope(InstrumentationScopeInterface $instrumentationScope): ScopeLogs + { + $pScopeLogs = new ScopeLogs(); + $pInstrumentationScope = new InstrumentationScope(); + $pInstrumentationScope->setName($instrumentationScope->getName()); + $pInstrumentationScope->setVersion((string) $instrumentationScope->getVersion()); + $this->setAttributes($pInstrumentationScope, $instrumentationScope->getAttributes()); + $pInstrumentationScope->setDroppedAttributesCount($instrumentationScope->getAttributes()->getDroppedAttributesCount()); + $pScopeLogs->setScope($pInstrumentationScope); + $pScopeLogs->setSchemaUrl((string) $instrumentationScope->getSchemaUrl()); + + return $pScopeLogs; + } + + private function convertResourceLogs(ResourceInfo $resource): ResourceLogs + { + $pResourceLogs = new ResourceLogs(); + $pResource = new Resource_(); + $this->setAttributes($pResource, $resource->getAttributes()); + $pResource->setDroppedAttributesCount($resource->getAttributes()->getDroppedAttributesCount()); + $pResourceLogs->setResource($pResource); + + return $pResourceLogs; + } + + /** + * @param Resource_|LogRecord|InstrumentationScope $pElement + */ + private function setAttributes($pElement, AttributesInterface $attributes): void + { + foreach ($attributes as $key => $value) { + /** @psalm-suppress InvalidArgument */ + $pElement->getAttributes()[] = (new KeyValue()) + ->setKey($key) + ->setValue(AttributesConverter::convertAnyValue($value)); + } + $pElement->setDroppedAttributesCount($attributes->getDroppedAttributesCount()); + } +} diff --git a/vendor/open-telemetry/exporter-otlp/LogsExporter.php b/vendor/open-telemetry/exporter-otlp/LogsExporter.php new file mode 100644 index 000000000..fb100391f --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/LogsExporter.php @@ -0,0 +1,85 @@ + $transport + */ + public function __construct(TransportInterface $transport) + { + if (!class_exists('\Google\Protobuf\Api')) { + throw new RuntimeException('No protobuf implementation found (ext-protobuf or google/protobuf)'); + } + $this->transport = $transport; + $this->serializer = ProtobufSerializer::forTransport($transport); + } + + /** + * @param iterable $batch + */ + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface + { + return $this->transport + ->send($this->serializer->serialize((new LogsConverter($this->serializer))->convert($batch)), $cancellation) + ->map(function (?string $payload): bool { + if ($payload === null) { + return true; + } + + $serviceResponse = new ExportLogsServiceResponse(); + $this->serializer->hydrate($serviceResponse, $payload); + + $partialSuccess = $serviceResponse->getPartialSuccess(); + if ($partialSuccess !== null && $partialSuccess->getRejectedLogRecords()) { + self::logError('Export partial success', [ + 'rejected_logs' => $partialSuccess->getRejectedLogRecords(), + 'error_message' => $partialSuccess->getErrorMessage(), + ]); + + return false; + } + if ($partialSuccess !== null && $partialSuccess->getErrorMessage()) { + self::logWarning('Export success with warnings/suggestions', ['error_message' => $partialSuccess->getErrorMessage()]); + } + + return true; + }) + ->catch(static function (Throwable $throwable): bool { + self::logError('Export failure', ['exception' => $throwable]); + + return false; + }); + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return $this->transport->forceFlush($cancellation); + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return $this->transport->shutdown($cancellation); + } +} diff --git a/vendor/open-telemetry/exporter-otlp/LogsExporterFactory.php b/vendor/open-telemetry/exporter-otlp/LogsExporterFactory.php new file mode 100644 index 000000000..17fd68887 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/LogsExporterFactory.php @@ -0,0 +1,85 @@ +transportFactory = $transportFactory; + } + + /** + * @psalm-suppress ArgumentTypeCoercion + */ + public function create(): LogRecordExporterInterface + { + $protocol = Configuration::has(Variables::OTEL_EXPORTER_OTLP_LOGS_PROTOCOL) + ? Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_LOGS_PROTOCOL) + : Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_PROTOCOL); + + return new LogsExporter($this->buildTransport($protocol)); + } + + /** + * @psalm-suppress UndefinedClass + */ + private function buildTransport(string $protocol): TransportInterface + { + $endpoint = $this->getEndpoint($protocol); + + $headers = Configuration::has(Variables::OTEL_EXPORTER_OTLP_LOGS_HEADERS) + ? Configuration::getMap(Variables::OTEL_EXPORTER_OTLP_LOGS_HEADERS) + : Configuration::getMap(Variables::OTEL_EXPORTER_OTLP_HEADERS); + $headers += OtlpUtil::getUserAgentHeader(); + $compression = $this->getCompression(); + + $factoryClass = Registry::transportFactory($protocol); + $factory = $this->transportFactory ?: new $factoryClass(); + + return $factory->create( + $endpoint, + Protocols::contentType($protocol), + $headers, + $compression, + ); + } + + private function getCompression(): string + { + return Configuration::has(Variables::OTEL_EXPORTER_OTLP_LOGS_COMPRESSION) ? + Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_LOGS_COMPRESSION) : + Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_COMPRESSION, self::DEFAULT_COMPRESSION); + } + + private function getEndpoint(string $protocol): string + { + if (Configuration::has(Variables::OTEL_EXPORTER_OTLP_LOGS_ENDPOINT)) { + return Configuration::getString(Variables::OTEL_EXPORTER_OTLP_LOGS_ENDPOINT); + } + $endpoint = Configuration::has(Variables::OTEL_EXPORTER_OTLP_ENDPOINT) + ? Configuration::getString(Variables::OTEL_EXPORTER_OTLP_ENDPOINT) + : Defaults::OTEL_EXPORTER_OTLP_ENDPOINT; + if ($protocol === Protocols::GRPC) { + return $endpoint . OtlpUtil::method(Signals::LOGS); + } + + return HttpEndpointResolver::create()->resolveToString($endpoint, Signals::LOGS); + } +} diff --git a/vendor/open-telemetry/exporter-otlp/MetricConverter.php b/vendor/open-telemetry/exporter-otlp/MetricConverter.php new file mode 100644 index 000000000..584c41365 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/MetricConverter.php @@ -0,0 +1,265 @@ +serializer = $serializer ?? ProtobufSerializer::getDefault(); + } + + /** + * @param iterable $batch + */ + public function convert(iterable $batch): ExportMetricsServiceRequest + { + $pExportMetricsServiceRequest = new ExportMetricsServiceRequest(); + + $resourceMetrics = []; + $resourceCache = []; + $scopeMetrics = []; + $scopeCache = []; + foreach ($batch as $metric) { + $resource = $metric->resource; + $instrumentationScope = $metric->instrumentationScope; + + $resourceId = $resourceCache[spl_object_id($resource)] ??= serialize([ + $resource->getSchemaUrl(), + $resource->getAttributes()->toArray(), + $resource->getAttributes()->getDroppedAttributesCount(), + ]); + $instrumentationScopeId = $scopeCache[spl_object_id($instrumentationScope)] ??= serialize([ + $instrumentationScope->getName(), + $instrumentationScope->getVersion(), + $instrumentationScope->getSchemaUrl(), + $instrumentationScope->getAttributes()->toArray(), + $instrumentationScope->getAttributes()->getDroppedAttributesCount(), + ]); + + if (($pResourceMetrics = $resourceMetrics[$resourceId] ?? null) === null) { + /** @psalm-suppress InvalidArgument */ + $pExportMetricsServiceRequest->getResourceMetrics()[] + = $resourceMetrics[$resourceId] + = $pResourceMetrics + = $this->convertResourceMetrics($resource); + } + + if (($pScopeMetrics = $scopeMetrics[$resourceId][$instrumentationScopeId] ?? null) === null) { + /** @psalm-suppress InvalidArgument */ + $pResourceMetrics->getScopeMetrics()[] + = $scopeMetrics[$resourceId][$instrumentationScopeId] + = $pScopeMetrics + = $this->convertScopeMetrics($instrumentationScope); + } + + /** @psalm-suppress InvalidArgument */ + $pScopeMetrics->getMetrics()[] = $this->convertMetric($metric); + } + + return $pExportMetricsServiceRequest; + } + + private function convertResourceMetrics(SDK\Resource\ResourceInfo $resource): ResourceMetrics + { + $pResourceMetrics = new ResourceMetrics(); + $pResource = new Resource_(); + $this->setAttributes($pResource, $resource->getAttributes()); + $pResourceMetrics->setResource($pResource); + $pResourceMetrics->setSchemaUrl((string) $resource->getSchemaUrl()); + + return $pResourceMetrics; + } + + private function convertScopeMetrics(SDK\Common\Instrumentation\InstrumentationScopeInterface $instrumentationScope): ScopeMetrics + { + $pScopeMetrics = new ScopeMetrics(); + $pInstrumentationScope = new InstrumentationScope(); + $pInstrumentationScope->setName($instrumentationScope->getName()); + $pInstrumentationScope->setVersion((string) $instrumentationScope->getVersion()); + $this->setAttributes($pInstrumentationScope, $instrumentationScope->getAttributes()); + $pScopeMetrics->setScope($pInstrumentationScope); + $pScopeMetrics->setSchemaUrl((string) $instrumentationScope->getSchemaUrl()); + + return $pScopeMetrics; + } + + private function convertMetric(SDK\Metrics\Data\Metric $metric): Metric + { + $pMetric = new Metric(); + $pMetric->setName($metric->name); + $pMetric->setDescription((string) $metric->description); + $pMetric->setUnit((string) $metric->unit); + + $data = $metric->data; + if ($data instanceof SDK\Metrics\Data\Gauge) { + $pMetric->setGauge($this->convertGauge($data)); + } + if ($data instanceof SDK\Metrics\Data\Histogram) { + $pMetric->setHistogram($this->convertHistogram($data)); + } + if ($data instanceof SDK\Metrics\Data\Sum) { + $pMetric->setSum($this->convertSum($data)); + } + + return $pMetric; + } + + private function convertTemporality($temporality): int + { + switch ($temporality) { + case SDK\Metrics\Data\Temporality::DELTA: + return AggregationTemporality::AGGREGATION_TEMPORALITY_DELTA; + case SDK\Metrics\Data\Temporality::CUMULATIVE: + return AggregationTemporality::AGGREGATION_TEMPORALITY_CUMULATIVE; + } + + // @codeCoverageIgnoreStart + return AggregationTemporality::AGGREGATION_TEMPORALITY_UNSPECIFIED; + // @codeCoverageIgnoreEnd + } + + private function convertGauge(SDK\Metrics\Data\Gauge $gauge): Gauge + { + $pGauge = new Gauge(); + foreach ($gauge->dataPoints as $dataPoint) { + /** @psalm-suppress InvalidArgument */ + $pGauge->getDataPoints()[] = $this->convertNumberDataPoint($dataPoint); + } + + return $pGauge; + } + + private function convertHistogram(SDK\Metrics\Data\Histogram $histogram): Histogram + { + $pHistogram = new Histogram(); + foreach ($histogram->dataPoints as $dataPoint) { + /** @psalm-suppress InvalidArgument */ + $pHistogram->getDataPoints()[] = $this->convertHistogramDataPoint($dataPoint); + } + $pHistogram->setAggregationTemporality($this->convertTemporality($histogram->temporality)); + + return $pHistogram; + } + + private function convertSum(SDK\Metrics\Data\Sum $sum): Sum + { + $pSum = new Sum(); + foreach ($sum->dataPoints as $dataPoint) { + /** @psalm-suppress InvalidArgument */ + $pSum->getDataPoints()[] = $this->convertNumberDataPoint($dataPoint); + } + $pSum->setAggregationTemporality($this->convertTemporality($sum->temporality)); + $pSum->setIsMonotonic($sum->monotonic); + + return $pSum; + } + + private function convertNumberDataPoint(SDK\Metrics\Data\NumberDataPoint $dataPoint): NumberDataPoint + { + $pNumberDataPoint = new NumberDataPoint(); + $this->setAttributes($pNumberDataPoint, $dataPoint->attributes); + $pNumberDataPoint->setStartTimeUnixNano($dataPoint->startTimestamp); + $pNumberDataPoint->setTimeUnixNano($dataPoint->timestamp); + if (is_int($dataPoint->value)) { + $pNumberDataPoint->setAsInt($dataPoint->value); + } + if (is_float($dataPoint->value)) { + $pNumberDataPoint->setAsDouble($dataPoint->value); + } + foreach ($dataPoint->exemplars as $exemplar) { + /** @psalm-suppress InvalidArgument */ + $pNumberDataPoint->getExemplars()[] = $this->convertExemplar($exemplar); + } + + return $pNumberDataPoint; + } + + private function convertHistogramDataPoint(SDK\Metrics\Data\HistogramDataPoint $dataPoint): HistogramDataPoint + { + $pHistogramDataPoint = new HistogramDataPoint(); + $this->setAttributes($pHistogramDataPoint, $dataPoint->attributes); + $pHistogramDataPoint->setStartTimeUnixNano($dataPoint->startTimestamp); + $pHistogramDataPoint->setTimeUnixNano($dataPoint->timestamp); + $pHistogramDataPoint->setCount($dataPoint->count); + $pHistogramDataPoint->setSum($dataPoint->sum); + /** @phpstan-ignore-next-line */ + $pHistogramDataPoint->setBucketCounts($dataPoint->bucketCounts); + /** @phpstan-ignore-next-line */ + $pHistogramDataPoint->setExplicitBounds($dataPoint->explicitBounds); + foreach ($dataPoint->exemplars as $exemplar) { + /** @psalm-suppress InvalidArgument */ + $pHistogramDataPoint->getExemplars()[] = $this->convertExemplar($exemplar); + } + + return $pHistogramDataPoint; + } + + private function convertExemplar(SDK\Metrics\Data\Exemplar $exemplar): Exemplar + { + $pExemplar = new Exemplar(); + $this->setFilteredAttributes($pExemplar, $exemplar->attributes); + $pExemplar->setTimeUnixNano($exemplar->timestamp); + $pExemplar->setSpanId($this->serializer->serializeSpanId(hex2bin((string) $exemplar->spanId))); + $pExemplar->setTraceId($this->serializer->serializeTraceId(hex2bin((string) $exemplar->traceId))); + if (is_int($exemplar->value)) { + $pExemplar->setAsInt($exemplar->value); + } + if (is_float($exemplar->value)) { + $pExemplar->setAsDouble($exemplar->value); + } + + return $pExemplar; + } + + /** + * @param Resource_|NumberDataPoint|HistogramDataPoint|InstrumentationScope $pElement + */ + private function setAttributes($pElement, SDK\Common\Attribute\AttributesInterface $attributes): void + { + foreach ($attributes as $key => $value) { + /** @psalm-suppress InvalidArgument */ + $pElement->getAttributes()[] = $pAttribute = new KeyValue(); + $pAttribute->setKey($key); + $pAttribute->setValue(AttributesConverter::convertAnyValue($value)); + } + if (method_exists($pElement, 'setDroppedAttributesCount')) { + $pElement->setDroppedAttributesCount($attributes->getDroppedAttributesCount()); + } + } + + private function setFilteredAttributes(Exemplar $pElement, SDK\Common\Attribute\AttributesInterface $attributes): void + { + foreach ($attributes as $key => $value) { + /** @psalm-suppress InvalidArgument */ + $pElement->getFilteredAttributes()[] = $pAttribute = new KeyValue(); + $pAttribute->setKey($key); + $pAttribute->setValue(AttributesConverter::convertAnyValue($value)); + } + } +} diff --git a/vendor/open-telemetry/exporter-otlp/MetricExporter.php b/vendor/open-telemetry/exporter-otlp/MetricExporter.php new file mode 100644 index 000000000..efd149c7f --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/MetricExporter.php @@ -0,0 +1,97 @@ + $transport + */ + public function __construct(TransportInterface $transport, $temporality = null) + { + if (!class_exists('\Google\Protobuf\Api')) { + throw new RuntimeException('No protobuf implementation found (ext-protobuf or google/protobuf)'); + } + $this->transport = $transport; + $this->serializer = ProtobufSerializer::forTransport($transport); + $this->temporality = $temporality; + } + + public function temporality(MetricMetadataInterface $metric) + { + return $this->temporality ?? $metric->temporality(); + } + + public function export(iterable $batch): bool + { + return $this->transport + ->send($this->serializer->serialize((new MetricConverter($this->serializer))->convert($batch))) + ->map(function (?string $payload): bool { + if ($payload === null) { + return true; + } + + $serviceResponse = new ExportMetricsServiceResponse(); + $this->serializer->hydrate($serviceResponse, $payload); + + $partialSuccess = $serviceResponse->getPartialSuccess(); + if ($partialSuccess !== null && $partialSuccess->getRejectedDataPoints()) { + self::logError('Export partial success', [ + 'rejected_data_points' => $partialSuccess->getRejectedDataPoints(), + 'error_message' => $partialSuccess->getErrorMessage(), + ]); + + return false; + } + if ($partialSuccess !== null && $partialSuccess->getErrorMessage()) { + self::logWarning('Export success with warnings/suggestions', ['error_message' => $partialSuccess->getErrorMessage()]); + } + + return true; + }) + ->catch(static function (Throwable $throwable): bool { + self::logError('Export failure', ['exception' => $throwable]); + + return false; + }) + ->await(); + } + + public function shutdown(): bool + { + return $this->transport->shutdown(); + } + + public function forceFlush(): bool + { + return $this->transport->forceFlush(); + } +} diff --git a/vendor/open-telemetry/exporter-otlp/MetricExporterFactory.php b/vendor/open-telemetry/exporter-otlp/MetricExporterFactory.php new file mode 100644 index 000000000..284428b73 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/MetricExporterFactory.php @@ -0,0 +1,110 @@ +transportFactory = $transportFactory; + } + + /** + * @psalm-suppress ArgumentTypeCoercion + */ + public function create(): MetricExporterInterface + { + $protocol = Configuration::has(Variables::OTEL_EXPORTER_OTLP_METRICS_PROTOCOL) + ? Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_METRICS_PROTOCOL) + : Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_PROTOCOL); + $temporality = $this->getTemporality(); + + return new MetricExporter($this->buildTransport($protocol), $temporality); + } + + /** + * @psalm-suppress UndefinedClass + */ + private function buildTransport(string $protocol): TransportInterface + { + /** + * @todo (https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#periodic-exporting-metricreader) + * - OTEL_METRIC_EXPORT_INTERVAL + * - OTEL_METRIC_EXPORT_TIMEOUT + */ + $endpoint = $this->getEndpoint($protocol); + + $headers = Configuration::has(Variables::OTEL_EXPORTER_OTLP_METRICS_HEADERS) + ? Configuration::getMap(Variables::OTEL_EXPORTER_OTLP_METRICS_HEADERS) + : Configuration::getMap(Variables::OTEL_EXPORTER_OTLP_HEADERS); + $headers += OtlpUtil::getUserAgentHeader(); + $compression = $this->getCompression(); + + $factoryClass = Registry::transportFactory($protocol); + $factory = $this->transportFactory ?: new $factoryClass(); + + return $factory->create( + $endpoint, + Protocols::contentType($protocol), + $headers, + $compression, + ); + } + + /** + * @todo return string|Temporality|null (php >= 8.0) + */ + private function getTemporality() + { + $value = Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE); + switch (strtolower($value)) { + case 'cumulative': + return Temporality::CUMULATIVE; + case 'delta': + return Temporality::DELTA; + case 'lowmemory': + return null; + default: + throw new \UnexpectedValueException('Unknown temporality: ' . $value); + } + } + + private function getCompression(): string + { + return Configuration::has(Variables::OTEL_EXPORTER_OTLP_METRICS_COMPRESSION) ? + Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_METRICS_COMPRESSION) : + Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_COMPRESSION, self::DEFAULT_COMPRESSION); + } + + private function getEndpoint(string $protocol): string + { + if (Configuration::has(Variables::OTEL_EXPORTER_OTLP_METRICS_ENDPOINT)) { + return Configuration::getString(Variables::OTEL_EXPORTER_OTLP_METRICS_ENDPOINT); + } + $endpoint = Configuration::has(Variables::OTEL_EXPORTER_OTLP_ENDPOINT) + ? Configuration::getString(Variables::OTEL_EXPORTER_OTLP_ENDPOINT) + : Defaults::OTEL_EXPORTER_OTLP_ENDPOINT; + if ($protocol === Protocols::GRPC) { + return $endpoint . OtlpUtil::method(Signals::METRICS); + } + + return HttpEndpointResolver::create()->resolveToString($endpoint, Signals::METRICS); + } +} diff --git a/vendor/open-telemetry/exporter-otlp/OtlpHttpTransportFactory.php b/vendor/open-telemetry/exporter-otlp/OtlpHttpTransportFactory.php new file mode 100644 index 000000000..5cf3ff9e4 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/OtlpHttpTransportFactory.php @@ -0,0 +1,33 @@ +create($endpoint, $contentType, $headers, $compression, $timeout, $retryDelay, $maxRetries, $cacert, $cert, $key); + } +} diff --git a/vendor/open-telemetry/exporter-otlp/OtlpUtil.php b/vendor/open-telemetry/exporter-otlp/OtlpUtil.php new file mode 100644 index 000000000..6901c1324 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/OtlpUtil.php @@ -0,0 +1,45 @@ + '/opentelemetry.proto.collector.trace.v1.TraceService/Export', + Signals::METRICS => '/opentelemetry.proto.collector.metrics.v1.MetricsService/Export', + Signals::LOGS => '/opentelemetry.proto.collector.logs.v1.LogsService/Export', + ]; + + public static function method(string $signal): string + { + if (!array_key_exists($signal, self::METHODS)) { + throw new UnexpectedValueException('gRPC method not defined for signal: ' . $signal); + } + + return self::METHODS[$signal]; + } + + /** + * @link https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#user-agent + */ + public static function getUserAgentHeader(): array + { + $resource = (new Sdk())->getResource(); + + return ['User-Agent' => sprintf( + 'OTel OTLP Exporter PHP/%s', + $resource->getAttributes()->get(ResourceAttributes::TELEMETRY_SDK_VERSION) ?: 'unknown' + )]; + } +} diff --git a/vendor/open-telemetry/exporter-otlp/ProtobufSerializer.php b/vendor/open-telemetry/exporter-otlp/ProtobufSerializer.php new file mode 100644 index 000000000..c244d0066 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/ProtobufSerializer.php @@ -0,0 +1,115 @@ +contentType = $contentType; + } + + public static function getDefault(): ProtobufSerializer + { + return new self(self::PROTOBUF); + } + + /** + * @psalm-param TransportInterface $transport + */ + public static function forTransport(TransportInterface $transport): ProtobufSerializer + { + switch ($contentType = $transport->contentType()) { + case self::PROTOBUF: + case self::JSON: + case self::NDJSON: + return new self($contentType); + default: + throw new InvalidArgumentException(sprintf('Not supported content type "%s"', $contentType)); + } + } + + public function serializeTraceId(string $traceId): string + { + switch ($this->contentType) { + case self::PROTOBUF: + return $traceId; + case self::JSON: + case self::NDJSON: + return base64_decode(bin2hex($traceId)); + default: + throw new AssertionError(); + } + } + + public function serializeSpanId(string $spanId): string + { + switch ($this->contentType) { + case self::PROTOBUF: + return $spanId; + case self::JSON: + case self::NDJSON: + return base64_decode(bin2hex($spanId)); + default: + throw new AssertionError(); + } + } + + public function serialize(Message $message): string + { + switch ($this->contentType) { + case self::PROTOBUF: + return $message->serializeToString(); + case self::JSON: + //@todo https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md#json-protobuf-encoding + return $message->serializeToJsonString(); + case self::NDJSON: + return $message->serializeToJsonString() . "\n"; + default: + throw new AssertionError(); + } + } + + /** + * @throws Exception + */ + public function hydrate(Message $message, string $payload): void + { + switch ($this->contentType) { + case self::PROTOBUF: + $message->mergeFromString($payload); + + break; + case self::JSON: + case self::NDJSON: + // @phan-suppress-next-line PhanParamTooManyInternal + $message->mergeFromJsonString($payload, true); + + break; + default: + throw new AssertionError(); + } + } +} diff --git a/vendor/open-telemetry/exporter-otlp/Protocols.php b/vendor/open-telemetry/exporter-otlp/Protocols.php new file mode 100644 index 000000000..96b04d8bf --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/Protocols.php @@ -0,0 +1,36 @@ + ContentTypes::PROTOBUF, + self::HTTP_PROTOBUF => ContentTypes::PROTOBUF, + self::HTTP_JSON => ContentTypes::JSON, + self::HTTP_NDJSON => ContentTypes::NDJSON, + ]; + + public static function validate(string $protocol): void + { + if (!array_key_exists($protocol, self::PROTOCOLS)) { + throw new UnexpectedValueException('Unknown protocol: ' . $protocol); + } + } + + public static function contentType(string $protocol): string + { + self::validate($protocol); + + return self::PROTOCOLS[$protocol]; + } +} diff --git a/vendor/open-telemetry/exporter-otlp/README.md b/vendor/open-telemetry/exporter-otlp/README.md new file mode 100644 index 000000000..a41349da0 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/README.md @@ -0,0 +1,45 @@ +[![Releases](https://img.shields.io/badge/releases-purple)](https://github.com/opentelemetry-php/exporter-otlp/releases) +[![Source](https://img.shields.io/badge/source-exporter--otlp-green)](https://github.com/open-telemetry/opentelemetry-php/tree/main/src/Contrib/Otlp) +[![Mirror](https://img.shields.io/badge/mirror-opentelemetry--php:exporter--otlp-blue)](https://github.com/opentelemetry-php/exporter-otlp) +[![Latest Version](http://poser.pugx.org/open-telemetry/exporter-otlp/v/unstable)](https://packagist.org/packages/open-telemetry/exporter-otlp/) +[![Stable](http://poser.pugx.org/open-telemetry/exporter-otlp/v/stable)](https://packagist.org/packages/open-telemetry/exporter-otlp/) + +# OpenTelemetry OTLP exporter + +## Documentation + +https://opentelemetry.io/docs/instrumentation/php/exporters/#otlp + +## Usage + +See https://github.com/open-telemetry/opentelemetry-php/blob/main/examples/traces/exporters/otlp_http.php + +## Http transport + +```php +$transport = (new \OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory())->create('http://collector:4318'); +$exporter = new \OpenTelemetry\Contrib\Otlp\SpanExporter($transport); +``` + +## gRPC transport + +To export over gRPC, you will need to additionally install the `open-telemetry/transport-grpc` package. + +## Protobuf Runtime library + +OTLP exporting requires a [protobuf implementation](https://github.com/protocolbuffers/protobuf/tree/main/php). + +The `open-telemetry/gen-otlp-protobuf` requires the `google/protobuf` native implementation. It's fine for development, but +not recommended for production usage. + +The recommended option for production is to install the Protobuf C extension for PHP. The extension +makes exporting _significantly_ more performant. This can be easily installed with the following command: + +```shell +pecl install protobuf +``` + +## Contributing + +This repository is a read-only git subtree split. +To contribute, please see the main [OpenTelemetry PHP monorepo](https://github.com/open-telemetry/opentelemetry-php). diff --git a/vendor/open-telemetry/exporter-otlp/SpanConverter.php b/vendor/open-telemetry/exporter-otlp/SpanConverter.php new file mode 100644 index 000000000..1a8b4369e --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/SpanConverter.php @@ -0,0 +1,187 @@ +serializer = $serializer ?? ProtobufSerializer::getDefault(); + } + + public function convert(iterable $spans): ExportTraceServiceRequest + { + $pExportTraceServiceRequest = new ExportTraceServiceRequest(); + + $resourceSpans = []; + $resourceCache = []; + $scopeSpans = []; + $scopeCache = []; + foreach ($spans as $span) { + $resource = $span->getResource(); + $instrumentationScope = $span->getInstrumentationScope(); + + $resourceId = $resourceCache[spl_object_id($resource)] ??= serialize([ + $resource->getSchemaUrl(), + $resource->getAttributes()->toArray(), + $resource->getAttributes()->getDroppedAttributesCount(), + ]); + $instrumentationScopeId = $scopeCache[spl_object_id($instrumentationScope)] ??= serialize([ + $instrumentationScope->getName(), + $instrumentationScope->getVersion(), + $instrumentationScope->getSchemaUrl(), + $instrumentationScope->getAttributes()->toArray(), + $instrumentationScope->getAttributes()->getDroppedAttributesCount(), + ]); + + if (($pResourceSpans = $resourceSpans[$resourceId] ?? null) === null) { + /** @psalm-suppress InvalidArgument */ + $pExportTraceServiceRequest->getResourceSpans()[] + = $resourceSpans[$resourceId] + = $pResourceSpans + = $this->convertResourceSpans($resource); + } + + if (($pScopeSpans = $scopeSpans[$resourceId][$instrumentationScopeId] ?? null) === null) { + /** @psalm-suppress InvalidArgument */ + $pResourceSpans->getScopeSpans()[] + = $scopeSpans[$resourceId][$instrumentationScopeId] + = $pScopeSpans + = $this->convertScopeSpans($instrumentationScope); + } + + /** @psalm-suppress InvalidArgument */ + $pScopeSpans->getSpans()[] = $this->convertSpan($span); + } + + return $pExportTraceServiceRequest; + } + + private function convertResourceSpans(ResourceInfo $resource): ResourceSpans + { + $pResourceSpans = new ResourceSpans(); + $pResource = new Resource_(); + $this->setAttributes($pResource, $resource->getAttributes()); + $pResourceSpans->setResource($pResource); + $pResourceSpans->setSchemaUrl((string) $resource->getSchemaUrl()); + + return $pResourceSpans; + } + + private function convertScopeSpans(InstrumentationScopeInterface $instrumentationScope): ScopeSpans + { + $pScopeSpans = new ScopeSpans(); + $pInstrumentationScope = new InstrumentationScope(); + $pInstrumentationScope->setName($instrumentationScope->getName()); + $pInstrumentationScope->setVersion((string) $instrumentationScope->getVersion()); + $this->setAttributes($pInstrumentationScope, $instrumentationScope->getAttributes()); + $pScopeSpans->setScope($pInstrumentationScope); + $pScopeSpans->setSchemaUrl((string) $instrumentationScope->getSchemaUrl()); + + return $pScopeSpans; + } + + /** + * @param Resource_|Span|Event|Link|InstrumentationScope $pElement + */ + private function setAttributes($pElement, AttributesInterface $attributes): void + { + foreach ($attributes as $key => $value) { + /** @psalm-suppress InvalidArgument */ + $pElement->getAttributes()[] = (new KeyValue()) + ->setKey($key) + ->setValue(AttributesConverter::convertAnyValue($value)); + } + $pElement->setDroppedAttributesCount($attributes->getDroppedAttributesCount()); + } + + private function convertSpanKind(int $kind): int + { + switch ($kind) { + case API\SpanKind::KIND_INTERNAL: return SpanKind::SPAN_KIND_INTERNAL; + case API\SpanKind::KIND_CLIENT: return SpanKind::SPAN_KIND_CLIENT; + case API\SpanKind::KIND_SERVER: return SpanKind::SPAN_KIND_SERVER; + case API\SpanKind::KIND_PRODUCER: return SpanKind::SPAN_KIND_PRODUCER; + case API\SpanKind::KIND_CONSUMER: return SpanKind::SPAN_KIND_CONSUMER; + } + + return SpanKind::SPAN_KIND_UNSPECIFIED; + } + + private function convertStatusCode(string $status): int + { + switch ($status) { + case API\StatusCode::STATUS_UNSET: return StatusCode::STATUS_CODE_UNSET; + case API\StatusCode::STATUS_OK: return StatusCode::STATUS_CODE_OK; + case API\StatusCode::STATUS_ERROR: return StatusCode::STATUS_CODE_ERROR; + } + + return StatusCode::STATUS_CODE_UNSET; + } + + private function convertSpan(SpanDataInterface $span): Span + { + $pSpan = new Span(); + $pSpan->setTraceId($this->serializer->serializeTraceId($span->getContext()->getTraceIdBinary())); + $pSpan->setSpanId($this->serializer->serializeSpanId($span->getContext()->getSpanIdBinary())); + $pSpan->setTraceState((string) $span->getContext()->getTraceState()); + if ($span->getParentContext()->isValid()) { + $pSpan->setParentSpanId($this->serializer->serializeSpanId($span->getParentContext()->getSpanIdBinary())); + } + $pSpan->setName($span->getName()); + $pSpan->setKind($this->convertSpanKind($span->getKind())); + $pSpan->setStartTimeUnixNano($span->getStartEpochNanos()); + $pSpan->setEndTimeUnixNano($span->getEndEpochNanos()); + $this->setAttributes($pSpan, $span->getAttributes()); + + foreach ($span->getEvents() as $event) { + /** @psalm-suppress InvalidArgument */ + $pSpan->getEvents()[] = $pEvent = new Event(); + $pEvent->setTimeUnixNano($event->getEpochNanos()); + $pEvent->setName($event->getName()); + $this->setAttributes($pEvent, $event->getAttributes()); + } + $pSpan->setDroppedEventsCount($span->getTotalDroppedEvents()); + + foreach ($span->getLinks() as $link) { + /** @psalm-suppress InvalidArgument */ + $pSpan->getLinks()[] = $pLink = new Link(); + $pLink->setTraceId($this->serializer->serializeTraceId($link->getSpanContext()->getTraceIdBinary())); + $pLink->setSpanId($this->serializer->serializeSpanId($link->getSpanContext()->getSpanIdBinary())); + $pLink->setTraceState((string) $link->getSpanContext()->getTraceState()); + $this->setAttributes($pLink, $link->getAttributes()); + } + $pSpan->setDroppedLinksCount($span->getTotalDroppedLinks()); + + $pStatus = new Status(); + $pStatus->setMessage($span->getStatus()->getDescription()); + $pStatus->setCode($this->convertStatusCode($span->getStatus()->getCode())); + $pSpan->setStatus($pStatus); + + return $pSpan; + } +} diff --git a/vendor/open-telemetry/exporter-otlp/SpanExporter.php b/vendor/open-telemetry/exporter-otlp/SpanExporter.php new file mode 100644 index 000000000..a496206f4 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/SpanExporter.php @@ -0,0 +1,81 @@ + $transport + */ + public function __construct(TransportInterface $transport) + { + if (!class_exists('\Google\Protobuf\Api')) { + throw new RuntimeException('No protobuf implementation found (ext-protobuf or google/protobuf)'); + } + $this->transport = $transport; + $this->serializer = ProtobufSerializer::forTransport($transport); + } + + public function export(iterable $batch, ?CancellationInterface $cancellation = null): FutureInterface + { + return $this->transport + ->send($this->serializer->serialize((new SpanConverter($this->serializer))->convert($batch)), $cancellation) + ->map(function (?string $payload): bool { + if ($payload === null) { + return true; + } + + $serviceResponse = new ExportTraceServiceResponse(); + $this->serializer->hydrate($serviceResponse, $payload); + + $partialSuccess = $serviceResponse->getPartialSuccess(); + if ($partialSuccess !== null && $partialSuccess->getRejectedSpans()) { + self::logError('Export partial success', [ + 'rejected_spans' => $partialSuccess->getRejectedSpans(), + 'error_message' => $partialSuccess->getErrorMessage(), + ]); + + return false; + } + if ($partialSuccess !== null && $partialSuccess->getErrorMessage()) { + self::logWarning('Export success with warnings/suggestions', ['error_message' => $partialSuccess->getErrorMessage()]); + } + + return true; + }) + ->catch(static function (Throwable $throwable): bool { + self::logError('Export failure', ['exception' => $throwable]); + + return false; + }); + } + + public function shutdown(?CancellationInterface $cancellation = null): bool + { + return $this->transport->shutdown($cancellation); + } + + public function forceFlush(?CancellationInterface $cancellation = null): bool + { + return $this->transport->forceFlush($cancellation); + } +} diff --git a/vendor/open-telemetry/exporter-otlp/SpanExporterFactory.php b/vendor/open-telemetry/exporter-otlp/SpanExporterFactory.php new file mode 100644 index 000000000..ce0550735 --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/SpanExporterFactory.php @@ -0,0 +1,96 @@ +transportFactory = $transportFactory; + } + + /** + * @psalm-suppress ArgumentTypeCoercion + */ + public function create(): SpanExporterInterface + { + $transport = $this->buildTransport(); + + return new SpanExporter($transport); + } + + /** + * @psalm-suppress ArgumentTypeCoercion + * @psalm-suppress UndefinedClass + */ + private function buildTransport(): TransportInterface + { + $protocol = $this->getProtocol(); + $contentType = Protocols::contentType($protocol); + $endpoint = $this->getEndpoint($protocol); + $headers = $this->getHeaders(); + $compression = $this->getCompression(); + + $factoryClass = Registry::transportFactory($protocol); + $factory = $this->transportFactory ?: new $factoryClass(); + + return $factory->create($endpoint, $contentType, $headers, $compression); + } + + private function getProtocol(): string + { + return Configuration::has(Variables::OTEL_EXPORTER_OTLP_TRACES_PROTOCOL) ? + Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_TRACES_PROTOCOL) : + Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_PROTOCOL); + } + + private function getEndpoint(string $protocol): string + { + if (Configuration::has(Variables::OTEL_EXPORTER_OTLP_TRACES_ENDPOINT)) { + return Configuration::getString(Variables::OTEL_EXPORTER_OTLP_TRACES_ENDPOINT); + } + $endpoint = Configuration::has(Variables::OTEL_EXPORTER_OTLP_ENDPOINT) + ? Configuration::getString(Variables::OTEL_EXPORTER_OTLP_ENDPOINT) + : Defaults::OTEL_EXPORTER_OTLP_ENDPOINT; + if ($protocol === Protocols::GRPC) { + return $endpoint . OtlpUtil::method(Signals::TRACE); + } + + return HttpEndpointResolver::create()->resolveToString($endpoint, Signals::TRACE); + } + + private function getHeaders(): array + { + $headers = Configuration::has(Variables::OTEL_EXPORTER_OTLP_TRACES_HEADERS) ? + Configuration::getMap(Variables::OTEL_EXPORTER_OTLP_TRACES_HEADERS) : + Configuration::getMap(Variables::OTEL_EXPORTER_OTLP_HEADERS); + + return $headers + OtlpUtil::getUserAgentHeader(); + } + + private function getCompression(): string + { + return Configuration::has(Variables::OTEL_EXPORTER_OTLP_TRACES_COMPRESSION) ? + Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_TRACES_COMPRESSION) : + Configuration::getEnum(Variables::OTEL_EXPORTER_OTLP_COMPRESSION, self::DEFAULT_COMPRESSION); + } +} diff --git a/vendor/open-telemetry/exporter-otlp/_register.php b/vendor/open-telemetry/exporter-otlp/_register.php new file mode 100644 index 000000000..b3acdc3af --- /dev/null +++ b/vendor/open-telemetry/exporter-otlp/_register.php @@ -0,0 +1,9 @@ +