File configuration (#1249)

* Add configuration model
* Add metrics and logs configuration model
* Remove accidentally added package dependency
* Fix `$properties` typehint to match config
Default value available -> cannot be null.
* Add configuration example that utilizes env substitution
* Fix/suppress config psalm issues
* Fix/suppress config phpstan issues
* Suppress config phan issues
* Apply cs-fixer
* Change config package version to development version 0.x
* Add README
* Add basic test
* Fix psalm and cs
* Fix composer requirement for PRs
* gitsplit, copy spi config to root composer.json
This commit is contained in:
Tobias Bachert 2024-04-01 09:13:01 +02:00 committed by GitHub
parent 6dd255deac
commit 7ec0e90402
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 2298 additions and 14 deletions

View File

@ -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"

View File

@ -319,6 +319,7 @@ return [
'exclude_analysis_directory_list' => [
'vendor/',
'proto/',
'src/Config/SDK',
],
// Enable this to enable checks of require/include statements referring to valid paths.

View File

@ -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"
]
}
}
}

29
examples/load_config.php Normal file
View File

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
use OpenTelemetry\API\Logs\EventLogger;
use OpenTelemetry\API\Logs\LogRecord;
use OpenTelemetry\Config\SDK\Configuration;
require __DIR__ . '/../vendor/autoload.php';
echo 'load config SDK example starting...' . PHP_EOL;
$config = Configuration::parseFile(__DIR__ . '/load_config.yaml');
$sdk = $config
->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;

44
examples/load_config.yaml Normal file
View File

@ -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

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
use OpenTelemetry\API\Logs\EventLogger;
use OpenTelemetry\API\Logs\LogRecord;
use OpenTelemetry\Config\SDK\Configuration;
require __DIR__ . '/../vendor/autoload.php';
echo 'load config SDK example starting...' . PHP_EOL;
$_SERVER['OTEL_SERVICE_NAME'] = 'opentelemetry-demo';
$_SERVER['OTEL_EXPORTER_OTLP_PROTOCOL'] = 'http/protobuf';
$_SERVER['OTEL_EXPORTER_OTLP_ENDPOINT'] = 'http://collector:4318';
$_SERVER['OTEL_TRACES_SAMPLER_ARG'] = '0.5';
$config = Configuration::parseFile(__DIR__ . '/load_config_env.yaml');
$sdk = $config
->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;

View File

@ -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

View File

@ -32,4 +32,8 @@ parameters:
-
message: "#Call to an undefined method .*:expects.*#"
paths:
- tests
- tests
-
message: "#Call to an undefined method Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeParentInterface::.*#"
paths:
- src/Config/SDK

View File

@ -23,13 +23,33 @@
<issueHandlers>
<UndefinedClass>
<errorLevel type="suppress">
<referencedClass name="GMP" />
<referencedClass name="GMP"/>
</errorLevel>
</UndefinedClass>
<ArgumentTypeCoercion>
</UndefinedClass>
<ArgumentTypeCoercion>
<errorLevel type="suppress">
<directory name="./examples" />
<directory name="./examples"/>
</errorLevel>
</ArgumentTypeCoercion>
</ArgumentTypeCoercion>
<UndefinedInterfaceMethod>
<errorLevel type="suppress">
<directory name="src/Config/SDK/ComponentProvider"/>
</errorLevel>
</UndefinedInterfaceMethod>
<PossiblyNullReference>
<errorLevel type="suppress">
<directory name="src/Config/SDK/ComponentProvider"/>
</errorLevel>
</PossiblyNullReference>
<MoreSpecificImplementedParamType>
<errorLevel type="suppress">
<directory name="src/Config/SDK/ComponentProvider"/>
</errorLevel>
</MoreSpecificImplementedParamType>
<InvalidDocblock>
<errorLevel type="suppress">
<directory name="src/Config/SDK/ComponentProvider"/>
</errorLevel>
</InvalidDocblock>
</issueHandlers>
</psalm>

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Logs;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Logs\Exporter\ConsoleExporter;
use OpenTelemetry\SDK\Logs\LogRecordExporterInterface;
use OpenTelemetry\SDK\Registry;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<LogRecordExporterInterface>
*/
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');
}
}

