06 / CONTROL
logging
RequestLog captures typed access-log fields (method, path, status, duration, request-id, client-ip, user-agent) and renders one JSON line per request; the structured_logging middleware emits it, timed on the clock.
WHERE IT SITS
INTERFACE
struct RequestLogstructA structured access-log record. Rather than a free-form line, each request is captured as typed fields and rendered as one JSON object per line — the format a log collector (ELK, Loki) expects.
impl ToJson for RequestLog with fn to_json(self)itemThe record as a JSON object with a stable field order, duration_ms a number of milliseconds.
extend RequestLog with ToJson::item
impl FromJson for RequestLog with fn from_json(json, path)itemRead a record back from the JSON to_json writes. Every field is required; a log line is written by this library, so a missing one means the document was not one of ours.
extend RequestLog with FromJson::item
fn RequestLog::render(self : RequestLog) -> StringfnThe record rendered as a single-line JSON string, ready to write to a log sink.
fn RequestLog::fields(self : RequestLog) -> Array[(String, Json)]fnThe record as logx fields, for logging it through a @logx.Logger — the method and path make the entry's message, so they are not repeated here.
fn headers_json(headers : Array[(String, String)]) -> JsonfnA header list as a JSON object, so a verbose log line carries the whole exchange and not just the fields the record names.
fn structured_logging( clock : @clock.Clock, logger? : @logx.Logger, verbose~ : Bool = false) -> MiddlewarefnStructured-logging middleware: time each HTTP request on the shared clock, capture its method/path/client-ip/user-agent and the response status observed on HttpResponseStart, and write one access entry through logger (the process logx by default) when the response starts. Access logs are info, so a service configured at error or above emits none of them. verbose adds both header sets and a preview of the request body to the entry — what a debugging deployment switches on and an ordinary one leaves off. The preview is the first verbose_body_preview bytes: dumps the whole body, which for a service that accepts uploads means a log line the size of the upload. Non-HTTP scopes pass through without logging.
let verbose_body_preview : Int32 = 1024letHow much of a request body a verbose access entry carries. Named because it is a policy, not an arithmetic detail: enough to recognise a payload, short of a log line the size of an upload.