Datadog Integration
Complete guide for integrating Autotel with Datadog using OpenTelemetry Protocol (OTLP).
Overview
Section titled “Overview”Autotel provides first-class support for Datadog through the industry-standard OpenTelemetry Protocol (OTLP). This approach offers several advantages over vendor-specific integrations:
Benefits of OTLP Integration
Section titled “Benefits of OTLP Integration”- Unified Observability: Send traces, logs, and metrics through a single protocol
- Vendor Neutrality: Switch between Datadog, Honeycomb, New Relic without code changes
- Future-Proof: Built on OpenTelemetry, the CNCF industry standard
- Automatic Correlation: Traces and logs are automatically linked
- Simplified Setup: Single configuration for all observability signals
- Datadog Best Practices: Built-in support for Unified Service Tagging, hostname detection, and proper resource attributes
What You Get
Section titled “What You Get”When you integrate Autotel with Datadog, you get:
| Signal | Destination | Features |
|---|---|---|
| Traces | Datadog APM | Distributed tracing, flame graphs, service maps, error tracking |
| Logs | Datadog Logs | Structured logs with automatic trace correlation |
| Metrics | Datadog Metrics | Custom business and application metrics |
| Infrastructure | Datadog Infrastructure (via Agent) | Host metrics, container metrics, process monitoring |
Quick Start
Section titled “Quick Start”1. Install Dependencies
Section titled “1. Install Dependencies”# Core packagenpm install autotel
# Backends (includes log export - no separate log packages needed)npm install autotel-backends2. Get Datadog API Key
Section titled “2. Get Datadog API Key”- Log in to Datadog
- Go to Organization Settings > API Keys
- Create or copy an existing API key
- Note your Datadog site (e.g.,
datadoghq.com,datadoghq.eu)
3. Initialize Autotel
Section titled “3. Initialize Autotel”Simple Configuration (Traces + Metrics only):
import { init } from 'autotel';
init({ service: 'my-app', environment: 'production', version: '1.0.0', endpoint: 'https://otlp.datadoghq.com', otlpHeaders: `dd-api-key=${process.env.DATADOG_API_KEY}`,});Recommended: Use the Datadog Preset (Traces + Logs + Metrics):
import { init } from 'autotel';import { createDatadogConfig } from 'autotel-backends/datadog';
init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'my-app', environment: 'production', version: '1.0.0', site: 'datadoghq.com', enableLogs: true, }),);Log libs are bundled in autotel-backends; no app-level install of @opentelemetry/sdk-logs or @opentelemetry/exporter-logs-otlp-http needed.
4. Instrument Your Code
Section titled “4. Instrument Your Code”import { trace, withTracing } from 'autotel';import { createBuiltinLogger } from 'autotel/logger';
const logger = createBuiltinLogger('my-app');
const processOrder = withTracing({})((ctx) => async (orderId: string) => { logger.info('Processing order', { orderId });
ctx.setAttribute('order.id', orderId); ctx.setAttribute('order.status', 'processing');
// Your business logic here
return { success: true };});5. View Results in Datadog
Section titled “5. View Results in Datadog”- Traces: https://app.datadoghq.com/apm/traces
- Logs: https://app.datadoghq.com/logs
- Metrics: https://app.datadoghq.com/metric/explorer
- Service Catalog: https://app.datadoghq.com/services
Architecture Choices
Section titled “Architecture Choices”Datadog supports two ingestion architectures. Choose based on your deployment type and requirements.
Direct Cloud Ingestion
Section titled “Direct Cloud Ingestion”How it works: Application sends OTLP data directly to Datadog cloud endpoints via HTTPS.
┌─────────────────┐│ Application ││ (autotel) │└────────┬────────┘ │ OTLP/HTTPS │ (API key in headers) ▼┌─────────────────┐│ Datadog Cloud ││ OTLP Intake │└─────────────────┘Best for:
- Serverless (AWS Lambda, Google Cloud Functions, Azure Functions)
- Edge runtimes (Cloudflare Workers, Vercel Edge, Deno Deploy)
- Containerized apps without persistent infrastructure (AWS Fargate, Cloud Run)
- Development environments
- Getting started quickly
Pros:
- Zero infrastructure - no Agent to install/manage
- Works anywhere with HTTPS egress
- Simple configuration
- Perfect for ephemeral workloads
Cons:
- Higher egress costs (every instance sends directly)
- No local data aggregation/buffering
- Missing Agent-specific features (see below)
Configuration:
import { createDatadogConfig } from 'autotel-backends/datadog';
init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'my-lambda', site: 'datadoghq.com', }),);Datadog Agent
Section titled “Datadog Agent”How it works: Application sends OTLP to local Datadog Agent, which aggregates and forwards to Datadog cloud.
┌─────────────────┐│ Application ││ (autotel) │└────────┬────────┘ │ OTLP/HTTP (localhost) │ (no API key needed) ▼┌─────────────────┐│ Datadog Agent ││ (localhost) ││ ││ • Aggregates ││ • Enriches ││ • Scrubs PII ││ • Buffers │└────────┬────────┘ │ Optimized protocol │ (API key in Agent) ▼┌─────────────────┐│ Datadog Cloud │└─────────────────┘Best for:
- Production long-running services (Node.js APIs, web servers)
- Kubernetes/container orchestration
- On-premise/VM deployments
- High-volume applications
- Advanced monitoring needs
Pros:
- Lower costs: Agent batches/compresses locally, reducing egress
- 500+ integrations: Auto-collect infrastructure metrics (CPU, memory, disk, network, database stats)
- Advanced log processing: Multi-line log parsing (stack traces), PII scrubbing and sensitive data redaction, log enrichment with Kubernetes/container tags
- Trace-log correlation: Enhanced correlation in Agent
- Local buffering: Queues data during network issues
- DogStatsD: Ultra-low latency metrics via UDP
- Live debugging: Datadog Live Tail, Dynamic Instrumentation
Cons:
- Requires Agent installation/management
- Not available in serverless/edge environments
- Additional infrastructure dependency
Configuration:
import { createDatadogConfig } from 'autotel-backends/datadog';
init( createDatadogConfig({ service: 'my-api', useAgent: true, agentHost: 'localhost', // Or Kubernetes service name agentPort: 4318, }),);Decision Matrix
Section titled “Decision Matrix”| Factor | Direct Cloud Ingestion | Datadog Agent |
|---|---|---|
| Deployment Type | Serverless, Edge, Ephemeral | Long-running, VMs, Kubernetes |
| Infrastructure Required | None | Datadog Agent |
| API Key Location | Application | Agent (not in app) |
| Egress Costs | Higher (per instance) | Lower (Agent batches) |
| Infrastructure Metrics | No | Yes (500+ integrations) |
| Log Processing | Basic | Advanced (multi-line, PII scrubbing) |
| Setup Complexity | Low | Medium |
| Buffering | None | Yes (Agent queues) |
| DogStatsD | No | Yes |
| Best For | Serverless, development | Production, Kubernetes |
Hybrid Approach (Recommended for large deployments):
- Serverless functions: Direct cloud ingestion
- Backend APIs/services: Datadog Agent
- Edge functions: Direct cloud ingestion
- Kubernetes workloads: Datadog Agent (DaemonSet)
Setup Instructions
Section titled “Setup Instructions”Direct Cloud Ingestion Setup
Section titled “Direct Cloud Ingestion Setup”1. Install Dependencies
Section titled “1. Install Dependencies”npm install autotel
# Optional: for log exportnpm install autotel-backends2. Set Environment Variables
Section titled “2. Set Environment Variables”export DATADOG_API_KEY="your_api_key_here"export DATADOG_SITE="datadoghq.com" # or datadoghq.eu, us3.datadoghq.com, etc.3. Configure Application
Section titled “3. Configure Application”import { init } from 'autotel';import { createDatadogConfig } from 'autotel-backends/datadog';
init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'my-app', environment: process.env.NODE_ENV || 'development', version: process.env.APP_VERSION, site: (process.env.DATADOG_SITE as any) || 'datadoghq.com', enableLogs: true, // Optional }),);4. Deploy and Verify
Section titled “4. Deploy and Verify”After deploying, check Datadog:
- APM > Traces: Should see traces within 1-2 minutes
- Logs > Search: Filter by
service:my-app - Service Catalog: Your service should appear automatically
Datadog Agent Setup
Section titled “Datadog Agent Setup”1. Install Datadog Agent
Section titled “1. Install Datadog Agent”On macOS:
DD_API_KEY="your_api_key" DD_SITE="datadoghq.com" bash -c "$(curl -L https://install.datadoghq.com/scripts/install_mac_os.sh)"On Ubuntu/Debian:
DD_API_KEY="your_api_key" DD_SITE="datadoghq.com" bash -c "$(curl -L https://install.datadoghq.com/scripts/install_script_agent7.sh)"On Kubernetes (Helm):
helm repo add datadog https://helm.datadoghq.comhelm repo update
helm install datadog-agent datadog/datadog \ --set datadog.apiKey=<YOUR_API_KEY> \ --set datadog.site=datadoghq.com \ --set datadog.otlp.receiver.protocols.http.enabled=true \ --set datadog.otlp.receiver.protocols.grpc.enabled=trueOn Docker:
docker run -d \ --name datadog-agent \ -e DD_API_KEY=<YOUR_API_KEY> \ -e DD_SITE="datadoghq.com" \ -e DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT="0.0.0.0:4318" \ -e DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINT="0.0.0.0:4317" \ -p 4318:4318 \ -p 4317:4317 \ gcr.io/datadoghq/agent:latest2. Enable OTLP Receiver
Section titled “2. Enable OTLP Receiver”Edit /etc/datadog-agent/datadog.yaml:
# Enable OTLP receiverotlp_config: receiver: protocols: http: endpoint: 0.0.0.0:4318 grpc: endpoint: 0.0.0.0:4317
# Optional: Enable debug logginglog_level: infoRestart the Agent:
sudo systemctl restart datadog-agentOr with environment variables (Docker/Kubernetes):
DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT=0.0.0.0:4318DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINT=0.0.0.0:43173. Configure Application
Section titled “3. Configure Application”import { init } from 'autotel';import { createDatadogConfig } from 'autotel-backends/datadog';
init( createDatadogConfig({ service: 'my-app', environment: 'production', version: '1.0.0', useAgent: true, agentHost: 'localhost', // Default agentPort: 4318, // Default }),);For Kubernetes: Use the Agent’s service hostname:
init( createDatadogConfig({ service: 'my-app', useAgent: true, // Agent runs as DaemonSet, accessible via node-local or service agentHost: process.env.DD_AGENT_HOST || 'datadog-agent.default.svc.cluster.local', }),);4. Verify Agent is Receiving Data
Section titled “4. Verify Agent is Receiving Data”sudo datadog-agent statusLook for the OTLP section showing received spans/metrics/logs:
=========OTLP========= HTTP: Endpoint: 0.0.0.0:4318 Spans: 1234 received Metrics: 567 received
Status: OKUsing the Datadog Preset
Section titled “Using the Datadog Preset”The createDatadogConfig() preset helper simplifies configuration for both architectures.
Basic Usage
Section titled “Basic Usage”import { init } from 'autotel';import { createDatadogConfig } from 'autotel-backends/datadog';
// Direct cloud ingestioninit( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'my-app', }),);
// Local Agentinit( createDatadogConfig({ service: 'my-app', useAgent: true, }),);Full Configuration Options
Section titled “Full Configuration Options”interface DatadogPresetConfig { // Required service: string;
// Cloud ingestion (required if useAgent: false) apiKey?: string; site?: | 'datadoghq.com' | 'datadoghq.eu' | 'us3.datadoghq.com' | 'us5.datadoghq.com' | 'ap1.datadoghq.com';
// Agent mode useAgent?: boolean; agentHost?: string; // Default: 'localhost' agentPort?: number; // Default: 4318
// Optional (both modes) environment?: string; // Default: DD_ENV || NODE_ENV || 'development' version?: string; // Default: DD_VERSION || auto-detected enableLogs?: boolean; // Default: false
// Advanced logRecordProcessors?: LogRecordProcessor[]; // Custom log processors}Environment Variables
Section titled “Environment Variables”The preset respects Datadog standard environment variables:
DD_ENV=production # Sets environmentDD_VERSION=1.2.3 # Sets versionDD_HOSTNAME=my-host # Sets hostnameDD_AGENT_HOST=localhost # Sets Agent hostExamples
Section titled “Examples”Serverless (Lambda):
init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'order-processor', environment: 'production', site: 'datadoghq.com', }),);Kubernetes with Agent:
init( createDatadogConfig({ service: 'api-gateway', useAgent: true, agentHost: process.env.DD_AGENT_HOST || 'datadog-agent.monitoring.svc.cluster.local', }),);Development:
init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'my-app-dev', environment: 'development', enableLogs: true, // More verbose in dev }),);Querying Datadog Back
Section titled “Querying Datadog Back”Everything above sends telemetry to Datadog. Reading it back, from
autotel-mcp or the autotel CLI, takes a second credential.
Two keys, two directions
Section titled “Two keys, two directions”Datadog splits its credentials by direction:
| Credential | Header | What it does | Where to get it |
|---|---|---|---|
| API key | DD-API-KEY |
Writes telemetry in. This is the one init() uses. |
Organization Settings -> API Keys |
| Application key | DD-APPLICATION-KEY |
Reads telemetry back out. | Organization Settings -> Application Keys |
Every read endpoint, /api/v2/apm/services and /api/v2/spans/events among
them, requires both headers. Scope the application key apm_read.
An app that only exports to Datadog needs the API key alone, so a working
.env from an exporting service usually lacks the application key. Add it:
export DD_API_KEY=... # already set if you export to Datadogexport DD_APP_KEY=... # add this to queryexport DD_SITE=datadoghq.eu # bare site, defaults to datadoghq.comBoth keys come from the environment. Neither has a flag form, because argv is
readable by any process that can list the process table.
Verify the pair
Section titled “Verify the pair”AUTOTEL_BACKEND=datadog AUTOTEL_TRANSPORT=http npx autotel-mcp &curl -s localhost:3000/healthA healthy backend counts the services it found:
{ "status": "healthy", "detail": "12 services available", "signals": { "traces": "available", "metrics": "unsupported", "logs": "unsupported" }}To check the credentials alone, ask Datadog directly:
# API key: 200 means validcurl -s -o /dev/null -w '%{http_code}\n' \ "https://api.$DD_SITE/api/v1/validate" -H "DD-API-KEY: $DD_API_KEY"
# Both keys together: 200 means the pair can read APMcurl -s -o /dev/null -w '%{http_code}\n' \ "https://api.$DD_SITE/api/v2/apm/services?filter%5Benv%5D=*" \ -H "DD-API-KEY: $DD_API_KEY" -H "DD-APPLICATION-KEY: $DD_APP_KEY"Reading the failures
Section titled “Reading the failures”| Symptom | Cause |
|---|---|
Datadog application key missing |
DD_APP_KEY unset. The health check names it rather than returning an empty result. |
403 from /api/v1/validate |
The API key is revoked, or belongs to a different site. Datadog answers an invalid key and a missing key identically, so compare against a deliberately wrong key to confirm you reached the API. |
403 from /api/v2/apm/services |
The API key validates but the application key does not carry apm_read, or the two keys belong to different orgs. |
| Healthy, but a service you expect is absent | The exporter is not landing spans. Check the write path before you suspect the query. |
A dead API key fails silently on the write side. Datadog drops unauthorized OTLP payloads without telling the exporter, so a service that reports no export errors can still be sending nothing.
Traces only
Section titled “Traces only”The Datadog backend serves traces. capabilities() reports metrics and
logs as unsupported, so those tools never register and an agent reads
“unsupported” instead of guessing from an empty list. Datadog exposes metrics
and logs through separate APIs that this backend does not call.
Migration from pino-datadog-transport
Section titled “Migration from pino-datadog-transport”If you’re currently using pino-datadog-transport, Autotel provides a superior alternative with traces and automatic correlation.
Why Migrate?
Section titled “Why Migrate?”| Feature | pino-datadog-transport | Autotel + OTLP |
|---|---|---|
| Logs | Yes | Yes |
| Traces | No | Yes |
| Metrics | No | Yes |
| Trace-Log Correlation | Manual | Automatic |
| Protocol | Proprietary Datadog API | OTLP (industry standard) |
| Vendor Lock-in | Datadog-only | Vendor-neutral |
| Infrastructure Metrics | No | Yes (with Agent) |
Migration Strategies
Section titled “Migration Strategies”Strategy 1: Incremental (Recommended)
Section titled “Strategy 1: Incremental (Recommended)”Keep pino-datadog-transport for logs, add Autotel for traces and metrics.
Before (logs only):
import pino from 'pino';
const logger = pino( pino.transport({ target: 'pino-datadog-transport', options: { ddClientConf: { authMethods: { apiKeyAuth: process.env.DATADOG_API_KEY }, }, ddServerConf: { site: 'datadoghq.com' }, service: 'my-app', }, }),);After (logs + traces + metrics):
import pino from 'pino';import { init, trace, withTracing } from 'autotel';
// Keep existing logger for nowconst logger = pino( pino.transport({ target: 'pino-datadog-transport', options: { ddClientConf: { authMethods: { apiKeyAuth: process.env.DATADOG_API_KEY }, }, ddServerConf: { site: 'datadoghq.com' }, service: 'my-app', }, }),);
// Add autotel for traces and metrics onlyinit({ service: 'my-app', endpoint: 'https://otlp.datadoghq.com', otlpHeaders: `dd-api-key=${process.env.DATADOG_API_KEY}`, // No logRecordProcessors - keep existing log pipeline});
// Now you have traces!const processOrder = trace(async (orderId) => { logger.info({ orderId }, 'Processing order'); // ... business logic});Benefits:
- Zero risk - no changes to existing log pipeline
- Immediately gain distributed tracing
- Can validate traces before migrating logs
- Only requires installing
autotel
Strategy 2: Full Migration
Section titled “Strategy 2: Full Migration”Replace everything with Autotel OTLP.
Before:
import pino from 'pino';
const logger = pino( pino.transport({ target: 'pino-datadog-transport', options: { ddClientConf: { authMethods: { apiKeyAuth: process.env.DATADOG_API_KEY }, }, ddServerConf: { site: 'datadoghq.eu' }, service: 'my-app', ddsource: 'nodejs', }, }),);
logger.info({ userId: '123' }, 'User created');After:
import { init, trace, withTracing } from 'autotel';import { createBuiltinLogger } from 'autotel/logger';import { createDatadogConfig } from 'autotel-backends/datadog';
const logger = createBuiltinLogger('my-app');
init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'my-app', site: 'datadoghq.eu', enableLogs: true, }),);
const createUser = withTracing({})((ctx) => async (userId: string) => { logger.info('User created', { userId }); // Trace ID automatically included in logs! ctx.setAttribute('user.id', userId); // ... business logic});Benefits:
- Unified observability (traces + logs + metrics)
- Automatic trace-log correlation (no manual injection)
- OTLP standard (can switch to Honeycomb, New Relic later)
- Simpler configuration
Migration Steps:
- Install:
npm install autotel-backends - Replace
pinosetup withcreateBuiltinLogger() - Update
init()to includelogRecordProcessors - Test in development
- Deploy to staging, validate logs appear in Datadog
- Remove
pino-datadog-transportdependency
Best Practices
Section titled “Best Practices”1. Use Unified Service Tagging
Section titled “1. Use Unified Service Tagging”Datadog’s Unified Service Tagging requires three tags on all telemetry:
init( createDatadogConfig({ service: 'checkout-api', // Required environment: 'production', // Required version: '2.1.0', // Required }),);Why: Enables Deployment Tracking, Service Catalog, and proper correlation across signals.
2. Use Environment Variables
Section titled “2. Use Environment Variables”Don’t hardcode configuration:
init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: process.env.SERVICE_NAME!, environment: process.env.DD_ENV || process.env.NODE_ENV, version: process.env.DD_VERSION || require('./package.json').version, site: (process.env.DATADOG_SITE as any) || 'datadoghq.com', }),);3. Use Adaptive Sampling in Production
Section titled “3. Use Adaptive Sampling in Production”Default sampling (10% baseline, 100% errors/slow) is good for most cases:
init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'my-app', // Default sampling is already adaptive - no config needed! }),);For custom sampling:
import { AdaptiveSampler } from 'autotel/sampling';
init({ service: 'my-app', endpoint: '...', otlpHeaders: '...', sampler: new AdaptiveSampler({ baselineSampleRate: 0.05, // 5% of normal traffic slowThresholdMs: 1000, // Requests >1s are "slow" alwaysSampleErrors: true, // Always capture errors alwaysSampleSlow: true, // Always capture slow requests }),});4. Add Meaningful Attributes
Section titled “4. Add Meaningful Attributes”Use semantic conventions where possible:
const processCheckout = withTracing({})((ctx) => async (userId, items) => { // Datadog recognizes these standard attributes ctx.setAttribute('user.id', userId); ctx.setAttribute('http.method', 'POST'); ctx.setAttribute('http.route', '/checkout');
// Custom business attributes ctx.setAttribute('checkout.items_count', items.length); ctx.setAttribute('checkout.total_amount', calculateTotal(items));});5. Use Structured Logging
Section titled “5. Use Structured Logging”Always log with context objects:
// Goodlogger.info('Order processed', { orderId, amount, customerId, processingTime: duration,});
// Bad - harder to query in Datadoglogger.info(`Order ${orderId} processed for customer ${customerId}`);6. Enable Log Correlation
Section titled “6. Enable Log Correlation”Logs automatically include trace IDs for correlation:
const logger = createBuiltinLogger('my-app');
const processOrder = withTracing({})((ctx) => async (orderId) => { // This log automatically includes: // - traceId (hex) // - spanId (hex) // - dd.trace_id (decimal, for Datadog) // - dd.span_id (decimal, for Datadog) logger.info('Processing order', { orderId });});View correlated logs in Datadog:
- Go to APM > Traces
- Click any trace
- See “Logs” tab with related log entries
7. Use Metrics for Business KPIs
Section titled “7. Use Metrics for Business KPIs”Track important business metrics:
import { Metric } from 'autotel/metric';
const metrics = new Metric('checkout');
const processCheckout = trace(async (items) => { const total = calculateTotal(items);
// Track business metrics metrics.trackEvent('checkout.completed', { payment_method: 'credit_card', currency: 'USD', });
metrics.trackValue('checkout.amount', total, { currency: 'USD', });});8. Use Agent in Production
Section titled “8. Use Agent in Production”For production workloads on Kubernetes/VMs, use the Datadog Agent:
Benefits:
- Lower costs (Agent batches/compresses)
- Infrastructure metrics (CPU, memory, network)
- Advanced log features (multi-line parsing, PII scrubbing)
- Better reliability (local buffering)
Deployment Patterns
Section titled “Deployment Patterns”AWS Lambda
Section titled “AWS Lambda”Challenge: Ephemeral, no persistent Agent Solution: Direct cloud ingestion
import { init } from 'autotel';import { createDatadogConfig } from 'autotel-backends/datadog';
// Initialize once (outside handler for warm starts)init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'order-processor', environment: process.env.ENVIRONMENT!, version: process.env.VERSION, site: 'datadoghq.com', }),);
export const handler = trace(async (event) => { // Your Lambda logic return { statusCode: 200, body: 'OK' };});Kubernetes
Section titled “Kubernetes”Challenge: Multiple pods, need infrastructure metrics Solution: Datadog Agent as DaemonSet
1. Install Agent:
helm install datadog-agent datadog/datadog \ --set datadog.apiKey=$DD_API_KEY \ --set datadog.otlp.receiver.protocols.http.enabled=true \ --set datadog.logs.enabled=true \ --set datadog.logs.containerCollectAll=true2. Configure app:
init( createDatadogConfig({ service: 'api-gateway', environment: 'production', useAgent: true, // Agent runs as DaemonSet on each node agentHost: process.env.DD_AGENT_HOST || 'localhost', }),);3. Set pod environment:
apiVersion: v1kind: Podmetadata: name: api-gatewayspec: containers: - name: app image: myapp:1.0.0 env: - name: DD_AGENT_HOST valueFrom: fieldRef: fieldPath: status.hostIP # DaemonSet agent on nodeDocker Compose
Section titled “Docker Compose”Solution: Agent as sidecar service
version: '3.8'
services: app: image: myapp:latest environment: DD_AGENT_HOST: datadog-agent SERVICE_NAME: my-app depends_on: - datadog-agent
datadog-agent: image: gcr.io/datadoghq/agent:latest environment: DD_API_KEY: ${DATADOG_API_KEY} DD_SITE: datadoghq.com DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT: '0.0.0.0:4318' ports: - '4318:4318'Cloudflare Workers / Vercel Edge
Section titled “Cloudflare Workers / Vercel Edge”Challenge: Edge runtime, no Node.js APIs
Solution: Use autotel-edge (not regular autotel)
import { init, trace, withTracing } from 'autotel-edge';
init({ service: 'edge-api', endpoint: 'https://otlp.datadoghq.com', otlpHeaders: `dd-api-key=${DATADOG_API_KEY}`,});
export default { fetch: trace(async (request) => { // Edge function logic return new Response('OK'); }),};Multi-Region Deployments
Section titled “Multi-Region Deployments”Challenge: Different Datadog sites per region Solution: Configure site via environment variable
// Automatically picks correct site based on deployment regioninit( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'global-api', site: (process.env.DATADOG_SITE as any) || 'datadoghq.com', // US: datadoghq.com // EU: datadoghq.eu // AP: ap1.datadoghq.com }),);Troubleshooting
Section titled “Troubleshooting”Traces/Logs Not Appearing
Section titled “Traces/Logs Not Appearing”1. Verify API Key
curl -X POST "https://http-intake.logs.datadoghq.com/api/v2/logs" \ -H "dd-api-key: ${DATADOG_API_KEY}" \ -H "Content-Type: application/json" \ -d '{"message":"test","ddsource":"test"}'Expected: HTTP 202 Accepted
If 403 Forbidden: Invalid API key
2. Check Endpoint URL
Verify the site matches your Datadog region:
- US1:
datadoghq.com - EU:
datadoghq.eu - US3:
us3.datadoghq.com
3. Check Application Logs
Enable debug logging:
import { init } from 'autotel';import { createBuiltinLogger } from 'autotel/logger';
const logger = createBuiltinLogger('my-app', { level: 'debug' });
init({ service: 'my-app', logger, // Autotel will log export errors // ...});4. Verify Data is Being Sent
Check for OTLP export errors in application logs:
ERROR: Failed to export traces to https://otlp.datadoghq.com/v1/traces5. Wait for Data Ingestion
Data may take 1-2 minutes to appear in Datadog UI after export.
Agent Not Receiving Data
Section titled “Agent Not Receiving Data”1. Check Agent Status
sudo datadog-agent statusLook for OTLP section. If missing, OTLP receiver is not enabled.
2. Verify OTLP is Enabled
cat /etc/datadog-agent/datadog.yaml | grep -A 10 otlpShould show:
otlp_config: receiver: protocols: http: endpoint: 0.0.0.0:43183. Check Agent Logs
sudo tail -f /var/log/datadog/agent.logLook for OTLP receiver startup messages.
4. Test OTLP Endpoint
curl -v http://localhost:4318/v1/tracesExpected: Response from OTLP receiver (not “connection refused”)
5. Check Firewall
Ensure port 4318 is open:
sudo netstat -tulpn | grep 4318Logs Missing Trace Correlation
Section titled “Logs Missing Trace Correlation”Symptom: Logs appear in Datadog but don’t show linked traces
Solution: Ensure you’re using createBuiltinLogger() from Autotel:
// Correct - includes trace correlationimport { createBuiltinLogger } from 'autotel/logger';const logger = createBuiltinLogger('my-app');
// Wrong - no trace correlationimport pino from 'pino';const logger = pino();Verify in Datadog:
- Go to Logs
- Click any log entry
- Check for
dd.trace_idanddd.span_idfields - If present, correlation should work
High Costs
Section titled “High Costs”Solution 1: Use Adaptive Sampling
import { AdaptiveSampler } from 'autotel/sampling';
init({ service: 'my-app', sampler: new AdaptiveSampler({ baselineSampleRate: 0.01, // 1% of normal traffic alwaysSampleErrors: true, // But always capture errors }), // ...});Solution 2: Use Datadog Agent
Agent batches/compresses data, reducing egress costs significantly.
Solution 3: Filter Noisy Endpoints
import { AdaptiveSampler } from 'autotel/sampling';
const sampler = new AdaptiveSampler({ shouldSample: (context) => { // Don't sample health checks const route = context.attributes['http.route']; if (route === '/health' || route === '/metrics') { return false; } return true; },});Advanced Configuration
Section titled “Advanced Configuration”Custom Resource Attributes
Section titled “Custom Resource Attributes”Add deployment-specific attributes:
import { Resource } from '@opentelemetry/resources';
init({ service: 'my-app', endpoint: '...', otlpHeaders: '...', resource: new Resource({ 'deployment.environment': 'production', 'service.namespace': 'payments', 'service.version': '2.1.0', 'host.name': process.env.HOSTNAME, 'cloud.provider': 'aws', 'cloud.region': 'us-east-1', }),});Custom Sampling Logic
Section titled “Custom Sampling Logic”Implement complex sampling rules:
import { AdaptiveSampler } from 'autotel/sampling';
const sampler = new AdaptiveSampler({ shouldSample: (context) => { // Always sample authenticated requests if (context.attributes['user.authenticated'] === true) { return true; }
// Sample 100% of payments if (context.attributes['http.route']?.includes('/payment')) { return true; }
// Sample 5% of everything else return Math.random() < 0.05; },});
init({ service: 'my-app', sampler, // ...});Per-Environment Configuration
Section titled “Per-Environment Configuration”const config = { development: { enableLogs: true, sampler: new AdaptiveSampler({ baselineSampleRate: 1.0 }), // 100% }, staging: { enableLogs: true, sampler: new AdaptiveSampler({ baselineSampleRate: 0.5 }), // 50% }, production: { enableLogs: false, // Use existing log pipeline sampler: new AdaptiveSampler({ baselineSampleRate: 0.1 }), // 10% useAgent: true, // Always use Agent in prod },};
const env = process.env.NODE_ENV as keyof typeof config;
init( createDatadogConfig({ apiKey: process.env.DATADOG_API_KEY!, service: 'my-app', environment: env, ...config[env], }),);Can I use both pino-datadog-transport and Autotel?
Section titled “Can I use both pino-datadog-transport and Autotel?”Yes! Use pino-datadog-transport for logs and Autotel for traces/metrics. This is the recommended incremental migration strategy. See Strategy 1: Incremental.
Do I need the Agent or can I just use direct ingestion?
Section titled “Do I need the Agent or can I just use direct ingestion?”Both work. Use direct ingestion for serverless/edge. Use Agent for production services (lower costs, more features). See Architecture Choices.
What’s the difference between Autotel and @datadog/dd-trace?
Section titled “What’s the difference between Autotel and @datadog/dd-trace?”@datadog/dd-trace: Datadog-specific tracing library, proprietary protocolautotel: Vendor-neutral OpenTelemetry wrapper, OTLP standard
Autotel is better if you want vendor flexibility. Both work with Datadog.
How do I reduce costs?
Section titled “How do I reduce costs?”- Use Datadog Agent (batches/compresses data)
- Use adaptive sampling (lower baseline rate)
- Filter noisy endpoints (health checks, metrics endpoints)
See High Costs troubleshooting.
Can I send logs to Datadog without OTLP?
Section titled “Can I send logs to Datadog without OTLP?”Yes! You can:
- Keep your existing log transport (pino-datadog-transport, winston-datadog)
- Use Autotel for traces/metrics only
- Set
enableLogs: falsein config
Traces will still correlate with logs if you use createBuiltinLogger() (it adds trace IDs to logs).
Does this work with Cloudflare Workers / Vercel Edge?
Section titled “Does this work with Cloudflare Workers / Vercel Edge?”Use autotel-edge instead of autotel. Same API, optimized for edge runtimes.
import { init, trace, withTracing } from 'autotel-edge';// ... rest is the sameHow do I see infrastructure metrics?
Section titled “How do I see infrastructure metrics?”Install the Datadog Agent. It auto-collects CPU, memory, disk, network, and has 500+ integrations (Redis, PostgreSQL, etc.).
Direct cloud ingestion only sends application metrics (traces, custom metrics), not infrastructure.
Can I switch from Datadog to Honeycomb later?
Section titled “Can I switch from Datadog to Honeycomb later?”Yes! That’s the benefit of OTLP. Just change the endpoint and otlpHeaders in your config:
// Switch from Datadog to Honeycombinit({ service: 'my-app', endpoint: 'https://api.honeycomb.io/v1/traces', // Changed otlpHeaders: `x-honeycomb-team=${HONEYCOMB_API_KEY}`, // Changed // No code changes needed!});Example Application
Section titled “Example Application”See the complete working example:
Location: example-datadog
Features demonstrated:
- Direct cloud ingestion setup
- Traces with custom attributes
- Logs with automatic trace correlation
- Custom business metrics
- Error handling and capture
- Nested spans
- Environment-based configuration
Run it:
cd apps/example-datadogcp .env.example .env# Add your DATADOG_API_KEY to .envpnpm installpnpm startAdditional Resources
Section titled “Additional Resources”- Datadog OTLP Documentation
- OpenTelemetry Specification
- Datadog Unified Service Tagging
- Datadog Agent OTLP Configuration
- Autotel GitHub
Support
Section titled “Support”Autotel Issues: GitHub Issues Datadog Support: Datadog Help
For integration questions, please open a GitHub issue with:
- Your deployment type (serverless, Kubernetes, etc.)
- Architecture choice (Agent vs direct ingestion)
- Configuration snippet (redact API keys!)
- Error messages or unexpected behavior