summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJjp137 <Jjp137@users.noreply.github.com>2019-03-24 10:53:04 -0700
committerMiran <narimiran@disroot.org>2019-03-24 18:53:04 +0100
commitb0e236674cea0f45eea8a086a8733c6449f8d7d6 (patch)
tree23bfb19fc0e8ff55ed6a87660e8ff21fadbda1b7
parent1332f649b2e32a84fb643b580750e2f554eb8a4f (diff)
downloadNim-b0e236674cea0f45eea8a086a8733c6449f8d7d6.tar.gz
logging: better documentation (#10895)
-rw-r--r--lib/pure/logging.nim666
1 files changed, 572 insertions, 94 deletions
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index febd0b602..4dcf181b8 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -7,94 +7,253 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements a simple logger. It has been designed to be as simple
-## as possible to avoid bloat, if this library does not fulfill your needs,
-## write your own.
+## This module implements a simple logger.
 ##
-## Format strings support the following variables which must be prefixed with
-## the dollar operator (``$``, see example below):
+## It has been designed to be as simple as possible to avoid bloat.
+## If this library does not fulfill your needs, write your own.
+##
+## Basic usage
+## ===========
+##
+## To get started, first create a logger:
+##
+## .. code-block::
+##   import logging
+##
+##   var logger = newConsoleLogger()
+##
+## The logger that was created above logs to the console, but this module
+## also provides loggers that log to files, such as the
+## `FileLogger<#FileLogger>`_. Creating custom loggers is also possible by
+## inheriting from the `Logger<#Logger>`_ type.
+##
+## Once a logger has been created, call its `log proc
+## <#log.e,ConsoleLogger,Level,varargs[string,]>`_ to log a message:
+##
+## .. code-block::
+##   logger.log(lvlInfo, "a log message")
+##   # Output: INFO a log message
+##
+## The ``INFO`` within the output is the result of a format string being
+## prepended to the message, and it will differ depending on the message's
+## level. Format strings are `explained in more detail
+## here<#basic-usage-format-strings>`_.
+##
+## There are six logging levels: debug, info, notice, warn, error, and fatal.
+## They are described in more detail within the `Level enum's documentation
+## <#Level>`_. A message is logged if its level is at or above both the logger's
+## ``levelThreshold`` field and the global log filter. The latter can be changed
+## with the `setLogFilter proc<#setLogFilter,Level>`_.
+##
+## **Warning:**
+## * For loggers that log to a console or to files, only error and fatal
+##   messages will cause their output buffers to be flushed immediately.
+##   Use the `flushFile proc <io.html#flushFile,File>`_ to flush the buffer
+##   manually if needed.
+##
+## Handlers
+## --------
+##
+## When using multiple loggers, calling the log proc for each logger can
+## become repetitive. Instead of doing that, register each logger that will be
+## used with the `addHandler proc<#addHandler,Logger>`_, which is demonstrated
+## in the following example:
+##
+## .. code-block::
+##   import logging
+##
+##   var consoleLog = newConsoleLogger()
+##   var fileLog = newFileLogger("errors.log", levelThreshold=lvlError)
+##   var rollingLog = newRollingFileLogger("rolling.log")
+##
+##   addHandler(consoleLog)
+##   addHandler(fileLog)
+##   addHandler(rollingLog)
+##
+## After doing this, use either the `log template
+## <#log.t,Level,varargs[string,]>`_ or one of the level-specific templates,
+## such as the `error template<#error.t,varargs[string,]>`_, to log messages
+## to all registered handlers at once.
+##
+## .. code-block::
+##   # This example uses the loggers created above
+##   log(lvlError, "an error occurred")
+##   error("an error occurred")  # Equivalent to the above line
+##   info("something normal happened")  # Will not be written to errors.log
+##
+## Note that a message's level is still checked against each handler's
+## ``levelThreshold`` and the global log filter.
+##
+## Format strings
+## --------------
+##
+## Log messages are prefixed with format strings. These strings contain
+## placeholders for variables, such as ``$time``, that are replaced with their
+## corresponding values, such as the current time, before they are prepended to
+## a log message. Characters that are not part of variables are unaffected.
+##
+## The format string used by a logger can be specified by providing the `fmtStr`
+## argument when creating the logger or by setting its `fmtStr` field afterward.
+## If not specified, the `default format string<#defaultFmtStr>`_ is used.
+##
+## The following variables, which must be prefixed with a dollar sign (``$``),
+## are available:
 ##
 ## ============  =======================
-##   Operator     Output
+##   Variable      Output
 ## ============  =======================
 ## $date         Current date
 ## $time         Current time
 ## $datetime     $dateT$time
-## $app          ``os.getAppFilename()``
-## $appname      base name of $app
-## $appdir       directory name of $app
-## $levelid      first letter of log level
-## $levelname    log level name
+## $app          `os.getAppFilename()<os.html#getAppFilename>`_
+## $appname      Base name of ``$app``
+## $appdir       Directory name of ``$app``
+## $levelid      First letter of log level
+## $levelname    Log level name
 ## ============  =======================
 ##
+## Note that ``$app``, ``$appname``, and ``$appdir`` are not supported when
+## using the JavaScript backend.
+##
+## The following example illustrates how to use format strings:
 ##
-## The following example demonstrates logging to three different handlers
-## simultaneously:
+## .. code-block::
+##   import logging
 ##
-## .. code-block:: nim
+##   var logger = newConsoleLogger(fmtStr="[$time] - $levelname: ")
+##   logger.log(lvlInfo, "this is a message")
+##   # Output: [19:50:13] - INFO: this is a message
 ##
-##    var L = newConsoleLogger()
-##    var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
-##    var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
-##    addHandler(L)
-##    addHandler(fL)
-##    addHandler(rL)
-##    info("920410:52 accepted")
-##    warn("4 8 15 16 23 4-- Error")
-##    error("922044:16 SYSTEM FAILURE")
-##    fatal("SYSTEM FAILURE SYSTEM FAILURE")
-##    # Using the aformetioned operator
-##    var opL = newConsoleLogger(fmtStr = "$datetime :: ")
-##    addHandler(opL)
-##    info("Starting web server...")
-##    # Will print something like 2018-12-17T19:28:05 :: Starting web server...
+## Notes when using multiple threads
+## ---------------------------------
 ##
-## **Warning:** The global list of handlers is a thread var, this means that
-## the handlers must be re-added in each thread.
-## **Warning:** When logging on disk or console, only error and fatal messages
-## are flushed out immediately. Use flushFile() where needed.
+## There are a few details to keep in mind when using this module within
+## multiple threads:
+## * The global log filter is actually a thread-local variable, so it needs to
+##   be set in each thread that uses this module.
+## * The list of registered handlers is also a thread-local variable. If a
+##   handler will be used in multiple threads, it needs to be registered in
+##   each of those threads.
+##
+## See also
+## ========
+## * `strutils module<strutils.html>`_ for common string functions
+## * `strformat module<strformat.html>`_ for string interpolation and formatting
+## * `strscans module<strscans.html>`_ for ``scanf`` and ``scanp`` macros, which
+##   offer easier substring extraction than regular expressions
 
 import strutils, times
 when not defined(js):
   import os
 
 type
-  Level* = enum  ## logging level
-    lvlAll,       ## all levels active
-    lvlDebug,     ## debug level (and any above) active
-    lvlInfo,      ## info level (and any above) active
-    lvlNotice,    ## info notice (and any above) active
-    lvlWarn,      ## warn level (and any above) active
-    lvlError,     ## error level (and any above) active
-    lvlFatal,     ## fatal level (and any above) active
-    lvlNone       ## no levels active
+  Level* = enum
+    ## Enumeration of logging levels.
+    ##
+    ## Debug messages represent the lowest logging level, and fatal error
+    ## messages represent the highest logging level. ``lvlAll`` can be used
+    ## to enable all messages, while ``lvlNone`` can be used to disable all
+    ## messages.
+    ##
+    ## Typical usage for each logging level, from lowest to highest, is
+    ## described below:
+    ##
+    ## * **Debug** - debugging information helpful only to developers
+    ## * **Info** - anything associated with normal operation and without
+    ##   any particular importance
+    ## * **Notice** - more important information that users should be
+    ##   notified about
+    ## * **Warn** - impending problems that require some attention
+    ## * **Error** - error conditions that the application can recover from
+    ## * **Fatal** - fatal errors that prevent the application from continuing
+    ##
+    ## It is completely up to the application how to utilize each level.
+    ##
+    ## Individual loggers have a ``levelThreshold`` field that filters out
+    ## any messages with a level lower than the threshold. There is also
+    ## a global filter that applies to all log messages, and it can be changed
+    ## using the `setLogFilter proc<#setLogFilter,Level>`_.
+    lvlAll,       ## All levels active
+    lvlDebug,     ## Debug level and above are active
+    lvlInfo,      ## Info level and above are active
+    lvlNotice,    ## Notice level and above are active
+    lvlWarn,      ## Warn level and above are active
+    lvlError,     ## Error level and above are active
+    lvlFatal,     ## Fatal level and above are active
+    lvlNone       ## No levels active; nothing is logged
 
 const
   LevelNames*: array[Level, string] = [
     "DEBUG", "DEBUG", "INFO", "NOTICE", "WARN", "ERROR", "FATAL", "NONE"
-  ]
+  ]  ## Array of strings representing each logging level.
 
