diff --git a/.gitsplit.yml b/.gitsplit.yml
index f21429504..9f7eb8289 100644
--- a/.gitsplit.yml
+++ b/.gitsplit.yml
@@ -16,6 +16,8 @@ splits:
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/api.git"
- prefix: "src/SDK"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/sdk.git"
+ - prefix: "src/Config/SDK"
+ target: "https://${GH_TOKEN}@github.com/opentelemetry-php/config-sdk.git"
- prefix: "src/Contrib/Otlp"
target: "https://${GH_TOKEN}@github.com/opentelemetry-php/exporter-otlp.git"
- prefix: "src/Contrib/Grpc"
diff --git a/.phan/config.php b/.phan/config.php
index 13248372a..d8c6d47e0 100644
--- a/.phan/config.php
+++ b/.phan/config.php
@@ -319,6 +319,7 @@
'exclude_analysis_directory_list' => [
'vendor/',
'proto/',
+ 'src/Config/SDK',
],
// Enable this to enable checks of require/include statements referring to valid paths.
diff --git a/composer.json b/composer.json
index 3865f61c3..b5521796a 100644
--- a/composer.json
+++ b/composer.json
@@ -16,14 +16,17 @@
"psr/http-message": "^1.0.1|^2.0",
"psr/log": "^1.1|^2.0|^3.0",
"symfony/polyfill-mbstring": "^1.23",
- "symfony/polyfill-php82": "^1.26"
+ "symfony/polyfill-php82": "^1.26",
+ "tbachert/otel-sdk-configuration": "^0.1",
+ "tbachert/spi": "^0.2"
},
"config": {
"sort-packages": true,
"allow-plugins": {
"composer/package-versions-deprecated": true,
"php-http/discovery": true,
- "symfony/runtime": true
+ "symfony/runtime": true,
+ "tbachert/spi": true
}
},
"authors": [
@@ -33,12 +36,17 @@
}
],
"replace": {
- "open-telemetry/api": "self.version",
- "open-telemetry/context": "self.version",
- "open-telemetry/gen-otlp-protobuf": "self.version",
- "open-telemetry/sdk": "self.version",
- "open-telemetry/sdk-contrib": "self.version",
- "open-telemetry/sem-conv": "self.version"
+ "open-telemetry/api": "1.0.x-dev",
+ "open-telemetry/context": "1.0.x-dev",
+ "open-telemetry/exporter-otlp": "1.0.x-dev",
+ "open-telemetry/exporter-zipkin": "1.0.x-dev",
+ "open-telemetry/extension-propagator-b3": "1.0.x-dev",
+ "open-telemetry/extension-propagator-jaeger": "0.0.2",
+ "open-telemetry/gen-otlp-protobuf": "1.0.x-dev",
+ "open-telemetry/sdk": "1.0.x-dev",
+ "open-telemetry/sdk-configuration": "0.1.x-dev",
+ "open-telemetry/sdk-contrib": "1.0.x-dev",
+ "open-telemetry/sem-conv": "1.0.x-dev"
},
"autoload": {
"psr-4": {
@@ -108,5 +116,37 @@
"ext-gmp": "To support unlimited number of synchronous metric readers",
"ext-grpc": "To use the OTLP GRPC Exporter",
"ext-protobuf": "For more performant protobuf/grpc exporting"
+ },
+ "extra": {
+ "spi": {
+ "Nevay\\OTelSDK\\Configuration\\ComponentProvider": [
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorB3",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorB3Multi",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorBaggage",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorComposite",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorJaeger",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorTraceContext",
+
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SamplerAlwaysOff",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SamplerAlwaysOn",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SamplerParentBased",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SamplerTraceIdRatioBased",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanExporterConsole",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanExporterOtlp",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanExporterZipkin",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanProcessorBatch",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanProcessorSimple",
+
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Metrics\\AggregationResolverDefault",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Metrics\\MetricExporterConsole",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Metrics\\MetricExporterOtlp",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Metrics\\MetricReaderPeriodic",
+
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordExporterConsole",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordExporterOtlp",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordProcessorBatch",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordProcessorSimple"
+ ]
+ }
}
}
diff --git a/examples/load_config.php b/examples/load_config.php
new file mode 100644
index 000000000..591f3f583
--- /dev/null
+++ b/examples/load_config.php
@@ -0,0 +1,29 @@
+create()
+ ->setAutoShutdown(true)
+ ->build();
+
+$tracer = $sdk->getTracerProvider()->getTracer('demo');
+$meter = $sdk->getMeterProvider()->getMeter('demo');
+$logger = $sdk->getLoggerProvider()->getLogger('demo');
+
+$tracer->spanBuilder('root')->startSpan()->end();
+$meter->createCounter('cnt')->add(1);
+
+$eventLogger = new EventLogger($logger, 'my-domain');
+$eventLogger->logEvent('foo', new LogRecord('hello, otel'));
+
+echo 'Finished!' . PHP_EOL;
diff --git a/examples/load_config.yaml b/examples/load_config.yaml
new file mode 100644
index 000000000..9e1901de8
--- /dev/null
+++ b/examples/load_config.yaml
@@ -0,0 +1,44 @@
+file_format: '0.1'
+
+resource:
+ attributes:
+ service.name: opentelemetry-demo
+
+propagators:
+ composite: [ tracecontext, baggage ]
+
+exporters:
+ otlp: &otlp-exporter
+ protocol: http/protobuf
+ endpoint: http://collector:4318
+
+tracer_provider:
+ sampler:
+ parent_based:
+ root:
+ always_on: {}
+ processors:
+ - simple:
+ exporter:
+ console: {}
+ - batch:
+ exporter:
+ otlp: *otlp-exporter
+meter_provider:
+ readers:
+ - periodic:
+ exporter:
+ console: {}
+ - periodic:
+ exporter:
+ otlp:
+ <<: *otlp-exporter
+ temporality_preference: lowmemory
+logger_provider:
+ processors:
+ - simple:
+ exporter:
+ console: {}
+ - batch:
+ exporter:
+ otlp: *otlp-exporter
diff --git a/examples/load_config_env.php b/examples/load_config_env.php
new file mode 100644
index 000000000..6fa447949
--- /dev/null
+++ b/examples/load_config_env.php
@@ -0,0 +1,34 @@
+create()
+ ->setAutoShutdown(true)
+ ->build();
+
+$tracer = $sdk->getTracerProvider()->getTracer('demo');
+$meter = $sdk->getMeterProvider()->getMeter('demo');
+$logger = $sdk->getLoggerProvider()->getLogger('demo');
+
+$tracer->spanBuilder('root')->startSpan()->end();
+$meter->createCounter('cnt')->add(1);
+
+$eventLogger = new EventLogger($logger, 'my-domain');
+$eventLogger->logEvent('foo', new LogRecord('hello, otel'));
+
+echo 'Finished!' . PHP_EOL;
diff --git a/examples/load_config_env.yaml b/examples/load_config_env.yaml
new file mode 100644
index 000000000..b62262d29
--- /dev/null
+++ b/examples/load_config_env.yaml
@@ -0,0 +1,49 @@
+file_format: '0.1'
+
+disabled: ${OTEL_SDK_DISABLED}
+
+resource:
+ attributes:
+ service.name: ${OTEL_SERVICE_NAME}
+
+propagators:
+ composite: [ tracecontext, baggage ]
+
+attribute_limits:
+ attribute_value_length_limit: ${OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT}
+ attribute_count_limit: ${OTEL_ATTRIBUTE_COUNT_LIMIT}
+
+exporters:
+ otlp: &otlp-exporter
+ protocol: ${OTEL_EXPORTER_OTLP_PROTOCOL}
+ endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT}
+ certificate: ${OTEL_EXPORTER_OTLP_CERTIFICATE}
+ client_key: ${OTEL_EXPORTER_OTLP_CLIENT_KEY}
+ client_certificate: ${OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE}
+ compression: ${OTEL_EXPORTER_OTLP_COMPRESSION}
+ timeout: ${OTEL_EXPORTER_OTLP_TIMEOUT}
+
+tracer_provider:
+ sampler:
+ parent_based:
+ root:
+ trace_id_ratio_based:
+ ratio: ${OTEL_TRACES_SAMPLER_ARG}
+ limits:
+ attribute_value_length_limit: ${OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT}
+ attribute_count_limit: ${OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT}
+ event_count_limit: ${OTEL_SPAN_EVENT_COUNT_LIMIT}
+ link_count_limit: ${OTEL_SPAN_LINK_COUNT_LIMIT}
+ event_attribute_count_limit: ${OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT}
+ link_attribute_count_limit: ${OTEL_LINK_ATTRIBUTE_COUNT_LIMIT}
+ processors:
+ - simple:
+ exporter:
+ console: {}
+ - batch:
+ schedule_delay: ${OTEL_BSP_SCHEDULE_DELAY}
+ export_timeout: ${OTEL_BSP_EXPORT_TIMEOUT}
+ max_queue_size: ${OTEL_BSP_MAX_QUEUE_SIZE}
+ max_export_batch_size: ${OTEL_BSP_MAX_EXPORT_BATCH_SIZE}
+ exporter:
+ otlp: *otlp-exporter
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index fc15014fb..48d227e80 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -32,4 +32,8 @@ parameters:
-
message: "#Call to an undefined method .*:expects.*#"
paths:
- - tests
\ No newline at end of file
+ - tests
+ -
+ message: "#Call to an undefined method Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeParentInterface::.*#"
+ paths:
+ - src/Config/SDK
diff --git a/psalm.xml.dist b/psalm.xml.dist
index b6f04150f..905e3b7d9 100644
--- a/psalm.xml.dist
+++ b/psalm.xml.dist
@@ -23,13 +23,33 @@
-
+
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Config/SDK/ComponentProvider/Logs/LogRecordExporterConsole.php b/src/Config/SDK/ComponentProvider/Logs/LogRecordExporterConsole.php
new file mode 100644
index 000000000..a978516c5
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Logs/LogRecordExporterConsole.php
@@ -0,0 +1,36 @@
+
+ */
+final class LogRecordExporterConsole implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): LogRecordExporterInterface
+ {
+ return new ConsoleExporter(Registry::transportFactory('stream')->create(
+ endpoint: 'php://stdout',
+ contentType: 'application/json',
+ ));
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('console');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Logs/LogRecordExporterOtlp.php b/src/Config/SDK/ComponentProvider/Logs/LogRecordExporterOtlp.php
new file mode 100644
index 000000000..2be5fd161
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Logs/LogRecordExporterOtlp.php
@@ -0,0 +1,75 @@
+
+ */
+#[PackageDependency('open-telemetry/exporter-otlp', '^1.0.5')]
+final class LogRecordExporterOtlp implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * protocol: 'http/protobuf'|'http/json'|'grpc',
+ * endpoint: string,
+ * certificate: ?string,
+ * client_key: ?string,
+ * client_certificate: ?string,
+ * headers: array,
+ * compression: 'gzip'|null,
+ * timeout: int<0, max>,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): LogRecordExporterInterface
+ {
+ $protocol = $properties['protocol'];
+
+ return new LogsExporter(Registry::transportFactory($protocol)->create(
+ endpoint: $properties['endpoint'] . OtlpUtil::path(Signals::LOGS, $protocol),
+ contentType: Protocols::contentType($protocol),
+ headers: $properties['headers'],
+ compression: $properties['compression'],
+ timeout: $properties['timeout'],
+ cacert: $properties['certificate'],
+ cert: $properties['client_certificate'],
+ key: $properties['client_certificate'],
+ ));
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('otlp');
+ $node
+ ->children()
+ ->enumNode('protocol')->isRequired()->values(['http/protobuf', 'http/json', 'grpc'])->end()
+ ->scalarNode('endpoint')->isRequired()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('client_key')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('client_certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->arrayNode('headers')
+ ->scalarPrototype()->end()
+ ->end()
+ ->enumNode('compression')->values(['gzip'])->defaultNull()->end()
+ ->integerNode('timeout')->min(0)->defaultValue(10)->end()
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Logs/LogRecordProcessorBatch.php b/src/Config/SDK/ComponentProvider/Logs/LogRecordProcessorBatch.php
new file mode 100644
index 000000000..712ca871b
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Logs/LogRecordProcessorBatch.php
@@ -0,0 +1,60 @@
+
+ */
+final class LogRecordProcessorBatch implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * schedule_delay: int<0, max>,
+ * export_timeout: int<0, max>,
+ * max_queue_size: int<0, max>,
+ * max_export_batch_size: int<0, max>,
+ * exporter: ComponentPlugin,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): LogRecordProcessorInterface
+ {
+ return new BatchLogRecordProcessor(
+ exporter: $properties['exporter']->create($context),
+ clock: ClockFactory::getDefault(),
+ maxQueueSize: $properties['max_queue_size'],
+ scheduledDelayMillis: $properties['schedule_delay'],
+ exportTimeoutMillis: $properties['export_timeout'],
+ maxExportBatchSize: $properties['max_export_batch_size'],
+ meterProvider: $context->meterProvider,
+ );
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('batch');
+ $node
+ ->children()
+ ->integerNode('schedule_delay')->min(0)->defaultValue(5000)->end()
+ ->integerNode('export_timeout')->min(0)->defaultValue(30000)->end()
+ ->integerNode('max_queue_size')->min(0)->defaultValue(2048)->end()
+ ->integerNode('max_export_batch_size')->min(0)->defaultValue(512)->end()
+ ->append($registry->component('exporter', LogRecordExporterInterface::class)->isRequired())
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Logs/LogRecordProcessorSimple.php b/src/Config/SDK/ComponentProvider/Logs/LogRecordProcessorSimple.php
new file mode 100644
index 000000000..edbaaa552
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Logs/LogRecordProcessorSimple.php
@@ -0,0 +1,45 @@
+
+ */
+final class LogRecordProcessorSimple implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * exporter: ComponentPlugin,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): LogRecordProcessorInterface
+ {
+ return new SimpleLogRecordProcessor(
+ exporter: $properties['exporter']->create($context),
+ );
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('simple');
+ $node
+ ->children()
+ ->append($registry->component('exporter', LogRecordExporterInterface::class)->isRequired())
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Metrics/AggregationResolverDefault.php b/src/Config/SDK/ComponentProvider/Metrics/AggregationResolverDefault.php
new file mode 100644
index 000000000..d96cf3040
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Metrics/AggregationResolverDefault.php
@@ -0,0 +1,35 @@
+
+ */
+final class AggregationResolverDefault implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): DefaultAggregationProviderInterface
+ {
+ // TODO Implement proper aggregation providers (default, drop, explicit_bucket_histogram, last_value, sum) to handle advisory
+ return new class() implements DefaultAggregationProviderInterface {
+ use DefaultAggregationProviderTrait;
+ };
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('default');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Metrics/MetricExporterConsole.php b/src/Config/SDK/ComponentProvider/Metrics/MetricExporterConsole.php
new file mode 100644
index 000000000..6fba58cc5
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Metrics/MetricExporterConsole.php
@@ -0,0 +1,32 @@
+
+ */
+final class MetricExporterConsole implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): MetricExporterInterface
+ {
+ return new ConsoleMetricExporter();
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('console');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Metrics/MetricExporterOtlp.php b/src/Config/SDK/ComponentProvider/Metrics/MetricExporterOtlp.php
new file mode 100644
index 000000000..5547de09c
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Metrics/MetricExporterOtlp.php
@@ -0,0 +1,92 @@
+
+ */
+#[PackageDependency('open-telemetry/exporter-otlp', '^1.0.5')]
+final class MetricExporterOtlp implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * protocol: 'http/protobuf'|'http/json'|'grpc',
+ * endpoint: string,
+ * certificate: ?string,
+ * client_key: ?string,
+ * client_certificate: ?string,
+ * headers: array,
+ * compression: 'gzip'|null,
+ * timeout: int<0, max>,
+ * temporality_preference: 'cumulative'|'delta'|'lowmemory',
+ * default_histogram_aggregation: 'explicit_bucket_histogram',
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): MetricExporterInterface
+ {
+ $protocol = $properties['protocol'];
+
+ $temporality = match ($properties['temporality_preference']) {
+ 'cumulative' => Temporality::CUMULATIVE,
+ 'delta' => Temporality::DELTA,
+ 'lowmemory' => null,
+ };
+
+ return new MetricExporter(Registry::transportFactory($protocol)->create(
+ endpoint: $properties['endpoint'] . OtlpUtil::path(Signals::METRICS, $protocol),
+ contentType: Protocols::contentType($protocol),
+ headers: $properties['headers'],
+ compression: $properties['compression'],
+ timeout: $properties['timeout'],
+ cacert: $properties['certificate'],
+ cert: $properties['client_certificate'],
+ key: $properties['client_certificate'],
+ ), $temporality);
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('otlp');
+ $node
+ ->children()
+ ->enumNode('protocol')->isRequired()->values(['http/protobuf', 'http/json', 'grpc'])->end()
+ ->scalarNode('endpoint')->isRequired()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('client_key')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('client_certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->arrayNode('headers')
+ ->scalarPrototype()->end()
+ ->end()
+ ->enumNode('compression')->values(['gzip'])->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->integerNode('timeout')->min(0)->defaultValue(10)->end()
+ ->enumNode('temporality_preference')
+ ->values(['cumulative', 'delta', 'lowmemory'])
+ ->defaultValue('cumulative')
+ ->end()
+ ->enumNode('default_histogram_aggregation')
+ ->values(['explicit_bucket_histogram'])
+ ->defaultValue('explicit_bucket_histogram')
+ ->end()
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Metrics/MetricReaderPeriodic.php b/src/Config/SDK/ComponentProvider/Metrics/MetricReaderPeriodic.php
new file mode 100644
index 000000000..0e77e2008
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Metrics/MetricReaderPeriodic.php
@@ -0,0 +1,49 @@
+
+ */
+final class MetricReaderPeriodic implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * interval: int<0, max>,
+ * timeout: int<0, max>,
+ * exporter: ComponentPlugin,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): MetricReaderInterface
+ {
+ return new ExportingReader(
+ exporter: $properties['exporter']->create($context),
+ );
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('periodic');
+ $node
+ ->children()
+ ->integerNode('interval')->min(0)->defaultValue(5000)->end()
+ ->integerNode('timeout')->min(0)->defaultValue(30000)->end()
+ ->append($registry->component('exporter', MetricExporterInterface::class)->isRequired())
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/OpenTelemetrySdk.php b/src/Config/SDK/ComponentProvider/OpenTelemetrySdk.php
new file mode 100644
index 000000000..c8a11fbe1
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/OpenTelemetrySdk.php
@@ -0,0 +1,400 @@
+
+ */
+final class OpenTelemetrySdk implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * file_format: '0.1',
+ * disabled: bool,
+ * resource: array{
+ * attributes: array,
+ * schema_url: ?string,
+ * },
+ * attribute_limits: array{
+ * attribute_value_length_limit: ?int<0, max>,
+ * attribute_count_limit: int<0, max>,
+ * },
+ * propagator: ?ComponentPlugin,
+ * tracer_provider: array{
+ * limits: array{
+ * attribute_value_length_limit: ?int<0, max>,
+ * attribute_count_limit: ?int<0, max>,
+ * event_count_limit: int<0, max>,
+ * link_count_limit: int<0, max>,
+ * event_attribute_count_limit: ?int<0, max>,
+ * link_attribute_count_limit: ?int<0, max>,
+ * },
+ * sampler: ?ComponentPlugin,
+ * processors: list>,
+ * },
+ * meter_provider: array{
+ * views: list,
+ * aggregation: ?ComponentPlugin,
+ * },
+ * selector: array{
+ * instrument_type: 'counter'|'histogram'|'observable_counter'|'observable_gauge'|'observable_up_down_counter'|'up_down_counter'|null,
+ * instrument_name: ?non-empty-string,
+ * unit: ?string,
+ * meter_name: ?string,
+ * meter_version: ?string,
+ * meter_schema_url: ?string,
+ * },
+ * }>,
+ * readers: list>,
+ * },
+ * logger_provider: array{
+ * limits: array{
+ * attribute_value_length_limit: ?int<0, max>,
+ * attribute_count_limit: ?int<0, max>,
+ * },
+ * processors: list>,
+ * },
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): SdkBuilder
+ {
+ $sdkBuilder = new SdkBuilder();
+
+ $propagator = $properties['propagator']?->create($context) ?? NoopTextMapPropagator::getInstance();
+ $sdkBuilder->setPropagator($propagator);
+
+ if ($properties['disabled']) {
+ return $sdkBuilder;
+ }
+
+ $resource = ResourceInfoFactory::defaultResource()
+ ->merge(ResourceInfo::create(
+ attributes: Attributes::create($properties['resource']['attributes']),
+ schemaUrl: $properties['resource']['schema_url'],
+ ));
+
+ $spanProcessors = [];
+ foreach ($properties['tracer_provider']['processors'] as $processor) {
+ $spanProcessors[] = $processor->create($context);
+ }
+
+ //
+
+ $tracerProvider = new TracerProvider(
+ spanProcessors: $spanProcessors,
+ sampler: $properties['tracer_provider']['sampler']?->create($context) ?? new ParentBased(new AlwaysOnSampler()),
+ resource: $resource,
+ spanLimits: new SpanLimits(
+ attributesFactory: Attributes::factory(
+ attributeCountLimit: $properties['tracer_provider']['limits']['attribute_count_limit']
+ ?? $properties['attribute_limits']['attribute_count_limit'],
+ attributeValueLengthLimit: $properties['tracer_provider']['limits']['attribute_value_length_limit']
+ ?? $properties['attribute_limits']['attribute_value_length_limit'],
+ ),
+ eventAttributesFactory: Attributes::factory(
+ attributeCountLimit: $properties['tracer_provider']['limits']['event_attribute_count_limit']
+ ?? $properties['tracer_provider']['limits']['attribute_count_limit']
+ ?? $properties['attribute_limits']['attribute_count_limit'],
+ attributeValueLengthLimit: $properties['tracer_provider']['limits']['attribute_value_length_limit']
+ ?? $properties['attribute_limits']['attribute_value_length_limit'],
+ ),
+ linkAttributesFactory: Attributes::factory(
+ attributeCountLimit: $properties['tracer_provider']['limits']['link_attribute_count_limit']
+ ?? $properties['tracer_provider']['limits']['attribute_count_limit']
+ ?? $properties['attribute_limits']['attribute_count_limit'],
+ attributeValueLengthLimit: $properties['tracer_provider']['limits']['attribute_value_length_limit']
+ ?? $properties['attribute_limits']['attribute_value_length_limit'],
+ ),
+ eventCountLimit: $properties['tracer_provider']['limits']['event_count_limit'],
+ linkCountLimit: $properties['tracer_provider']['limits']['link_count_limit'],
+ ),
+ );
+
+ //
+
+ //
+
+ $metricReaders = [];
+ foreach ($properties['meter_provider']['readers'] as $reader) {
+ $metricReaders[] = $reader->create($context);
+ }
+
+ $viewRegistry = new CriteriaViewRegistry();
+ foreach ($properties['meter_provider']['views'] as $view) {
+ $criteria = [];
+ if (isset($view['selector']['instrument_type'])) {
+ $criteria[] = new InstrumentTypeCriteria(match ($view['selector']['instrument_type']) {
+ 'counter' => InstrumentType::COUNTER,
+ 'histogram' => InstrumentType::HISTOGRAM,
+ 'observable_counter' => InstrumentType::ASYNCHRONOUS_COUNTER,
+ 'observable_gauge' => InstrumentType::ASYNCHRONOUS_GAUGE,
+ 'observable_up_down_counter' => InstrumentType::ASYNCHRONOUS_UP_DOWN_COUNTER,
+ 'up_down_counter' => InstrumentType::UP_DOWN_COUNTER,
+ });
+ }
+ if (isset($view['selector']['instrument_name'])) {
+ $criteria[] = new InstrumentNameCriteria($view['selector']['instrument_name']);
+ }
+ if (isset($view['selector']['unit'])) {
+ // TODO Add unit criteria
+ }
+ if (isset($view['selector']['meter_name'])) {
+ $criteria[] = new InstrumentationScopeNameCriteria($view['selector']['meter_name']);
+ }
+ if (isset($view['selector']['meter_version'])) {
+ $criteria[] = new InstrumentationScopeVersionCriteria($view['selector']['meter_version']);
+ }
+ if (isset($view['selector']['meter_schema_url'])) {
+ $criteria[] = new InstrumentationScopeSchemaUrlCriteria($view['selector']['meter_schema_url']);
+ }
+
+ $viewTemplate = ViewTemplate::create();
+ if (isset($view['stream']['name'])) {
+ $viewTemplate = $viewTemplate->withName($view['stream']['name']);
+ }
+ if (isset($view['stream']['description'])) {
+ $viewTemplate = $viewTemplate->withDescription($view['stream']['description']);
+ }
+ if ($view['stream']['attribute_keys']) {
+ $viewTemplate = $viewTemplate->withAttributeKeys($view['stream']['attribute_keys']);
+ }
+ if (isset($view['stream']['aggregation'])) {
+ // TODO Add support for aggregation providers in views to allow usage of advisory
+ }
+
+ $viewRegistry->register(new AllCriteria($criteria), $viewTemplate);
+ }
+
+ /** @psalm-suppress InvalidArgument TODO update metric reader interface */
+ $meterProvider = new MeterProvider(
+ contextStorage: null,
+ resource: $resource,
+ clock: ClockFactory::getDefault(),
+ attributesFactory: Attributes::factory(),
+ instrumentationScopeFactory: new InstrumentationScopeFactory(Attributes::factory()),
+ metricReaders: $metricReaders, // @phpstan-ignore-line
+ viewRegistry: $viewRegistry,
+ exemplarFilter: null,
+ stalenessHandlerFactory: new NoopStalenessHandlerFactory(),
+ );
+
+ //
+
+ //
+
+ $logRecordProcessors = [];
+ foreach ($properties['logger_provider']['processors'] as $processor) {
+ $logRecordProcessors[] = $processor->create($context);
+ }
+
+ // TODO Allow injecting log record attributes factory
+ $loggerProvider = new LoggerProvider(
+ processor: new MultiLogRecordProcessor($logRecordProcessors),
+ instrumentationScopeFactory: new InstrumentationScopeFactory(Attributes::factory()),
+ resource: $resource,
+ );
+
+ //
+
+ $sdkBuilder->setTracerProvider($tracerProvider);
+ $sdkBuilder->setMeterProvider($meterProvider);
+ $sdkBuilder->setLoggerProvider($loggerProvider);
+
+ return $sdkBuilder;
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('open_telemetry');
+ $node
+ ->addDefaultsIfNotSet()
+ ->ignoreExtraKeys()
+ ->children()
+ ->scalarNode('file_format')
+ ->isRequired()
+ ->example('0.1')
+ ->validate()->always(Validation::ensureString())->end()
+ ->validate()->ifNotInArray(['0.1'])->thenInvalid('unsupported version')->end()
+ ->end()
+ ->booleanNode('disabled')->defaultFalse()->end()
+ ->append($this->getResourceConfig())
+ ->append($this->getAttributeLimitsConfig())
+ ->append($registry->component('propagator', TextMapPropagatorInterface::class))
+ ->append($this->getTracerProviderConfig($registry))
+ ->append($this->getMeterProviderConfig($registry))
+ ->append($this->getLoggerProviderConfig($registry))
+ ->end();
+
+ return $node;
+ }
+
+ private function getResourceConfig(): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('resource');
+ $node
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->arrayNode('attributes')
+ ->variablePrototype()->end()
+ ->end()
+ ->scalarNode('schema_url')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->end();
+
+ return $node;
+ }
+
+ private function getAttributeLimitsConfig(): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('attribute_limits');
+ $node
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->integerNode('attribute_value_length_limit')->min(0)->defaultNull()->end()
+ ->integerNode('attribute_count_limit')->min(0)->defaultValue(128)->end()
+ ->end();
+
+ return $node;
+ }
+
+ private function getTracerProviderConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('tracer_provider');
+ $node
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->arrayNode('limits')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->integerNode('attribute_value_length_limit')->min(0)->defaultNull()->end()
+ ->integerNode('attribute_count_limit')->min(0)->defaultNull()->end()
+ ->integerNode('event_count_limit')->min(0)->defaultValue(128)->end()
+ ->integerNode('link_count_limit')->min(0)->defaultValue(128)->end()
+ ->integerNode('event_attribute_count_limit')->min(0)->defaultNull()->end()
+ ->integerNode('link_attribute_count_limit')->min(0)->defaultNull()->end()
+ ->end()
+ ->end()
+ ->append($registry->component('sampler', SamplerInterface::class))
+ ->append($registry->componentList('processors', SpanProcessorInterface::class))
+ ->end()
+ ;
+
+ return $node;
+ }
+
+ private function getMeterProviderConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('meter_provider');
+ $node
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->arrayNode('views')
+ ->arrayPrototype()
+ ->children()
+ ->arrayNode('stream')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->scalarNode('name')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('description')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->arrayNode('attribute_keys')
+ ->scalarPrototype()->validate()->always(Validation::ensureString())->end()->end()
+ ->end()
+ ->append($registry->component('aggregation', DefaultAggregationProviderInterface::class))
+ ->end()
+ ->end()
+ ->arrayNode('selector')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->enumNode('instrument_type')
+ ->values([
+ 'counter',
+ 'histogram',
+ 'observable_counter',
+ 'observable_gauge',
+ 'observable_up_down_counter',
+ 'up_down_counter',
+ ])
+ ->defaultNull()
+ ->end()
+ ->scalarNode('instrument_name')->defaultNull()->validate()->always(Validation::ensureString())->end()->cannotBeEmpty()->end()
+ ->scalarNode('unit')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('meter_name')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('meter_version')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('meter_schema_url')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->append($registry->componentList('readers', MetricReaderInterface::class))
+ ->end()
+ ;
+
+ return $node;
+ }
+
+ private function getLoggerProviderConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('logger_provider');
+ $node
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->arrayNode('limits')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->integerNode('attribute_value_length_limit')->min(0)->defaultNull()->end()
+ ->integerNode('attribute_count_limit')->min(0)->defaultNull()->end()
+ ->end()
+ ->end()
+ ->append($registry->componentList('processors', LogRecordProcessorInterface::class))
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorB3.php b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorB3.php
new file mode 100644
index 000000000..9640f1e32
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorB3.php
@@ -0,0 +1,34 @@
+
+ */
+#[PackageDependency('open-telemetry/extension-propagator-b3', '^1.0.1')]
+final class TextMapPropagatorB3 implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): TextMapPropagatorInterface
+ {
+ return B3Propagator::getB3SingleHeaderInstance();
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('b3');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorB3Multi.php b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorB3Multi.php
new file mode 100644
index 000000000..787e99911
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorB3Multi.php
@@ -0,0 +1,34 @@
+
+ */
+#[PackageDependency('open-telemetry/extension-propagator-b3', '^1.0.1')]
+final class TextMapPropagatorB3Multi implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): TextMapPropagatorInterface
+ {
+ return B3Propagator::getB3MultiHeaderInstance();
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('b3multi');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorBaggage.php b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorBaggage.php
new file mode 100644
index 000000000..ecfde7fa1
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorBaggage.php
@@ -0,0 +1,32 @@
+
+ */
+final class TextMapPropagatorBaggage implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): TextMapPropagatorInterface
+ {
+ return BaggagePropagator::getInstance();
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('baggage');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorComposite.php b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorComposite.php
new file mode 100644
index 000000000..6eba5391a
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorComposite.php
@@ -0,0 +1,38 @@
+
+ */
+final class TextMapPropagatorComposite implements ComponentProvider
+{
+
+ /**
+ * @param list> $properties
+ */
+ public function createPlugin(array $properties, Context $context): TextMapPropagatorInterface
+ {
+ $propagators = [];
+ foreach ($properties as $plugin) {
+ $propagators[] = $plugin->create($context);
+ }
+
+ return new MultiTextMapPropagator($propagators);
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return $registry->componentNames('composite', TextMapPropagatorInterface::class);
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorJaeger.php b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorJaeger.php
new file mode 100644
index 000000000..6d8e2f4a7
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorJaeger.php
@@ -0,0 +1,34 @@
+
+ */
+#[PackageDependency('open-telemetry/extension-propagator-jaeger', '^0.0.2')]
+final class TextMapPropagatorJaeger implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): TextMapPropagatorInterface
+ {
+ return JaegerPropagator::getInstance();
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('jaeger');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorTraceContext.php b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorTraceContext.php
new file mode 100644
index 000000000..0913be336
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Propagator/TextMapPropagatorTraceContext.php
@@ -0,0 +1,32 @@
+
+ */
+final class TextMapPropagatorTraceContext implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): TextMapPropagatorInterface
+ {
+ return TraceContextPropagator::getInstance();
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('tracecontext');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Trace/SamplerAlwaysOff.php b/src/Config/SDK/ComponentProvider/Trace/SamplerAlwaysOff.php
new file mode 100644
index 000000000..7da8a2d25
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Trace/SamplerAlwaysOff.php
@@ -0,0 +1,32 @@
+
+ */
+final class SamplerAlwaysOff implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): SamplerInterface
+ {
+ return new AlwaysOffSampler();
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('always_off');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Trace/SamplerAlwaysOn.php b/src/Config/SDK/ComponentProvider/Trace/SamplerAlwaysOn.php
new file mode 100644
index 000000000..15dbe61b6
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Trace/SamplerAlwaysOn.php
@@ -0,0 +1,32 @@
+
+ */
+final class SamplerAlwaysOn implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): SamplerInterface
+ {
+ return new AlwaysOnSampler();
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('always_on');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Trace/SamplerParentBased.php b/src/Config/SDK/ComponentProvider/Trace/SamplerParentBased.php
new file mode 100644
index 000000000..121282359
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Trace/SamplerParentBased.php
@@ -0,0 +1,58 @@
+
+ */
+final class SamplerParentBased implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * root: ComponentPlugin,
+ * remote_parent_sampled: ?ComponentPlugin,
+ * remote_parent_not_sampled: ?ComponentPlugin,
+ * local_parent_sampled: ?ComponentPlugin,
+ * local_parent_not_sampled: ?ComponentPlugin,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): SamplerInterface
+ {
+ return new ParentBased(
+ root: $properties['root']->create($context),
+ remoteParentSampler: $properties['remote_parent_sampled']?->create($context) ?? new AlwaysOnSampler(),
+ remoteParentNotSampler: $properties['remote_parent_not_sampled']?->create($context) ?? new AlwaysOffSampler(),
+ localParentSampler: $properties['local_parent_sampled']?->create($context) ?? new AlwaysOnSampler(),
+ localParentNotSampler: $properties['local_parent_not_sampled']?->create($context) ?? new AlwaysOffSampler(),
+ );
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('parent_based');
+ $node
+ ->children()
+ ->append($registry->component('root', SamplerInterface::class)->isRequired())
+ ->append($registry->component('remote_parent_sampled', SamplerInterface::class))
+ ->append($registry->component('remote_parent_not_sampled', SamplerInterface::class))
+ ->append($registry->component('local_parent_sampled', SamplerInterface::class))
+ ->append($registry->component('local_parent_not_sampled', SamplerInterface::class))
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Trace/SamplerTraceIdRatioBased.php b/src/Config/SDK/ComponentProvider/Trace/SamplerTraceIdRatioBased.php
new file mode 100644
index 000000000..c66d203da
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Trace/SamplerTraceIdRatioBased.php
@@ -0,0 +1,43 @@
+
+ */
+final class SamplerTraceIdRatioBased implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * ratio: float,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): SamplerInterface
+ {
+ return new TraceIdRatioBasedSampler(
+ probability: $properties['ratio'],
+ );
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('trace_id_ratio_based');
+ $node
+ ->children()
+ ->floatNode('ratio')->min(0)->max(1)->isRequired()->end()
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Trace/SpanExporterConsole.php b/src/Config/SDK/ComponentProvider/Trace/SpanExporterConsole.php
new file mode 100644
index 000000000..f36fe5258
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Trace/SpanExporterConsole.php
@@ -0,0 +1,36 @@
+
+ */
+final class SpanExporterConsole implements ComponentProvider
+{
+
+ /**
+ * @param array{} $properties
+ */
+ public function createPlugin(array $properties, Context $context): SpanExporterInterface
+ {
+ return new ConsoleSpanExporter(Registry::transportFactory('stream')->create(
+ endpoint: 'php://stdout',
+ contentType: 'application/json',
+ ));
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ return new ArrayNodeDefinition('console');
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Trace/SpanExporterOtlp.php b/src/Config/SDK/ComponentProvider/Trace/SpanExporterOtlp.php
new file mode 100644
index 000000000..6166bd725
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Trace/SpanExporterOtlp.php
@@ -0,0 +1,75 @@
+
+ */
+#[PackageDependency('open-telemetry/exporter-otlp', '^1.0.5')]
+final class SpanExporterOtlp implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * protocol: 'http/protobuf'|'http/json'|'grpc',
+ * endpoint: string,
+ * certificate: ?string,
+ * client_key: ?string,
+ * client_certificate: ?string,
+ * headers: array,
+ * compression: 'gzip'|null,
+ * timeout: int<0, max>,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): SpanExporterInterface
+ {
+ $protocol = $properties['protocol'];
+
+ return new SpanExporter(Registry::transportFactory($protocol)->create(
+ endpoint: $properties['endpoint'] . OtlpUtil::path(Signals::TRACE, $protocol),
+ contentType: Protocols::contentType($protocol),
+ headers: $properties['headers'],
+ compression: $properties['compression'],
+ timeout: $properties['timeout'],
+ cacert: $properties['certificate'],
+ cert: $properties['client_certificate'],
+ key: $properties['client_certificate'],
+ ));
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('otlp');
+ $node
+ ->children()
+ ->enumNode('protocol')->isRequired()->values(['http/protobuf', 'http/json', 'grpc'])->end()
+ ->scalarNode('endpoint')->isRequired()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('client_key')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->scalarNode('client_certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
+ ->arrayNode('headers')
+ ->scalarPrototype()->end()
+ ->end()
+ ->enumNode('compression')->values(['gzip'])->defaultNull()->end()
+ ->integerNode('timeout')->min(0)->defaultValue(10)->end()
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Trace/SpanExporterZipkin.php b/src/Config/SDK/ComponentProvider/Trace/SpanExporterZipkin.php
new file mode 100644
index 000000000..4e13f49ea
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Trace/SpanExporterZipkin.php
@@ -0,0 +1,51 @@
+
+ */
+#[PackageDependency('open-telemetry/exporter-zipkin', '^1.0')]
+final class SpanExporterZipkin implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * endpoint: string,
+ * timeout: int<0, max>,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): SpanExporterInterface
+ {
+ return new Zipkin\Exporter(Registry::transportFactory('http')->create(
+ endpoint: $properties['endpoint'],
+ contentType: 'application/json',
+ timeout: $properties['timeout'],
+ ));
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('zipkin');
+ $node
+ ->children()
+ ->scalarNode('endpoint')->isRequired()->validate()->always(Validation::ensureString())->end()->end()
+ ->integerNode('timeout')->min(0)->defaultValue(10)->end()
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Trace/SpanProcessorBatch.php b/src/Config/SDK/ComponentProvider/Trace/SpanProcessorBatch.php
new file mode 100644
index 000000000..3688473f0
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Trace/SpanProcessorBatch.php
@@ -0,0 +1,60 @@
+
+ */
+final class SpanProcessorBatch implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * schedule_delay: int<0, max>,
+ * export_timeout: int<0, max>,
+ * max_queue_size: int<0, max>,
+ * max_export_batch_size: int<0, max>,
+ * exporter: ComponentPlugin,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): SpanProcessorInterface
+ {
+ return new BatchSpanProcessor(
+ exporter: $properties['exporter']->create($context),
+ clock: ClockFactory::getDefault(),
+ maxQueueSize: $properties['max_queue_size'],
+ scheduledDelayMillis: $properties['schedule_delay'],
+ exportTimeoutMillis: $properties['export_timeout'],
+ maxExportBatchSize: $properties['max_export_batch_size'],
+ meterProvider: $context->meterProvider,
+ );
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('batch');
+ $node
+ ->children()
+ ->integerNode('schedule_delay')->min(0)->defaultValue(5000)->end()
+ ->integerNode('export_timeout')->min(0)->defaultValue(30000)->end()
+ ->integerNode('max_queue_size')->min(0)->defaultValue(2048)->end()
+ ->integerNode('max_export_batch_size')->min(0)->defaultValue(512)->end()
+ ->append($registry->component('exporter', SpanExporterInterface::class)->isRequired())
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/ComponentProvider/Trace/SpanProcessorSimple.php b/src/Config/SDK/ComponentProvider/Trace/SpanProcessorSimple.php
new file mode 100644
index 000000000..ad15e00d4
--- /dev/null
+++ b/src/Config/SDK/ComponentProvider/Trace/SpanProcessorSimple.php
@@ -0,0 +1,45 @@
+
+ */
+final class SpanProcessorSimple implements ComponentProvider
+{
+
+ /**
+ * @param array{
+ * exporter: ComponentPlugin,
+ * } $properties
+ */
+ public function createPlugin(array $properties, Context $context): SpanProcessorInterface
+ {
+ return new SimpleSpanProcessor(
+ exporter: $properties['exporter']->create($context),
+ );
+ }
+
+ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinition
+ {
+ $node = new ArrayNodeDefinition('simple');
+ $node
+ ->children()
+ ->append($registry->component('exporter', SpanExporterInterface::class)->isRequired())
+ ->end()
+ ;
+
+ return $node;
+ }
+}
diff --git a/src/Config/SDK/Configuration.php b/src/Config/SDK/Configuration.php
new file mode 100644
index 000000000..b06f596e7
--- /dev/null
+++ b/src/Config/SDK/Configuration.php
@@ -0,0 +1,61 @@
+ $sdkPlugin
+ */
+ private function __construct(
+ private readonly ComponentPlugin $sdkPlugin,
+ ) {
+ }
+
+ public function create(Context $context = new Context()): SdkBuilder
+ {
+ return $this->sdkPlugin->create($context);
+ }
+
+ /**
+ * @param string|list $file
+ */
+ public static function parseFile(
+ string|array $file,
+ ?string $cacheFile = null,
+ bool $debug = true,
+ ): Configuration {
+ return new self(self::factory()->parseFile($file, $cacheFile, $debug));
+ }
+
+ /**
+ * @return ConfigurationFactory
+ */
+ private static function factory(): ConfigurationFactory
+ {
+ static $factory;
+
+ return $factory ??= new ConfigurationFactory(
+ ServiceLoader::load(ComponentProvider::class),
+ new OpenTelemetrySdk(),
+ new EnvSourceReader([
+ new ServerEnvSource(),
+ new PhpIniEnvSource(),
+ ]),
+ );
+ }
+}
diff --git a/src/Config/SDK/README.md b/src/Config/SDK/README.md
new file mode 100644
index 000000000..022d2ce47
--- /dev/null
+++ b/src/Config/SDK/README.md
@@ -0,0 +1,34 @@
+# OpenTelemetry SDK configuration
+
+## Installation
+
+```shell
+composer require open-telemetry/sdk-configuration
+```
+
+## Usage
+
+### Initialization from [configuration file](https://opentelemetry.io/docs/specs/otel/configuration/file-configuration/)
+
+```php
+$configuration = Configuration::parseFile(__DIR__ . '/kitchen-sink.yaml');
+$sdkBuilder = $configuration->create();
+```
+
+#### Performance considerations
+
+Parsing and processing the configuration is rather expensive. It is highly recommended to provide the `$cacheFile`
+parameter when running in a shared-nothing setup.
+
+```php
+$configuration = Configuration::parseFile(
+ __DIR__ . '/kitchen-sink.yaml',
+ __DIR__ . '/var/cache/opentelemetry.php',
+);
+$sdkBuilder = $configuration->create();
+```
+
+## 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/src/Config/SDK/composer.json b/src/Config/SDK/composer.json
new file mode 100644
index 000000000..7b6809c3f
--- /dev/null
+++ b/src/Config/SDK/composer.json
@@ -0,0 +1,65 @@
+{
+ "name": "open-telemetry/sdk-configuration",
+ "description": "SDK configuration for OpenTelemetry PHP.",
+ "keywords": ["opentelemetry", "otel", "sdk", "configuration"],
+ "type": "library",
+ "support": {
+ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
+ "source": "https://github.com/open-telemetry/opentelemetry-php",
+ "docs": "https://opentelemetry.io/docs/php",
+ "chat": "https://app.slack.com/client/T08PSQ7BQ/C01NFPCV44V"
+ },
+ "license": "Apache-2.0",
+ "authors": [
+ {
+ "name": "opentelemetry-php contributors",
+ "homepage": "https://github.com/open-telemetry/opentelemetry-php/graphs/contributors"
+ }
+ ],
+ "require": {
+ "php": "^8.1",
+ "open-telemetry/sdk": "^1.0",
+ "tbachert/otel-sdk-configuration": "^0.1",
+ "tbachert/spi": "^0.2"
+ },
+ "autoload": {
+ "psr-4": {
+ "OpenTelemetry\\Config\\SDK\\": ""
+ }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-main": "0.1.x-dev"
+ },
+ "spi": {
+ "Nevay\\OTelSDK\\Configuration\\ComponentProvider": [
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorB3",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorB3Multi",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorBaggage",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorComposite",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorJaeger",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Propagator\\TextMapPropagatorTraceContext",
+
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SamplerAlwaysOff",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SamplerAlwaysOn",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SamplerParentBased",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SamplerTraceIdRatioBased",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanExporterConsole",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanExporterOtlp",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanExporterZipkin",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanProcessorBatch",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Trace\\SpanProcessorSimple",
+
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Metrics\\AggregationResolverDefault",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Metrics\\MetricExporterConsole",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Metrics\\MetricExporterOtlp",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Metrics\\MetricReaderPeriodic",
+
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordExporterConsole",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordExporterOtlp",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordProcessorBatch",
+ "OpenTelemetry\\Config\\SDK\\ComponentProvider\\Logs\\LogRecordProcessorSimple"
+ ]
+ }
+ }
+}
diff --git a/src/Contrib/Otlp/OtlpUtil.php b/src/Contrib/Otlp/OtlpUtil.php
index 62feb6d91..3de3085d6 100644
--- a/src/Contrib/Otlp/OtlpUtil.php
+++ b/src/Contrib/Otlp/OtlpUtil.php
@@ -4,6 +4,7 @@
namespace OpenTelemetry\Contrib\Otlp;
+use function explode;
use OpenTelemetry\API\Signals;
use OpenTelemetry\SDK\Common\Configuration\Configuration;
use OpenTelemetry\SDK\Common\Configuration\Variables;
@@ -37,6 +38,22 @@ public static function method(string $signal): string
return self::METHODS[$signal];
}
+ /**
+ * @param 'trace'|'metrics'|'logs' $signal
+ * @param 'grpc'|'http/protobuf'|'http/json' $protocol
+ */
+ public static function path(string $signal, string $protocol): string
+ {
+ return match (explode('/', $protocol)[0]) { // @phpstan-ignore-line
+ 'grpc' => self::method($signal),
+ 'http' => match ($signal) {
+ Signals::TRACE => '/v1/traces',
+ Signals::METRICS => '/v1/metrics',
+ Signals::LOGS => '/v1/logs',
+ },
+ };
+ }
+
public static function getHeaders(string $signal): array
{
$headers = Configuration::has(self::HEADER_VARS[$signal]) ?
diff --git a/src/Contrib/Otlp/Protocols.php b/src/Contrib/Otlp/Protocols.php
index 96b04d8bf..736436a8f 100644
--- a/src/Contrib/Otlp/Protocols.php
+++ b/src/Contrib/Otlp/Protocols.php
@@ -27,6 +27,9 @@ public static function validate(string $protocol): void
}
}
+ /**
+ * @psalm-return ContentTypes::*
+ */
public static function contentType(string $protocol): string
{
self::validate($protocol);
diff --git a/tests/Integration/Config/ConfigurationTest.php b/tests/Integration/Config/ConfigurationTest.php
new file mode 100644
index 000000000..c5391ed24
--- /dev/null
+++ b/tests/Integration/Config/ConfigurationTest.php
@@ -0,0 +1,28 @@
+expectNotToPerformAssertions();
+ Configuration::parseFile($file)->create();
+ }
+
+ public static function openTelemetryConfigurationDataProvider(): iterable
+ {
+ yield 'kitchen-sink' => [__DIR__ . '/configurations/kitchen-sink.yaml'];
+ yield 'anchors' => [__DIR__ . '/configurations/anchors.yaml'];
+ }
+}
diff --git a/tests/Integration/Config/configurations/anchors.yaml b/tests/Integration/Config/configurations/anchors.yaml
new file mode 100644
index 000000000..18e409d1a
--- /dev/null
+++ b/tests/Integration/Config/configurations/anchors.yaml
@@ -0,0 +1,41 @@
+# anchors.yaml demonstrates anchor substitution to reuse OTLP exporter configuration across signals.
+
+file_format: "0.1"
+exporters:
+ otlp: &otlp-exporter
+ protocol: http/protobuf
+ endpoint: http://localhost:4318
+ certificate: /app/cert.pem
+ client_key: /app/cert.pem
+ client_certificate: /app/cert.pem
+ headers:
+ api-key: !!str 1234
+ compression: gzip
+ timeout: 10000
+
+logger_provider:
+ processors:
+ - batch:
+ exporter:
+ otlp:
+ # expand the otlp-exporter anchor
+ <<: *otlp-exporter
+
+meter_provider:
+ readers:
+ - periodic:
+ interval: 5000
+ timeout: 30000
+ exporter:
+ otlp:
+ # expand the otlp-exporter anchor and add metric specific configuration
+ <<: *otlp-exporter
+ temporality_preference: delta
+
+tracer_provider:
+ processors:
+ - batch:
+ exporter:
+ otlp:
+ # expand the otlp-exporter anchor
+ <<: *otlp-exporter
diff --git a/tests/Integration/Config/configurations/kitchen-sink.yaml b/tests/Integration/Config/configurations/kitchen-sink.yaml
new file mode 100644
index 000000000..c331f6891
--- /dev/null
+++ b/tests/Integration/Config/configurations/kitchen-sink.yaml
@@ -0,0 +1,352 @@
+# kitchen-sink.yaml demonstrates all configurable surface area, including explanatory comments.
+#
+# It DOES NOT represent expected real world configuration, as it makes strange configuration
+# choices in an effort to exercise the full surface area.
+#
+# Configuration values are set to their defaults when default values are defined.
+
+# The file format version
+file_format: "0.1"
+
+# Configure if the SDK is disabled or not. This is not required to be provided
+# to ensure the SDK isn't disabled, the default value when this is not provided
+# is for the SDK to be enabled.
+#
+# Environment variable: OTEL_SDK_DISABLED
+disabled: false
+
+# Configure general attribute limits. See also tracer_provider.limits, logger_provider.limits.
+attribute_limits:
+ # Configure max attribute value size.
+ #
+ # Environment variable: OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT
+ attribute_value_length_limit: 4096
+ # Configure max attribute count.
+ #
+ # Environment variable: OTEL_ATTRIBUTE_COUNT_LIMIT
+ attribute_count_limit: 128
+
+# Configure logger provider.
+logger_provider:
+ # Configure log record processors.
+ processors:
+ # Configure a batch log record processor.
+ - batch:
+ # Configure delay interval (in milliseconds) between two consecutive exports.
+ #
+ # Environment variable: OTEL_BLRP_SCHEDULE_DELAY
+ schedule_delay: 5000
+ # Configure maximum allowed time (in milliseconds) to export data.
+ #
+ # Environment variable: OTEL_BLRP_EXPORT_TIMEOUT
+ export_timeout: 30000
+ # Configure maximum queue size.
+ #
+ # Environment variable: OTEL_BLRP_MAX_QUEUE_SIZE
+ max_queue_size: 2048
+ # Configure maximum batch size.
+ #
+ # Environment variable: OTEL_BLRP_MAX_EXPORT_BATCH_SIZE
+ max_export_batch_size: 512
+ # Configure exporter.
+ #
+ # Environment variable: OTEL_LOGS_EXPORTER
+ exporter:
+ # Configure exporter to be OTLP.
+ otlp:
+ # Configure protocol.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_LOGS_PROTOCOL
+ protocol: http/protobuf
+ # Configure endpoint.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT
+ endpoint: http://localhost:4318
+ # Configure certificate.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE
+ certificate: /app/cert.pem
+ # Configure mTLS private client key.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_CLIENT_KEY, OTEL_EXPORTER_OTLP_LOGS_CLIENT_KEY
+ client_key: /app/cert.pem
+ # Configure mTLS client certificate.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_LOGS_CLIENT_CERTIFICATE
+ client_certificate: /app/cert.pem
+ # Configure headers.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_LOGS_HEADERS
+ headers:
+ api-key: "1234"
+ # Configure compression.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_LOGS_COMPRESSION
+ compression: gzip
+ # Configure max time (in milliseconds) to wait for each export.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_LOGS_TIMEOUT
+ timeout: 10000
+ # Configure log record limits. See also attribute_limits.
+ limits:
+ # Configure max log record attribute value size. Overrides attribute_limits.attribute_value_length_limit.
+ #
+ # Environment variable: OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT
+ attribute_value_length_limit: 4096
+ # Configure max log record attribute count. Overrides attribute_limits.attribute_count_limit.
+ #
+ # Environment variable: OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT
+ attribute_count_limit: 128
+
+# Configure meter provider.
+meter_provider:
+ # Configure metric readers.
+ readers:
+ # Configure a periodic metric reader.
+ - periodic:
+ # Configure delay interval (in milliseconds) between start of two consecutive exports.
+ #
+ # Environment variable: OTEL_METRIC_EXPORT_INTERVAL
+ interval: 5000
+ # Configure maximum allowed time (in milliseconds) to export data.
+ #
+ # Environment variable: OTEL_METRIC_EXPORT_TIMEOUT
+ timeout: 30000
+ # Configure exporter.
+ #
+ # Environment variable: OTEL_METRICS_EXPORTER
+ exporter:
+ # Configure exporter to be OTLP.
+ otlp:
+ # Configure protocol.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_METRICS_PROTOCOL
+ protocol: http/protobuf
+ # Configure endpoint.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
+ endpoint: http://localhost:4318
+ # Configure certificate.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE
+ certificate: /app/cert.pem
+ # Configure mTLS private client key.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_CLIENT_KEY, OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY
+ client_key: /app/cert.pem
+ # Configure mTLS client certificate.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE
+ client_certificate: /app/cert.pem
+ # Configure headers.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_METRICS_HEADERS
+ headers:
+ api-key: !!str 1234
+ # Configure compression.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_METRICS_COMPRESSION
+ compression: gzip
+ # Configure max time (in milliseconds) to wait for each export.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_METRICS_TIMEOUT
+ timeout: 10000
+ # Configure temporality preference.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE
+ temporality_preference: delta
+ # Configure a periodic metric reader.
+ - periodic:
+ # Configure exporter.
+ exporter:
+ # Configure exporter to be console.
+ console: {}
+ # Configure views. Each view has a selector which determines the instrument(s) it applies to, and a configuration for the resulting stream(s).
+ views:
+ # Configure a view.
+ - selector:
+ # Configure instrument name selection criteria.
+ instrument_name: my-instrument
+ # Configure instrument type selection criteria.
+ instrument_type: histogram
+ # Configure the instrument unit selection criteria.
+ unit: ms
+ # Configure meter name selection criteria.
+ meter_name: my-meter
+ # Configure meter version selection criteria.
+ meter_version: 1.0.0
+ # Configure meter schema url selection criteria.
+ meter_schema_url: https://opentelemetry.io/schemas/1.16.0
+ # Configure stream.
+ stream:
+ # Configure metric name of the resulting stream(s).
+ name: new_instrument_name
+ # Configure metric description of the resulting stream(s).
+ description: new_description
+ # Configure aggregation of the resulting stream(s). Known values include: default, drop, explicit_bucket_histogram, base2_exponential_bucket_histogram, last_value, sum.
+ aggregation: ~
+ # Configure attribute keys retained in the resulting stream(s).
+ attribute_keys:
+ - key1
+ - key2
+
+# Configure text map context propagators.
+#
+# Environment variable: OTEL_PROPAGATORS
+propagator:
+ composite: [tracecontext, baggage, b3, b3multi, jaeger]
+
+# Configure tracer provider.
+tracer_provider:
+ # Configure span processors.
+ processors:
+ # Configure a batch span processor.
+ - batch:
+ # Configure delay interval (in milliseconds) between two consecutive exports.
+ #
+ # Environment variable: OTEL_BSP_SCHEDULE_DELAY
+ schedule_delay: 5000
+ # Configure maximum allowed time (in milliseconds) to export data.
+ #
+ # Environment variable: OTEL_BSP_EXPORT_TIMEOUT
+ export_timeout: 30000
+ # Configure maximum queue size.
+ #
+ # Environment variable: OTEL_BSP_MAX_QUEUE_SIZE
+ max_queue_size: 2048
+ # Configure maximum batch size.
+ #
+ # Environment variable: OTEL_BSP_MAX_EXPORT_BATCH_SIZE
+ max_export_batch_size: 512
+ # Configure exporter.
+ #
+ # Environment variable: OTEL_TRACES_EXPORTER
+ exporter:
+ # Configure exporter to be OTLP.
+ otlp:
+ # Configure protocol.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_PROTOCOL, OTEL_EXPORTER_OTLP_TRACES_PROTOCOL
+ protocol: http/protobuf
+ # Configure endpoint.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
+ endpoint: http://localhost:4318
+ # Configure certificate.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_CERTIFICATE, OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE
+ certificate: /app/cert.pem
+ # Configure mTLS private client key.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_CLIENT_KEY, OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY
+ client_key: /app/cert.pem
+ # Configure mTLS client certificate.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE, OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE
+ client_certificate: /app/cert.pem
+ # Configure headers.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TRACES_HEADERS
+ headers:
+ api-key: !!str 1234
+ # Configure compression.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_TRACES_COMPRESSION
+ compression: gzip
+ # Configure max time (in milliseconds) to wait for each export.
+ #
+ # Environment variable: OTEL_EXPORTER_OTLP_TIMEOUT, OTEL_EXPORTER_OTLP_TRACES_TIMEOUT
+ timeout: 10000
+ # Configure a batch span processor.
+ - batch:
+ # Configure exporter.
+ #
+ # Environment variable: OTEL_TRACES_EXPORTER
+ exporter:
+ # Configure exporter to be zipkin.
+ zipkin:
+ # Configure endpoint.
+ #
+ # Environment variable: OTEL_EXPORTER_ZIPKIN_ENDPOINT
+ endpoint: http://localhost:9411/api/v2/spans
+ # Configure max time (in milliseconds) to wait for each export.
+ #
+ # Environment variable: OTEL_EXPORTER_ZIPKIN_TIMEOUT
+ timeout: 10000
+ # Configure a simple span processor.
+ - simple:
+ # Configure exporter.
+ exporter:
+ # Configure exporter to be console.
+ console: {}
+ # Configure span limits. See also attribute_limits.
+ limits:
+ # Configure max span attribute value size. Overrides attribute_limits.attribute_value_length_limit.
+ #
+ # Environment variable: OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT
+ attribute_value_length_limit: 4096
+ # Configure max span attribute count. Overrides attribute_limits.attribute_count_limit.
+ #
+ # Environment variable: OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT
+ attribute_count_limit: 128
+ # Configure max span event count.
+ #
+ # Environment variable: OTEL_SPAN_EVENT_COUNT_LIMIT
+ event_count_limit: 128
+ # Configure max span link count.
+ #
+ # Environment variable: OTEL_SPAN_LINK_COUNT_LIMIT
+ link_count_limit: 128
+ # Configure max attributes per span event.
+ #
+ # Environment variable: OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT
+ event_attribute_count_limit: 128
+ # Configure max attributes per span link.
+ #
+ # Environment variable: OTEL_LINK_ATTRIBUTE_COUNT_LIMIT
+ link_attribute_count_limit: 128
+ # Configure the sampler.
+ sampler:
+ # Configure sampler to be parent_based. Known values include: always_off, always_on, jaeger_remote, parent_based, trace_id_ratio_based.
+ #
+ # Environment variable: OTEL_TRACES_SAMPLER=parentbased_*
+ parent_based:
+ # Configure root sampler.
+ #
+ # Environment variable: OTEL_TRACES_SAMPLER=parentbased_traceidratio
+ root:
+ # Configure sampler to be trace_id_ratio_based.
+ trace_id_ratio_based:
+ # Configure trace_id_ratio.
+ #
+ # Environment variable: OTEL_TRACES_SAMPLER_ARG=traceidratio=0.0001
+ ratio: 0.0001
+ # Configure remote_parent_sampled sampler.
+ remote_parent_sampled:
+ # Configure sampler to be always_on.
+ always_on: {}
+ # Configure remote_parent_not_sampled sampler.
+ remote_parent_not_sampled:
+ # Configure sampler to be always_off.
+ always_off: {}
+ # Configure local_parent_sampled sampler.
+ local_parent_sampled:
+ # Configure sampler to be always_on.
+ always_on: {}
+ # Configure local_parent_not_sampled sampler.
+ local_parent_not_sampled:
+ # Configure sampler to be always_off.
+ always_off: {}
+
+# Configure resource for all signals.
+resource:
+ # Configure resource attributes.
+ #
+ # Environment variable: OTEL_RESOURCE_ATTRIBUTES
+ attributes:
+ # Configure `service.name` resource attribute
+ #
+ # Environment variable: OTEL_SERVICE_NAME
+ service.name: !!str "unknown_service"
+ # Configure the resource schema URL.
+ schema_url: https://opentelemetry.io/schemas/1.23.1