View File

@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Logs;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\OTelSDK\Configuration\Validation;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\API\Signals;
use OpenTelemetry\Contrib\Otlp\LogsExporter;
use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\Contrib\Otlp\Protocols;
use OpenTelemetry\SDK\Logs\LogRecordExporterInterface;
use OpenTelemetry\SDK\Registry;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<LogRecordExporterInterface>
*/
#[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<string, string>,
* 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;
}
}

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Logs;
use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Logs\LogRecordExporterInterface;
use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface;
use OpenTelemetry\SDK\Logs\Processor\BatchLogRecordProcessor;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<LogRecordProcessorInterface>
*/
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<LogRecordExporterInterface>,
* } $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;
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Logs;
use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Logs\LogRecordExporterInterface;
use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface;
use OpenTelemetry\SDK\Logs\Processor\SimpleLogRecordProcessor;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<LogRecordProcessorInterface>
*/
final class LogRecordProcessorSimple implements ComponentProvider
{
/**
* @param array{
* exporter: ComponentPlugin<LogRecordExporterInterface>,
* } $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;
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Metrics;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Metrics\DefaultAggregationProviderInterface;
use OpenTelemetry\SDK\Metrics\DefaultAggregationProviderTrait;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<DefaultAggregationProviderInterface>
*/
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');
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Metrics;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Metrics\MetricExporter\ConsoleMetricExporter;
use OpenTelemetry\SDK\Metrics\MetricExporterInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<MetricExporterInterface>
*/
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');
}
}

View File

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Metrics;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\OTelSDK\Configuration\Validation;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\API\Signals;
use OpenTelemetry\Contrib\Otlp\MetricExporter;
use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\Contrib\Otlp\Protocols;
use OpenTelemetry\SDK\Metrics\Data\Temporality;
use OpenTelemetry\SDK\Metrics\MetricExporterInterface;
use OpenTelemetry\SDK\Registry;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<MetricExporterInterface>
*/
#[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<string, string>,
* 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;
}
}

