Logging in Nim

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

import std/logging
import std/times
import std/json

proc main() =
  # Simply invoking procedures like `info` from the
  # `logging` module uses the *standard* logger, which
  # is already pre-configured for reasonable logging
  # output to stdout.
  info("standard logger")

  # Loggers can be configured with *levels* to set
  # their output format. By default, the standard
  # logger has the `lvlInfo` level set.
  # We can change its level to emit debug messages, for example.
  setLogLevel(lvlDebug)
  debug("with debug level")

  # It also supports emitting the file name and
  # line from which the log procedure is called.
  let L = newConsoleLogger(fmtStr="[$time] - $levelname: ")
  addHandler(L)
  info("with custom format")

  # It may be useful to create a custom logger and
  # pass it around. When creating a new logger, we
  # can set a *format string* to distinguish its output
  # from other loggers.
  let mylog = newConsoleLogger(fmtStr="my:[$time] - $levelname: ")
  addHandler(mylog)
  info("from mylog")

  # We can set the format string
  # on existing loggers with the `fmtStr` parameter.
  mylog.fmtStr = "ohmy:[$time] - $levelname: "
  info("from mylog again")

  # Loggers can have custom output targets;
  # any `File` or `Stream` works.
  let buflog = newFileLogger("buffer.log", fmtStr="buf:[$time] - $levelname: ")
  addHandler(buflog)
  info("hello")

  # This will actually show it on standard output.
  echo "from buflog: ", readFile("buffer.log")

  # Nim doesn't have a built-in structured logging package like slog,
  # but we can use the json module to create similar functionality.
  proc structuredLog(msg: string, args: varargs[tuple[key: string, val: JsonNode]]) =
    var log = %*{
      "time": now().format("yyyy-MM-dd'T'HH:mm:ss'Z'"),
      "level": "INFO",
      "msg": msg
    }
    for arg in args:
      log[arg.key] = arg.val
    echo $log

  structuredLog("hi there")
  structuredLog("hello again", ("key", %"val"), ("age", %25))

main()

This Nim code demonstrates logging functionality similar to the Go example. Here’s a breakdown of the changes and explanations:

  1. We use the logging module from Nim’s standard library, which provides similar functionality to Go’s log package.

  2. Nim doesn’t have a direct equivalent to Go’s log.SetFlags(), but we can achieve similar results by creating custom loggers with specific format strings.

  3. Instead of log.New(), we use newConsoleLogger() and newFileLogger() to create custom loggers.

  4. Nim doesn’t have a built-in structured logging package like Go’s slog. We’ve simulated this functionality using Nim’s json module.

  5. The structuredLog procedure demonstrates how to create JSON-formatted log entries similar to what slog provides in Go.

To run this program, save it as logging.nim and use the following command:

$ nim c -r logging.nim

This will compile and run the Nim program. The output will be similar to the Go example, with timestamps and log levels included in the output.

Note that the exact output may vary depending on the current date and time when you run the program.