logging
nimony/lib/std/logging.nim
This module implements a simple logger. It is a port of Nim's std/logging with one important difference: every log entry is a line of NIF, in NIF's line-based syntax. A log file is therefore a NIF module that NIF tools can read, with the line-based extension enabled (for example nifreader.open(filename, lineBased = true)).
An entry is the level as the tag, followed by the fields of the logger's format string, followed by the message as a string literal:
info "server started" warn 2026-09-29T09:14:03Z "myapp" "disk almost full"
is the same as the core NIF (info "server started") and (warn "2026-09-29T09:14:03Z" "myapp" "disk almost full").
Format strings ==============
Unlike Nim's logger, the format string is not a free-form prefix but a whitespace separated list of fields; each one becomes a child of the entry. A word that starts with $ is one of the variables below, any other word is emitted as a string literal.
================ ======================================================= Variable Output ================ ======================================================= $date Current date in UTC (2026-09-29) $time Current time in UTC (09:14:03) $datetime $date and $time in ISO 8601 (2026-09-29T09:14:03Z) $app os.getAppFilename() $appname Base name of $app $appdir Directory name of $app $levelid First letter of the log level as an identifier (I) $levelname The log level as an identifier (INFO) ================ =======================================================
Nim's std/times is local time; Nimony's is UTC, hence the Z.
Usage =====
import std/logging var logger = newConsoleLogger(fmtStr = verboseFmtStr) addHandler(logger) info("server started on port ", 8080)
Just like in Nim, the handlers are thread-local: every thread must call addHandler for the loggers it uses.
type Level = enum lvlAll = (0, "lvlAll") lvlDebug = (1, "lvlDebug") lvlInfo = (2, "lvlInfo") lvlNotice = (3, "lvlNotice") lvlWarn = (4, "lvlWarn") lvlError = (5, "lvlError") lvlFatal = (6, "lvlFatal") lvlNone = (7, "lvlNone")
func dollar`.Level(e: Level): stringconst LevelNames: array[0..7, string]Array of strings representing each logging level.
const LevelTags: array[0..7, string]The NIF tag of an entry of each logging level.
const defaultFmtStr: stringThe default format string: no fields besides the level and the message.
const verboseFmtStr: string\ A more verbose format string: the time and the application's name.
type Logger = ref Logger.Objtype Logger.Obj = object levelThreshold: Level fmtStr: string
type ConsoleLogger = ref ConsoleLogger.Objtype ConsoleLogger.Obj = object useStderr: bool flushThreshold: Level
type FileLogger = ref FileLogger.Objtype FileLogger.Obj = object file: ref FileObj flushThreshold: Level
type RollingFileLogger = ref RollingFileLogger.Objtype RollingFileLogger.Obj = object maxLines: int64 curLine: int64 baseName: string baseMode: FileMode logFiles: int64 bufSize: int64
proc substituteLog(frmt: string; level: Level; args: varargs[string, $]): stringFormats a log entry: the level as the tag, the fields of the format string
frmt, and the concatenatedargsas a string literal. The result is one line of line-based NIF, without the trailing newline.See
Format strings_ for the fields that can be used.method log(logger: ref Logger.Obj; level: Level; args: varargs[string, $])Override this method in custom loggers. The default implementation does nothing.
method log(logger: ref ConsoleLogger.Obj; level: Level; args: varargs[string, $])Logs to the console, if
levelpasses both the logger's threshold and the global log filter.proc newConsoleLogger(levelThreshold: Level; fmtStr: string; useStderr: bool; flushThreshold: Level): ref ConsoleLogger.ObjCreates a new ConsoleLogger. Entries at or above
flushThresholdare flushed immediately.method log(logger: ref FileLogger.Obj; level: Level; args: varargs[string, $])Logs to the logger's file, if
levelpasses both the logger's threshold and the global log filter.proc defaultFilename(): stringReturns the filename used by default: the application's name with the
.logextension.proc newFileLogger(file: ref FileObj; levelThreshold: Level; fmtStr: string; flushThreshold: Level): ref FileLogger.ObjCreates a new FileLogger that logs to an already open
file.proc newFileLogger(filename: string; mode: FileMode; levelThreshold: Level; fmtStr: string; bufSize: int64; flushThreshold: Level): ref FileLogger.ObjCreates a new FileLogger that logs to the file
filename. By default the file is appended to, so the log file stays one line-based NIF module across runs.proc newRollingFileLogger(filename: string; mode: FileMode; levelThreshold: Level; fmtStr: string; maxLines: 1..9223372036854775807; bufSize: int64; flushThreshold: Level): ref RollingFileLogger.ObjCreates a new RollingFileLogger. Once the current file reaches
maxLinesentries, it is renamed tofilename.1(an existingfilename.1becomesfilename.2, and so on) and a new file is started.method log(logger: ref RollingFileLogger.Obj; level: Level; args: varargs[string, $])Logs to the logger's file, starting a new file if the current one is full, if
levelpasses both the logger's threshold and the global log filter.proc getLogFilter(): LevelGets the global log filter.
proc setLogFilter(lvl: Level)Sets the global log filter: messages below
lvlare not logged by any handler.template log(level: Level; args: varargs[string, $])Logs a message at
levelto all registered handlers.template debug(args: varargs[string, $])Logs a debug message to all registered handlers.
template info(args: varargs[string, $])Logs an info message to all registered handlers.
template notice(args: varargs[string, $])Logs a notice to all registered handlers.
template warn(args: varargs[string, $])Logs a warning to all registered handlers.
template error(args: varargs[string, $])Logs an error to all registered handlers.
template fatal(args: varargs[string, $])Logs a fatal error to all registered handlers. This does not quit the program.
proc addHandler(handler: ref Logger.Obj)Adds a handler to the list of handlers of the current thread.
proc removeHandler(handler: ref Logger.Obj)Removes a handler from the list of handlers of the current thread.
proc getHandlers(): seq[ref Logger.Obj]Returns the list of handlers of the current thread.