View File

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Metrics;
use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Metrics\MetricExporterInterface;
use OpenTelemetry\SDK\Metrics\MetricReader\ExportingReader;
use OpenTelemetry\SDK\Metrics\MetricReaderInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<MetricReaderInterface>
*/
final class MetricReaderPeriodic implements ComponentProvider
{
/**
* @param array{
* interval: int<0, max>,
* timeout: int<0, max>,
* exporter: ComponentPlugin<MetricExporterInterface>,
* } $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;
}
}

View File

@ -0,0 +1,400 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\OTelSDK\Configuration\Validation;
use OpenTelemetry\Context\Propagation\NoopTextMapPropagator;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Logs\LoggerProvider;
use OpenTelemetry\SDK\Logs\LogRecordProcessorInterface;
use OpenTelemetry\SDK\Logs\Processor\MultiLogRecordProcessor;
use OpenTelemetry\SDK\Metrics\DefaultAggregationProviderInterface;
use OpenTelemetry\SDK\Metrics\InstrumentType;
use OpenTelemetry\SDK\Metrics\MeterProvider;
use OpenTelemetry\SDK\Metrics\MetricReaderInterface;
use OpenTelemetry\SDK\Metrics\StalenessHandler\NoopStalenessHandlerFactory;
use OpenTelemetry\SDK\Metrics\View\CriteriaViewRegistry;
use OpenTelemetry\SDK\Metrics\View\SelectionCriteria\AllCriteria;
use OpenTelemetry\SDK\Metrics\View\SelectionCriteria\InstrumentationScopeNameCriteria;
use OpenTelemetry\SDK\Metrics\View\SelectionCriteria\InstrumentationScopeSchemaUrlCriteria;
use OpenTelemetry\SDK\Metrics\View\SelectionCriteria\InstrumentationScopeVersionCriteria;
use OpenTelemetry\SDK\Metrics\View\SelectionCriteria\InstrumentNameCriteria;
use OpenTelemetry\SDK\Metrics\View\SelectionCriteria\InstrumentTypeCriteria;
use OpenTelemetry\SDK\Metrics\View\ViewTemplate;
use OpenTelemetry\SDK\Resource\ResourceInfo;
use OpenTelemetry\SDK\Resource\ResourceInfoFactory;
use OpenTelemetry\SDK\SdkBuilder;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\Sampler\ParentBased;
use OpenTelemetry\SDK\Trace\SamplerInterface;
use OpenTelemetry\SDK\Trace\SpanLimits;
use OpenTelemetry\SDK\Trace\SpanProcessorInterface;
use OpenTelemetry\SDK\Trace\TracerProvider;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @internal
*
* @implements ComponentProvider<SdkBuilder>
*/
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<TextMapPropagatorInterface>,
* 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<SamplerInterface>,
* processors: list<ComponentPlugin<SpanProcessorInterface>>,
* },
* meter_provider: array{
* views: list<array{
* stream: array{
* name: ?string,
* description: ?string,
* attribute_keys: list<string>,
* aggregation: ?ComponentPlugin<DefaultAggregationProviderInterface>,
* },
* 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<ComponentPlugin<MetricReaderInterface>>,
* },
* logger_provider: array{
* limits: array{
* attribute_value_length_limit: ?int<0, max>,
* attribute_count_limit: ?int<0, max>,
* },
* processors: list<ComponentPlugin<LogRecordProcessorInterface>>,
* },
* } $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);
}
// <editor-fold desc="tracer_provider">
$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'],
),
);
// </editor-fold>
// <editor-fold desc="meter_provider">
$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(),
);
// </editor-fold>
// <editor-fold desc="logger_provider">
$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,
);
// </editor-fold>
$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;
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Propagator;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use OpenTelemetry\Extension\Propagator\B3\B3Propagator;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<TextMapPropagatorInterface>
*/
#[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');
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Propagator;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use OpenTelemetry\Extension\Propagator\B3\B3Propagator;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<TextMapPropagatorInterface>
*/
#[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');
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Propagator;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\API\Baggage\Propagation\BaggagePropagator;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<TextMapPropagatorInterface>
*/
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');
}
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Propagator;
use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\Context\Propagation\MultiTextMapPropagator;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<TextMapPropagatorInterface>
*/
final class TextMapPropagatorComposite implements ComponentProvider
{
/**
* @param list<ComponentPlugin<TextMapPropagatorInterface>> $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);
}
}

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Propagator;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use OpenTelemetry\Extension\Propagator\Jaeger\JaegerPropagator;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<TextMapPropagatorInterface>
*/
#[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');
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Propagator;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<TextMapPropagatorInterface>
*/
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');
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Trace;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOffSampler;
use OpenTelemetry\SDK\Trace\SamplerInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<SamplerInterface>
*/
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');
}
}

View File

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Trace;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\SamplerInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<SamplerInterface>
*/
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');
}
}

View File

@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Trace;
use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOffSampler;
use OpenTelemetry\SDK\Trace\Sampler\AlwaysOnSampler;
use OpenTelemetry\SDK\Trace\Sampler\ParentBased;
use OpenTelemetry\SDK\Trace\SamplerInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<SamplerInterface>
*/
final class SamplerParentBased implements ComponentProvider
{
/**
* @param array{
* root: ComponentPlugin<SamplerInterface>,
* remote_parent_sampled: ?ComponentPlugin<SamplerInterface>,
* remote_parent_not_sampled: ?ComponentPlugin<SamplerInterface>,
* local_parent_sampled: ?ComponentPlugin<SamplerInterface>,
* local_parent_not_sampled: ?ComponentPlugin<SamplerInterface>,
* } $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;
}
}

View File

@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Trace;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Trace\Sampler\TraceIdRatioBasedSampler;
use OpenTelemetry\SDK\Trace\SamplerInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<SamplerInterface>
*/
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;
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Trace;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Registry;
use OpenTelemetry\SDK\Trace\SpanExporter\ConsoleSpanExporter;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<SpanExporterInterface>
*/
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');
}
}

