Ostium wire protocol codec: newline-framed text lines over a unix
stream socket, fields separated by |. Shared by the bundled client
and the ostiarius daemon, so encoder and decoder can never drift.
Metric lines (m) carry counter deltas, gauges, or pre-aggregated
timings; block commands (b) and CLI queries (q) get replies
(ok/err/qd/qe). Label values and free-text fields
percent-encode %, |, ,, = and control bytes, so a raw split
on the delimiters is always safe.
| Name | Signature |
|---|---|
| valid_app | valid_app(app) -> ok |
| valid_name | valid_name(name) -> ok |
| valid_ip | valid_ip(ip) -> ok |
| escape | escape(s) -> escaped |
| unescape | unescape(s) -> decoded, err |
| format_num | format_num(n) -> formatted, err |
| canonical_labels | canonical_labels(labels) -> labels_str, err |
| parse_labels | parse_labels(labels_str) -> labels, err |
| series_id | series_id(app, name, labels) -> id, err |
| encode_counter | encode_counter(app, name, labels, delta) -> line, err |
| encode_gauge | encode_gauge(app, name, labels, value) -> line, err |
| encode_timing | encode_timing(app, name, labels, agg) -> line, err |
| encode_block | encode_block(app, ip, opts) -> line, err |
| encode_query | encode_query(cmd, arg) -> line, err |
| encode_reply | encode_reply(kind, a, b) -> line, err |
| decode | decode(line) -> msg, err |
valid_app(
app) ->ok
Check that an app name is valid for the wire
App names are 1 to 32 bytes of [a-z0-9_-]. The alphabet excludes
every field delimiter, so an app name never needs escaping.
valid_name(
name) ->ok
Check that a metric name is valid for the wire
Metric names are 1 to 64 bytes of [a-z0-9_], the same
delimiter-free alphabet rule that applies to app names.
valid_ip(
ip) ->ok
Check that a string is plausibly an IP address
A shape check only: up to 45 bytes of hex digits, dots and colons, which covers IPv4, IPv6 and IPv4-mapped forms. The daemon hands the address to ipset, which is the real parser.
escape(
s) ->escaped
Percent-encode the characters that would break field framing
Encodes %, |, ,, = and control bytes as %XX. Applied to
label values and to free text such as the block reason, so a raw
split on the delimiters is always safe.
unescape(
s) ->decoded,err
Decode a percent-encoded field back to its raw bytes
Rejects a % that is not followed by two hex digits; every other
byte passes through untouched.
format_num(
n) ->formatted,err
Format a number for the wire
%.14g matches LuaJIT's own tostring precision: enough significant
digits to carry unix timestamps intact (a plain %.9g would round
them), while never printing locale-dependent or exponentless noise.
Non-finite values are rejected.
canonical_labels(
labels) ->labels_str,err
Canonicalize a labels table into the wire labels string
Validates label keys against [a-z0-9_]{1,32}, escapes values (max
128 bytes before escaping), sorts pairs by key and joins them as
key=value,.... A nil or empty table yields the empty string. Series
identity relies on this canonical form: the same table always encodes
to the same string.
parse_labels(
labels_str) ->labels,err
Parse a canonical labels string back into a table
series_id(
app,name,labels) ->id,err
Build the canonical series identity string
Returns app|name|labels with labels in canonical form. Accepts
either a labels table (canonicalized here) or an already-canonical
labels string (passed through untouched).
encode_counter(
app,name,labels,delta) ->line,err
Encode a counter delta metric line
The delta is the increment accumulated since the last flush, never a running total, and must be a finite number no smaller than zero.
encode_gauge(
app,name,labels,value) ->line,err
Encode a gauge metric line
The value is absolute and replaces whatever the daemon currently holds for the series.
encode_timing(
app,name,labels,agg) ->line,err
Encode a timing aggregate metric line
agg is {count, sum, min, max} in seconds, accumulated by the
client between flushes. Count must be a positive integer and min
must not exceed max.
encode_block(
app,ip,opts) ->line,err
Encode a block command line
opts.ttl is a non-negative integer in seconds (0 or absent means
the ipset default); opts.reason is free text, escaped on the wire.
encode_query(
cmd,arg) ->line,err
Encode a CLI query line
encode_reply(
kind,a,b) ->line,err
Encode a reply line
Kinds: ("ok", mtype), ("err", mtype, message) with the message
escaped, ("qd", fields) where fields is an array of raw strings
that must not contain | or control bytes (the producer escapes
free-text portions itself), ("qe", count).
decode(
line) ->msg,err
Decode one protocol line into a tagged message table
Accepts a line with or without the trailing newline (\r\n is
tolerated for interactive debugging). Returns a table tagged by
kind: "metric", "block", "query", "ok", "err", "qd" or "qe".
Metric labels stay in their raw canonical string form; the daemon
treats them as an opaque, sorted identity component.