On this page

Log drains

Send a project's API, Auth, REST, Postgres and Edge Function logs to Datadog, Loki (or Grafana Cloud) or your own https endpoint.

LimitFreeProScaleEnterprise
Log drains per project01310

A log drain sends your project's logs to your own log service as well, about a minute after they happen. They are the same lines you search in the dashboard, and they stay searchable there. Open your project, choose Logs → Log drains and Add log drain. Owners and admins of the project can manage them.

#Destinations

Send toWhat you enterWhat arrives
DatadogYour Datadog site (datadoghq.com, datadoghq.eu, us3, us5, ap1, gov) and an API key; optionally a service name and tagsLines through the Logs intake API with ddsource:stitchdb, service:stitchdb-<source> (or your service), host = project ref, the level as status, tags project:<ref> and source:<source>, and every field under stitchdb.*
Loki / Grafana CloudThe Loki URL, and a user + token (Grafana Cloud) or a bearer token; optionally a tenantStreams labelled service_name="stitchdb", project, source and level; each line is JSON with message and the source's fields
HTTPS endpointAn https URL and up to 10 extra headersA POST per batch: a gzip'ed JSON array of lines, signed (below)

For each drain you choose the sources (API requests, Auth, REST server, Postgres, Edge Functions) and the lowest level to send: everything, info and above (the default), warnings and errors, or errors only. Send test sends one line now and shows what the service answered.

#Your own endpoint

Each request has Content-Type: application/json, Content-Encoding: gzip and a body like:

JSON
[
  { "timestamp": "2026-10-26T10:00:01.234Z", "level": "error", "message": "GET /rest/v1/orders 500", "source": "api",
    "project_ref": "<ref>", "method": "GET", "path": "/rest/v1/orders", "status": 500, "ms": 41, "ip": "203.0.113.7" }
]

A batch has up to 1,000 lines. Answer with any 2xx status. The headers StitchDB-Timestamp and StitchDB-Signature: v1=<hex> let you check that it came from us: the signature is the HMAC-SHA256 of <timestamp>.<body> (the body after un-gzipping) with the drain's signing secret, which is shown once when you add the drain.

JavaScript
import { createHmac, timingSafeEqual } from 'node:crypto'

function verify(body, headers, secret) {
  const want = 'v1=' + createHmac('sha256', secret).update(headers['stitchdb-timestamp'] + '.' + body).digest('hex')
  const got = headers['stitchdb-signature'] || ''
  const fresh = Math.abs(Date.now() / 1000 - Number(headers['stitchdb-timestamp'])) < 300
  return fresh && got.length === want.length && timingSafeEqual(Buffer.from(got), Buffer.from(want))
}

#When the service is down

Lines wait on our side and are retried with growing delays (10 seconds up to 30 minutes), oldest first, so nothing is lost during a short outage. Up to 3 days or 256 MB of lines wait per drain; older lines are dropped and counted on the drain. When sending has failed for an hour, the project owner gets one e-mail. The dashboard shows each drain's status, lines sent, lines waiting and the last error.

#From the API

Terminal
curl -X POST "https://stitchdb.com/platform/v1/projects/<ref>/log-drains" \
  -H "Authorization: Bearer $STITCHDB_TOKEN" -H "Content-Type: application/json" \
  -d '{ "name": "Datadog", "kind": "datadog", "config": { "site": "datadoghq.eu", "api_key": "<key>" }, "sources": ["api", "postgres"], "min_level": "warn" }'
RequestWhat it does
GET /projects/<ref>/log-drainsThe drains with status, counts and last error (never the keys)
POST /projects/<ref>/log-drainsAdd a drain: name, kind (datadog, loki, http), config, sources, min_level
PATCH /projects/<ref>/log-drains/<id>Change it, or { "enabled": false } to turn it off. Keys left out are kept.
POST /projects/<ref>/log-drains/<id>/testSend one test line
DELETE /projects/<ref>/log-drains/<id>Delete it and the lines waiting for it
Was this helpful?