#lang scribble/manual @(require (for-label racket/base racket/date racket/logging racket-sprintf)) @title{Logging} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @section{Overview} Small wrapper around @racket[logger] with per-logger callbacks. A logger consists of a @racket[logger], a @racket[log-receiver] (level @racket['debug]), a mutable callback list, five logging procedures, and a background thread dispatching messages. @section{Definition} @defform*[([(def-log id)] [(def-log id parent)])]{ Defines a logger @racket[id]. If @racket[parent] is omitted, @racket[(current-logger)] is used. Creates: @itemlist[ #:style 'ordered @item{@racket[(make-logger 'id parent)]} @item{@racket[(make-log-receiver ... 'debug)]} @item{callback list} @item{procedures @racket[dbg-id], @racket[info-id], @racket[warn-id], @racket[err-id], @racket[fatal-id]} ] Starts a thread that @racket[sync]s on the receiver and forwards messages to callbacks. } @section{Logging} @defproc[(dbg-id [msg string?] [arg any/c] ...) void?] @defproc[(info-id [msg string?] [arg any/c] ...) void?] @defproc[(warn-id [msg string?] [arg any/c] ...) void?] @defproc[(err-id [msg string?] [arg any/c] ...) void?] @defproc[(fatal-id [msg string?] [arg any/c] ...) void?] Formats with @racket[(apply format (cons msg args))] and calls @racket[log-message]. Attached data: @racketblock[ (list (iso-timestamp) 'id) ] @section{Callbacks} @defform[(log-to id name callback)]{ Registers @racket[callback] under @racket[name]. Existing entry with same name is replaced. Callback signature: @racketblock[ (λ (topic level dt msg) ...) ] } @section{Output helpers} @defform[(log-to-display id)]{ Registers @racket['display]. Output: @verbatim{topic:level:timestamp:message} } @defform[(log-to-file id filename)]{ Registers @racket['file]. File opened with @racket[#:exists 'replace]. One line per message, flushed. } @section{Timestamp} @defproc[(iso-timestamp) string?]{ Returns @verbatim{YYYY-MM-DDTHH:MM:SS} using @racket[seconds->date] and @racket[sprintf]. } @section{Execution} Per logger thread: @itemlist[ #:style 'ordered @item{@racket[sync] receiver} @item{extract level, msg, data} @item{dispatch callbacks} ] Callbacks run sequentially in that thread.