# Configuration

Sources, highest priority first:

| # | Source |
|---|---|
| 1 | `OTEL_CONFIG_FILE` (YAML) — overrides everything below |
| 2 | `config :otel, ...` in `config/*.exs` |
| 3 | `OTEL_*` environment variables |
| 4 | Built-in defaults |

## Application env

```elixir
import Config

config :otel,
  trace: [
    resource: Otel.SDK.Resource.create(%{"service.name" => "my_app"}),
    sampler: :parentbased_always_on,
    exporter: :otlp,
    processor: :batch,
    span_limits: %{attribute_count_limit: 256}
  ],
  metrics: [
    resource: Otel.SDK.Resource.create(%{"service.name" => "my_app"}),
    exporter: :otlp,
    reader_config: %{export_interval_ms: 30_000}
  ],
  logs: [
    resource: Otel.SDK.Resource.create(%{"service.name" => "my_app"}),
    exporter: :otlp,
    processor: :batch
  ],
  propagators: [:tracecontext, :baggage]
```

## OS environment

```bash
export OTEL_SERVICE_NAME=my_app
export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=prod,service.version=1.2.3"
export OTEL_TRACES_SAMPLER=parentbased_always_on
export OTEL_TRACES_EXPORTER=otlp
export OTEL_METRICS_EXPORTER=otlp
export OTEL_METRIC_EXPORT_INTERVAL=30000
export OTEL_LOGS_EXPORTER=otlp
export OTEL_PROPAGATORS=tracecontext,baggage
```

## Declarative YAML (`OTEL_CONFIG_FILE`)

Schema: OpenTelemetry Configuration `v1.0.0`.

```yaml
# /etc/otel/config.yaml
file_format: "1.0"

resource:
  attributes_list: ${OTEL_RESOURCE_ATTRIBUTES}

propagator:
  composite:
    - tracecontext:
    - baggage:

tracer_provider:
  sampler:
    parent_based:
      root:
        always_on:
  processors:
    - batch:
        exporter:
          otlp_http:
            endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318}/v1/traces

meter_provider:
  readers:
    - periodic:
        exporter:
          otlp_http:
            endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318}/v1/metrics

logger_provider:
  processors:
    - batch:
        exporter:
          otlp_http:
            endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318}/v1/logs
```

```bash
export OTEL_CONFIG_FILE=/etc/otel/config.yaml
```

`${VAR}` / `${VAR:-default}` substitution works anywhere. More examples in
`test/fixtures/v1.0.0/`.

## Disable the SDK

`OTEL_SDK_DISABLED=true` makes telemetry calls no-ops. Propagator stays active.

## Selectors

Module-valued options (`exporter:`, `processor:`, `sampler:`, items in
`propagators:`) accept:

- a shortcut atom (see tables below)
- a module — same as `{Module, %{}}`
- a `{module, %{...}}` tuple

## Trace pillar

| Option | `config :otel, trace:` | `OTEL_*` | Accepted values | Default |
|---|---|---|---|---|
| Sampler | `sampler:` | `OTEL_TRACES_SAMPLER` | `:always_on` / `:always_off` / `:parentbased_always_on` / `:parentbased_always_off` / `:traceidratio` / `:parentbased_traceidratio` / `{:traceidratio, 0.5}` / `{Module, opts}` | `:parentbased_always_on` |
| Sampler arg | via `{:traceidratio, n}` tuple | `OTEL_TRACES_SAMPLER_ARG` | float in `0.0..1.0` | `1.0` |
| Exporter | `exporter:` | `OTEL_TRACES_EXPORTER` | `:otlp` / `:console` / `:none` / `Module` / `{Module, %{}}` | `:otlp` |
| Processor | `processor:` | — | `:batch` / `:simple` / `Module` | `:batch` |
| Processor list | `processors:` | — | list of `{module, config}` | inferred |
| Batch schedule delay | `processor_config: %{scheduled_delay_ms: _}` | `OTEL_BSP_SCHEDULE_DELAY` | non-negative integer (ms) | `5000` |
| Batch export timeout | `processor_config: %{export_timeout_ms: _}` | `OTEL_BSP_EXPORT_TIMEOUT` | integer (ms); `0` ⇒ `:infinity` | `30000` |
| Batch queue size | `processor_config: %{max_queue_size: _}` | `OTEL_BSP_MAX_QUEUE_SIZE` | positive integer | `2048` |
| Batch export batch size | `processor_config: %{max_export_batch_size: _}` | `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` | positive integer | `512` |
| Span attribute count | `span_limits: %{attribute_count_limit: _}` | `OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT` (or `OTEL_ATTRIBUTE_COUNT_LIMIT`) | non-negative integer | `128` |
| Span attribute value length | `span_limits: %{attribute_value_length_limit: _}` | `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` (or `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT`) | non-negative integer or `:infinity` | `:infinity` |
| Event count | `span_limits: %{event_count_limit: _}` | `OTEL_SPAN_EVENT_COUNT_LIMIT` | non-negative integer | `128` |
| Link count | `span_limits: %{link_count_limit: _}` | `OTEL_SPAN_LINK_COUNT_LIMIT` | non-negative integer | `128` |
| Per-event attribute count | `span_limits: %{attribute_per_event_limit: _}` | `OTEL_EVENT_ATTRIBUTE_COUNT_LIMIT` | non-negative integer | `128` |
| Per-link attribute count | `span_limits: %{attribute_per_link_limit: _}` | `OTEL_LINK_ATTRIBUTE_COUNT_LIMIT` | non-negative integer | `128` |
| Resource | `resource:` | `OTEL_RESOURCE_ATTRIBUTES`, `OTEL_SERVICE_NAME` | `%Otel.SDK.Resource{}` | `telemetry.sdk.*` attributes |
| ID generator | `id_generator:` | — | module | `Otel.SDK.Trace.IdGenerator.Default` |

