Log v0.1.0

Source
Structured logging: levels, typed fields, text and JSON-lines records, a process-wide log for every thread, and log files that rotate by size

Installation

Add Log to the [Dependencies] table of your package's Rux.toml:

[Dependencies]
Log = { Namespace = "Rux", Version = "0.1.0" }

Standard packages are declared by hand: the registry does not serve them, so rux add Rux/Log cannot add them.

Dependencies

Guide

Structured logging: levels, typed fields, one line of text or JSON per record, a process-wide log that every thread can write to, and log files that rotate by size.

What it provides

ModuleCovers
LevelLevel from Trace to Error with Name, Label and Parse, and CompiledLevel from the LogLevel define
FieldField with Text, Integer, Unsigned, Float and Boolean, and its Value
RecordLogFormat: Text or JsonLines
LoggerLogger over any Io::Writer, with a level, context fields, optional times, and Trace to Error
Globalthe process-wide log on standard error: Trace to Error, Log, SetLevel, SetFormat, SetTimestamps, Enabled
RotationRotatingFile, a log file moved aside for a fresh one before a write would take it past a size, and its RotatingStream

The module names describe where each declaration comes from; they are not part of an import path.

Example

import Log::{ Field, Info, LogFormat, SetFormat, Warn };

func Serve(port: uint64) {
    SetFormat(LogFormat::JsonLines);
    Info("listening", [Field::Unsigned("port", port)]);
    Warn("no certificate configured");
}

Design

A record has a level, a message, and fields whose values keep their types. As text it is one line: the time, the level, the message, then key=value for each field, with a value that holds spaces, quotes or = in quotes. As JSON lines it is one object per line, with time, level and message members followed by the fields, and a number that is not finite written as null. Line breaks and other control characters are escaped in both formats, so a record never spans lines. Times are RFC 3339 in UTC to the millisecond. They can be turned off for a destination that adds its own, such as a service manager's journal.

Each record is built whole and handed to its destination in a single write. The process-wide functions write to standard error. Their level, format and time settings are read and written atomically, and a lock is held only for the write of a finished record, so threads build records at the same time and their lines never interleave. A Logger writes to any Io::Writer, such as a file or a socket, and is used by one thread at a time. Logging never fails: a Logger keeps the first failure to write for Failure to report, and the process-wide log drops a record it cannot write.

A RotatingFile is a Writer over a path that keeps a log from growing without end. Before a write would take the current file past its limit, the file is renamed to path.1, after an older path.1 becomes path.2 and so on up to the number of older files kept, and an empty file takes its place. Rotation happens only between writes, and a Logger writes each record in one call, so no record is ever split across two files; a record larger than the limit gets a file of its own. Hand one to a Logger with (@file).Stream(), keeping the file in place while the logger uses it.

The LogLevel build define sets the least severe level a build keeps: trace, debug, info, warn or error. A record below it is dropped before any of it is built, whatever level a logger is set to. So a release build defined with LogLevel = "info" does no tracing work, while the process-wide level, which starts at Info, and each logger's own level are changed at run time.

Index

Types

NameSummary
ValueThe value of a field.
FieldA named value of a record.
LevelHow severe a record is, from the most detailed to the most serious.
LoggerWrites records at or above a level to a stream, each as one write.
LogFormatHow records are written.
RotatingFileA log file that starts afresh before a write would take it past a size.
RotatingStreamA stored borrow of a RotatingFile that speaks Writer, for a Logger to keep.

Functions

NameSummary
SetLevelWrites process-wide records at level and above from now on.
SetFormatWrites process-wide records in format from now on.
SetTimestampsWhether process-wide records start with the time.
EnabledWhether a process-wide record at level would be written.
LogWrites a process-wide record at level with message and fields to standard error, if the level is enabled.
TraceWrites a process-wide Trace record with no fields.
DebugWrites a process-wide Debug record with no fields.
InfoWrites a process-wide Info record with no fields.
WarnWrites a process-wide Warn record with no fields.
ErrorWrites a process-wide Error record with no fields.
CompiledLevelThe least severe level this build keeps, from the LogLevel build define: trace, debug, info, warn or error, and trace when it is not defined.