-  defaultFmtStr* = "$levelname " ## default format string
-  verboseFmtStr* = "$levelid, [$datetime] -- $appname: "
+  defaultFmtStr* = "$levelname " ## \
+  ## The default format string.
+  verboseFmtStr* = "$levelid, [$datetime] -- $appname: " ## \
+  ## A more verbose format string.
+  ##
+  ## This string can be passed as the ``frmStr`` argument to procs that create
+  ## new loggers, such as the `newConsoleLogger proc<#newConsoleLogger>`_.
+  ##
+  ## If a different format string is preferred, refer to the
+  ## `documentation about format strings<#basic-usage-format-strings>`_
+  ## for more information, including a list of available variables.
 
 type
-  Logger* = ref object of RootObj ## abstract logger; the base type of all loggers
-    levelThreshold*: Level    ## only messages of level >= levelThreshold
-                              ## should be processed
-    fmtStr*: string ## = defaultFmtStr by default, see substituteLog for $date etc.
-
-  ConsoleLogger* = ref object of Logger ## logger that writes the messages to the
-                                        ## console
-    useStderr*: bool ## will send logs into Stderr if set 
+  Logger* = ref object of RootObj
+    ## The abstract base type of all loggers.
+    ##
+    ## Custom loggers should inherit from this type. They should also provide
+    ## their own implementation of the
+    ## `log method<#log.e,Logger,Level,varargs[string,]>`_.
+    ##
+    ## See also:
+    ## * `ConsoleLogger<#ConsoleLogger>`_
+    ## * `FileLogger<#FileLogger>`_
+    ## * `RollingFileLogger<#RollingFileLogger>`_
+    levelThreshold*: Level    ## Only messages that are at or above this
+                              ## threshold will be logged
+    fmtStr*: string ## Format string to prepend to each log message;
+                    ## defaultFmtStr is the default
+
+  ConsoleLogger* = ref object of Logger
+    ## A logger that writes log messages to the console.
+    ##
+    ## Create a new ``ConsoleLogger`` with the `newConsoleLogger proc
+    ## <#newConsoleLogger>`_.
+    ##
+    ## See also:
+    ## * `FileLogger<#FileLogger>`_
+    ## * `RollingFileLogger<#RollingFileLogger>`_
+    useStderr*: bool ## If true, writes to stderr; otherwise, writes to stdout
 
 when not defined(js):
   type
