Skip to main content
Version: 3.0 (next)

Datadog HTTP intake — NDJSON ingest from MaestroHub

Datadog's Logs → HTTP intake accepts line-delimited JSON directly. Our format=ndjson output ships every field Datadog needs to build correlations without a custom parser.

1. Create an OAuth2 client​

Same as Splunk setup step 1.

2. Configure the collector​

We recommend a small forwarder (Vector, Fluent Bit, or your own systemd timer) rather than the Datadog Agent's built-in HTTP source — the Agent's HTTP source doesn't support opaque cursors natively.

Vector​

[sources.maestrohub_audit]
type = "http_client"
endpoint = "https://<your-maestro>/api/v1/audit/export"
method = "GET"
query = { format = "ndjson", from = "${MAESTRO_LAST_CURSOR_TS}", to = "now", cursor = "${MAESTRO_LAST_CURSOR}", limit = "1000" }
scrape_interval_secs = 60
auth = { strategy = "bearer", token = "${MAESTRO_ACCESS_TOKEN}" }
decoding = { codec = "json" }
framing = { method = "newline_delimited" }

[transforms.tag_source]
type = "remap"
inputs = ["maestrohub_audit"]
source = '''
.service = "maestrohub"
.@source = "maestrohub-audit"
'''

[sinks.datadog_logs]
type = "datadog_logs"
inputs = ["tag_source"]
default_api_key = "${DATADOG_API_KEY}"
site = "datadoghq.com"

Vector persists the cursor via its state_dir — set that to a durable path.

Refresh loop​

Handle both token refresh and cursor persistence in a tiny wrapper script alongside Vector — Vector doesn't manage OAuth2 refresh natively.

3. Set up Datadog service correlation​

In Datadog:

  1. Logs → Configuration → Pipelines → New Pipeline.
  2. Filter: service:maestrohub.
  3. Add a Grok Parser processor:
%%{data::json}
  1. Add a Standard Attribute Remapper:
    • correlation_id → dd.trace_id (so audit events correlate with APM traces)
    • actor.id → usr.id (Datadog's user-facet field)
    • org_id → dd.tags.tenant

4. Validate​

Datadog log explorer:

service:maestrohub action:role.assigned

Every event carries:

  • action (e.g. role.assigned)
  • actor_id, actor_email
  • subject
  • resource_type, resource_id
  • org_id, correlation_id
  • severity (0–10), category

Correlation with APM​

When your MaestroHub deployment ships APM traces to the same Datadog account, the correlation_id on every audit event equals the OpenTelemetry trace_id on the corresponding request. In Datadog:

  • From an audit event, click through to the trace.
  • From an APM trace, filter logs by dd.trace_id:* to see every audit event the request produced.

Troubleshooting​

Vector logs "unexpected response body". The audit endpoint response is line-delimited JSON, not an array. Set framing.method = "newline_delimited" in Vector's decoding — a common misconfiguration.

Datadog shows records with no correlation_id. Records emitted before UC36 shipped carry empty correlation IDs. Records emitted after ship carry the trace id iff the request had an OpenTelemetry trace context (i.e. the caller's HTTP framework enabled the OTel middleware).