Configuration
Autotel supports standard OpenTelemetry environment variables for configuration. This enables zero-code configuration changes across environments.
Environment Variables
Section titled “Environment Variables”Service Configuration:
OTEL_SERVICE_NAME— Service name (maps toserviceininit())
Exporter Configuration:
OTEL_EXPORTER_OTLP_ENDPOINT— OTLP collector URL (e.g.http://localhost:4318)OTEL_EXPORTER_OTLP_PROTOCOL— Protocol:httporgrpcOTEL_EXPORTER_OTLP_HEADERS— Auth headers as comma-separatedkey=valuepairs
Resource Attributes:
OTEL_RESOURCE_ATTRIBUTES— Custom metadata tags as comma-separatedkey=valuepairs
Configuration Precedence
Section titled “Configuration Precedence”- Explicit
init()parameters — highest priority - YAML file —
autotel.yamlorAUTOTEL_CONFIG_FILEenv var - Environment variables —
OTEL_*,AUTOTEL_* - Built-in defaults — sensible defaults for development
init({ service: 'my-service', // Overrides YAML and OTEL_SERVICE_NAME endpoint: 'http://localhost:4318', // Overrides YAML and OTEL_EXPORTER_OTLP_ENDPOINT});Init Locking
Section titled “Init Locking”Framework plugins can lock init() to prevent accidental re-initialization from user code:
import { init, lockLogger, isLoggerLocked } from 'autotel';
// Framework plugin calls this after setting up instrumentationlockLogger();
// Subsequent init() calls are ignoredisLoggerLocked(); // trueSilent Mode
Section titled “Silent Mode”Suppress internal autotel diagnostic output while keeping exporters running:
init({ service: 'my-app', endpoint: 'http://localhost:4318', silent: true, // Suppress console output (default: false) minLevel: 'warn', // Only log warnings and errors (default: 'info')});Useful for platforms like GCP Cloud Run or AWS Lambda where stdout is managed externally.
Attribute Redaction
Section titled “Attribute Redaction”Automatically redact PII and sensitive data from span attributes for compliance:
init({ service: 'my-app', attributeRedactor: 'default', // 'default' | 'strict' | 'pci-dss'});Presets:
default— Emails, phone numbers, SSNs, credit cards (last 4), sensitive keys (password, token, etc.)strict— All of default plus JWTs, Bearer tokens, IBANs, API keys in valuespci-dss— Focused on payment card data
Custom configuration:
init({ service: 'my-app', attributeRedactor: { keyPatterns: [/password/i, /secret/i], // Keys to redact entirely valuePatterns: [ // Custom patterns with smart masking { name: 'customerId', pattern: /CUST-\d{8}/g, replacement: 'CUST-***' } ], builtins: ['email', 'creditCard'], // Enable specific built-in patterns replacement: '[REDACTED]', // Default replacement (default) },});Built-in patterns: email, phone, creditCard, ipv4, jwt, bearer, iban
YAML Configuration
Section titled “YAML Configuration”Create an autotel.yaml file in your project root:
service: name: my-service version: 1.0.0 environment: ${env:NODE_ENV:-development}
exporter: endpoint: ${env:OTEL_EXPORTER_OTLP_ENDPOINT:-http://localhost:4318} protocol: http headers: x-honeycomb-team: ${env:HONEYCOMB_API_KEY}
resource: deployment.environment: ${env:NODE_ENV:-development} team: backend
autoInstrumentations: - express - http - pino
debug: falseKey features:
- Auto-discovery: Automatically loads
autotel.yamlorautotel.ymlfrom the current directory - Explicit path: Set
AUTOTEL_CONFIG_FILE=./config/otel.yamlto use a custom path - Environment variable substitution: Use
${env:VAR_NAME}or${env:VAR_NAME:-default} - Programmatic loading: Use
loadYamlConfigFromFile()fromautotel/yaml
Usage with autotel/auto (zero-config):
# Just create autotel.yaml and run:tsx --import autotel/auto src/index.tsProgrammatic loading:
import { loadYamlConfigFromFile } from 'autotel/yaml';import { init } from 'autotel';
const yamlConfig = loadYamlConfigFromFile('./config/otel.yaml');init({ ...yamlConfig, debug: true });See packages/autotel/autotel.yaml.example for a complete template.
Example Usage
Section titled “Example Usage”Development (local collector):
export OTEL_SERVICE_NAME=my-appexport OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318Production (Honeycomb):
export OTEL_SERVICE_NAME=my-appexport OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.ioexport OTEL_EXPORTER_OTLP_HEADERS=x-honeycomb-team=YOUR_API_KEYexport OTEL_RESOURCE_ATTRIBUTES=service.version=1.2.3,deployment.environment=productionProduction (Datadog):
export OTEL_SERVICE_NAME=my-appexport OTEL_EXPORTER_OTLP_ENDPOINT=https://http-intake.logs.datadoghq.comexport OTEL_EXPORTER_OTLP_HEADERS=DD-API-KEY=YOUR_API_KEYexport OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,team=backendSee packages/autotel/.env.example for a complete template.
Implementation Details
Section titled “Implementation Details”Environment variable resolution is handled in packages/autotel/src/env-config.ts. The resolver:
- Validates env var formats (URLs, enum values)
- Parses complex values (comma-separated key=value pairs)
- Provides type-safe config objects
YAML configuration is handled in packages/autotel/src/yaml-config.ts. The loader:
- Auto-discovers
autotel.yamlorautotel.ymlin the current directory - Supports
AUTOTEL_CONFIG_FILEenv var for custom paths - Substitutes
${env:VAR}and${env:VAR:-default}syntax in YAML values - Converts YAML structure to
AutotelConfigtype
Config merging happens in init() with the priority: explicit > yaml > env > defaults
Event Delivery Timing
Section titled “Event Delivery Timing”Events via track() are batched and delivered asynchronously. The default flush interval is 10 seconds with a batch size of 100 events. Use flush() before process exit or in serverless environments to ensure events aren't lost.
Flushing Events
Section titled “Flushing Events”Before assertions in tests or process shutdown, manually flush the event queue:
import { getEventQueue } from 'autotel';
await getEventQueue()?.flush();Serverless / Scripts
Section titled “Serverless / Scripts”Always flush before the process exits:
import { track, getEventQueue } from 'autotel';
track('script.started', { scriptName: 'data-import' });// ... do work ...track('script.completed', { recordsProcessed: 1000 });
await getEventQueue()?.flush();Or use a process handler:
process.on('beforeExit', async () => { await getEventQueue()?.flush();});Testing
Section titled “Testing”When testing event tracking, flush before assertions:
import { track, getEventQueue } from 'autotel';import { expect, test } from 'vitest';
test('tracks user signup', async () => { track('user.signup', { userId: '123' });
// Flush events before assertions await getEventQueue()?.flush();
// Now verify events were sent to your mock/test subscriber expect(mockSubscriber.events).toContainEqual( expect.objectContaining({ name: 'user.signup' }), );});Queue Configuration
Section titled “Queue Configuration”| Setting | Default | Description |
| --------------- | -------- | --------------------------------------- |
| maxSize | 50,000 | Maximum events in queue before dropping |
| batchSize | 100 | Events per batch |
| flushInterval | 10,000ms | Automatic flush interval |
| maxRetries | 3 | Retry attempts for failed deliveries |
| rateLimit | 100/sec | Maximum events per second |
Correlation ID
Section titled “Correlation ID”The correlation ID is a stable join key across events, logs, and spans. It is available via getCorrelationId() and getOrCreateCorrelationId() from autotel.
- Where it's set: The first use of
getOrCreateCorrelationId()in an async context creates it; or set it at a boundary (e.g. HTTP handler, message processor) viarunWithCorrelationId(id, fn)orsetCorrelationId(id)fromautotel/correlation-id. - Stability: The same value is used for the duration of the same AsyncLocalStorage context (the same async chain). A new context (e.g. a new request) gets a new ID unless you propagate it (e.g. via baggage or Kafka headers).
- Public API:
getCorrelationId()andgetOrCreateCorrelationId()are exported fromautotel. For cross-service propagation, usesetCorrelationIdInBaggage()fromautotel/correlation-id.
import { getOrCreateCorrelationId } from 'autotel';
// Inside a request or message handler: same ID for the whole async chainconst correlationId = getOrCreateCorrelationId();Guarantee: Events tracked within a request context will have the same correlation_id as the HTTP response header. The ID is captured synchronously at track() call time, before any async delivery occurs.
Event payload and autotel context
Section titled “Event payload and autotel context”With events.includeTraceContext and events.traceUrl configured in init(), every track(name, props) call automatically includes correlation_id and trace_url: no wrappers needed.
When using track() or the Event class, subscribers receive an optional autotel context (e.g. correlation_id, trace_id, span_id, trace_url) when events.includeTraceContext is enabled in init(). Subscribers that support it (e.g. WebhookSubscriber) receive this via the third parameter to trackEvent and include it in the payload (e.g. as a top-level autotel field or merged into attributes), so consumers can correlate events with traces.
Event Attribute Types
Section titled “Event Attribute Types”EventAttributes accepts any JSON-serializable values including nested objects:
- Primitives:
string,number,boolean - Nested objects:
{ user: { id: '123', roles: ['admin'] } } - Arrays:
['tag1', 'tag2']
Nested objects are validated with a max depth of 3 levels (configurable). Circular references are replaced with '[CIRCULAR]'.