-    FileLogger* = ref object of Logger ## logger that writes the messages to a file
-      file*: File  ## the wrapped file.
-
-    RollingFileLogger* = ref object of FileLogger ## logger that writes the
-                                                  ## messages to a file and
-                                                  ## performs log rotation
+    FileLogger* = ref object of Logger
+      ## A logger that writes log messages to a file.
+      ##
+      ## Create a new ``FileLogger`` with the `newFileLogger proc
+      ## <#newFileLogger,File>`_.
+      ##
+      ## **Note:** This logger is not available for the JavaScript backend.
+      ##
+      ## See also:
+      ## * `ConsoleLogger<#ConsoleLogger>`_
+      ## * `RollingFileLogger<#RollingFileLogger>`_
+      file*: File  ## The wrapped file
+
+    RollingFileLogger* = ref object of FileLogger
+      ## A logger that writes log messages to a file while performing log
+      ## rotation.
+      ##
+      ## Create a new ``RollingFileLogger`` with the `newRollingFileLogger proc
+      ## <#newRollingFileLogger,FileMode,int,int>`_.
+      ##
+      ## **Note:** This logger is not available for the JavaScript backend.
+      ##
+      ## See also:
+      ## * `ConsoleLogger<#ConsoleLogger>`_
+      ## * `FileLogger<#FileLogger>`_
       maxLines: int # maximum number of lines
       curLine : int
       baseName: string # initial filename
