Environment variables¶
Who actually reads these¶
Not this module. otelcore, tracing, metrics and logs contain no os.Getenv
call. Every variable below is read by the OpenTelemetry SDK or by the OTLP/HTTP
exporters underneath, and the only thing this module decides is which SDK options it
passes on top — because an explicitly-passed option always wins over an environment
variable.
That single rule explains the whole page. A variable works when this module passes no option for that setting, and is ignored when it does.
Everything here was read from otel/sdk v1.44.0, the OTLP/HTTP exporters at v1.44.0
(sdk/log v0.20.0), and confirmed by exporting to a real collector.
Choosing the target: OTEL_EXPORTER_OTLP_ENDPOINT¶
| Variable | Applies when |
|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
Settings.Endpoint is "" |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT |
Settings.Endpoint is "" (traces only; wins over the generic form) |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT |
Settings.Endpoint is "" (metrics only) |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT |
Settings.Endpoint is "" (logs only) |
A non-empty Settings.Endpoint makes this module pass WithEndpoint and WithURLPath,
and the variables are then ignored. There is no way to make configuration and
environment cooperate on the endpoint: one or the other decides.
The signal-specific form takes the URL whole, including the path. The generic form
takes a base and the SDK appends /v1/traces, /v1/metrics or /v1/logs — the same
thing this module does with a configured endpoint.
If neither is set and Settings.Endpoint is empty, the exporter does not do
nothing. It falls back to the SDK default of localhost:4318, and every export attempt
fails against a machine with no collector on it. An empty endpoint means "somebody else
will say where", never "disabled".
Variables that still apply when you configure an endpoint¶
These change settings this module passes no option for, so they work on both paths — the
env-fallback path and a configured Settings.Endpoint. Each also has a
signal-specific form (OTEL_EXPORTER_OTLP_TRACES_TIMEOUT, and so on).
| Variable | Effect | Default |
|---|---|---|
OTEL_EXPORTER_OTLP_TIMEOUT |
Per-request timeout, in milliseconds | 10000 |
OTEL_EXPORTER_OTLP_COMPRESSION |
gzip or none |
none |
OTEL_EXPORTER_OTLP_CERTIFICATE |
PEM file of trusted CA certificates | system roots |
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE |
Client certificate for mTLS | unset |
OTEL_EXPORTER_OTLP_CLIENT_KEY |
Client key for mTLS | unset |
HTTPS_PROXY / HTTP_PROXY / NO_PROXY |
Standard Go proxy resolution | unset |
The TLS variables are the only route to a private CA or to mTLS — this module exposes no
WithTLSClientConfig equivalent.
Combining OTEL_EXPORTER_OTLP_CERTIFICATE with an insecure endpoint is rejected at
construction time: the exporter refuses a TLS config on a plaintext connection, and
NewProvider returns creating OTLP … exporter. See Errors.
OTEL_EXPORTER_OTLP_HEADERS replaces, or is replaced — it never merges¶
| Situation | Result |
|---|---|
Settings.Headers is empty and the variable is set |
The variable's headers are sent |
Settings.Headers is non-empty |
The configured map is sent and the variable is discarded entirely |
This module passes WithHeaders(s.Headers) whenever the map is non-empty, on both the
configured-endpoint and env-fallback paths, and the SDK's WithHeaders assigns the map
rather than merging into it. So a service with a single telemetry.headers entry loses
every header an operator set in the environment — including on the env-fallback path,
where the endpoint is coming from the environment and the headers are not.
If you need both, merge them in your own configuration layer before building Settings.
OTEL_EXPORTER_OTLP_INSECURE can downgrade a configured https:// endpoint¶
This one is worth stating plainly, because it runs against what the rest of the module
does. otelcore.ParseEndpoint validates the scheme and rejects anything but http and
https — and then OTEL_EXPORTER_OTLP_INSECURE=true can still make an https://
endpoint export in plaintext.
The mechanism: the SDK applies environment configuration first and options second, and
this module only ever adds WithInsecure(). It never adds the SDK's WithSecure(), so
there is nothing to undo an insecure flag that arrived from the environment.
Settings.Endpoint |
Settings.Insecure |
Environment | Wire protocol |
|---|---|---|---|
https://host:4318 |
false |
— | TLS |
https://host:4318 |
false |
OTEL_EXPORTER_OTLP_INSECURE=true |
plaintext |
https://host:4318 |
false |
OTEL_EXPORTER_OTLP_ENDPOINT=http://anything |
plaintext |
https://host:4318 |
true |
— | plaintext |
http://host:4318 |
false |
— | plaintext |
The third row is the surprising one. A configured endpoint means the environment's
host is ignored — but the SDK derives an insecure flag from the environment
endpoint's scheme before this module's options are applied, and that flag survives.
So a stale OTEL_EXPORTER_OTLP_ENDPOINT=http://… left over from a local development
setup downgrades production traffic to a host it does not even point at.
Treat both variables as deployment-level switches that outrank your configuration, and
do not rely on an https:// endpoint alone to guarantee TLS.
OTEL_RESOURCE_ATTRIBUTES is merged underneath your resource¶
otelcore.Resource(name, version) builds a resource carrying exactly service.name and
service.version. All three SDK providers then merge that over resource.Environment(),
so OTEL_RESOURCE_ATTRIBUTES does reach the exported resource — for anything that
does not collide.
Resource attributes:
-> deployment.environment: Str(prod)
-> service.instance.id: Str(pod-7)
-> service.name: Str(checkout)
-> service.version: Str(0.1.0)
OTEL_SERVICE_NAME, and a service.name inside OTEL_RESOURCE_ATTRIBUTES, are the
exception: otelcore.Resource always sets service.name, and the explicit resource wins
the merge. The service name is a code-level decision here, not an operator-level one.
What you will not see is anything from resource.Default() — no
telemetry.sdk.name, telemetry.sdk.language or telemetry.sdk.version, and no host or
process attributes. otelcore.Resource uses resource.NewWithAttributes, which runs no
detectors. If your backend groups by service.instance.id or host.name, supply them
through OTEL_RESOURCE_ATTRIBUTES.
Variables this module always overrides¶
Setting any of these changes nothing, because this module unconditionally passes the corresponding SDK option — even when you supply no functional option, since the option carries the package default.
| Variable | Overridden by | Use instead |
|---|---|---|
OTEL_TRACES_SAMPLER |
sdktrace.WithSampler(...), always passed |
tracing.WithSampling(ratio) |
OTEL_TRACES_SAMPLER_ARG |
as above | tracing.WithSampling(ratio) |
OTEL_METRIC_EXPORT_INTERVAL |
sdkmetric.WithInterval(...), always passed |
metrics.WithInterval(d) |
OTEL_METRIC_EXPORT_TIMEOUT is not in this table — this module passes no timeout
option, so that one works.
If you need an operator to be able to change the sampling ratio or the export interval without a rebuild, read the value into your own configuration and pass it to the option.
Batching and limits¶
Passed through untouched, because this module configures none of them.
| Variable group | Applies to | Documented in |
|---|---|---|
OTEL_BSP_* |
Span batch processor | Provider options |
OTEL_BLRP_* |
Log-record batch processor | Provider options |
OTEL_METRIC_EXPORT_TIMEOUT |
Periodic metric reader | Provider options |
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT, OTEL_SPAN_EVENT_COUNT_LIMIT, OTEL_SPAN_LINK_COUNT_LIMIT, OTEL_ATTRIBUTE_COUNT_LIMIT, OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT |
Span limits | OpenTelemetry specification |
OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT, OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT |
Log-record limits | OpenTelemetry specification |
OTEL_METRICS_EXEMPLAR_FILTER |
Whether metric exemplars record trace context | OpenTelemetry specification |
OTEL_SDK_DISABLED is not honoured. It is read by the SDK's own auto-configuration
package, which this module does not use — building a provider always builds a working
one. Use Settings.Enabled and skip the constructor.