Adapters

Datadog Adapter

Send wide events to Datadog Logs via the native HTTP intake API. Supports all Datadog sites and DD_* environment variables.

Datadog is a monitoring and security platform. The evlog Datadog adapter sends your wide events to Datadog Logs using the HTTP Logs intake API (v2) with the DD-API-KEY header.

For OpenTelemetry-based ingestion instead, see the OTLP adapter.

Prompt
Add the Datadog drain adapter to send evlog wide events to Datadog Logs.

1. Identify which framework I'm using and follow its evlog integration pattern
2. Install evlog if not already installed
3. Import createDatadogDrain from 'evlog/datadog'
4. Wire createDatadogDrain() into my framework's drain configuration
5. Set DD_API_KEY (or DATADOG_API_KEY) and optionally DD_SITE in .env
6. Test by triggering a request and checking Log Explorer in Datadog

Adapter docs: https://www.evlog.dev/adapters/datadog
Framework setup: https://www.evlog.dev/frameworks

Installation

The Datadog adapter comes bundled with evlog:

src/index.ts
import { createDatadogDrain } from 'evlog/datadog'

Quick Start

1. Get your API key

  1. Open Datadog Organization Settings → API Keys
  2. Create or copy an API key with permission to submit logs

2. Set environment variables

.env
DD_API_KEY=your-api-key
# Optional — defaults to datadoghq.com (US1)
DD_SITE=datadoghq.eu

3. Wire the drain to your framework

// server/plugins/evlog-drain.ts
import { createDatadogDrain } from 'evlog/datadog'

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('evlog:drain', createDatadogDrain())
})

Wide events appear in Logs → Explorer. The adapter sets ddsource to evlog and message to a JSON string of the full wide event for easy JSON parsing in pipelines.

Configuration

The adapter reads configuration from multiple sources (highest priority first):

  1. Overrides passed to createDatadogDrain()
  2. Runtime config at runtimeConfig.datadog or runtimeConfig.evlog.datadog (Nuxt/Nitro)
  3. Environment variables — see table below

Environment Variables

VariableNuxt aliasDescription
DD_API_KEYNUXT_DATADOG_API_KEYDatadog API key (required). Also: DATADOG_API_KEY
DD_SITENUXT_DATADOG_SITESite hostname (e.g. datadoghq.com, datadoghq.eu, us3.datadoghq.com). Also: DATADOG_SITE
DATADOG_LOGS_URLNUXT_DATADOG_LOGS_URLFull intake URL — overrides URL derived from site

Runtime Config (Nuxt only)

nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    datadog: {
      apiKey: '', // Set via NUXT_DATADOG_API_KEY or DD_API_KEY
      site: 'datadoghq.eu',
    },
  },
})

Override Options

server/plugins/evlog-drain.ts
const drain = createDatadogDrain({
  apiKey: '***',
  site: 'us5.datadoghq.com',
  timeout: 10000,
})

Full Configuration Reference

OptionTypeDefaultDescription
apiKeystringDatadog API key (required)
sitestringdatadoghq.comSite for intake host http-intake.logs.${site}
intakeUrlstringfrom siteFull POST URL for /api/v2/logs
timeoutnumber5000Request timeout (ms)
retriesnumber2Retries on transient failures

Log shape

Each wide event becomes one Datadog log with:

  • message — short one-line summary for the list view (e.g. ERROR GET /api/checkout (400)), built with formatDatadogMessageLine. Easier to scan than a full JSON blob in Live Tail.
  • evlog — full wide event as a JSON object (not a string). Numeric HTTP status fields anywhere in the tree are renamed to httpStatusCode so they never clash with Datadog’s reserved severity status.
  • service, status (Datadog severity — drives Live Tail color), ddsource: evlog, ddtags: env:… and optional version:…
  • timestamp: Unix milliseconds from WideEvent.timestamp

Severity (status) at intake root is computed by the adapter from the wide event’s level and HTTP status (resolveDatadogLogStatus in evlog/datadog). Business-only fields on HTTP 200 stay info unless you call log.error().

For advanced use, sanitizeWideEventForDatadog(event) returns only the sanitized object you would store under evlog.

Querying in Datadog

  • Log Explorer: source:evlog, service:your-app, status:error
  • Facets: prefer @evlog.path, @evlog.requestId, @evlog.level, etc. — core fields are under evlog, not a JSON string in message
  • Metrics: log-based metrics on @evlog.* attributes
  • Pipelines: if you previously parsed a full JSON string inside message, move those facets to @evlog.*. The message field is now a short summary line only.

Simple logs vs wide events

Plain-text lines in Live Tail (e.g. “Form field is empty”) usually come from log.info('tag', 'msg') or similar, not from the wide event sent on emit(). Those lines go to the console (and any Agent-based log stream), while the Datadog drain sends one structured log per wide event under source:evlog.

Troubleshooting

Missing API key

Console
[evlog/datadog] Missing API key. Set NUXT_DATADOG_API_KEY, DATADOG_API_KEY, or DD_API_KEY...

Set DD_API_KEY (or unprefixed DATADOG_API_KEY) and restart the process.

403 Forbidden

The API key may lack log ingestion permission or belong to the wrong organization. Verify the key in Datadog and try a new key.

Wrong region / site

If logs never appear, confirm DD_SITE matches your Datadog account (e.g. EU: datadoghq.eu). For a custom intake URL, set DATADOG_LOGS_URL / NUXT_DATADOG_LOGS_URL.

Direct API usage

server/utils/datadog.ts
import { sendToDatadog, sendBatchToDatadog } from 'evlog/datadog'

await sendToDatadog(event, {
  apiKey: process.env.DD_API_KEY!,
  site: process.env.DD_SITE,
})

await sendBatchToDatadog(events, {
  apiKey: process.env.DD_API_KEY!,
})

Next Steps