@@ -107,8 +266,27 @@ var
   handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
 
 proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string =
-  ## Format a log message using the ``frmt`` format string, ``level`` and varargs.
-  ## See the module documentation for the format string syntax.
+  ## Formats a log message at the specified level with the given format string.
+  ##
+  ## The `format variables<#basic-usage-format-strings>`_ present within
+  ## ``frmt`` will be replaced with the corresponding values before being
+  ## prepended to ``args`` and returned.
+  ##
+  ## Unless you are implementing a custom logger, there is little need to call
+  ## this directly. Use either a logger's log method or one of the logging
+  ## templates.
+  ##
+  ## See also:
+  ## * `log method<#log.e,ConsoleLogger,Level,varargs[string,]>`_
+  ##   for the ConsoleLogger
+  ## * `log method<#log.e,FileLogger,Level,varargs[string,]>`_
+  ##   for the FileLogger
+  ## * `log method<#log.e,RollingFileLogger,Level,varargs[string,]>`_
+  ##   for the RollingFileLogger
+  ## * `log template<#log.t,Level,varargs[string,]>`_
+  runnableExamples:
+    doAssert substituteLog(defaultFmtStr, lvlInfo, "a message") == "INFO a message"
+    doAssert substituteLog("$levelid - ", lvlError, "an error") == "E - an error"
   var msgLen = 0
   for arg in args:
     msgLen += arg.len
@@ -143,12 +321,45 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
 method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
             raises: [Exception], gcsafe,
             tags: [TimeEffect, WriteIOEffect, ReadIOEffect], base.} =
-  ## Override this method in custom loggers. Default implementation does
+  ## Override this method in custom loggers. The default implementation does
   ## nothing.
+  ##
+  ## See also:
+  ## * `log method<#log.e,ConsoleLogger,Level,varargs[string,]>`_
+  ##   for the ConsoleLogger
+  ## * `log method<#log.e,FileLogger,Level,varargs[string,]>`_
+  ##   for the FileLogger
+  ## * `log method<#log.e,RollingFileLogger,Level,varargs[string,]>`_
+  ##   for the RollingFileLogger
+  ## * `log template<#log.t,Level,varargs[string,]>`_
   discard
 
 method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
-  ## Logs to the console using ``logger`` only.
+  ## Logs to the console with the given `ConsoleLogger<#ConsoleLogger>`_ only.
+  ##
+  ## This method ignores the list of registered handlers.
+  ##
+  ## Whether the message is logged depends on both the ConsoleLogger's
+  ## ``levelThreshold`` field and the global log filter set using the
+  ## `setLogFilter proc<#setLogFilter,Level>`_.
+  ##
+  ## **Note:** Only error and fatal messages will cause the output buffer
+  ## to be flushed immediately. Use the `flushFile proc
+  ## <io.html#flushFile,File>`_ to flush the buffer manually if needed.
+  ##
+  ## See also:
+  ## * `log method<#log.e,FileLogger,Level,varargs[string,]>`_
+  ##   for the FileLogger
+  ## * `log method<#log.e,RollingFileLogger,Level,varargs[string,]>`_
+  ##   for the RollingFileLogger
+  ## * `log template<#log.t,Level,varargs[string,]>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var consoleLog = newConsoleLogger()
+  ##   consoleLog.log(lvlInfo, "this is a message")
+  ##   consoleLog.log(lvlError, "error code is: ", 404)
   if level >= logging.level and level >= logger.levelThreshold:
     let ln = substituteLog(logger.fmtStr, level, args)
     when defined(js):
@@ -165,7 +376,26 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
         discard
 
 proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, useStderr=false): ConsoleLogger =
