Web & APIs
Observability
Zornux treats logs, metrics, health, and audit as language constructs, not library calls. Your program emits structured events; the host decides where they go — so the same code runs quietly in tests and verbosely in production.
Structured logging
log LEVEL "message" emits a structured event, optionally with
a map of fields. The four levels are debug, info,
warning, and error:
log info "Order received"
log warning "Low stock" with { "product": "P-1", "remaining": 3 }
Where logs go and the minimum level come from configuration — log_level (debug / info / warning / error), log_output (console / file / none), and log_file — never from code. That's what keeps the same program quiet in tests and detailed in production.
Metrics
count "name" adds one to a named counter; measure
"name" as value records a numeric sample. Read them back with the
metric_count and metric_values built-ins:
for each price in [12, 30, 7]
count "sales"
measure "sale_amount" as price
end
show "sales: " + text(metric_count("sales")) # sales: 3
Request tracing
Inside a web request, every log event automatically carries
the request's correlation id and the handling component —
so one provider chain tells the whole request story. Pair it with the
add correlation id and
log requests pipeline steps for end-to-end tracing.
Requests carry a W3C trace context, and the host can export spans and metrics to any OpenTelemetry collector over OTLP — set traces_endpoint and metrics_endpoint in configuration. No vendor SDK to install.
Health checks
A web block's health … end block auto-registers
GET /health. Give back ok for healthy
(200) or failing "reason" for unhealthy
(503) — and the current metric counters ride along in the
payload:
controller Products at "/products"
on GET "/"
count "product_views"
give back ok message "3 products"
end
end
web Store
create open = true
health
if open
give back ok
end
give back failing "store is closed"
end
use Products
end
publish Store on port 5000
The /health route bypasses the request pipeline, so probes aren't rate-limited or short-circuited. It also reports background-job vitals — pending, failed, and scheduled counts.
Audit trail
audit "event" records an always-on business event. Unlike
log, it bypasses the minimum log level — an
audit trail can't be silenced by configuration — and it carries the acting
principal as actor:
audit "user_deleted" with { "user_id": 42 }
| Construct | Purpose |
|---|---|
log debug|info|warning|error "msg" [with { … }] | A structured, level-filtered event. |
count "name" / measure "name" as value | Counter / numeric metric. |
health … end | The web block's GET /health check. |
audit "event" [with { … }] | An always-recorded event carrying the actor. |
No new reserved keywords — every word above is contextual. Diagnostics are ZX2800–ZX2899. Next: policy-based access control — Authorization.