Skip to content
Obsevo
Skip to docs navigation

Docs

Sending logs

Three ways in, all authenticated with an event key, all landing on one timeline beside your runs and nodes.

Everything Obsevo observes — log lines, run outcomes and node executions — shares one timeline in Log explorer, filterable by record type, severity, workflow, source, environment and any attribute in the payload.

Log lines get in three ways. All are authenticated with an event key (Instances → the instance's key icon) and all land on that key's instance.

PathFor
POST /ingest/logsthe n8n-nodes-obsevo community node
POST /ingest/logs/rawanything that can post JSON
POST /v1/logsOpenTelemetry exporters (OTLP/HTTP, JSON and protobuf)

The instance is derived from the key, so there is no field in any of these payloads for saying which instance a line belongs to.

The raw endpoint

It takes whatever shape you already have — a single object, an array, { "logs": [...] } (records and items also work as the wrapper key), or newline-delimited JSON.

curl -X POST https://ingest.example.com/ingest/logs/raw \
  -H 'authorization: Bearer obse_…' \
  -H 'content-type: application/json' \
  -d '{"message":"card declined","level":"error","orderId":"A-1"}'

The message, the level and the timestamp are worked out server-side, so a payload written for pino, Datadog, GCP, OTel or syslog lands correctly without being reshaped first — see the field precedence reference.

Newline-delimited JSON is detected by content rather than by content-type, on the grounds that a sender posting NDJSON with application/json is wrong about the header but right about the intent. An unparseable line is skipped rather than failing the batch: one bad line in a thousand should not lose the other 999.

OpenTelemetry

Point an exporter at /v1/logs. No encoding override is needed — protobuf is accepted as well as JSON.

exporters:
  otlphttp:
    logs_endpoint: https://ingest.example.com/v1/logs
    headers:
      authorization: Bearer obse_…

Set n8n.execution.id (an OTLP attribute) or executionId (raw JSON) to correlate a line with an n8n run. The explorer then shows it beside that run and its nodes.

The response is the OTLP spec's { "partialSuccess": {} } rather than Obsevo's usual shape, because an exporter reads partialSuccess and will retry forever against anything else.

Limits and refusals

ResponseMeaning
202 { "accepted": n }Accepted for processing
413 batch_too_largeMore than 200 records in one batch
429 rate_limitedOver the per-instance log budget. retry-after: 60
402 quota_exceededThe workspace's monthly log line and business event allowance is used up (Cloud)
400 invalid_payloadThe batch failed validation; the body names the offending paths

When the monthly allowance runs out

On Obsevo Cloud, log lines and business events count against a monthly allowance set by the plan. Once it is used up, every log, raw-log, event and OTLP logs request is answered 402 quota_exceeded, and nothing in that batch is stored — a batch is admitted whole or not at all, never partly. The meter resets at 00:00 UTC on the 1st of the month; from then on the same requests succeed again.

What the sender does with the 402 is up to the sender:

  • An OpenTelemetry exporter treats it as permanent and drops the batch. The OTLP spec retries only 429, 502, 503 and 504.
  • A workflow posting through the n8n node or an HTTP Request node gets an error back from that node, like any other failed request.

Retrying before the reset achieves nothing. Owners are emailed at 80% and 100% of the allowance, and the dashboard shows a banner. Run monitoring is not part of this: executions are counted but never refused, so runs, incidents and alerts keep working whatever the meter says.

Logs have their own rate budget, separate from business events and from agent pushes. A workflow that emits one KPI event per run may well log a line per item, and sharing a limiter would throttle normal use the moment someone turned logging on.

Values under credential-shaped keys are redacted on arrival, and env is never read from the payload — it comes from the instance the event key belongs to.

Documentation