-  ## Creates a new console logger. This logger logs to the console.
+  ## Creates a new `ConsoleLogger<#ConsoleLogger>`_.
+  ##
+  ## By default, log messages are written to ``stdout``. If ``useStderr`` is
+  ## true, they are written to ``stderr`` instead.
+  ##
+  ## For the JavaScript backend, log messages are written to the console,
+  ## and ``useStderr`` is ignored.
+  ##
+  ## See also:
+  ## * `newFileLogger proc<#newFileLogger,File>`_ that uses a file handle
+  ## * `newFileLogger proc<#newFileLogger,FileMode,int>`_
+  ##   that accepts a filename
+  ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,int,int>`_
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var normalLog = newConsoleLogger()
+  ##   var formatLog = newConsoleLogger(fmtStr=verboseFmtStr)
+  ##   var errorLog = newConsoleLogger(levelThreshold=lvlError, useStderr=true)
   new result
   result.fmtStr = fmtStr
   result.levelThreshold = levelThreshold
@@ -173,20 +403,68 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, useStder
 
 when not defined(js):
   method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
-    ## Logs to a file using ``logger`` only.
+    ## Logs a message at the specified level using the given
+    ## `FileLogger<#FileLogger>`_ only.
+    ##
+    ## This method ignores the list of registered handlers.
+    ##
+    ## Whether the message is logged depends on both the FileLogger's
+    ## ``levelThreshold`` field and the global log filter set using the
+    ## `setLogFilter proc<#setLogFilter,Level>`_.
+    ##
+    ## **Notes:**
+    ## * Only error and fatal messages will cause the output buffer
+    ##   to be flushed immediately. Use the `flushFile proc
+    ##   <io.html#flushFile,File>`_ to flush the buffer manually if needed.
+    ## * This method is not available for the JavaScript backend.
+    ##
+    ## See also:
+    ## * `log method<#log.e,ConsoleLogger,Level,varargs[string,]>`_
+    ##   for the ConsoleLogger
+    ## * `log method<#log.e,RollingFileLogger,Level,varargs[string,]>`_
+    ##   for the RollingFileLogger
+    ## * `log template<#log.t,Level,varargs[string,]>`_
+    ##
+    ## **Examples:**
+    ##
+    ## .. code-block::
+    ##   var fileLog = newFileLogger("messages.log")
+    ##   fileLog.log(lvlInfo, "this is a message")
+    ##   fileLog.log(lvlError, "error code is: ", 404)
     if level >= logging.level and level >= logger.levelThreshold:
       writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
       if level in {lvlError, lvlFatal}: flushFile(logger.file)
 
   proc defaultFilename*(): string =
-    ## Returns the default filename for a logger.
+    ## Returns the filename that is used by default when naming log files.
+    ##
+    ## **Note:** This proc is not available for the JavaScript backend.
     var (path, name, _) = splitFile(getAppFilename())
     result = changeFileExt(path / name, "log")
 
   proc newFileLogger*(file: File,
                       levelThreshold = lvlAll,
                       fmtStr = defaultFmtStr): FileLogger =
