Skip to content
GuidesDocs 1.3.x

Backends & Configuration ​

This guide targets the documented 1.3.x release line. Features marked Since 1.3.0 are not available in the published 1.2.x packages until the 1.3.0 release; check the installed package version before using them.

Configure OpenTelemetry exporters, provider management, and integration with observability backends like Jaeger and Grafana.

Environment Variables Reference ​

Service Metadata ​

VariableDescription
OTEL_SERVICE_NAMEOptional service name; falls back to npm_package_name, then unknown-service
OTEL_RESOURCE_ATTRIBUTESComma-separated resource attributes, including service.version and service.namespace

Connectum reads OTEL_SERVICE_NAME, but does not read dedicated OTEL_SERVICE_VERSION or OTEL_SERVICE_NAMESPACE variables. The version defaults to npm_package_version, then 0.0.0. Set additional resource attributes with OTEL_RESOURCE_ATTRIBUTES or ProviderOptions.resourceAttributes.

Exporters ​

VariableDescriptionValues
OTEL_TRACES_EXPORTERTrace exporterotlp, otlp/http, otlp/http-protobuf, otlp/grpc, console, none
OTEL_METRICS_EXPORTERMetrics exporterotlp, otlp/http, otlp/http-protobuf, otlp/grpc, console, none
OTEL_LOGS_EXPORTERLogs exporterotlp, otlp/http, otlp/http-protobuf, otlp/grpc, console, none

otlp takes its transport and encoding from the protocol variables below and sends protobuf-encoded OTLP/HTTP when none is set, as the OpenTelemetry specification defines. otlp/http (JSON), otlp/http-protobuf and otlp/grpc name the transport explicitly and ignore the protocol variables. The bare otlp value, the protocol variables below and otlp/http-protobuf are available since 1.3.0; earlier versions accept only otlp/http and otlp/grpc.

OTLP Endpoints ​

VariableDescription
OTEL_EXPORTER_OTLP_ENDPOINTBase OTLP endpoint. OTLP/HTTP appends /v1/traces, /v1/metrics or /v1/logs. An empty value counts as not set
OTEL_EXPORTER_OTLP_TRACES_ENDPOINTTraces endpoint, used as given (overrides base)
OTEL_EXPORTER_OTLP_METRICS_ENDPOINTMetrics endpoint, used as given (overrides base)
OTEL_EXPORTER_OTLP_LOGS_ENDPOINTLogs endpoint, used as given (overrides base)

With OTLP/HTTP and no endpoint variable set, the exporter sends to http://localhost:4318/v1/<signal>. A value that is not a URL makes the service fail when telemetry is first initialized, rather than exporting elsewhere.

The "overrides base" order holds for OTLP/HTTP. OTLP/gRPC exporters receive a set OTEL_EXPORTER_OTLP_ENDPOINT explicitly, so it takes precedence over the per-signal variables.

OTLP Settings ​

VariableDescription
OTEL_EXPORTER_OTLP_PROTOCOLProtocol for the otlp exporter value: grpc, http/protobuf or http/json. grpc selects OTLP/gRPC; http/protobuf sends protobuf-encoded OTLP/HTTP (Content-Type: application/x-protobuf); http/json sends JSON-encoded OTLP/HTTP (Content-Type: application/json)
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL, OTEL_EXPORTER_OTLP_METRICS_PROTOCOL, OTEL_EXPORTER_OTLP_LOGS_PROTOCOLThe same for one signal (overrides the general variable)
OTEL_EXPORTER_OTLP_HEADERSHeaders (comma-separated key=value)

An unrecognized protocol value is rejected when a signal set to otlp reads it. The explicit otlp/http value predates the protocol variables and keeps sending JSON; use otlp with http/protobuf, or otlp/http-protobuf, for the binary encoding.

Batch Span Processor ​

VariableDefaultDescription
OTEL_BSP_SCHEDULE_DELAY1000Schedule delay (ms)
OTEL_BSP_MAX_QUEUE_SIZE1000Max queued spans
OTEL_BSP_MAX_EXPORT_BATCH_SIZE100Max spans per export batch
OTEL_BSP_EXPORT_TIMEOUT10000Export timeout (ms)

Connectum passes these values to the trace provider's BatchSpanProcessor. Tune them against measurements from your service and collector; Connectum has no validated spans-per-second capacity threshold.

Instrumentations ​

VariableDescription
OTEL_NODE_DISABLED_INSTRUMENTATIONSRead by separately configured Node.js auto-instrumentation packages, not by @connectum/otel

Provider Management ​

The OTel provider initializes lazily when you first call getProvider(), getTracer(), getMeter(), or getLogger(). For explicit control:

