loki drain pushes to Grafana Cloud Loki or a Loki you run yourself. Each record becomes one entry in a stream, labelled with five labels and carrying the whole Lua record as its JSON line — so | json reaches every field at query time without a label for it.
Vendor destinations are opened per deployment. Where
loki is not open yet, a create answers 422 DRAIN_TYPE_UNAVAILABLE and the message names the types that are. It may not be enabled on your deployment yet.- Your Loki host. On Grafana Cloud it is the Loki data source’s URL,
https://logs-prod-012.grafana.net. - Credentials: on Grafana Cloud, your instance ID and an access policy token, used as HTTP Basic. A self-hosted Loki behind a gateway may take a bearer token instead.
- For a multi-tenant Loki: your tenant id, for
X-Scope-OrgID.
What to enter
/loki/api/v1/push is composed onto whatever host you give, and composition is idempotent — paste the bare host or the full push URL, whichever your Grafana UI showed you. A non-default port is kept, which a self-hosted Loki usually needs; a query string or fragment is dropped.
There is no host allow-list for this type: Grafana Cloud and a self-hosted stack are equally your host. It is still validated as https: and as resolving entirely to public addresses, re-checked on every send.
X-Scope-OrgID is a per-customer value, so it rides as one of the drain’s own headers rather than as something the preset sets. Add it with --header X-Scope-OrgID (the CLI prompts for the value) only if your Loki is multi-tenant. Grafana Cloud does not want it — the Basic credential already carries the tenant.How ownership verification works
204, which is a 2xx and verifies fine. A 401 means the Basic credential is wrong or is missing its scheme; a 403 on Grafana Cloud usually means the access policy lacks logs:write. Verification is limited to 5 attempts per drain per hour.
Loki deliveries are not signed.
What arrives
unordered_writes window.
Five labels, and why there are only five
Loki indexes label sets: every distinct combination is a stream with its own index entry and its own chunks. A label whose values are not a small closed enum is a cost bug in your Loki bill, not in ours — which is why
eventName, tool names, and primitive names are deliberately not labels. They ride inside the JSON line, where | json reaches them at query time for free.
Loki’s own ceiling is 15 labels. Five leaves room for whatever your own pipeline adds.
Useful queries
| json flattens nested keys with _, so attributes["gen_ai.tool.name"] is reachable as attributes_gen_ai_tool_name.
Caps
A record over 256 KiB has its
body cut and suffixed ... [truncated by lua] rather than being dropped.
Two terminal 400s worth recognising
Every non-429 4xx is terminal — the batch is dropped and counted under rejected, not retried, because the same bytes would be refused again.
line_too_long— an entry exceeded your Loki’smax_line_size. The 256 KiB per-record cap exists to make this unreachable, so if you see it, your Loki’s limit is set below the default. Raisemax_line_size, or narrow the drain’s sources so the long records stop being produced.entry too far behind/too_far_behind— the record is older than yourreject_old_samples_max_age. Lua only retries a batch for 6 hours, so this normally only bites a drain that was paused for longer and then resumed with a deep backlog. Raisereject_old_samples_max_age, or accept the loss of the oldest range.
Test the credential with curl
204 with an empty body means accepted. Then query it back:
If it isn’t working
401 on every push
401 on every push
The stored
Authorization value is incomplete. It must be the whole header value — Basic <base64> or Bearer <token> — with the scheme. Re-enter it with lua drains update <id> --header Authorization.400 with no tenant provided
400 with no tenant provided
Your Loki is multi-tenant and wants
X-Scope-OrgID. Add it: lua drains update <id> --header X-Scope-OrgID.Queries return nothing although the drain is healthy
Queries return nothing although the drain is healthy
healthy means Loki accepted the push. Check the label selector first — every stream carries org, agent, and environment, so {org="…"} alone should match. Then check the time range: Loki files entries at the record’s own timestamp, not at ingest.Our Loki bill jumped
Our Loki bill jumped
Not from these labels — five is deliberately few. Check whether a pipeline of yours is promoting fields out of the JSON line into labels.
eventName and tool names have high cardinality and belong in the line.Next steps
Grafana dashboard pack
An importable dashboard built on these fields.
Event schema
Every field inside the JSON line.
Protecting your destination
What verification does and does not prove.
lua drains
Every verb and flag.