## Metrics pillar

| Option | `config :otel, metrics:` | `OTEL_*` | Accepted values | Default |
|---|---|---|---|---|
| Exporter | `exporter:` | `OTEL_METRICS_EXPORTER` | `:otlp` / `:console` / `:none` / `Module` / `{Module, %{}}` | `:otlp` |
| Reader list | `readers:` | — | list of `{module, config}` | inferred from `exporter:` |
| Reader export interval | `reader_config: %{export_interval_ms: _}` | `OTEL_METRIC_EXPORT_INTERVAL` | non-negative integer (ms) | `60000` |
| Reader export timeout | `reader_config: %{export_timeout_ms: _}` | `OTEL_METRIC_EXPORT_TIMEOUT` | integer (ms); `0` ⇒ `:infinity` | `30000` |
| Exemplar filter | `exemplar_filter:` | `OTEL_METRICS_EXEMPLAR_FILTER` | `:always_on` / `:always_off` / `:trace_based` | `:trace_based` |
| Views | `views:` | — | list of `Otel.SDK.Metrics.View.t()` | `[]` |
| Resource | `resource:` | `OTEL_RESOURCE_ATTRIBUTES`, `OTEL_SERVICE_NAME` | `%Otel.SDK.Resource{}` | `telemetry.sdk.*` attributes |

## Logs pillar

| Option | `config :otel, logs:` | `OTEL_*` | Accepted values | Default |
|---|---|---|---|---|
| Exporter | `exporter:` | `OTEL_LOGS_EXPORTER` | `:otlp` / `:console` / `:none` / `Module` / `{Module, %{}}` | `:otlp` |
| Processor | `processor:` | — | `:batch` / `:simple` / `Module` | `:batch` |
| Processor list | `processors:` | — | list of `{module, config}` | inferred |
| Batch schedule delay | `processor_config: %{scheduled_delay_ms: _}` | `OTEL_BLRP_SCHEDULE_DELAY` | non-negative integer (ms) | `1000` |
| Batch export timeout | `processor_config: %{export_timeout_ms: _}` | `OTEL_BLRP_EXPORT_TIMEOUT` | integer (ms); `0` ⇒ `:infinity` | `30000` |
| Batch queue size | `processor_config: %{max_queue_size: _}` | `OTEL_BLRP_MAX_QUEUE_SIZE` | positive integer | `2048` |
| Batch export batch size | `processor_config: %{max_export_batch_size: _}` | `OTEL_BLRP_MAX_EXPORT_BATCH_SIZE` | positive integer | `512` |
| LogRecord attribute count | `log_record_limits: %{attribute_count_limit: _}` | `OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT` (or `OTEL_ATTRIBUTE_COUNT_LIMIT`) | non-negative integer | `128` |
| LogRecord attribute value length | `log_record_limits: %{attribute_value_length_limit: _}` | `OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT` (or `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT`) | non-negative integer or `:infinity` | `:infinity` |
| Resource | `resource:` | `OTEL_RESOURCE_ATTRIBUTES`, `OTEL_SERVICE_NAME` | `%Otel.SDK.Resource{}` | `telemetry.sdk.*` attributes |

## Propagators

| Option | `config :otel,` | `OTEL_*` | Accepted values | Default |
|---|---|---|---|---|
| Propagators | `propagators:` | `OTEL_PROPAGATORS` | list of `:tracecontext` / `:baggage` / `:none` (or custom modules) | `[:tracecontext, :baggage]` |

Deduplicated. `[:none]` or `[]` → Noop. `:b3` / `:b3multi` / `:jaeger` /
`:xray` / `:ottrace` raise; supply a custom module instead.

## OTLP HTTP — SSL / TLS

The OTLP HTTP exporter uses Erlang's `:httpc`. For `https://` endpoints,
certificate verification is enabled by default using system CA
certificates (`:public_key.cacerts_get/0`).

To override the defaults — custom CA bundle, mutual TLS, etc. — pass
the exporter explicitly with an `ssl_options:` keyword list:

```elixir
config :otel,
  trace: [
    exporter:
      {Otel.OTLP.Trace.SpanExporter.HTTP,
       %{
         endpoint: "https://collector.example.com:4318/v1/traces",
         ssl_options: [
           verify: :verify_peer,
           cacertfile: "/etc/ssl/certs/ca.crt"
         ]
       }}
  ]
```

`ssl_options:` accepts any
[Erlang `:ssl` client_option](https://www.erlang.org/doc/apps/ssl/ssl.html#client_option).
Common patterns:

| Pattern | Options |
|---|---|
| Custom CA bundle | `verify: :verify_peer, cacertfile: "ca.crt"` |
| Mutual TLS | add `certfile: "client.crt", keyfile: "client.key"` |
| Disable verification (dev only) | `verify: :verify_none` |

The same `{Module, opts}` shape works for `metrics:`
(`Otel.OTLP.Metrics.MetricExporter.HTTP`) and `logs:`
(`Otel.OTLP.Logs.LogRecordExporter.HTTP`).
