Skip to content

Commit

Permalink
add sdk-config 0.3 support for key/value headers and attributes (#1428)
Browse files Browse the repository at this point in the history
- headers and attributes are now arrays with `key` and `value` elements
- headers can optionally contain a `headers_list` element which supports a lower-priority CSV of key/value entries
- attributes can optionally contain an `attributes_list` element which supports a lower-priority CSV of key/value/data-type entries
  • Loading branch information
brettmc authored Nov 26, 2024
1 parent 8857b0c commit f1c9827
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 34 deletions.
4 changes: 3 additions & 1 deletion examples/load_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ file_format: '0.3'

resource:
attributes:
service.name: opentelemetry-demo
- name: service.name
value: opentelemetry-demo
attributes_list: service.name=unused,example.foo=foo_value,example.bar=bar_value

propagators:
composite: [ tracecontext, baggage ]
Expand Down
3 changes: 2 additions & 1 deletion examples/load_config_env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ disabled: ${OTEL_SDK_DISABLED}

resource:
attributes:
service.name: ${OTEL_SERVICE_NAME}
- name: service.name
value: ${OTEL_SERVICE_NAME}

propagators:
composite: [ tracecontext, baggage ]
Expand Down
16 changes: 13 additions & 3 deletions src/Config/SDK/ComponentProvider/Logs/LogRecordExporterOtlp.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use OpenTelemetry\Contrib\Otlp\LogsExporter;
use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\Contrib\Otlp\Protocols;
use OpenTelemetry\SDK\Common\Configuration\Parser\MapParser;
use OpenTelemetry\SDK\Logs\LogRecordExporterInterface;
use OpenTelemetry\SDK\Registry;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
Expand All @@ -31,7 +32,8 @@ final class LogRecordExporterOtlp implements ComponentProvider
* certificate: ?string,
* client_key: ?string,
* client_certificate: ?string,
* headers: array<string, string>,
* headers: list<array{name: string, value: string}>,
* headers_list: ?string,
* compression: 'gzip'|null,
* timeout: int<0, max>,
* } $properties
Expand All @@ -40,10 +42,12 @@ public function createPlugin(array $properties, Context $context): LogRecordExpo
{
$protocol = $properties['protocol'];

$headers = array_column($properties['headers'], 'value', 'name') + MapParser::parse($properties['headers_list']);

return new LogsExporter(Registry::transportFactory($protocol)->create(
endpoint: $properties['endpoint'] . OtlpUtil::path(Signals::LOGS, $protocol),
contentType: Protocols::contentType($protocol),
headers: $properties['headers'],
headers: $headers,
compression: $properties['compression'],
timeout: $properties['timeout'],
cacert: $properties['certificate'],
Expand All @@ -63,8 +67,14 @@ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinit
->scalarNode('client_key')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('client_certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->arrayNode('headers')
->scalarPrototype()->end()
->arrayPrototype()
->children()
->scalarNode('name')->isRequired()->cannotBeEmpty()->end()
->scalarNode('value')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->end()
->end()
->end()
->scalarNode('headers_list')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->enumNode('compression')->values(['gzip'])->defaultNull()->end()
->integerNode('timeout')->min(0)->defaultValue(10)->end()
->end()
Expand Down
16 changes: 13 additions & 3 deletions src/Config/SDK/ComponentProvider/Metrics/MetricExporterOtlp.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use OpenTelemetry\Contrib\Otlp\MetricExporter;
use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\Contrib\Otlp\Protocols;
use OpenTelemetry\SDK\Common\Configuration\Parser\MapParser;
use OpenTelemetry\SDK\Metrics\Data\Temporality;
use OpenTelemetry\SDK\Metrics\MetricExporterInterface;
use OpenTelemetry\SDK\Registry;
Expand All @@ -32,7 +33,8 @@ final class MetricExporterOtlp implements ComponentProvider
* certificate: ?string,
* client_key: ?string,
* client_certificate: ?string,
* headers: array<string, string>,
* headers: list<array{name: string, value: string}>,
* headers_list: ?string,
* compression: 'gzip'|null,
* timeout: int<0, max>,
* temporality_preference: 'cumulative'|'delta'|'lowmemory',
Expand All @@ -43,6 +45,8 @@ public function createPlugin(array $properties, Context $context): MetricExporte
{
$protocol = $properties['protocol'];

$headers = array_column($properties['headers'], 'value', 'name') + MapParser::parse($properties['headers_list']);

$temporality = match ($properties['temporality_preference']) {
'cumulative' => Temporality::CUMULATIVE,
'delta' => Temporality::DELTA,
Expand All @@ -52,7 +56,7 @@ public function createPlugin(array $properties, Context $context): MetricExporte
return new MetricExporter(Registry::transportFactory($protocol)->create(
endpoint: $properties['endpoint'] . OtlpUtil::path(Signals::METRICS, $protocol),
contentType: Protocols::contentType($protocol),
headers: $properties['headers'],
headers: $headers,
compression: $properties['compression'],
timeout: $properties['timeout'],
cacert: $properties['certificate'],
Expand All @@ -72,8 +76,14 @@ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinit
->scalarNode('client_key')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('client_certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->arrayNode('headers')
->scalarPrototype()->end()
->arrayPrototype()
->children()
->scalarNode('name')->isRequired()->cannotBeEmpty()->end()
->scalarNode('value')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->end()
->end()
->end()
->scalarNode('headers_list')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->enumNode('compression')->values(['gzip'])->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->integerNode('timeout')->min(0)->defaultValue(10)->end()
->enumNode('temporality_preference')
Expand Down
18 changes: 15 additions & 3 deletions src/Config/SDK/ComponentProvider/OpenTelemetrySdk.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use OpenTelemetry\Context\Propagation\NoopTextMapPropagator;
use OpenTelemetry\Context\Propagation\TextMapPropagatorInterface;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Configuration\Parser\MapParser;
use OpenTelemetry\SDK\Common\Instrumentation\InstrumentationScopeFactory;
use OpenTelemetry\SDK\Logs\EventLoggerProvider;
use OpenTelemetry\SDK\Logs\LoggerProvider;
Expand Down Expand Up @@ -56,6 +57,7 @@ final class OpenTelemetrySdk implements ComponentProvider
* disabled: bool,
* resource: array{
* attributes: array,
* attributes_list: ?string,
* schema_url: ?string,
* },
* attribute_limits: array{
Expand Down Expand Up @@ -113,10 +115,10 @@ public function createPlugin(array $properties, Context $context): SdkBuilder
if ($properties['disabled']) {
return $sdkBuilder;
}

$attributes = array_column($properties['resource']['attributes'], 'value', 'name') + MapParser::parse($properties['resource']['attributes_list']);
$resource = ResourceInfoFactory::defaultResource()
->merge(ResourceInfo::create(
attributes: Attributes::create($properties['resource']['attributes']),
attributes: Attributes::create($attributes),
schemaUrl: $properties['resource']['schema_url'],
));

Expand Down Expand Up @@ -284,8 +286,18 @@ private function getResourceConfig(): ArrayNodeDefinition
->addDefaultsIfNotSet()
->children()
->arrayNode('attributes')
->variablePrototype()->end()
->arrayPrototype()
->children()
->scalarNode('name')->isRequired()->end()
->variableNode('value')->isRequired()->end()
// @todo use type to validate and/or cast attributes
->enumNode('type')->defaultNull()
->values(['string', 'bool', 'int', 'double', 'string_array', 'bool_array', 'int_array', 'double_array'])
->end()
->end()
->end()
->end()
->scalarNode('attributes_list')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('schema_url')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->end();

Expand Down
16 changes: 13 additions & 3 deletions src/Config/SDK/ComponentProvider/Trace/SpanExporterOtlp.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use OpenTelemetry\Contrib\Otlp\OtlpUtil;
use OpenTelemetry\Contrib\Otlp\Protocols;
use OpenTelemetry\Contrib\Otlp\SpanExporter;
use OpenTelemetry\SDK\Common\Configuration\Parser\MapParser;
use OpenTelemetry\SDK\Registry;
use OpenTelemetry\SDK\Trace\SpanExporterInterface;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
Expand All @@ -31,7 +32,8 @@ final class SpanExporterOtlp implements ComponentProvider
* certificate: ?string,
* client_key: ?string,
* client_certificate: ?string,
* headers: array<string, string>,
* headers: list<array{name: string, value: string}>,
* headers_list: ?string,
* compression: 'gzip'|null,
* timeout: int<0, max>,
* } $properties
Expand All @@ -40,10 +42,12 @@ public function createPlugin(array $properties, Context $context): SpanExporterI
{
$protocol = $properties['protocol'];

$headers = array_column($properties['headers'], 'value', 'name') + MapParser::parse($properties['headers_list']);

return new SpanExporter(Registry::transportFactory($protocol)->create(
endpoint: $properties['endpoint'] . OtlpUtil::path(Signals::TRACE, $protocol),
contentType: Protocols::contentType($protocol),
headers: $properties['headers'],
headers: $headers,
compression: $properties['compression'],
timeout: $properties['timeout'],
cacert: $properties['certificate'],
Expand All @@ -63,8 +67,14 @@ public function getConfig(ComponentProviderRegistry $registry): ArrayNodeDefinit
->scalarNode('client_key')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->scalarNode('client_certificate')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->arrayNode('headers')
->scalarPrototype()->end()
->arrayPrototype()
->children()
->scalarNode('name')->isRequired()->cannotBeEmpty()->end()
->scalarNode('value')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->end()
->end()
->end()
->scalarNode('headers_list')->defaultNull()->validate()->always(Validation::ensureString())->end()->end()
->enumNode('compression')->values(['gzip'])->defaultNull()->end()
->integerNode('timeout')->min(0)->defaultValue(10)->end()
->end()
Expand Down
3 changes: 2 additions & 1 deletion tests/Integration/Config/configurations/anchors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ exporters:
client_key: /app/cert.pem
client_certificate: /app/cert.pem
headers:
api-key: !!str 1234
- name: api-key
value: "str 1234"
compression: gzip
timeout: 10000

Expand Down
68 changes: 49 additions & 19 deletions tests/Integration/Config/configurations/kitchen-sink.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ logger_provider:
#
# 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
# Configure headers. Entries have higher priority than entries from .headers_list.
headers:
api-key: "1234"
- name: api-key
value: "1234"
# Configure headers. Entries have lower priority than entries from .headers.
# The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details.
headers_list: "api-key=1234"
# Configure compression.
#
# Environment variable: OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_LOGS_COMPRESSION
Expand Down Expand Up @@ -138,11 +140,13 @@ meter_provider:
#
# 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
# Configure headers. Entries have higher priority than entries from .headers_list.
headers:
api-key: !!str 1234
- name: api-key
value: "1234"
# Configure headers. Entries have lower priority than entries from .headers.
# The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details.
headers_list: "api-key=1234"
# Configure compression.
#
# Environment variable: OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_METRICS_COMPRESSION
Expand Down Expand Up @@ -244,11 +248,13 @@ tracer_provider:
#
# 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
# Configure headers. Entries have higher priority than entries from .headers_list.
headers:
api-key: !!str 1234
- name: api-key
value: "1234"
# Configure headers. Entries have lower priority than entries from .headers.
# The value is a list of comma separated key-value pairs matching the format of OTEL_EXPORTER_OTLP_HEADERS. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options for details.
headers_list: "api-key=1234"
# Configure compression.
#
# Environment variable: OTEL_EXPORTER_OTLP_COMPRESSION, OTEL_EXPORTER_OTLP_TRACES_COMPRESSION
Expand Down Expand Up @@ -340,14 +346,38 @@ tracer_provider:

# Configure resource for all signals.
resource:
# Configure resource attributes.
#
# Environment variable: OTEL_RESOURCE_ATTRIBUTES
# Configure resource attributes. Entries have higher priority than entries from .resource.attributes_list.
# Entries must contain .name nand .value, and may optionally include .type, which defaults ot "string" if not set. The value must match the type. Values for .type include: string, bool, int, double, string_array, bool_array, int_array, double_array.
attributes:
# Configure `service.name` resource attribute
#
# Environment variable: OTEL_SERVICE_NAME
service.name: !!str "unknown_service"
- name: service.name
value: unknown_service
- name: string_key
value: value
type: string
- name: bool_key
value: true
type: bool
- name: int_key
value: 1
type: int
- name: double_key
value: 1.1
type: double
- name: string_array_key
value: [ "value1", "value2" ]
type: string_array
- name: bool_array_key
value: [ true, false ]
type: bool_array
- name: int_array_key
value: [ 1, 2 ]
type: int_array
- name: double_array_key
value: [ 1.1, 2.2 ]
type: double_array
# Configure resource attributes. Entries have lower priority than entries from .resource.attributes.
# The value is a list of comma separated key-value pairs matching the format of OTEL_RESOURCE_ATTRIBUTES. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md#general-sdk-configuration for details.
attributes_list: "service.namespace=my-namespace,service.version=1.0.0"
# Configure the resource schema URL.
schema_url: https://opentelemetry.io/schemas/1.27.0

Expand Down

0 comments on commit f1c9827

Please sign in to comment.