Bilis
Features Pricing Docs Blog
Documentation

Ingestion

View raw

Sentry-compatible ingest

Bilis speaks the Sentry SDKs' ingest protocol, so an SDK you already have can ship exceptions here as searchable error logs.

Sentry's SDKs are good at one thing Bilis does not do itself: catching an exception in your application and packaging it with the context around it. Bilis implements the ingest protocol those SDKs speak, so you can point one at Bilis and have its exceptions land in your log stream.

This is protocol compatibility for log ingestion, and nothing more. Bilis is a log store: exceptions arrive as ERROR records in the same table, searchable over the same time range as everything else you ship. There is no issue list, no grouping, no assignment and no resolve button, and none is planned. If you want error tracking, you want Sentry — this is for putting the exceptions your app already reports next to the logs that explain them.

Sentry is a trademark of Functional Software, Inc. Bilis is not affiliated with, endorsed by, or a replacement for it; the SDKs remain theirs, and this page only describes an endpoint that accepts what they send.

Pointing an SDK at Bilis

An SDK is configured with a DSN, which carries the public half of an API key. Copy it from Projects → your project, under the key you want to use:

https://bilis_pk_YOUR_PUBLIC_KEY@bilis.example.com/1

Set it wherever the SDK reads its DSN:

SENTRY_DSN="https://bilis_pk_YOUR_PUBLIC_KEY@bilis.example.com/1"

That is the whole setup. The SDK builds its own endpoint from the DSN and posts envelopes to POST /api/{id}/envelope/, which is why the path is Sentry's shape rather than /api/v1.

The project id at the end of the DSN is ignored. The project is always the one the public key belongs to, exactly as it is for the other ingest endpoints.

What is stored

One envelope event becomes one log record:

Log field Comes from
Body Type: message of the thrown exception, or the event's message
Severity The SDK's level (warning becomes WARN)
Service The service tag, falling back to server_name
Trace / span id contexts.trace, which is already OpenTelemetry's hex
Timestamp The event timestamp

Everything else is flattened into attributes, under the OpenTelemetry names the rest of your logs already use rather than the ones on the wire:

Attribute Was
exception.type, exception.message the thrown exception
exception.stacktrace the frames, most recent first
exception.origin the innermost frame in your own code
exception.handled, exception.mechanism how it was caught
service.version, service.dist release, dist
deployment.environment environment
transaction.name, logger.name, event.id transaction, logger, event id
host.name server name
telemetry.sdk.name, .version, .language which client reported it
process.runtime.name, .version the runtime context
tag.*, extra.*, user.*, http.* tags, extras, user, request
breadcrumbs breadcrumbs, newest first

Search them the way you search any attribute — exception.type is a good place to start when you want one class of failure.

What is not stored

An SDK sends more than events. Performance transactions, sessions, attachments, minidumps and client reports all belong to features Bilis does not have, so they are counted and dropped. The SDK is never told they failed — it would only retry them.

transaction items are among what is dropped: this endpoint stores errors, and Bilis takes traces over OTLP instead. Leave traces_sample_rate at zero, or a transaction is sent only to be discarded.

Errors still join the traces you send over OTLP. When the SDK puts a contexts.trace on an event — which it does whenever it is running inside a propagated trace — its trace_id and span_id are stored in the log record's TraceId / SpanId columns, so the error links to that trace's waterfall and the span links back to the error. Both must be OpenTelemetry's hex spelling (32 and 16 characters); an id in any other shape is left empty rather than stored as something no trace will ever match.

From the browser

A page can only post to Bilis from an origin you have listed. Add it under Projects → your project → Browser origins, one per line:

https://shop.example.com
https://*.staging.example.com

Scheme and host, plus a port if it is not the default. A leading *. stands for exactly one subdomain label, so https://*.example.com covers https://app.example.com and not https://a.b.example.com. A lone * allows any origin, which is worth doing only while you are testing.

An empty list means no browser may post at all, which is the right setting for a project that only ships from servers. Nothing is rejected outright — the request may still reach Bilis — but without a header naming its origin the browser discards the response, and the SDK is told its request went nowhere.

This is per project, not per key, because it describes where your application is served from. It is also why the public key being readable costs you little: the key alone is not enough to post from a page you do not control.

Compatibility

  • Server-side SDKs work as they are.
  • Browser SDKs work once their origin is listed above.
  • The older POST /api/{id}/store/ endpoint is accepted too.
  • Gzipped bodies, which most SDKs send by default, are inflated.

Everything else follows the usual ingest contract: a payload Bilis cannot read is counted and dropped, never answered with a client error. See Limits and behavior.