From 9e1aeb7e5733a71ff3a4dfd7d4588bc5f3d12b62 Mon Sep 17 00:00:00 2001 From: jack-berg <34418638+jack-berg@users.noreply.github.com> Date: Thu, 15 Aug 2024 15:35:58 -0500 Subject: [PATCH] Define instrumentation configuration API (#4128) Resolves #3535. This introduces an API component to file configuration, which has been limited to SDK (i.e. end user facing) up until this point. The configuration model recently added the first surface area related to instrumentation configuration properties in https://github.com/open-telemetry/opentelemetry-configuration/pull/91. The API proposed in this PR is collectively called the "Instrumentation config API", and provides a mechanism for instrumentation libraries to participate in file configuration and read relevant properties during initialization. The intent is for both OpenTelemetry-authored and native instrumentation alike to be able to be configured by users in a standard way. New API surface area is necessary to accomplish this to avoid instrumentation libraries from needing to take a dependency on SDK artifacts. The following summarizes the additions: - Introduce ConfigProvider, the instrumentation config API analog of TracerProvider, MeterProvider, LoggerProvider. This is the entry point to the API. - Define "Get instrumentation config" operation for ConfigProvider. This returns something called ConfigProperties, which is a programmatic representation of a YAML mapping node. The ConfigProperties returned by "Get instrumentation config" represents the [`.instrumentation`](https://github.com/open-telemetry/opentelemetry-configuration/blob/670901762dd5cce1eecee423b8660e69f71ef4be/examples/kitchen-sink.yaml#L438-L439) node defined in a config file. - Rebrand "file configuration" to "declarative configuration". This expresses the intent without coupling to the file representation, which although will be the most popular way to consume these features is just one possible way to represent the configuration model and use these tools. - Break out dedicated `api.md`, `data-model.md`, and `sdk.md` files for respective API, data model, and SDK portions of declarative configuration. This aligns with other portions of the spec. The separation should improve clarity regarding what should and should not be exposed in the API. I've prototyped this new API in `opentelemetry-java` here: https://github.com/open-telemetry/opentelemetry-java/pull/6549 cc @open-telemetry/configuration-maintainers, @open-telemetry/specs-semconv-maintainers --- spec-compliance-matrix.md | 5 +- specification/README.md | 2 +- specification/configuration/README.md | 57 ++- specification/configuration/api.md | 80 +++ specification/configuration/data-model.md | 148 ++++++ .../configuration/file-configuration.md | 458 ------------------ .../configuration/sdk-configuration.md | 56 --- .../sdk-environment-variables.md | 14 +- specification/configuration/sdk.md | 353 ++++++++++++++ specification/vendors.md | 2 +- 10 files changed, 649 insertions(+), 526 deletions(-) create mode 100644 specification/configuration/api.md create mode 100644 specification/configuration/data-model.md delete mode 100644 specification/configuration/file-configuration.md delete mode 100644 specification/configuration/sdk-configuration.md create mode 100644 specification/configuration/sdk.md diff --git a/spec-compliance-matrix.md b/spec-compliance-matrix.md index 374e1e2b340..b0b84365d74 100644 --- a/spec-compliance-matrix.md +++ b/spec-compliance-matrix.md @@ -294,10 +294,11 @@ Note: Support for environment variables is optional. | OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION | | + | | | | | | | | | | | OTEL_EXPERIMENTAL_CONFIG_FILE | | | | | | | | | | | | -## File Configuration +## Declarative configuration -See [File Configuration](./specification/configuration/file-configuration.md) +See [declarative configuration](./specification/configuration/README.md#declarative-configuration) for details. +Disclaimer: Declarative configuration is currently in Development status - work in progress. | Feature | Go | Java | JS | Python | Ruby | Erlang | PHP | Rust | C++ | .NET | Swift | |-------------------------------------------------------------------------------------------------------------------------|----|------|----|--------|------|--------|-----|------|-----|------|-------| diff --git a/specification/README.md b/specification/README.md index fefec0b4cba..d1136d70243 100644 --- a/specification/README.md +++ b/specification/README.md @@ -36,7 +36,7 @@ path_base_for_github_subdir: - [Metrics](metrics/sdk.md) - [Logs](logs/sdk.md) - [Resource](resource/sdk.md) - - [Configuration](configuration/sdk-configuration.md) + - [Configuration](configuration/README.md) - Data Specification - [Semantic Conventions](overview.md#semantic-conventions) - [Protocol](protocol/README.md) diff --git a/specification/configuration/README.md b/specification/configuration/README.md index af3fe3bb908..811e753a7b7 100644 --- a/specification/configuration/README.md +++ b/specification/configuration/README.md @@ -4,4 +4,59 @@ path_base_for_github_subdir: to: configuration/README.md ---> -# Configuration +# Overview + +OpenTelemetry SDK components are highly configurable. This specification +outlines the mechanisms by which OpenTelemetry components can be configured. It +does not attempt to specify the details of what can be configured. + +## Configuration Interfaces + +### Programmatic + +The SDK MUST provide a programmatic interface for all configuration. +This interface SHOULD be written in the language of the SDK itself. +All other configuration mechanisms SHOULD be built on top of this interface. + +An example of this programmatic interface is accepting a well-defined +struct on an SDK builder class. From that, one could build a CLI that accepts a +file (YAML, JSON, TOML, ...) and then transforms into that well-defined struct +consumable by the programmatic interface ( +see [declarative configuration](#declarative-configuration)). + +### Environment variables + +Environment variable configuration defines a set of language agnostic +environment variables for common configuration goals. + +See [OpenTelemetry Environment Variable Specification](./sdk-environment-variables.md). + +### Declarative configuration + +Declarative configuration provides a mechanism for configuring OpenTelemetry +which is more expressive and full-featured than +the [environment variable](#environment-variables) based scheme, and language +agnostic in a way not possible with [programmatic configuration](#programmatic). +Notably, declarative configuration defines tooling allowing users to load +OpenTelemetry components according to a file-based representation of a +standardized configuration data model. + +Declarative configuration consists of the following main components: + +* [Data model](./data-model.md) defines data structures which allow users to + specify an intended configuration of OpenTelemetry SDK components and + instrumentation. The data model includes a file-based representation. +* [Instrumentation configuration API](./api.md) allows + instrumentation libraries to consume configuration by reading relevant + configuration options during initialization. +* [Configuration SDK](./sdk.md) defines SDK capabilities around file + configuration, including an In-Memory configuration model, support for + referencing custom extension plugin interfaces in configuration files, and + operations to parse configuration files and interpret the configuration data + model. + +### Other Mechanisms + +Additional configuration mechanisms SHOULD be provided in whatever +language/format/style is idiomatic for the language of the SDK. The +SDK can include as many configuration mechanisms as appropriate. diff --git a/specification/configuration/api.md b/specification/configuration/api.md new file mode 100644 index 00000000000..f96bcfd5802 --- /dev/null +++ b/specification/configuration/api.md @@ -0,0 +1,80 @@ +# Instrumentation Configuration API + +**Status**: [Development](../document-status.md) + + + +- [Overview](#overview) + * [ConfigProvider](#configprovider) + + [ConfigProvider operations](#configprovider-operations) + - [Get instrumentation config](#get-instrumentation-config) + * [ConfigProperties](#configproperties) + + + +## Overview + +The instrumentation configuration API is part of +the [declarative configuration interface](./README.md#declarative-configuration). + +The API allows [instrumentation libraries](../glossary.md#instrumentation-library) +to consume configuration by reading relevant configuration during +initialization. For example, an instrumentation library for an HTTP client can +read the set of HTTP request and response headers to capture. + +It consists of the following main components: + +* [ConfigProvider](#configprovider) is the entry point of the API. +* [ConfigProperties](#configproperties) is a programmatic representation of a + configuration mapping node. + +### ConfigProvider + +`ConfigProvider` provides access to configuration properties relevant to +instrumentation. + +Instrumentation libraries access `ConfigProvider` during +initialization. `ConfigProvider` may be passed as an argument to the +instrumentation library, or the instrumentation library may access it from a +central place. Thus, the API SHOULD provide a way to access a global +default `ConfigProvider`, and set/register it. + +#### ConfigProvider operations + +The `ConfigProvider` MUST provide the following functions: + +* [Get instrumentation config](#get-instrumentation-config) + +TODO: decide if additional operations are needed to improve API ergonomics + +##### Get instrumentation config + +Obtain configuration relevant to instrumentation libraries. + +**Returns:** [`ConfigProperties`](#configproperties) representing +the [`.instrumentation`](https://github.com/open-telemetry/opentelemetry-configuration/blob/670901762dd5cce1eecee423b8660e69f71ef4be/examples/kitchen-sink.yaml#L438-L439) +configuration mapping node. + +If the `.instrumentation` node is not set, get instrumentation config MUST +return nil, null, undefined or another language-specific idiomatic pattern +denoting empty. + +### ConfigProperties + +`ConfigProperties` is a programmatic representation of a configuration mapping +node (i.e. a YAML mapping node). + +`ConfigProperties` MUST provide accessors for reading all properties from the +mapping node it represents, including: + +* scalars (string, boolean, double precision floating point, 64-bit integer) +* mappings, which SHOULD be represented as `ConfigProperties` +* sequences of scalars +* sequences of mappings, which SHOULD be represented as `ConfigProperties` +* the set of property keys present + +`ConfigProperties` SHOULD provide access to properties in a type safe manner, +based on what is idiomatic in the language. + +`ConfigProperties` SHOULD allow a caller to determine if a property is present +with a null value, versus not set. diff --git a/specification/configuration/data-model.md b/specification/configuration/data-model.md new file mode 100644 index 00000000000..6b7abcac269 --- /dev/null +++ b/specification/configuration/data-model.md @@ -0,0 +1,148 @@ +# Configuration Data Model + +**Status**: [Development](../document-status.md) + + + +- [Overview](#overview) + * [Stability definition](#stability-definition) + * [File-based configuration model](#file-based-configuration-model) + + [YAML file format](#yaml-file-format) + + [Environment variable substitution](#environment-variable-substitution) + + + +## Overview + +The OpenTelemetry configuration data model is part of +the [declarative configuration interface](./README.md#declarative-configuration). + +The data model defines data structures which allow users to specify an intended +configuration of OpenTelemetry SDK components and instrumentation. + +The data model is defined +in [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) +using [JSON Schema](https://json-schema.org/). + +The data model itself is an abstraction with multiple built-in representations: + +* [File-based configuration model](#file-based-configuration-model) +* [SDK in-memory configuration model](./sdk.md#in-memory-configuration-model) + +### Stability definition + +TODO: define stability guarantees and backwards compatibility + +### File-based configuration model + +A configuration file is a serialized file-based representation of +the configuration data model. + +Configuration files SHOULD use one the following serialization formats: + +* [YAML file format](#yaml-file-format) + +#### YAML file format + +[YAML](https://yaml.org/spec/1.2.2/) configuration files SHOULD follow YAML spec +revision >= 1.2. + +YAML configuration files SHOULD be parsed using [v1.2 YAML core schema](https://yaml.org/spec/1.2.2/#103-core-schema). + +YAML configuration files MUST use file extensions `.yaml` or `.yml`. + +#### Environment variable substitution + +Configuration files support environment variables substitution for references +which match the following PCRE2 regular expression: + +```regexp +\$\{(?:env:)?(?[a-zA-Z_][a-zA-Z0-9_]*)(:-(?[^\n]*))?\} +``` + +The `ENV_NAME` MUST start with an alphabetic or `_` character, and is followed +by 0 or more alphanumeric or `_` characters. + +For example, `${API_KEY}` and `${env:API_KEY}` are valid, while `${1API_KEY}` +and `${API_$KEY}` are invalid. + +Environment variable substitution MUST only apply to scalar values. Mapping keys +are not candidates for substitution. + +The `DEFAULT_VALUE` is an optional fallback value which is substituted +if `ENV_NAME` is null, empty, or undefined. `DEFAULT_VALUE` consists of 0 or +more non line break characters (i.e. any character except `\n`). If a referenced +environment variable is not defined and does not have a `DEFAULT_VALUE`, it MUST +be replaced with an empty value. + +When parsing a configuration file that contains a reference not matching +the references regular expression but does match the following PCRE2 +regular expression, the parser MUST return an empty result (no partial +results are allowed) and an error describing the parse failure to the user. + +```regexp +\$\{(?[^}]+)\} +``` + +Node types MUST be interpreted after environment variable substitution takes +place. This ensures the environment string representation of boolean, integer, +or floating point fields can be properly converted to expected types. + +It MUST NOT be possible to inject YAML structures by environment variables. For +example, see references to `INVALID_MAP_VALUE` environment variable below. + +It MUST NOT be possible to inject environment variable by environment variables. +For example, see references to `DO_NOT_REPLACE_ME` environment variable below. + +For example, consider the following environment variables, +and [YAML](#yaml-file-format) configuration file: + +```shell +export STRING_VALUE="value" +export BOOL_VALUE="true" +export INT_VALUE="1" +export FLOAT_VALUE="1.1" +export HEX_VALUE="0xdeadbeef" # A valid integer value written in hexadecimal +export INVALID_MAP_VALUE="value\nkey:value" # An invalid attempt to inject a map key into the YAML +export DO_NOT_REPLACE_ME="Never use this value" # An unused environment variable +export REPLACE_ME='${DO_NOT_REPLACE_ME}' # A valid replacement text, used verbatim, not replaced with "Never use this value" +``` + +```yaml +string_key: ${STRING_VALUE} # Valid reference to STRING_VALUE +env_string_key: ${env:STRING_VALUE} # Valid reference to STRING_VALUE +other_string_key: "${STRING_VALUE}" # Valid reference to STRING_VALUE inside double quotes +another_string_key: "${BOOL_VALUE}" # Valid reference to BOOL_VALUE inside double quotes +string_key_with_quoted_hex_value: "${HEX_VALUE}" # Valid reference to HEX_VALUE inside double quotes +yet_another_string_key: ${INVALID_MAP_VALUE} # Valid reference to INVALID_MAP_VALUE, but YAML structure from INVALID_MAP_VALUE MUST NOT be injected +bool_key: ${BOOL_VALUE} # Valid reference to BOOL_VALUE +int_key: ${INT_VALUE} # Valid reference to INT_VALUE +int_key_with_unquoted_hex_value: ${HEX_VALUE} # Valid reference to HEX_VALUE without quotes +float_key: ${FLOAT_VALUE} # Valid reference to FLOAT_VALUE +combo_string_key: foo ${STRING_VALUE} ${FLOAT_VALUE} # Valid reference to STRING_VALUE and FLOAT_VALUE +string_key_with_default: ${UNDEFINED_KEY:-fallback} # UNDEFINED_KEY is not defined but a default value is included +undefined_key: ${UNDEFINED_KEY} # Invalid reference, UNDEFINED_KEY is not defined and is replaced with "" +${STRING_VALUE}: value # Invalid reference, substitution is not valid in mapping keys and reference is ignored +recursive_key: ${REPLACE_ME} # Valid reference to REPLACE_ME +# invalid_identifier_key: ${STRING_VALUE:?error} # If uncommented, this is an invalid identifier, it would fail to parse +``` + +Environment variable substitution results in the following YAML: + +```yaml +string_key: value # Interpreted as type string, tag URI tag:yaml.org,2002:str +env_string_key: value # Interpreted as type string, tag URI tag:yaml.org,2002:str +other_string_key: "value" # Interpreted as type string, tag URI tag:yaml.org,2002:str +another_string_key: "true" # Interpreted as type string, tag URI tag:yaml.org,2002:str +string_key_with_quoted_hex_value: "0xdeadbeef" # Interpreted as type string, tag URI tag:yaml.org,2002:str +yet_another_string_key: "value\nkey:value" # Interpreted as type string, tag URI tag:yaml.org,2002:str +bool_key: true # Interpreted as type bool, tag URI tag:yaml.org,2002:bool +int_key: 1 # Interpreted as type int, tag URI tag:yaml.org,2002:int +int_key_with_unquoted_hex_value: 3735928559 # Interpreted as type int, tag URI tag:yaml.org,2002:int +float_key: 1.1 # Interpreted as type float, tag URI tag:yaml.org,2002:float +combo_string_key: foo value 1.1 # Interpreted as type string, tag URI tag:yaml.org,2002:str +string_key_with_default: fallback # Interpreted as type string, tag URI tag:yaml.org,2002:str +undefined_key: # Interpreted as type null, tag URI tag:yaml.org,2002:null +${STRING_VALUE}: value # Interpreted as type string, tag URI tag:yaml.org,2002:str +recursive_key: ${DO_NOT_REPLACE_ME} # Interpreted as type string, tag URI tag:yaml.org,2002:str +``` diff --git a/specification/configuration/file-configuration.md b/specification/configuration/file-configuration.md deleted file mode 100644 index e8a01dbc56a..00000000000 --- a/specification/configuration/file-configuration.md +++ /dev/null @@ -1,458 +0,0 @@ - - -# File Configuration - -**Status**: [Development](../document-status.md) - - - -- [Overview](#overview) -- [Configuration Model](#configuration-model) - * [Stability Definition](#stability-definition) -- [Configuration file](#configuration-file) - * [YAML file format](#yaml-file-format) - * [Environment variable substitution](#environment-variable-substitution) -- [SDK Configuration](#sdk-configuration) - * [In-Memory Configuration Model](#in-memory-configuration-model) - * [SDK Extension Components](#sdk-extension-components) - + [Component Provider](#component-provider) - + [Create Plugin](#create-plugin) - * [Operations](#operations) - + [Parse](#parse) - + [Create](#create) - + [Register Component Provider](#register-component-provider) -- [Examples](#examples) - * [Via File Configuration API](#via-file-configuration-api) - * [Via OTEL_EXPERIMENTAL_CONFIG_FILE](#via-otel_experimental_config_file) -- [References](#references) - - - -## Overview - -File configuration provides a mechanism for configuring OpenTelemetry which is -more expressive and full-featured than -the [environment variable](sdk-environment-variables.md) based scheme, and -language agnostic in a way not possible -with [programmatic configuration](sdk-configuration.md#programmatic). - -File configuration defines a [Configuration Model](#configuration-model), -which can be expressed in a [configuration file](#configuration-file). -Configuration files can be validated against the Configuration Schema, and -interpreted to produce configured OpenTelemetry components. - -## Configuration Model - -The configuration model is defined -in [opentelemetry-configuration](https://github.com/open-telemetry/opentelemetry-configuration) -using the [JSON Schema](https://json-schema.org/). - -### Stability Definition - -TODO: define stability guarantees and backwards compatibility - -## Configuration file - -A configuration file is a serialized file-based representation of -the [Configuration Model](#configuration-model). - -Configuration files SHOULD use one the following serialization formats: - -### YAML file format - -[YAML](https://yaml.org/spec/1.2.2/) configuration files SHOULD follow YAML spec -revision >= 1.2. - -YAML configuration files SHOULD be parsed using [v1.2 YAML core schema](https://yaml.org/spec/1.2.2/#103-core-schema). - -YAML configuration files MUST use file extensions `.yaml` or `.yml`. - -### Environment variable substitution - -Configuration files support environment variables substitution for references -which match the following PCRE2 regular expression: - -```regexp -\$\{(?:env:)?(?[a-zA-Z_][a-zA-Z0-9_]*)(:-(?[^\n]*))?\} -``` - -The `ENV_NAME` MUST start with an alphabetic or `_` character, and is followed -by 0 or more alphanumeric or `_` characters. - -For example, `${API_KEY}` and `${env:API_KEY}` are valid, while `${1API_KEY}` -and `${API_$KEY}` are invalid. - -Environment variable substitution MUST only apply to scalar values. Mapping keys -are not candidates for substitution. - -The `DEFAULT_VALUE` is an optional fallback value which is substituted -if `ENV_NAME` is null, empty, or undefined. `DEFAULT_VALUE` consists of 0 or -more non line break characters (i.e. any character except `\n`). If a referenced -environment variable is not defined and does not have a `DEFAULT_VALUE`, it MUST -be replaced with an empty value. - -When parsing a configuration file that contains a reference not matching -the references regular expression but does match the following PCRE2 -regular expression, the parser MUST return an empty result (no partial -results are allowed) and an error describing the parse failure to the user. - -```regexp -\$\{(?[^}]+)\} -``` - -Node types MUST be interpreted after environment variable substitution takes -place. This ensures the environment string representation of boolean, integer, -or floating point fields can be properly converted to expected types. - -It MUST NOT be possible to inject YAML structures by environment variables. For -example, references to `INVALID_MAP_VALUE` environment variable below. - -It MUST NOT be possible to inject environment variable by environment variables. -For example, references to `DO_NOT_REPLACE_ME` environment variable below. - -For example, consider the following environment variables, -and [YAML](#yaml-file-format) configuration file: - -```shell -export STRING_VALUE="value" -export BOOL_VALUE="true" -export INT_VALUE="1" -export FLOAT_VALUE="1.1" -export HEX_VALUE="0xdeadbeef" # A valid integer value written in hexadecimal -export INVALID_MAP_VALUE="value\nkey:value" # An invalid attempt to inject a map key into the YAML -export DO_NOT_REPLACE_ME="Never use this value" # An unused environment variable -export REPLACE_ME='${DO_NOT_REPLACE_ME}' # A valid replacement text, used verbatim, not replaced with "Never use this value" -``` - -```yaml -string_key: ${STRING_VALUE} # Valid reference to STRING_VALUE -env_string_key: ${env:STRING_VALUE} # Valid reference to STRING_VALUE -other_string_key: "${STRING_VALUE}" # Valid reference to STRING_VALUE inside double quotes -another_string_key: "${BOOL_VALUE}" # Valid reference to BOOL_VALUE inside double quotes -string_key_with_quoted_hex_value: "${HEX_VALUE}" # Valid reference to HEX_VALUE inside double quotes -yet_another_string_key: ${INVALID_MAP_VALUE} # Valid reference to INVALID_MAP_VALUE, but YAML structure from INVALID_MAP_VALUE MUST NOT be injected -bool_key: ${BOOL_VALUE} # Valid reference to BOOL_VALUE -int_key: ${INT_VALUE} # Valid reference to INT_VALUE -int_key_with_unquoted_hex_value: ${HEX_VALUE} # Valid reference to HEX_VALUE without quotes -float_key: ${FLOAT_VALUE} # Valid reference to FLOAT_VALUE -combo_string_key: foo ${STRING_VALUE} ${FLOAT_VALUE} # Valid reference to STRING_VALUE and FLOAT_VALUE -string_key_with_default: ${UNDEFINED_KEY:-fallback} # UNDEFINED_KEY is not defined but a default value is included -undefined_key: ${UNDEFINED_KEY} # Invalid reference, UNDEFINED_KEY is not defined and is replaced with "" -${STRING_VALUE}: value # Invalid reference, substitution is not valid in mapping keys and reference is ignored -recursive_key: ${REPLACE_ME} # Valid reference to REPLACE_ME -# invalid_identifier_key: ${STRING_VALUE:?error} # If uncommented, this is an invalid identifier, it would fail to parse -``` - -Environment variable substitution results in the following YAML: - -```yaml -string_key: value # Interpreted as type string, tag URI tag:yaml.org,2002:str -env_string_key: value # Interpreted as type string, tag URI tag:yaml.org,2002:str -other_string_key: "value" # Interpreted as type string, tag URI tag:yaml.org,2002:str -another_string_key: "true" # Interpreted as type string, tag URI tag:yaml.org,2002:str -string_key_with_quoted_hex_value: "0xdeadbeef" # Interpreted as type string, tag URI tag:yaml.org,2002:str -yet_another_string_key: "value\nkey:value" # Interpreted as type string, tag URI tag:yaml.org,2002:str -bool_key: true # Interpreted as type bool, tag URI tag:yaml.org,2002:bool -int_key: 1 # Interpreted as type int, tag URI tag:yaml.org,2002:int -int_key_with_unquoted_hex_value: 3735928559 # Interpreted as type int, tag URI tag:yaml.org,2002:int -float_key: 1.1 # Interpreted as type float, tag URI tag:yaml.org,2002:float -combo_string_key: foo value 1.1 # Interpreted as type string, tag URI tag:yaml.org,2002:str -string_key_with_default: fallback # Interpreted as type string, tag URI tag:yaml.org,2002:str -undefined_key: # Interpreted as type null, tag URI tag:yaml.org,2002:null -${STRING_VALUE}: value # Interpreted as type string, tag URI tag:yaml.org,2002:str -recursive_key: ${DO_NOT_REPLACE_ME} # Interpreted as type string, tag URI tag:yaml.org,2002:str -``` - -## SDK Configuration - -SDK configuration defines the interfaces and operations that SDKs are expected -to expose to enable file based configuration. - -### In-Memory Configuration Model - -SDKs SHOULD provide an in-memory representation of -the [Configuration Model](#configuration-model). In general, SDKs are encouraged -to provide this in-memory representation in a manner that is idiomatic for their -language. If an SDK needs to expose a class or interface, the -name `Configuration` is RECOMMENDED. - -### SDK Extension Components - -The SDK supports a variety of -extension [plugin interfaces](../glossary.md#sdk-plugins), allowing users and -libraries to customize behaviors including the sampling, processing, and -exporting of data. In general, the [configuration model](#configuration-model) -defines specific types for built-in implementations of these plugin interfaces. -For example, -the [BatchSpanProcessor](https://github.com/open-telemetry/opentelemetry-configuration/blob/f38ac7c3a499ae5f81924ef9c455c27a56130562/schema/tracer_provider.json#L22) -type refers to the -built-in [Batching span processor](../trace/sdk.md#batching-processor). The -schema SHOULD also support the ability to specify custom implementations of -plugin interfaces defined by libraries or users. - -For example, a custom [span exporter](../trace/sdk.md#span-exporter) might be configured as follows: - -```yaml -tracer_provider: - processors: - - batch: - exporter: - my-exporter: - config-parameter: value -``` - -Here we specify that the tracer provider has a batch span processor -paired with a custom span exporter named `my-exporter`, which is configured -with `config-parameter: value`. For this configuration to succeed, -a [component provider](#component-provider) must -be [registered](#register-component-provider) with `type: SpanExporter`, -and `name: my-exporter`. When [parse](#parse) is called, the implementation will -encounter `my-exporter` and translate the corresponding configuration to an -equivalent generic `properties` representation ( -i.e. `properties: {config-parameter: value}`). When [create](#create) is called, -the implementation will encounter `my-exporter` and -invoke [create plugin](#create-plugin) on the registered component provider -with the configuration `properties` determined during `parse`. - -Given the inherent differences across languages, the details of extension -component mechanisms are likely to vary to a greater degree than is the case -with other APIs defined by OpenTelemetry. This is to be expected and is -acceptable so long as the implementation results in the defined behaviors. - -#### Component Provider - -A component provider is responsible for interpreting configuration and returning -an implementation of a particular type of SDK extension plugin interface. - -Component providers are registered with an SDK implementation of configuration -via [register](#register-component-provider). This MAY be done automatically or -require manual intervention by the user based on what is possible and idiomatic -in the language ecosystem. For example in Java, component providers might be -registered automatically using -the [service provider interface (SPI)](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html) -mechanism. - -See [create](#create), which details component provider usage in file -configuration interpretation. - -#### Create Plugin - -Interpret configuration to create a instance of a SDK extension plugin -interface. - -**Parameters:** - -* `properties` - The configuration properties. Properties MUST fully represent - the configuration as specified in - the [configuration file](#configuration-file), including the ability to access - scalars, mappings, and sequences (of scalars and other structures). It MUST be - possible to determine if a particular property is present. It SHOULD be - possible to access properties in a type safe manner, based on what is idiomatic - in the language. - -**Returns:** A configured SDK extension plugin interface implementation. - -The plugin interface MAY have properties which are optional or required, and -have specific requirements around type or format. The set of properties a -component provider accepts, along with their requirement level and expected -type, comprise a configuration schema. A component provider SHOULD document its -configuration schema. - -When Create Plugin is invoked, the component provider interprets `properties` -and attempts to extract data according to its configuration schema. If this -fails (e.g. a required property is not present, a type is mismatches, etc.), -Create Plugin SHOULD return an error. - -### Operations - -SDK implementations of configuration MUST provide the following operations. - -Note: Because these operations are stateless pure functions, they are not -defined as part of any type, class, interface, etc. SDKs may organize them in -whatever manner is idiomatic for the language. - -TODO: Add operation to update SDK components with new configuration for usage -with OpAmp - -#### Parse - -Parse and validate a [configuration file](#configuration-file). - -**Parameters:** - -* `file`: The [configuration file](#configuration-file) to parse. This MAY be a - file path, or language specific file data structure, or a stream of a file's content. -* `file_format`: The file format of the `file` (e.g. [yaml](#yaml-file-format)). - Implementations MAY accept a `file_format` parameter, or infer it from - the `file` extension, or include file format specific overloads of `parse`, - e.g. `parseYaml(file)`. If `parse` accepts `file_format`, the API SHOULD be - structured so a user is obligated to provide it. - -**Returns:** [configuration model](#in-memory-configuration-model) - -Parse MUST perform [environment variable substitution](#environment-variable-substitution). - -Parse MUST interpret null as equivalent to unset. - -When encountering a reference to -a [SDK extension component](#sdk-extension-components) which is not built in to -the SDK, Parse MUST resolve corresponding configuration to a -generic `properties` representation as described -in [Create Plugin](#create-plugin). - -Parse SHOULD return an error if: - -* The `file` doesn't exist or is invalid -* The parsed `file` content does not conform to - the [configuration model](#configuration-model) schema. - -#### Create - -Interpret [configuration model](#in-memory-configuration-model) and return SDK components. - -**Parameters:** - -* `configuration` - The configuration model. - -**Returns:** Top level SDK components: - -* `TracerProvider` -* `MeterProvider` -* `LoggerProvider` -* `Propagators` - -The multiple responses MAY be returned using a tuple, or some other data -structure encapsulating the components. - -If a field is null or unset and a default value is defined, Create MUST ensure -the SDK component is configured with the default value. If a field is null or -unset and no default value is defined, Create SHOULD return an error. For -example, if configuring -the [span batching processor](../trace/sdk.md#batching-processor) and -the `scheduleDelayMillis` field is null or unset, the component is configured -with the default value of `5000`. However, if the `exporter` field is null or -unset, Create fails fast since there is no default value for `exporter`. - -When encountering a reference to -a [SDK extension component](#sdk-extension-components) which is not built in to -the SDK, Create MUST resolve the component using [Create Plugin](#create-plugin) -of the [component provider](#component-provider) of the corresponding `type` -and `name` used to [register](#register-component-provider), including the -configuration `properties` as an argument. If no component provider is -registered with the `type` and `name`, Create SHOULD return an error. -If [Create Plugin](#create-plugin) returns an error, Create SHOULD propagate the -error. - -This SHOULD return an error if it encounters an error in `configuration` (i.e. -fail fast) in accordance with -initialization [error handling principles](../error-handling.md#basic-error-handling-principles). - -TODO: define behavior if some portion of configuration model is not supported - -#### Register Component Provider - -The file configuration implementation MUST provide a mechanism to -register [component providers](#component-provider). - -**Parameters:** - -* `component_provider` - The [component provider](#component-provider). -* `type` - The type of plugin interface it provides (e.g. SpanExporter, Sampler, - etc). -* `name` - The name used to identify the type of component. This is used - in [configuration files](#configuration-file) to specify that the - corresponding `component_provider` is to provide the component. - -The `type` and `name` comprise a unique key. Register MUST return an error if it -is called multiple times with the same `type` and `name` combination. - -## Examples - -### Via File Configuration API - -The file configuration [Parse](#parse) and [Create](#create) operations along -with the [Configuration Model](#configuration-model) can be combined in a -variety of ways to achieve simple or complex configuration goals. - -For example, a simple case would consist of calling `Parse` with a configuration -file, and passing the result to `Create` to obtain configured SDK components: - -```java -OpenTelemetry openTelemetry = OpenTelemetry.noop(); -try { - // Parse configuration file to configuration model - OpenTelemetryConfiguration configurationModel = FileConfiguration.parse(new File("/app/sdk-config.yaml")); - // Create SDK components from configuration model - openTelemetry = FileConfiguration.create(configurationModel); -} catch (Throwable e) { - log.error("Error initializing SDK from configuration file", e); -} - -// Access SDK components and install instrumentation -TracerProvider tracerProvider = openTelemetry.getTracerProvider(); -MeterProvider meterProvider = openTelemetry.getMeterProvider(); -LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); -ContextPropagators propagators = openTelemetry.getPropagators(); -``` - -A more complex case might consist of parsing multiple configuration files from -different sources, merging them using custom logic, and creating SDK components -from the merged configuration model: - -```java -OpenTelemetry openTelemetry = OpenTelemetry.noop(); -try { - // Parse local and remote configuration files to configuration models - OpenTelemetryConfiguration localConfigurationModel = FileConfiguration.parse(new File("/app/sdk-config.yaml")); - OpenTelemetryConfiguration remoteConfigurationModel = FileConfiguration.parse(getRemoteConfiguration("http://example-host/config/my-application")); - - // Merge the configuration models using custom logic - OpenTelemetryConfiguration resolvedConfigurationModel = merge(localConfigurationModel, remoteConfigurationModel); - - // Create SDK components from resolved configuration model - openTelemetry = FileConfiguration.create(resolvedConfigurationModel); -} catch (Throwable e) { - log.error("Error initializing SDK from configuration file", e); -} - -// Access SDK components and install instrumentation -TracerProvider tracerProvider = openTelemetry.getTracerProvider(); -MeterProvider meterProvider = openTelemetry.getMeterProvider(); -LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); -ContextPropagators propagators = openTelemetry.getPropagators(); -``` - -### Via OTEL_EXPERIMENTAL_CONFIG_FILE - -If an SDK -supports [OTEL_EXPERIMENTAL_CONFIG_FILE](./sdk-environment-variables.md#file-configuration), -then setting `OTEL_EXPERIMENTAL_CONFIG_FILE` provides a simple way to obtain an -SDK initialized from the specified config file. The pattern for accessing the -configured SDK components and installing into instrumentation will vary by -language. For example, the usage in Java might resemble: - -```shell -# Set the required env var to the location of the configuration file -export OTEL_EXPERIMENTAL_CONFIG_FILE="/app/sdk-config.yaml" -``` - -```java -// Initialize SDK using autoconfigure model, which recognizes that OTEL_EXPERIMENTAL_CONFIG_FILE is set and configures the SDK accordingly -OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); - -// Access SDK components and install instrumentation -TracerProvider tracerProvider = openTelemetry.getTracerProvider(); -MeterProvider meterProvider = openTelemetry.getMeterProvider(); -LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); -ContextPropagators propagators = openTelemetry.getPropagators(); -``` - -If using auto-instrumentation, this initialization flow might occur -automatically. - -## References - -* Configuration - proposal ([OTEP #225](https://github.com/open-telemetry/oteps/pull/225)) diff --git a/specification/configuration/sdk-configuration.md b/specification/configuration/sdk-configuration.md deleted file mode 100644 index 5eb99024b12..00000000000 --- a/specification/configuration/sdk-configuration.md +++ /dev/null @@ -1,56 +0,0 @@ - - -# Default SDK Configuration - -
-Table of Contents - - - -- [Abstract](#abstract) -- [Configuration Interface](#configuration-interface) - * [Programmatic](#programmatic) - * [Environment Variables](#environment-variables) - * [Configuration File](#configuration-file) - * [Other Mechanisms](#other-mechanisms) - - - -
- -## Abstract - -The default Open Telemetry SDK (hereafter referred to as "The SDK") -is highly configurable. This specification outlines the mechanisms by -which the SDK can be configured. It does -not attempt to specify the details of what can be configured. - -## Configuration Interface - -### Programmatic - -The SDK MUST provide a programmatic interface for all configuration. -This interface SHOULD be written in the language of the SDK itself. -All other configuration mechanisms SHOULD be built on top of this interface. - -An example of this programmatic interface is accepting a well-defined -struct on an SDK builder class. From that, one could build a CLI that accepts a -file (YAML, JSON, TOML, ...) and then transforms into that well-defined struct -consumable by the programmatic interface. - -### Environment Variables - -See [OpenTelemetry Environment Variable Specification](./sdk-environment-variables.md). - -### Configuration File - -See [File Configuration](./file-configuration.md). - -### Other Mechanisms - -Additional configuration mechanisms SHOULD be provided in whatever -language/format/style is idiomatic for the language of the SDK. The -SDK can include as many configuration mechanisms as appropriate. diff --git a/specification/configuration/sdk-environment-variables.md b/specification/configuration/sdk-environment-variables.md index 50923b015f5..a19a2f3c1f6 100644 --- a/specification/configuration/sdk-environment-variables.md +++ b/specification/configuration/sdk-environment-variables.md @@ -35,7 +35,7 @@ aliases: - [Metrics SDK Configuration](#metrics-sdk-configuration) * [Exemplar](#exemplar) * [Periodic exporting MetricReader](#periodic-exporting-metricreader) -- [File Configuration](#file-configuration) +- [Declarative configuration](#declarative-configuration) - [Language Specific Environment Variables](#language-specific-environment-variables) @@ -296,25 +296,25 @@ that use [periodic exporting MetricReader](../metrics/sdk.md#periodic-exporting- | `OTEL_METRIC_EXPORT_INTERVAL` | The time interval (in milliseconds) between the start of two export attempts. | 60000 | | | `OTEL_METRIC_EXPORT_TIMEOUT` | Maximum allowed time (in milliseconds) to export data. | 30000 | | -## File Configuration +## Declarative configuration **Status**: [Development](../document-status.md) -Environment variables involved in [file configuration](file-configuration.md). +Environment variables involved in [declarative configuration](./README.md#declarative-configuration). | Name | Description | Default | Notes | |-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|-----------| | OTEL_EXPERIMENTAL_CONFIG_FILE | The path of the configuration file used to configure the SDK. If set, the configuration in this file takes precedence over all other SDK configuration environment variables. | | See below | If `OTEL_EXPERIMENTAL_CONFIG_FILE` is set, the file at the specified path is used to -call [Parse](file-configuration.md#parse). The -resulting [configuration model](./file-configuration.md#configuration-model) is -used to call [Create](file-configuration.md#create) to produce fully configured +call [Parse](./sdk.md#parse). The +resulting [configuration model](./sdk.md#in-memory-configuration-model) is +used to call [Create](./sdk.md#create) to produce fully configured SDK components. When `OTEL_EXPERIMENTAL_CONFIG_FILE` is set, all other environment variables besides those referenced in the configuration file -for [environment variable substitution](file-configuration.md#environment-variable-substitution) +for [environment variable substitution](./data-model.md#environment-variable-substitution) MUST be ignored. Ignoring the environment variables is necessary because there is no intuitive way to merge the flat environment variable scheme with the structured file configuration scheme in all cases. Users that require merging diff --git a/specification/configuration/sdk.md b/specification/configuration/sdk.md new file mode 100644 index 00000000000..7baa0e18367 --- /dev/null +++ b/specification/configuration/sdk.md @@ -0,0 +1,353 @@ +# Configuration SDK + +**Status**: [Development](../document-status.md) + + + +- [Overview](#overview) + * [In-Memory configuration model](#in-memory-configuration-model) + * [ConfigProvider](#configprovider) + * [SDK extension components](#sdk-extension-components) + + [ComponentProvider](#componentprovider) + - [ComponentsProvider operations](#componentsprovider-operations) + * [Create Plugin](#create-plugin) + * [Config operations](#config-operations) + + [Parse](#parse) + + [Create](#create) + + [Register ComponentProvider](#register-componentprovider) + * [Examples](#examples) + + [Via configuration API](#via-configuration-api) + + [Via OTEL_EXPERIMENTAL_CONFIG_FILE](#via-otel_experimental_config_file) + * [References](#references) + + + +## Overview + +The configuration SDK is part of +the [declarative configuration interface](./README.md#declarative-configuration). + +The SDK is an implementation +of [Instrumenation Config API](./api.md) and other +user facing declarative configuration capabilities. It consists of the following main +components: + +* [In-Memory configuration model](#in-memory-configuration-model) is an + in-memory representation of the [configuration model](./data-model.md). +* [ConfigProvider](#configprovider) defines the SDK implementation + of the [ConfigProvider API](./api.md#configprovider). +* [SDK extension components](#sdk-extension-components) defines how users and + libraries extend file configuration with custom SDK extension plugin + interfaces (exporters, processors, etc). +* [Config operations](#config-operations) defines user APIs to parse + configuration files and produce SDK components from their contents. + +### In-Memory configuration model + +SDKs SHOULD provide an in-memory representation of +the [configuration model](./data-model.md). +Whereas [`ConfigProperties`](./api.md#configproperties) is a schemaless +representation of any mapping node, the in-memory configuration model SHOULD +reflect the schema of the configuration model. + +SDKs are encouraged to provide this in-memory representation in a manner that is +idiomatic for their language. If an SDK needs to expose a class or interface, +the name `Configuration` is RECOMMENDED. + +### ConfigProvider + +The SDK implementation of [`ConfigProvider`](./api.md#configprovider) MUST be +created using a [`ConfigProperties`](./api.md#configproperties) representing +the [`.instrumentation`](https://github.com/open-telemetry/opentelemetry-configuration/blob/670901762dd5cce1eecee423b8660e69f71ef4be/examples/kitchen-sink.yaml#L438-L439) +mapping node of the [configuration model](./data-model.md). + +### SDK extension components + +The SDK supports a variety of +extension [plugin interfaces](../glossary.md#sdk-plugins), allowing users and +libraries to customize behaviors including the sampling, processing, and +exporting of data. In general, the [configuration data model](./data-model.md) +defines specific types for built-in implementations of these plugin interfaces. +For example, +the [BatchSpanProcessor](https://github.com/open-telemetry/opentelemetry-configuration/blob/f38ac7c3a499ae5f81924ef9c455c27a56130562/schema/tracer_provider.json#L22) +type refers to the +built-in [Batching span processor](../trace/sdk.md#batching-processor). The +schema SHOULD also support the ability to specify custom implementations of +plugin interfaces defined by libraries or users. + +For example, a custom [span exporter](../trace/sdk.md#span-exporter) might be configured as follows: + +```yaml +tracer_provider: + processors: + - batch: + exporter: + my-exporter: + config-parameter: value +``` + +Here we specify that the tracer provider has a batch span processor +paired with a custom span exporter named `my-exporter`, which is configured +with `config-parameter: value`. For this configuration to succeed, +a [`ComponentProvider`](#componentprovider) must +be [registered](#register-componentprovider) with `type: SpanExporter`, +and `name: my-exporter`. When [parse](#parse) is called, the implementation will +encounter `my-exporter` and translate the corresponding configuration to an +equivalent [`ConfigProperties`](./api.md#configproperties) representation ( +i.e. `properties: {config-parameter: value}`). When [create](#create) is called, +the implementation will encounter `my-exporter` and +invoke [create plugin](#create-plugin) on the registered `ComponentProvider`with +the `ConfigProperties` determined during `parse`. + +Given the inherent differences across languages, the details of extension +component mechanisms are likely to vary to a greater degree than is the case +with other APIs defined by OpenTelemetry. This is to be expected and is +acceptable so long as the implementation results in the defined behaviors. + +#### ComponentProvider + +A `ComponentProvider` is responsible for interpreting configuration and returning +an implementation of a particular type of SDK extension plugin interface. + +`ComponentProvider`s are registered with an SDK implementation of configuration +via [register](#register-componentprovider). This MAY be done automatically or +require manual intervention by the user based on what is possible and idiomatic +in the language ecosystem. For example in Java, `ComponentProvider`s might be +registered automatically using +the [service provider interface (SPI)](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html) +mechanism. + +See [create](#create), which details `ComponentProvider` usage in +configuration model interpretation. + +##### ComponentsProvider operations + +The `ComponentsProvider` MUST provide the following functions: + +* [Create Plugin](#create-plugin) + +###### Create Plugin + +Interpret configuration to create a instance of a SDK extension plugin +interface. + +**Parameters:** + +* `properties` - The [`ConfigProperties`](./api.md#configproperties) representing the + configuration specified for the component in + the [configuration model](#in-memory-configuration-model). + +**Returns:** A configured SDK extension plugin interface implementation. + +The plugin interface MAY have properties which are optional or required, and +have specific requirements around type or format. The set of properties a +`ComponentProvider` accepts, along with their requirement level and expected +type, comprise a configuration schema. A `ComponentProvider` SHOULD document its +configuration schema and include examples. + +When Create Plugin is invoked, the `ComponentProvider` interprets `properties` +and attempts to extract data according to its configuration schema. If this +fails (e.g. a required property is not present, a type is mismatches, etc.), +Create Plugin SHOULD return an error. + +### Config operations + +SDK implementations of configuration MUST provide the following operations. + +Note: Because these operations are stateless pure functions, they are not +defined as part of any type, class, interface, etc. SDKs may organize them in +whatever manner is idiomatic for the language. + +TODO: Add operation to update SDK components with new configuration for usage +with OpAmp + +#### Parse + +Parse and validate a [configuration file](./data-model.md#file-based-configuration-model). + +**Parameters:** + +* `file`: The [configuration file](./data-model.md#file-based-configuration-model) to parse. This MAY be a + file path, or language specific file data structure, or a stream of a file's content. +* `file_format`: The file format of the `file` (e.g. [yaml](./data-model.md#yaml-file-format)). + Implementations MAY accept a `file_format` parameter, or infer it from + the `file` extension, or include file format specific overloads of `parse`, + e.g. `parseYaml(file)`. If `parse` accepts `file_format`, the API SHOULD be + structured so a user is obligated to provide it. + +**Returns:** [configuration model](#in-memory-configuration-model) + +Parse MUST perform [environment variable substitution](./data-model.md#environment-variable-substitution). + +Parse MUST interpret null as equivalent to unset. + +When encountering a reference to +a [SDK extension component](#sdk-extension-components) which is not built in to +the SDK, Parse MUST resolve corresponding configuration to a +generic [ConfigProperties](./api.md#configproperties) representation as described +in [Create Plugin](#create-plugin). + +Parse SHOULD return an error if: + +* The `file` doesn't exist or is invalid +* The parsed `file` content does not conform to + the [configuration model](data-model.md) schema. + +#### Create + +Interpret configuration model and return SDK components. + +**Parameters:** + +* `configuration` - An [in-memory configuration model](#in-memory-configuration-model). + +**Returns:** Top level SDK components: + +* [TracerProvider](../trace/sdk.md#tracer-provider) +* [MeterProvider](../metrics/sdk.md#meterprovider) +* [LoggerProvider](../logs/sdk.md#loggerprovider) +* [Propagators](../context/api-propagators.md#composite-propagator) +* [ConfigProvider](#configprovider) + +The multiple responses MAY be returned using a tuple, or some other data +structure encapsulating the components. + +If a field is null or unset and a default value is defined, Create MUST ensure +the SDK component is configured with the default value. If a field is null or +unset and no default value is defined, Create SHOULD return an error. For +example, if configuring +the [span batching processor](../trace/sdk.md#batching-processor) and +the `scheduleDelayMillis` field is null or unset, the component is configured +with the default value of `5000`. However, if the `exporter` field is null or +unset, Create fails fast since there is no default value for `exporter`. + +When encountering a reference to +a [SDK extension component](#sdk-extension-components) which is not built in to +the SDK, Create MUST resolve the component using [Create Plugin](#create-plugin) +of the [`ComponentProvider`](#componentprovider) of the corresponding `type` +and `name` used to [register](#register-componentprovider), including the +configuration `properties` as an argument. If no `ComponentProvider` is +registered with the `type` and `name`, Create SHOULD return an error. +If [Create Plugin](#create-plugin) returns an error, Create SHOULD propagate the +error. + +This SHOULD return an error if it encounters an error in `configuration` (i.e. +fail fast) in accordance with +initialization [error handling principles](../error-handling.md#basic-error-handling-principles). + +TODO: define behavior if some portion of configuration model is not supported + +#### Register ComponentProvider + +The SDK MUST provide a mechanism to +register [`ComponentProvider`](#componentprovider). The mechanism MAY be +language-specific and automatic. For example, a java implementation might use +the [service provider interface](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html) +mechanism to register implementations of a particular interface +as `ComponentProvider`s. + +**Parameters:** + +* `component_provider` - The `ComponentProvider`. +* `type` - The type of plugin interface it provides (e.g. SpanExporter, Sampler, + etc). +* `name` - The name used to identify the type of component. This is used + in [configuration model](./data-model.md) to specify that the + corresponding `component_provider` is to provide the component. + +The `type` and `name` comprise a unique key. Register MUST return an error if it +is called multiple times with the same `type` and `name` combination. + +### Examples + +#### Via configuration API + +The configuration [Parse](#parse) and [Create](#create) operations along +with the [Configuration Model](./data-model.md) can be combined in a +variety of ways to achieve simple or complex configuration goals. + +For example, a simple case would consist of calling `Parse` with a configuration +file, and passing the result to `Create` to obtain configured SDK components: + +```java +OpenTelemetry openTelemetry = OpenTelemetry.noop(); +try { + // Parse configuration file to configuration model + OpenTelemetryConfiguration configurationModel = parse(new File("/app/sdk-config.yaml")); + // Create SDK components from configuration model + openTelemetry = create(configurationModel); +} catch (Throwable e) { + log.error("Error initializing SDK from configuration file", e); +} + +// Access SDK components and install instrumentation +TracerProvider tracerProvider = openTelemetry.getTracerProvider(); +MeterProvider meterProvider = openTelemetry.getMeterProvider(); +LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); +ContextPropagators propagators = openTelemetry.getPropagators(); +ConfigProvider configProvider = openTelemetry.getConfigProvider(); +``` + +A more complex case might consist of parsing multiple configuration files from +different sources, merging them using custom logic, and creating SDK components +from the merged configuration model: + +```java +OpenTelemetry openTelemetry = OpenTelemetry.noop(); +try { + // Parse local and remote configuration files to configuration models + OpenTelemetryConfiguration localConfigurationModel = parse(new File("/app/sdk-config.yaml")); + OpenTelemetryConfiguration remoteConfigurationModel = parse(getRemoteConfiguration("http://example-host/config/my-application")); + + // Merge the configuration models using custom logic + OpenTelemetryConfiguration resolvedConfigurationModel = merge(localConfigurationModel, remoteConfigurationModel); + + // Create SDK components from resolved configuration model + openTelemetry = create(resolvedConfigurationModel); +} catch (Throwable e) { + log.error("Error initializing SDK from configuration file", e); +} + +// Access SDK components and install instrumentation +TracerProvider tracerProvider = openTelemetry.getTracerProvider(); +MeterProvider meterProvider = openTelemetry.getMeterProvider(); +LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); +ContextPropagators propagators = openTelemetry.getPropagators(); +ConfigProvider configProvider = openTelemetry.getConfigProvider(); +``` + +#### Via OTEL_EXPERIMENTAL_CONFIG_FILE + +Setting +the [OTEL_EXPERIMENTAL_CONFIG_FILE](./sdk-environment-variables.md#declarative-configuration) +environment variable (for languages that support it) provides users a convenient +way to initialize OpenTelemetry components without needing to learn +language-specific configuration details or use a large number of environment +variables. The pattern for accessing the configured components and installing +into instrumentation will vary by language. For example, the usage in Java might +resemble: + +```shell +# Set the required env var to the location of the configuration file +export OTEL_EXPERIMENTAL_CONFIG_FILE="/app/sdk-config.yaml" +``` + +```java +// Initialize SDK using autoconfigure model, which recognizes that OTEL_EXPERIMENTAL_CONFIG_FILE is set and configures the SDK accordingly +OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); + +// Access SDK components and install instrumentation +TracerProvider tracerProvider = openTelemetry.getTracerProvider(); +MeterProvider meterProvider = openTelemetry.getMeterProvider(); +LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); +ContextPropagators propagators = openTelemetry.getPropagators(); +ConfigProvider configProvider = openTelemetry.getConfigProvider(); +``` + +If using auto-instrumentation, this initialization flow might occur +automatically. + +### References + +* Configuration + proposal ([OTEP #225](https://github.com/open-telemetry/oteps/pull/225)) diff --git a/specification/vendors.md b/specification/vendors.md index 6ce2333f47e..2256a97ebf0 100644 --- a/specification/vendors.md +++ b/specification/vendors.md @@ -20,7 +20,7 @@ The OpenTelemetry project consists of both a [specification](https://github.com/open-telemetry/opentelemetry-specification) for the API, SDK, protocol and semantic conventions, as well as an implementation of each for a number of languages. The default SDK implementation -is [highly configurable](configuration/sdk-configuration.md) and extendable, for example +is [highly configurable](configuration/README.md) and extendable, for example through [Span Processors](trace/sdk.md#span-processor), to allow for additional logic needed by particular vendors to be added without having to implement a custom SDK. By not requiring a custom SDK means for most languages a user will