typescript
import { initProvider, shutdownProvider } from '@connectum/otel';

// Explicit initialization (optional)
initProvider({
  serviceName: 'my-service',
  serviceVersion: '1.0.0',
});

// Graceful shutdown (flush pending telemetry)
server.onShutdown('otel', async () => {
  await shutdownProvider();
});

What shutdown guarantees ​

Since 1.3.0, shutdownProvider() always releases the provider, whether stopping succeeds or fails:

  • A failing flush does not block the provider. If an exporter cannot deliver its last batch (an unreachable collector, for example), the promise rejects with that error, but the next getProvider() or initProvider() starts from a clean state and a repeated shutdownProvider() is a no-op. Earlier versions kept returning the half-stopped provider and repeated the same error.
  • Every signal is stopped. Tracing, metrics and logging are stopped independently, so a failure in one does not leave the others running. One failure is rethrown as it is; several arrive together in an AggregateError.
  • Global registrations are released. The provider unregisters the OpenTelemetry API globals it took (trace, context, propagation, metrics, logs), so a provider created afterwards registers cleanly and delivers metrics. A registration that belonged to other code, such as your own NodeSDK, is neither taken over nor removed.
  • Interceptors keep working. createOtelInterceptor() and createOtelClientInterceptor() created before a shutdown record into whichever provider is current.

Earlier versions left the globals registered after a shutdown, so a provider created afterwards was refused as a duplicate and its meter became a no-op: RPC metrics disappeared without a message.

initProvider() applies its options only when no provider exists yet. Once getProvider(), getTracer(), getMeter(), or getLogger() has created the provider from environment defaults, a later initProvider() call does nothing. Call it at startup, before any instrumentation code runs.

Access the provider ​

getProvider() returns the provider that initProvider(), getTracer(), getMeter(), and getLogger() from @connectum/otel share, typed as OtelProvider, and creates it from environment defaults if needed. The provider exposes the tracer, meter, and logger bound to the service name and version, plus shutdown(). getTracer(), getMeter(), and getLogger() read the same provider.

Use getProvider() when one component needs all three signals or must be handed the provider explicitly. Since 1.3.0 the OtelProvider type is exported, so you can name it in a field or parameter. It is an interface only: the provider is created by initProvider() or getProvider(), never with a constructor.

typescript
import { getProvider, type OtelProvider } from '@connectum/otel';

function createOrderTelemetry(provider: OtelProvider) {
  const recorded = provider.meter.createCounter('orders.recorded');

  return {
    recordOrder(): void {
      provider.tracer.startActiveSpan('order.record', (span) => {
        recorded.add(1);
        span.end();
      });
    },
  };
}

const telemetry = createOrderTelemetry(getProvider());

provider.shutdown() shuts down the trace, metric, and log providers it created, but keeps the instance: getProvider() keeps returning the stopped provider. To shut down at process exit, call shutdownProvider() instead. It shuts the provider down and clears it, so the next getProvider() or initProvider() creates a new one.

See OtelProvider and getProvider for the exact types.

Development vs Production Configuration ​

Development ​

Use console exporters for immediate visibility:

bash
OTEL_SERVICE_NAME=greeter-service
OTEL_TRACES_EXPORTER=console
OTEL_METRICS_EXPORTER=none
OTEL_LOGS_EXPORTER=console

Production ​

Export to an OTLP-compatible collector (Jaeger, Grafana Tempo, Datadog):

bash
OTEL_SERVICE_NAME=greeter-service
OTEL_RESOURCE_ATTRIBUTES=service.version=1.0.0,service.namespace=production

OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_LOGS_EXPORTER=otlp

OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf

OTEL_BSP_SCHEDULE_DELAY=1000
OTEL_BSP_MAX_QUEUE_SIZE=1000

Integration with Backends ​

Jaeger ​

yaml
# docker-compose.yml
services:
  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686"   # Jaeger UI
      - "4318:4318"     # OTLP HTTP
bash
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318

Grafana (Tempo + Prometheus + Loki) ​

bash
# Traces -> Tempo
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://tempo:4318/v1/traces

# Metrics -> Prometheus (via OTLP)
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://prometheus:9090/api/v1/otlp/v1/metrics

# Logs -> Loki (via OTLP)
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=http://loki:3100/otlp/v1/logs

Prometheus accepts OTLP metrics only when its OTLP receiver is enabled with --web.enable-otlp-receiver; it does not receive traces or logs. The endpoint above follows its documented receiver path. Loki's OTLP HTTP endpoint is /otlp; the exporter appends /v1/logs. Configure Loki structured metadata before sending OpenTelemetry logs.