A dependency-free, SBCL-only structured logging toolkit for Common Lisp,
modelled on Go's log/slog. It separates immutable log records from the
handlers that serialize them: every built-in handler emits a record through
exactly one handle-log-record method, so a line cannot reach output twice
by two paths. The shipped system depends on nothing but ASDF, and field
snapshotting is deep, cycle-safe, and bounded, so a logging call stays safe
on attacker-influenced values.
Full documentation is published at https://nerima-lisp.github.io/cl-log-kit/. The source for that site lives in docs/src/.
(defpackage #:my-app
(:use #:cl #:log-kit)
(:shadowing-import-from #:log-kit #:log))
(in-package #:my-app)
(defparameter *logger*
(make-logger :name "api"
:handler (make-instance 'json-handler)
:level +level-info+
:fields '(:service "orders")))
(log-info *logger* "server started" :port 8080)
;; => {"time":...,"level":"INFO","logger":"api","message":"server started",
;; "fields":{"port":8080,"service":"orders"}}
(defparameter *request-logger* (logger-with *logger* :request-id "abc123"))
(log-warn *request-logger* "slow response" :duration-ms 842)logger-with returns a new logger; call-site fields override logger fields
with the same case-insensitive canonical name. Continue with
Quick Start.
# flake.nix
inputs.cl-log-kit = {
url = "github:nerima-lisp/cl-log-kit/v1.0.0";
inputs.nixpkgs.follows = "nixpkgs";
};Note the pinned tag. Consumers inside this org pin a release tag rather than follow the default branch.
With plain ASDF, clone the repository somewhere ASDF can find it and load the system:
(asdf:load-system "cl-log-kit")See Installation for both paths in full.
- Quick Start — a first logger, a first log line, JSON output.
- Handlers — text and JSON output, composition, rotation, buffering, and the lifecycle protocol.
- API Reference — every exported symbol, grouped by area.
- Compatibility — supported platforms, the stability promise, and the security scope.
nix develop # SBCL with CL_SOURCE_REGISTRY already set
nix run .#test # run the test suite
nix flake check # tests + formatting + docs, the same gate CI uses
nix fmt # format Nix sources (treefmt)Tests live in t/ and run under
cl-weave, the org's test
framework. Coverage runs from the dev shell, because it writes next to the
source it instruments:
nix develop -c sbcl --script run-coverage.lispThe coverage gate fails the build on a regression below the floors recorded
in run-coverage.lisp. See
Development for the
non-Nix invocation, the coverage accounting, and the cl-weave facilities
this suite uses.
Two constraints are load-bearing: the shipped cl-log-kit system has zero
runtime dependencies, and handle-log-record is the only place a handler
writes output. A change that violates either will be asked to change rather
than to justify itself.
See the org-wide CONTRIBUTING guide and the package standard.
See SUPPORT. Report vulnerabilities privately through GitHub security advisories, never in a public issue.
MIT. See LICENSE.