SDKs
The ScaiLog SDK is the emit side of the system: your service calls it to write a
structured log entry, and it ships that entry to the local scailog-agent (or a
standalone server's embedded agent). ScaiLog ships four SDKs — Python,
TypeScript, Go, and .NET — that are wire-identical: the same log emitted from
any of them is encrypted at ingest and decrypts correctly back through DSAR, and
each SDK re-checks the shared Annex A.3 checksum vector in its own test suite so
the wire format cannot drift between languages.
The shared model#
Every SDK enforces the same contract, so the rules you learn in one language carry over unchanged to the others.
- A mandatory, validated
call_site_id. The first argument to every emit call is a developer-assigned call-site id. It must match^[A-Z0-9]+(-[A-Z0-9]+){2,}$(at least three uppercase-alphanumeric segments, e.g.SCAI-CHECKOUT-PAID-001). TheAUTO-andSCAILOG-prefixes are reserved. Call-site provenance is first-class in ScaiLog: GDPR remediation is "fix one call site." - Field-level PI marking with
pi(value, type). You mark a single named field as personal information by wrapping its value, e.g.pi("jan@example.nl", "direct_identifier"). Markers attach to fields only — never to the whole entry and never to the free-textmessage, which is indexed in plaintext (FTS5) and must stay PI-free. - A subject is required whenever any PI is present. If an entry carries one
or more
pi()fields, it must also carry asubject(the data-subject id). This is enforced in the SDK before the entry leaves the process, and again at the server (SUBJECT_REQUIRED). - Reserved field names are rejected. Field names that collide with reserved
top-level keys (
event_id,tenant,service,env,site,level,ts,msg,fields,pi,subject,trace_id,request_id) are not allowed. - ULID event ids. Each entry gets a lexicographically sortable ULID, returned by the emit call.
- Socket NDJSON with a non-silent stderr fallback. Entries are queued in process and sent as newline-delimited JSON over a Unix domain socket to the local agent. If the queue is full or the socket is unavailable, the entry is written to stderr in the same NDJSON shape rather than being silently dropped — and PI field values are redacted first (the field name and PI type stay, so the drop is auditable) so stderr never leaks the plaintext ScaiLog exists to protect.
The six log levels are the same everywhere: trace, debug, info, warn,
error, fatal.
Language pages#
| SDK | Package | Page |
|---|---|---|
| Python (reference) | scailog (PyPI) |
Python SDK |
| TypeScript | @scailabs/scailog (npm) |
TypeScript SDK |
| Go | github.com/scailabs/scailog-go |
Go SDK |
| .NET | ScaiLabs.ScaiLog (net8.0) |
.NET SDK |
The Python SDK is the reference implementation; the other three mirror it. The
Python base install is pure stdlib — pip install scailog pulls zero
third-party dependencies, so a service that only emits logs stays featherweight.
Validating call sites in CI#
Beyond the runtime SDK, the zero-dependency scailog-ci tool statically checks
your call sites at build time — constant, unique, well-formed call_site_id; no
message interpolation; pi() accompanied by a subject — and can push a call-site
manifest to the server. See
CI call-site validation.