simple-log
| (require simple-log) | package: simple-log |
A small logging layer on top of Racket’s logger system. A log definition creates a logger and convenience procedures for the standard log levels. Messages are formatted with format, timestamped, and dispatched asynchronously to one or more registered destinations.
1 Quick start
(require simple-log) (sl-def-log example) (sl-log-to-display) (info-example "Started with ~a items" 3) (warn-example "This is only an example")
A log line has the following format:
example:info:2026-08-03T10:30:00:Started with 3 items |
2 Defining a logger
syntax
(sl-def-log id)
(sl-def-log id prefix) (sl-def-log id prefix parent)
For example:
(sl-def-log player)
creates dbg-player, info-player, warn-player, err-player, fatal-player, and sync-log-player.
With an explicit prefix:
(sl-def-log media-renderer renderer)
creates the same procedures with renderer in their names, while the log topic remains 'media-renderer.
If parent is omitted, #f is used as the parent logger.
3 Log destinations
syntax
(sl-log-to name callback)
The callback is invoked as:
(callback topic level timestamp message)
The arguments are a topic symbol, a level symbol, an ISO-like timestamp in YYYY-MM-DDTHH:MM:SS form, and the formatted message string.
For example:
(sl-log-to collect-errors (lambda (topic level timestamp message) (when (memq level '(error fatal)) (displayln (list timestamp topic message)))))
procedure
procedure
(sl-log-to-file filename) → void?
filename : path-string?
procedure
(sl-log-to-file&display filename) → void?
filename : path-string?
procedure
(sl-log-to-store [max-length]) → any/c
max-length : exact-nonnegative-integer? = 1000
Only one destination named store is active. A later call to sl-log-to-store replaces the previous store destination, but does not modify the previously returned store.
Logging is asynchronous. Use the generated synchronization procedure before reading the store when all previously submitted messages must be present.
(sl-def-log worker) (define logs (sl-log-to-store 200)) (info-worker "Starting job ~a" 42) (warn-worker "Job ~a is slow" 42) (sync-log-worker) (sl-store->display logs)
4 Log level
procedure
(sl-set-log-level level) → symbol?
level :
(or/c 'debug 'dbg 'info 'warning 'warn 'error 'err 'fatal)
procedure
(sl-log-level) → symbol?
5 Synchronization
Synchronization is useful before inspecting an in-memory store or before a program exits immediately after its final log message.
6 In-memory stores
A store contains log entries in chronological order. Every entry consists of:
(list topic level timestamp message)
The filtering procedures return new stores and leave the original store unchanged. The new store has the same maximum length as the original.
procedure
(make-sl-store [max-length]) → any/c
max-length : exact-nonnegative-integer? = 1000
procedure
(sl-store-enqueue! store topic level timestamp message) → void? store : any/c topic : symbol?
level :
(or/c 'debug 'dbg 'info 'warning 'warn 'error 'err 'fatal) timestamp : string? message : string?
procedure
(sl-store-length store) → exact-nonnegative-integer?
store : any/c
procedure
store : any/c
procedure
(sl-store->list store) → list?
store : any/c
procedure
(sl-store->display store) → void?
store : any/c
procedure
(sl-store-grep-message store regexp [ #:invert? invert?]) → any/c store : any/c regexp : regexp? invert? : boolean? = #f
procedure
(sl-store-grep-topic store topic-filter [ #:invert? invert?]) → any/c store : any/c
topic-filter :
(or/c symbol? regexp? (listof (or/c symbol? regexp?))) invert? : boolean? = #f
(sl-store-grep-topic logs '(webview webview-backend)) (sl-store-grep-topic logs 'webview-backend #:invert? #t)
procedure
(sl-store-grep-level store level-or-regexp) → any/c
store : any/c
level-or-regexp :
(or/c regexp? 'debug 'dbg 'info 'warning 'warn 'error 'err 'fatal)
(sl-store-grep-level logs 'warning) (sl-store-grep-level logs #rx"err(or)?")
procedure
(sl-store-grep store value [ #:invert? invert?]) → any/c store : any/c value : (or/c symbol? regexp?) invert? : boolean? = #f
When value is a log-level symbol, the result contains entries at that level or a more severe level. Any other symbol is treated as an exact topic. A regular expression is matched against both topic and message. If that same regular expression also identifies a log level, entries below that level are excluded. When invert? is true, matching entries are excluded, similar to grep -v.
procedure
(sl-store-tail store count) → any/c
store : any/c count : exact-nonnegative-integer?
procedure
(sl-store-head store count) → any/c
store : any/c count : exact-nonnegative-integer?
7 Store examples
(sl-def-log player) (define logs (sl-log-to-store 500)) (info-player "Opening ~a" "album.flac") (warn-player "No duration available") (err-player "Renderer returned status ~a" 701) (sync-log-player) (define warnings-and-errors (sl-store-grep-level logs 'warning)) (define renderer-errors (sl-store-grep (sl-store-grep-topic logs 'player) #rx"renderer|status")) (sl-store->display (sl-store-tail warnings-and-errors 20))
8 Generated procedures
For a definition such as:
(sl-def-log my-module)
simple-log creates the following procedures:
procedure
(sync-log-my-module) → void?
The message procedures pass message and argument values to format. Log delivery to the registered destinations is asynchronous.