View File

@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Trace;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\OTelSDK\Configuration\Validation;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\API\Signals;
use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\Contrib\Otlp\Protocols;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Registry;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<SpanExporterInterface>
*/
#[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<string, string>,
* 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;
}
}

View File

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Trace;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\OTelSDK\Configuration\Validation;
use Nevay\SPI\ServiceProviderDependency\PackageDependency;
use OpenTelemetry\Contrib\Zipkin;
use OpenTelemetry\SDK\Registry;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<SpanExporterInterface>
*/
#[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;
}
}

View File

@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Trace;
use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Common\Time\ClockFactory;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
use OpenTelemetry\SDK\Trace\SpanProcessor\BatchSpanProcessor;
use OpenTelemetry\SDK\Trace\SpanProcessorInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<SpanProcessorInterface>
*/
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<SpanExporterInterface>,
* } $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;
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK\ComponentProvider\Trace;
use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ComponentProviderRegistry;
use Nevay\OTelSDK\Configuration\Context;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;
use OpenTelemetry\SDK\Trace\SpanProcessorInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
/**
* @implements ComponentProvider<SpanProcessorInterface>
*/
final class SpanProcessorSimple implements ComponentProvider
{
/**
* @param array{
* exporter: ComponentPlugin<SpanExporterInterface>,
* } $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;
}
}

View File

@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace OpenTelemetry\Config\SDK;
use Nevay\OTelSDK\Configuration\ComponentPlugin;
use Nevay\OTelSDK\Configuration\ComponentProvider;
use Nevay\OTelSDK\Configuration\ConfigurationFactory;
use Nevay\OTelSDK\Configuration\Context;
use Nevay\OTelSDK\Configuration\Environment\EnvSourceReader;
use Nevay\OTelSDK\Configuration\Environment\PhpIniEnvSource;
use Nevay\OTelSDK\Configuration\Environment\ServerEnvSource;
use Nevay\SPI\ServiceLoader;
use OpenTelemetry\Config\SDK\ComponentProvider\OpenTelemetrySdk;
use OpenTelemetry\SDK\SdkBuilder;
final class Configuration
{
/**
* @param ComponentPlugin<SdkBuilder> $sdkPlugin
*/
private function __construct(
private readonly ComponentPlugin $sdkPlugin,
) {
}
public function create(Context $context = new Context()): SdkBuilder
{
return $this->sdkPlugin->create($context);
}
/**
* @param string|list<string> $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<SdkBuilder>
*/
private static function factory(): ConfigurationFactory
{
static $factory;
return $factory ??= new ConfigurationFactory(
ServiceLoader::load(ComponentProvider::class),
new OpenTelemetrySdk(),
new EnvSourceReader([
new ServerEnvSource(),
new PhpIniEnvSource(),
]),
);
}
}

34
src/Config/SDK/README.md Normal file
View File

@ -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).

View File

@ -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"
]
}
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
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 @@ class OtlpUtil
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]) ?

View File

@ -27,6 +27,9 @@ class Protocols
}
}
/**
* @psalm-return ContentTypes::*
*/
public static function contentType(string $protocol): string
{
self::validate($protocol);

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Config;
use OpenTelemetry\Config\SDK\Configuration;
use PHPUnit\Framework\TestCase;
final class ConfigurationTest extends TestCase
{
/**
* @dataProvider openTelemetryConfigurationDataProvider
* @coversNothing
*/
public function test_open_telemetry_configuration(string $file): void
{
$this->expectNotToPerformAssertions();
Configuration::parseFile($file)->create();
}
public static function openTelemetryConfigurationDataProvider(): iterable
{
yield 'kitchen-sink' => [__DIR__ . '/configurations/kitchen-sink.yaml'];
yield 'anchors' => [__DIR__ . '/configurations/anchors.yaml'];
}
}

View File

@ -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

View File

@ -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