-    ## Creates a new file logger. This logger logs to ``file``.
+    ## Creates a new `FileLogger<#FileLogger>`_ that uses the given file handle.
+    ##
+    ## **Note:** This proc is not available for the JavaScript backend.
+    ##
+    ## See also:
+    ## * `newConsoleLogger proc<#newConsoleLogger>`_
+    ## * `newFileLogger proc<#newFileLogger,FileMode,int>`_
+    ##   that accepts a filename
+    ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,int,int>`_
+    ##
+    ## **Examples:**
+    ##
+    ## .. code-block::
+    ##   var messages = open("messages.log", fmWrite)
+    ##   var formatted = open("formatted.log", fmWrite)
+    ##   var errors = open("errors.log", fmWrite)
+    ##
+    ##   var normalLog = newFileLogger(messages)
+    ##   var formatLog = newFileLogger(formatted, fmtStr=verboseFmtStr)
+    ##   var errorLog = newFileLogger(errors, levelThreshold=lvlError)
     new(result)
     result.file = file
     result.levelThreshold = levelThreshold
@@ -197,10 +475,28 @@ when not defined(js):
                       levelThreshold = lvlAll,
                       fmtStr = defaultFmtStr,
                       bufSize: int = -1): FileLogger =
-    ## Creates a new file logger. This logger logs to a file, specified
-    ## by ``fileName``.
-    ## Use ``bufSize`` as size of the output buffer when writing the file
-    ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
+    ## Creates a new `FileLogger<#FileLogger>`_ that logs to a file with the
+    ## given filename.
+    ##
+    ## ``bufSize`` controls the size of the output buffer that is used when
+    ## writing to the log file. The following values can be provided:
+    ## * ``-1`` - use system defaults
+    ## * ``0`` - unbuffered
+    ## * ``> 0`` - fixed buffer size
+    ##
+    ## **Note:** This proc is not available for the JavaScript backend.
+    ##
+    ## See also:
+    ## * `newConsoleLogger proc<#newConsoleLogger>`_
+    ## * `newFileLogger proc<#newFileLogger,File>`_ that uses a file handle
+    ## * `newRollingFileLogger proc<#newRollingFileLogger,FileMode,int,int>`_
+    ##
+    ## **Examples:**
+    ##
+    ## .. code-block::
+    ##   var normalLog = newFileLogger("messages.log")
+    ##   var formatLog = newFileLogger("formatted.log", fmtStr=verboseFmtStr)
+    ##   var errorLog = newFileLogger("errors.log", levelThreshold=lvlError)
     let file = open(filename, mode, bufSize = bufSize)
     newFileLogger(file, levelThreshold, fmtStr)
 
@@ -236,10 +532,32 @@ when not defined(js):
                             fmtStr = defaultFmtStr,
                             maxLines = 1000,
                             bufSize: int = -1): RollingFileLogger =
-    ## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines
-    ## a new log file will be started and the old will be renamed.
-    ## Use ``bufSize`` as size of the output buffer when writing the file
-    ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
+    ## Creates a new `RollingFileLogger<#RollingFileLogger>`_.
+    ##
+    ## Once the current log file being written to contains ``maxLines`` lines,
+    ## a new log file will be created, and the old log file will be renamed.
+    ##
+    ## ``bufSize`` controls the size of the output buffer that is used when
+    ## writing to the log file. The following values can be provided:
+    ## * ``-1`` - use system defaults
+    ## * ``0`` - unbuffered
+    ## * ``> 0`` - fixed buffer size
+    ##
+    ## **Note:** This proc is not available in the JavaScript backend.
+    ##
+    ## See also:
+    ## * `newConsoleLogger proc<#newConsoleLogger>`_
+    ## * `newFileLogger proc<#newFileLogger,File>`_ that uses a file handle
+    ## * `newFileLogger proc<#newFileLogger,FileMode,int>`_
+    ##   that accepts a filename
+    ##
+    ## **Examples:**
+    ##
+    ## .. code-block::
+    ##   var normalLog = newRollingFileLogger("messages.log")
+    ##   var formatLog = newRollingFileLogger("formatted.log", fmtStr=verboseFmtStr)
+    ##   var shortLog = newRollingFileLogger("short.log", maxLines=200)
+    ##   var errorLog = newRollingFileLogger("errors.log", levelThreshold=lvlError)
     new(result)
     result.levelThreshold = levelThreshold
     result.fmtStr = fmtStr
@@ -264,7 +582,34 @@ when not defined(js):
               dir / (name & ext & ExtSep & $(i+1)))
 
   method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) =
-    ## Logs to a file using rolling ``logger`` only.
+    ## Logs a message at the specified level using the given
+    ## `RollingFileLogger<#RollingFileLogger>`_ only.
+    ##
+    ## This method ignores the list of registered handlers.
+    ##
+    ## Whether the message is logged depends on both the RollingFileLogger's
+    ## ``levelThreshold`` field and the global log filter set using the
+    ## `setLogFilter proc<#setLogFilter,Level>`_.
+    ##
+    ## **Notes:**
+    ## * Only error and fatal messages will cause the output buffer
+    ##   to be flushed immediately. Use the `flushFile proc
+    ##   <io.html#flushFile,File>`_ to flush the buffer manually if needed.
+    ## * This method is not available for the JavaScript backend.
+    ##
+    ## See also:
+    ## * `log method<#log.e,ConsoleLogger,Level,varargs[string,]>`_
+    ##   for the ConsoleLogger
+    ## * `log method<#log.e,FileLogger,Level,varargs[string,]>`_
+    ##   for the FileLogger
+    ## * `log template<#log.t,Level,varargs[string,]>`_
+    ##
+    ## **Examples:**
+    ##
+    ## .. code-block::
+    ##   var rollingLog = newRollingFileLogger("messages.log")
+    ##   rollingLog.log(lvlInfo, "this is a message")
+    ##   rollingLog.log(lvlError, "error code is: ", 404)
     if level >= logging.level and level >= logger.levelThreshold:
       if logger.curLine >= logger.maxLines:
         logger.file.close()
