Logging in Racket

Here’s the translation of the Go logging example to Racket, formatted for Hugo:

#lang racket

(require racket/date)

; The Racket standard library provides tools for outputting logs
; from Racket programs, with the `racket/logging` module for
; free-form output.

(require racket/logging)

; Simply invoking functions like `log-info` from the
; `racket/logging` module uses the standard logger, which
; is already pre-configured for reasonable logging
; output to current-error-port.

(log-info "standard logger")

; Loggers can be configured with levels to set
; their output format. By default, the standard
; logger has the 'info level set.
; We can change its level to emit more detailed information.

(current-logging-level 'debug)
(log-debug "with debug level")

; It also supports emitting the source location
; from which the log function is called.

(current-logger-uses-srclocs #t)
(log-info "with source location")

; It may be useful to create a custom logger and
; pass it around. When creating a new logger, we
; can set a name to distinguish its output
; from other loggers.

(define mylog (make-logger 'mylog))
(log-info mylog "from mylog")

; We can set the name on existing loggers
; when we create them.

(define ohmy-log (make-logger 'ohmy))
(log-info ohmy-log "from ohmy-log")

; Loggers can have custom output targets;
; any output port works.

(define buf (open-output-string))
(define buflog (make-logger 'buflog (current-logger) 'info buf))

; This call writes the log output into `buf`.
(log-info buflog "hello")

; This will actually show it on standard output.
(displayln (format "from buflog: ~a" (get-output-string buf)))

; Racket doesn't have a built-in structured logging package like slog,
; but we can create a simple JSON-like output format.

(define (log-json level msg . kwargs)
  (define timestamp (date->string (current-date) #t))
  (define json-string 
    (format "{\"time\":\"~a\",\"level\":\"~a\",\"msg\":\"~a\"~a}"
            timestamp
            level
            msg
            (if (empty? kwargs)
                ""
                (format ",~a" 
                        (string-join 
                         (for/list ([k (in-list kwargs)]
                                    [v (in-list (cdr kwargs))])
                           (format "\"~a\":\"~a\"" k v))
                         ",")))))
  (displayln json-string))

(log-json 'INFO "hi there")
(log-json 'INFO "hello again" 'key "val" 'age "25")

This Racket code demonstrates logging functionality similar to the Go example. Here’s a breakdown of the translation:

  1. We use the racket/logging module for basic logging functionality.
  2. The log-info, log-debug, etc. functions are used for logging at different levels.
  3. We can create custom loggers with make-logger.
  4. To demonstrate logging to a string buffer, we use open-output-string and get-output-string.
  5. For JSON-like structured logging, we create a custom log-json function that formats the output similar to the Go slog package.

The code includes comments explaining each section, similar to the original Go example. Note that Racket doesn’t have an exact equivalent to Go’s slog package, so we’ve created a simple JSON-like logging function to demonstrate the concept.

To run this Racket program, save it to a file (e.g., logging.rkt) and use the racket command:

$ racket logging.rkt

The output will be similar to the Go example, with timestamps and log messages formatted according to the Racket implementation.