3 Logging
| (require toolbox/logging) | package: toolbox-lib |
provide syntax
(logger-out id)
syntax
(define-log-message-transformers id logger-expr)
logger-expr : logger?
The defined forms log messages to logger-expr instead of the current logger.
A log-message-info structure is sent to the logger instead of (current-continuation-marks).
syntax
(define-root-logger id option ...)
option = #:topic topic-expr | #:parent parent-expr
topic-expr : (or/c symbol? #f)
parent-expr : (or/c logger? #f)
The define-root-logger form also defines log-id-fatal, log-id-error, log-id-warning, log-id-info, and log-id-debug in the same way as define-log-message-transformers, with id-logger as the target logger.
Finally, define-root-logger defines define-id-logger as a form like define-root-logger itself, except id-logger is always used as the parent logger (and the #:parent option is not allowed). This form can be used to conveniently define child loggers to form a logging hierarchy.
> (define-root-logger toolbox) > (define toolbox-receiver (make-log-receiver toolbox-logger 'debug)) > (log-toolbox-info "message on the root logger") > (sync toolbox-receiver)
(vector
'info
"message on the root logger"
(log-message-info 1757866910787.5793 #<continuation-mark-set>)
'toolbox)
> (define-toolbox-logger toolbox:example) > (log-toolbox:example-debug "message on a child logger") > (sync toolbox-receiver)
(vector
'debug
"message on a child logger"
(log-message-info 1757866910794.5232 #<continuation-mark-set>)
'toolbox:example)
struct
(struct log-message-info (milliseconds continuation-marks) #:extra-constructor-name make-log-message-info) milliseconds : rational? continuation-marks : continuation-mark-set?
The log-message-info structure type implements gen:moment-provider using the value of the milliseconds field.
3.1 Log writers
procedure
(spawn-pretty-log-writer receiver [ #:out out #:process-name process-name #:millis? millis? #:color? color?]) → log-writer? receiver : (evt/c (vector/c log-level/c string? any/c (or/c symbol? #f))) out : output-port? = (current-output-port) process-name : any/c = #f millis? : any/c = #f color? : any/c = (terminal-port? out)
> (define-root-logger toolbox)
> (define writer (spawn-pretty-log-writer (make-log-receiver toolbox-logger 'debug))) > (log-toolbox-info "an informational message") [2025-09-14 16:21:51] [toolbox/INFO] an informational message
> (log-toolbox-fatal "a fatal message!!") [2025-09-14 16:21:51] [toolbox/FATAL] a fatal message!!
> (close-log-writer writer)
Because log messages are written asynchronously, most programs should explicitly call close-log-writer to ensure all log messages are flushed before exiting. Otherwise, messages logged immediately prior to termination may be lost.
If process-name is not #f, it is written after the topic and log level using display:
> (spawn-pretty-log-writer (make-log-receiver toolbox-logger 'debug) #:process-name 'worker) #<log-writer:worker>
> (log-toolbox-info "message from a worker process") [2025-09-14 16:21:51] [toolbox/INFO@worker] message from a worker process
If the third element of the result of receiver implements gen:moment-provider, ->moment is used to extract a timestamp for the message. Otherwise, the timestamp is based on the moment the message is received, rather than when the message was logged, which can be substantially less accurate. The logging forms defined by define-log-message-transformers send a log-message-info structure with each message, which do implement gen:moment-provider and supply a reliable timestamp.
If millis? is not #f, timestamps are written with millisecond precision. However, see the caveat about timestamp accuracy from the previous paragraph.
> (spawn-pretty-log-writer (make-log-receiver toolbox-logger 'debug) #:millis? #t) #<log-writer>
> (log-toolbox-info "high-precision message") [2025-09-14 16:21:51.146] [toolbox/INFO] high-precision message
If color? is not #f, ANSI escape codes are included in the formatted output to colorize the output for log levels other than 'info.
procedure
(log-writer? v) → boolean?
v : any/c
procedure
(close-log-writer writer [#:wait? wait?]) → void?
writer : log-writer? wait? : any/c = #t
procedure
(log-writer-closed? writer) → boolean?
writer : log-writer?
procedure
(flush-log-writer writer) → void?
writer : (and/c log-writer? (not/c log-writer-closed?))
This function is not generally necessary, as spawn-pretty-log-writer calls flush-output after writing each log message it receives regardless of whether flush-log-writer is used. The only effect of flush-log-writer is to block the calling thread until the log writer thread has had a chance to receive and write any pending messages. However, this can rarely be useful if the calling thread writes to the same output port and wants to avoid output being interleaved, for example.
3.2 Toolbox logger
| (require toolbox/logger) | package: toolbox-lib |
value