@@ -285,7 +630,27 @@ proc logLoop(level: Level, args: varargs[string, `$`]) =
       log(logger, level, args)
 
 template log*(level: Level, args: varargs[string, `$`]) =
-  ## Logs a message to all registered handlers at the given level.
+  ## Logs a message at the specified level to all registered handlers.
+  ##
+  ## Whether the message is logged depends on both the FileLogger's
+  ## `levelThreshold` field and the global log filter set using the
+  ## `setLogFilter proc<#setLogFilter,Level>`_.
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var logger = newConsoleLogger()
+  ##   addHandler(logger)
+  ##
+  ##   log(lvlInfo, "This is an example.")
+  ##
+  ## See also:
+  ## * `debug template<#debug.t,varargs[string,]>`_
+  ## * `info template<#info.t,varargs[string,]>`_
+  ## * `notice template<#notice.t,varargs[string,]>`_
+  ## * `warn template<#warn.t,varargs[string,]>`_
+  ## * `error template<#error.t,varargs[string,]>`_
+  ## * `fatal template<#fatal.t,varargs[string,]>`_
   bind logLoop
   bind `%`
   bind logging.level
@@ -296,62 +661,175 @@ template log*(level: Level, args: varargs[string, `$`]) =
 template debug*(args: varargs[string, `$`]) =
   ## Logs a debug message to all registered handlers.
   ##
-  ## Messages that are useful to the application developer only and are usually
-  ## turned off in release.
+  ## Debug messages are typically useful to the application developer only,
+  ## and they are usually disabled in release builds, although this template
+  ## does not make that distinction.
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var logger = newConsoleLogger()
+  ##   addHandler(logger)
+  ##
+  ##   debug("myProc called with arguments: foo, 5")
+  ##
+  ## See also:
+  ## * `log template<#log.t,Level,varargs[string,]>`_
+  ## * `info template<#info.t,varargs[string,]>`_
+  ## * `notice template<#notice.t,varargs[string,]>`_
   log(lvlDebug, args)
 
 template info*(args: varargs[string, `$`]) =
   ## Logs an info message to all registered handlers.
   ##
-  ## Messages that are generated during the normal operation of an application
-  ## and are of no particular importance. Useful to aggregate for potential
-  ## later analysis.
+  ## Info messages are typically generated during the normal operation
+  ## of an application and are of no particular importance. It can be useful to
+  ## aggregate these messages for later analysis.
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var logger = newConsoleLogger()
+  ##   addHandler(logger)
+  ##
+  ##   info("Application started successfully.")
+  ##
+  ## See also:
+  ## * `log template<#log.t,Level,varargs[string,]>`_
+  ## * `debug template<#debug.t,varargs[string,]>`_
+  ## * `notice template<#notice.t,varargs[string,]>`_
   log(lvlInfo, args)
 
 template notice*(args: varargs[string, `$`]) =
-  ## Logs an notice message to all registered handlers.
+  ## Logs an notice to all registered handlers.
+  ##
+  ## Notices are semantically very similar to info messages, but they are meant
+  ## to be messages that the user should be actively notified about, depending
+  ## on the application.
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var logger = newConsoleLogger()
+  ##   addHandler(logger)
+  ##
+  ##   notice("An important operation has completed.")
   ##
-  ## Semantically very similar to `info`, but meant to be messages you want to
-  ## be actively notified about (depending on your application).
-  ## These could be, for example, grouped by hour and mailed out.
+  ## See also:
+  ## * `log template<#log.t,Level,varargs[string,]>`_
+  ## * `debug template<#debug.t,varargs[string,]>`_
+  ## * `info template<#info.t,varargs[string,]>`_
   log(lvlNotice, args)
 
 template warn*(args: varargs[string, `$`]) =
   ## Logs a warning message to all registered handlers.
   ##
