On this page:
logger-out
define-log-message-transformers
define-root-logger
log-message-info
3.1 Log writers
spawn-pretty-log-writer
log-writer?
close-log-writer
log-writer-closed?
flush-log-writer
3.2 Toolbox logger
toolbox-logger
8.18.0.15

3 Logging🔗

 (require toolbox/logging) package: toolbox-lib

provide syntax

(logger-out id)

When used in provide, exports log-id-fatal, log-id-error, log-id-warning, log-id-info, and log-id-debug.

syntax

(define-log-message-transformers id logger-expr)

 
  logger-expr : logger?
Defines log-id-fatal, log-id-error, log-id-warning, log-id-info, and log-id-debug as forms like log-fatal, log-error, log-warning, log-info, and log-debug, with two differences:

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)
Defines id-logger as a new logger. The logger’s default topic is the result of topic-expr, or 'id if no topic-expr is provided. The logger’s parent is the result of parent-expr, or (current-logger) if no parent-expr is provided.

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.

Examples:
> (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?
A structure type used by the forms defined by define-log-message-transformers to record when and from where a message was sent to a logger. The value of the milliseconds field should be (current-inexact-milliseconds) and the value of the continuation-marks field should be (current-continuation-marks).

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)
Starts a new thread that repeatedly synchronizes on receiver (which is usually the result of a call to make-log-receiver) and writes a formatted version of each synchronization result to out. The result of spawn-pretty-log-writer is a log writer handle that can be used to flush or terminate the writer thread.

Examples:
> (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.

Examples:
> (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
Returns #t if v is a log writer handle returned by spawn-pretty-log-writer, otherwise returns #f.

procedure

(close-log-writer writer [#:wait? wait?])  void?

  writer : log-writer?
  wait? : any/c = #t
Closes the given log writer by flushing all pending log messages and terminating the writer thread. If wait? is not #f, the call to close-log-writer blocks until the shutdown is complete. If writer is already closed, close-log-writer has no effect.

procedure

(log-writer-closed? writer)  boolean?

  writer : log-writer?
Returns #t if the given log writer has been closed by close-log-writer or if its writer thread has been killed by some other means. Otherwise, log-writer-closed? returns #f.

procedure

(flush-log-writer writer)  void?

  writer : (and/c log-writer? (not/c log-writer-closed?))
Forces the given log writer to write any pending messages, blocking until all messages have been written.

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

A logger used by various functions in this library. Generally, messages are not written to toolbox-logger directly, but it serves as a parent logger for module-specific loggers, such as toolbox:db-logger.