OpenTelemetry SDKs and language agents read their exporter settings from environment variables. The same variables work for every language and both protocols.
The environment variables
export OTEL_EXPORTER_OTLP_ENDPOINT=https://obs-ingest.ezghcloud.com
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf # or grpc, or http/json
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer%20${EZGH_INGEST_KEY}"
export OTEL_RESOURCE_ATTRIBUTES="service.name=checkout,ezgh.metadata.application=storefront,ezgh.metadata.environment=production"
export OTEL_LOGS_EXPORTER=otlp
export OTEL_TRACES_EXPORTER=none
export OTEL_METRICS_EXPORTER=none| Variable | Value |
|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
https://obs-ingest.ezghcloud.com, the base URL, for every protocol. HTTP exporters add /v1/logs; gRPC exporters connect to port 443 with TLS. |
OTEL_EXPORTER_OTLP_PROTOCOL |
grpc, http/protobuf or http/json. All three are accepted. Set it explicitly: defaults differ between SDKs. |
OTEL_EXPORTER_OTLP_HEADERS |
authorization=Bearer%20<ingest key>. The value uses the W3C Baggage format, where the space is written %20; SDKs decode it. |
OTEL_RESOURCE_ATTRIBUTES |
service.name, ezgh.metadata.application and ezgh.metadata.environment. See service metadata. |
OTEL_LOGS_EXPORTER |
otlp. |
OTEL_TRACES_EXPORTER, OTEL_METRICS_EXPORTER |
none. Only logs are accepted today; traces and metrics are refused with 404 / UNIMPLEMENTED. |
Keep the ingest key in your secret manager and pass it in as EZGH_INGEST_KEY. Don’t put it in
code or images. Don’t set OTEL_EXPORTER_OTLP_LOGS_ENDPOINT unless you need it: it’s used as
the exact URL, without /v1/logs added.
Java
The OpenTelemetry Java agent sends what
your application logs through Logback, Log4j or java.util.logging.
java -javaagent:opentelemetry-javaagent.jar -jar app.jarPython
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
opentelemetry-instrument python app.pyRecords written with the standard logging module are sent.
Node.js
npm install @opentelemetry/api @opentelemetry/auto-instrumentations-node
node --require @opentelemetry/auto-instrumentations-node/register app.jsRecords written with winston, pino or bunyan are sent through their instrumentations.
Go
Go has no agent: create a logger provider with an OTLP exporter. The exporters and
resource.Default() read the environment variables above.
import (
"context"
"go.opentelemetry.io/contrib/bridges/otelslog"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp" // or otlploggrpc
"go.opentelemetry.io/otel/log/global"
sdklog "go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/resource"
)
func setupLogs(ctx context.Context) (*sdklog.LoggerProvider, error) {
exporter, err := otlploghttp.New(ctx)
if err != nil {
return nil, err
}
provider := sdklog.NewLoggerProvider(
sdklog.WithResource(resource.Default()),
sdklog.WithProcessor(sdklog.NewBatchProcessor(exporter)),
)
global.SetLoggerProvider(provider)
return provider, nil // call provider.Shutdown(ctx) before exiting
}
// Then log with log/slog through the bridge:
// logger := otelslog.NewLogger("checkout")
// logger.ErrorContext(ctx, "payment timeout", "order", orderID).NET
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.AddOtlpExporter();
});AddOtlpExporter reads the environment variables above, including OTEL_EXPORTER_OTLP_PROTOCOL.
Check that it works
Send a log line, then search for it a few seconds later:
ezgh obs search --environment production --from 5m --project webIf nothing arrives, see Troubleshooting. An exporter logs the status it gets back.