-  ## A non-error message that may indicate a potential problem rising or
-  ## impacted performance.
+  ## A warning is a non-error message that may indicate impending problems or
+  ## degraded performance.
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var logger = newConsoleLogger()
+  ##   addHandler(logger)
+  ##
+  ##   warn("The previous operation took too long to process.")
+  ##
+  ## See also:
+  ## * `log template<#log.t,Level,varargs[string,]>`_
+  ## * `error template<#error.t,varargs[string,]>`_
+  ## * `fatal template<#fatal.t,varargs[string,]>`_
   log(lvlWarn, args)
 
 template error*(args: varargs[string, `$`]) =
   ## Logs an error message to all registered handlers.
   ##
-  ## A application-level error condition. For example, some user input generated
-  ## an exception. The application will continue to run, but functionality or
-  ## data was impacted, possibly visible to users.
+  ## Error messages are for application-level error conditions, such as when
+  ## some user input generated an exception. Typically, the application will
+  ## continue to run, but with degraded functionality or loss of data, and
+  ## these effects might be visible to users.
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var logger = newConsoleLogger()
+  ##   addHandler(logger)
+  ##
+  ##   error("An exception occurred while processing the form.")
+  ##
+  ## See also:
+  ## * `log template<#log.t,Level,varargs[string,]>`_
+  ## * `warn template<#warn.t,varargs[string,]>`_
+  ## * `fatal template<#fatal.t,varargs[string,]>`_
   log(lvlError, args)
 
 template fatal*(args: varargs[string, `$`]) =
   ## Logs a fatal error message to all registered handlers.
   ##
-  ## A application-level fatal condition. FATAL usually means that the application
-  ## cannot go on and will exit (but this logging event will not do that for you).
+  ## Fatal error messages usually indicate that the application cannot continue
+  ## to run and will exit due to a fatal condition. This template only logs the
+  ## message, and it is the application's responsibility to exit properly.
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block::
+  ##   var logger = newConsoleLogger()
+  ##   addHandler(logger)
+  ##
+  ##   fatal("Can't open database -- exiting.")
+  ##
+  ## See also:
+  ## * `log template<#log.t,Level,varargs[string,]>`_
+  ## * `warn template<#warn.t,varargs[string,]>`_
+  ## * `error template<#error.t,varargs[string,]>`_
   log(lvlFatal, args)
 
 proc addHandler*(handler: Logger) =
-  ## Adds ``handler`` to the list of handlers.
+  ## Adds a logger to the list of registered handlers.
+  ##
+  ## **Warning:** The list of handlers is a thread-local variable. If the given
+  ## handler will be used in multiple threads, this proc should be called in
+  ## each of those threads.
+  ##
+  ## See also:
+  ## * `getHandlers proc<#getHandlers>`_
+  runnableExamples:
+    var logger = newConsoleLogger()
+    addHandler(logger)
+    doAssert logger in getHandlers()
   handlers.add(handler)
 
 proc getHandlers*(): seq[Logger] =
   ## Returns a list of all the registered handlers.
+  ##
+  ## See also:
+  ## * `addHandler proc<#addHandler,Logger>`_
   return handlers
 
 proc setLogFilter*(lvl: Level) =
   ## Sets the global log filter.
+  ##
+  ## Messages below the provided level will not be logged regardless of an
+  ## individual logger's ``levelThreshold``. By default, all messages are
+  ## logged.
+  ##
+  ## **Warning:** The global log filter is a thread-local variable. If logging
+  ## is being performed in multiple threads, this proc should be called in each
+  ## thread unless it is intended that different threads should log at different
+  ## logging levels.
+  ##
+  ## See also:
+  ## * `getLogFilter proc<#getLogFilter>`_
+  runnableExamples:
+    setLogFilter(lvlError)
+    doAssert getLogFilter() == lvlError
   level = lvl
 
 proc getLogFilter*(): Level =
   ## Gets the global log filter.
+  ##
+  ## See also:
+  ## * `setLogFilter proc<#setLogFilter,Level>`_
   return level
 
 # --------------