Bilis Docs
Documentation

Ingestion

Timestamps

What Bilis accepts as a time, how it is normalised, and why event time is not arrival time.

Every log line is stored with one timestamp, in a ClickHouse DateTime64(9, 'UTC') column. Nine fractional digits: nanosecond resolution, always UTC.

Accepted formats

The simple JSON endpoint takes whatever your shipper already has:

Input Example Read as
ISO 8601 with an offset 2026-08-26T14:02:11.418+02:00 That instant, converted to UTC
ISO 8601 without an offset 2026-08-26 12:02:11.418 Assumed UTC
Unix seconds 1756211400 or 1756211400.418 Seconds
Unix milliseconds 1756211400123 Milliseconds
Unix microseconds 1756211400123456 Microseconds
Unix nanoseconds 1756211400123456789 Nanoseconds

Numeric values are disambiguated by digit count, not by a unit field: 18 digits or more is nanoseconds, 15–17 is microseconds, 12–14 is milliseconds, and anything shorter is seconds. That covers every unix epoch value from 1970 to well past 2200 without you having to declare a unit.

The OTLP endpoint uses OTLP's own field, timeUnixNano, which is always nanoseconds.

If a value cannot be understood at all, the record is not rejected — it falls back to arrival time.

Note: a naive timestamp is assumed to be UTC, not local. If your shipper emits 2026-08-26 14:02:11 in Europe/Bratislava, the line will land two hours in the future. Send an offset.

Event time and arrival time

Two different instants exist for any log line:

  • Event time — when the thing happened, according to the client.
  • Arrival time — when Bilis received the request.

Bilis stores the client's event time when there is one, and falls back to arrival time when there is not. OTLP has both fields, and the fallback order is exactly: timeUnixNano, then observedTimeUnixNano, then arrival.

This matters because shippers buffer. A Monolog handler that flushes after the response, a collector with a persistent sending queue, a mobile client that was offline for an hour — all of them deliver lines minutes or hours after the event. If arrival time won, a queue drain would stack thousands of lines onto one instant and your incident timeline would be fiction. Event time keeps the ordering that actually happened.

The consequence to know about: a line can appear "in the past". A batch delivered at 14:20 carrying events from 14:02 lands at 14:02 in the viewer, behind where you were looking. If a line seems missing, widen the time range before you suspect ingest.

Precision is preserved

Nanoseconds are formatted with string arithmetic — never round-tripped through a float or a DateTime object, both of which would quietly truncate. What you send at nanosecond resolution is what is stored:

1756211400123456789  ->  2026-08-26 12:30:00.123456789

Most shippers only have milliseconds, which is fine; the remaining digits are zero-padded.