Logging in Scheme

Here’s the translation of the Go logging example to Scheme, formatted in Markdown for Hugo:

(import (rnrs)
        (rnrs io simple)
        (srfi :19))

;; Define a simple logging function
(define (log-message message)
  (display (string-append 
             (date->string (current-date) "~Y/~m/~d ~H:~M:~S ")
             message
             "\n")))

;; Define a function to log with microsecond precision
(define (log-message-micro message)
  (let ((time (current-time)))
    (display (string-append 
               (date->string (time-utc->date time) "~Y/~m/~d ~H:~M:~S.")
               (number->string (time-nanosecond time))
               " "
               message
               "\n"))))

;; Define a function to log with file and line information
(define (log-message-file message file line)
  (display (string-append 
             (date->string (current-date) "~Y/~m/~d ~H:~M:~S ")
             file
             ":"
             (number->string line)
             ": "
             message
             "\n")))

;; Define a custom logger with a prefix
(define (make-custom-logger prefix)
  (lambda (message)
    (display (string-append 
               prefix
               (date->string (current-date) "~Y/~m/~d ~H:~M:~S ")
               message
               "\n"))))

;; Define a function to log to a string port
(define (log-to-string message)
  (let ((out (open-output-string)))
    (display (string-append 
               "buf:"
               (date->string (current-date) "~Y/~m/~d ~H:~M:~S ")
               message
               "\n")
             out)
    (get-output-string out)))

;; Define a simple JSON logger
(define (log-json message . key-values)
  (display (string-append 
             "{\"time\":\""
             (date->string (current-date) "~Y-~m-~dT~H:~M:~S")
             "\",\"level\":\"INFO\",\"msg\":\""
             message
             "\""
             (if (null? key-values)
                 ""
                 (string-append 
                   ","
                   (string-join 
                     (map (lambda (kv) 
                            (string-append 
                              "\""
                              (symbol->string (car kv))
                              "\":\""
                              (if (number? (cadr kv))
                                  (number->string (cadr kv))
                                  (cadr kv))
                              "\""))
                          (zip key-values (cdr key-values)))
                     ",")))
             "}\n")))

(define (main)
  ;; Simple logging
  (log-message "standard logger")

  ;; Logging with microsecond precision
  (log-message-micro "with micro")

  ;; Logging with file and line information
  (log-message-file "with file/line" "logging.scm" 58)

  ;; Using a custom logger with a prefix
  (let ((mylog (make-custom-logger "my:")))
    (mylog "from mylog")
    ;; Change the prefix
    (set! mylog (make-custom-logger "ohmy:"))
    (mylog "from mylog"))

  ;; Logging to a string
  (let ((log-string (log-to-string "hello")))
    (display "from buflog:")
    (display log-string))

  ;; Structured logging in JSON format
  (log-json "hi there")
  (log-json "hello again" 'key "val" 'age 25))

(main)

This Scheme code provides similar functionality to the original Go logging example. Here’s a breakdown of the translation:

  1. We import necessary libraries for I/O operations and date/time handling.

  2. We define custom logging functions to mimic the behavior of Go’s log package:

    • log-message for standard logging
    • log-message-micro for logging with microsecond precision
    • log-message-file for logging with file and line information
  3. We create a make-custom-logger function to generate loggers with custom prefixes.

  4. We implement log-to-string to log to a string, similar to logging to a buffer in the Go example.

  5. We create a log-json function to provide structured logging similar to Go’s slog package.

  6. In the main function, we demonstrate the use of these logging functions.

Note that Scheme doesn’t have built-in logging packages like Go’s log and slog, so we’ve implemented basic versions of these functionalities. The output format and exact behavior may differ slightly from the Go version, but the core concepts are maintained.

To run this program, save it as logging.scm and execute it using a Scheme interpreter that supports the required libraries (e.g., Chez Scheme). The output will be similar to the Go version, with timestamps and structured data logged to the console.