summary refs log tree commit diff stats
path: root/lib/pure/logging.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/logging.nim')
-rw-r--r--lib/pure/logging.nim244
1 files changed, 129 insertions, 115 deletions
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index 6a27e6af8..b23b1e5bb 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -47,7 +47,9 @@
 ## **Warning:** The global list of handlers is a thread var, this means that
 ## the handlers must be re-added in each thread.
 
-import strutils, os, times
+import strutils, times
+when not defined(js):
+  import os
 
 type
   Level* = enum  ## logging level
@@ -77,21 +79,24 @@ type
   ConsoleLogger* = ref object of Logger ## logger that writes the messages to the
                                         ## console
 
-  FileLogger* = ref object of Logger ## logger that writes the messages to a file
-    file*: File  ## the wrapped file.
+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
-    maxLines: int # maximum number of lines
-    curLine : int
-    baseName: string # initial filename
-    baseMode: FileMode # initial file mode
-    logFiles: int # how many log files already created, e.g. basename.1, basename.2...
-    bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size)
+    RollingFileLogger* = ref object of FileLogger ## logger that writes the
+                                                  ## messages to a file and
+                                                  ## performs log rotation
+      maxLines: int # maximum number of lines
+      curLine : int
+      baseName: string # initial filename
+      baseMode: FileMode # initial file mode
+      logFiles: int # how many log files already created, e.g. basename.1, basename.2...
+      bufSize: int # size of output buffer (-1: use system defaults, 0: unbuffered, >0: fixed buffer size)
 
-{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
-    PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
+  {.deprecated: [PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
+
+{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger].}
 
 var
   level {.threadvar.}: Level   ## global log filter
@@ -112,7 +117,7 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
     else:
       inc(i)
       var v = ""
-      var app = getAppFilename()
+      let app = when defined(js): "" else: getAppFilename()
       while frmt[i] in IdentChars:
         v.add(toLower(frmt[i]))
         inc(i)
@@ -121,8 +126,10 @@ proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): str
       of "time": result.add(getClockStr())
       of "datetime": result.add(getDateStr() & "T" & getClockStr())
       of "app":  result.add(app)
-      of "appdir": result.add(app.splitFile.dir)
-      of "appname": result.add(app.splitFile.name)
+      of "appdir":
+        when not defined(js): result.add(app.splitFile.dir)
+      of "appname":
+        when not defined(js): result.add(app.splitFile.name)
       of "levelid": result.add(LevelNames[level][0])
       of "levelname": result.add(LevelNames[level])
       else: discard
@@ -139,19 +146,13 @@ method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
 method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
   ## Logs to the console using ``logger`` only.
   if level >= logging.level and level >= logger.levelThreshold:
-    writeLine(stdout, substituteLog(logger.fmtStr, level, args))
-    if level in {lvlError, lvlFatal}: flushFile(stdout)
-
-method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
-  ## Logs to a file using ``logger`` only.
-  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.
-  var (path, name, _) = splitFile(getAppFilename())
-  result = changeFileExt(path / name, "log")
+    let ln = substituteLog(logger.fmtStr, level, args)
+    when defined(js):
+      let cln: cstring = ln
+      {.emit: "console.log(`cln`);".}
+    else:
+      writeLine(stdout, ln)
+      if level in {lvlError, lvlFatal}: flushFile(stdout)
 
 proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger =
   ## Creates a new console logger. This logger logs to the console.
@@ -159,87 +160,99 @@ proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): Console
   result.fmtStr = fmtStr
   result.levelThreshold = levelThreshold
 
-proc newFileLogger*(filename = defaultFilename(),
-                    mode: FileMode = fmAppend,
-                    levelThreshold = lvlAll,
-                    fmtStr = defaultFmtStr,
-                    bufSize: int = -1): FileLogger =
-  ## Creates a new file logger. This logger logs to a file.
-  ## Use ``bufSize`` as size of the output buffer when writing the file
-  ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
-  new(result)
-  result.levelThreshold = levelThreshold
-  result.file = open(filename, mode, bufSize = bufSize)
-  result.fmtStr = fmtStr
-
-# ------
-
-proc countLogLines(logger: RollingFileLogger): int =
-  result = 0
-  for line in logger.file.lines():
-    result.inc()
-
-proc countFiles(filename: string): int =
-  # Example: file.log.1
-  result = 0
-  let (dir, name, ext) = splitFile(filename)
-  for kind, path in walkDir(dir):
-    if kind == pcFile:
-      let llfn = name & ext & ExtSep
-      if path.extractFilename.startsWith(llfn):
-        let numS = path.extractFilename[llfn.len .. ^1]
-        try:
-          let num = parseInt(numS)
-          if num > result:
-            result = num
-        except ValueError: discard
-
-proc newRollingFileLogger*(filename = defaultFilename(),
-                           mode: FileMode = fmReadWrite,
-                           levelThreshold = lvlAll,
-                           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).
-  new(result)
-  result.levelThreshold = levelThreshold
-  result.fmtStr = fmtStr
-  result.maxLines = maxLines
-  result.bufSize = bufSize
-  result.file = open(filename, mode, bufSize=result.bufSize)
-  result.curLine = 0
-  result.baseName = filename
-  result.baseMode = mode
-
-  result.logFiles = countFiles(filename)
-
-  if mode == fmAppend:
-    # We need to get a line count because we will be appending to the file.
-    result.curLine = countLogLines(result)
-
-proc rotate(logger: RollingFileLogger) =
-  let (dir, name, ext) = splitFile(logger.baseName)
-  for i in countdown(logger.logFiles, 0):
-    let srcSuff = if i != 0: ExtSep & $i else: ""
-    moveFile(dir / (name & ext & srcSuff),
-             dir / (name & ext & ExtSep & $(i+1)))
-
-method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) =
-  ## Logs to a file using rolling ``logger`` only.
-  if level >= logging.level and level >= logger.levelThreshold:
-    if logger.curLine >= logger.maxLines:
-      logger.file.close()
-      rotate(logger)
-      logger.logFiles.inc
-      logger.curLine = 0
-      logger.file = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
-
-    writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
-    if level in {lvlError, lvlFatal}: flushFile(logger.file)
-    logger.curLine.inc
+when not defined(js):
+  method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
+    ## Logs to a file using ``logger`` only.
+    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.
+    var (path, name, _) = splitFile(getAppFilename())
+    result = changeFileExt(path / name, "log")
+
+  proc newFileLogger*(filename = defaultFilename(),
+                      mode: FileMode = fmAppend,
+                      levelThreshold = lvlAll,
+                      fmtStr = defaultFmtStr,
+                      bufSize: int = -1): FileLogger =
+    ## Creates a new file logger. This logger logs to a file.
+    ## Use ``bufSize`` as size of the output buffer when writing the file
+    ## (-1: use system defaults, 0: unbuffered, >0: fixed buffer size).
+    new(result)
+    result.levelThreshold = levelThreshold
+    result.file = open(filename, mode, bufSize = bufSize)
+    result.fmtStr = fmtStr
+
+  # ------
+
+  proc countLogLines(logger: RollingFileLogger): int =
+    result = 0
+    for line in logger.file.lines():
+      result.inc()
+
+  proc countFiles(filename: string): int =
+    # Example: file.log.1
+    result = 0
+    let (dir, name, ext) = splitFile(filename)
+    for kind, path in walkDir(dir):
+      if kind == pcFile:
+        let llfn = name & ext & ExtSep
+        if path.extractFilename.startsWith(llfn):
+          let numS = path.extractFilename[llfn.len .. ^1]
+          try:
+            let num = parseInt(numS)
+            if num > result:
+              result = num
+          except ValueError: discard
+
+  proc newRollingFileLogger*(filename = defaultFilename(),
+                            mode: FileMode = fmReadWrite,
+                            levelThreshold = lvlAll,
+                            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).
+    new(result)
+    result.levelThreshold = levelThreshold
+    result.fmtStr = fmtStr
+    result.maxLines = maxLines
+    result.bufSize = bufSize
+    result.file = open(filename, mode, bufSize=result.bufSize)
+    result.curLine = 0
+    result.baseName = filename
+    result.baseMode = mode
+
+    result.logFiles = countFiles(filename)
+
+    if mode == fmAppend:
+      # We need to get a line count because we will be appending to the file.
+      result.curLine = countLogLines(result)
+
+  proc rotate(logger: RollingFileLogger) =
+    let (dir, name, ext) = splitFile(logger.baseName)
+    for i in countdown(logger.logFiles, 0):
+      let srcSuff = if i != 0: ExtSep & $i else: ""
+      moveFile(dir / (name & ext & srcSuff),
+              dir / (name & ext & ExtSep & $(i+1)))
+
+  method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) =
+    ## Logs to a file using rolling ``logger`` only.
+    if level >= logging.level and level >= logger.levelThreshold:
+      if logger.curLine >= logger.maxLines:
+        logger.file.close()
+        rotate(logger)
+        logger.logFiles.inc
+        logger.curLine = 0
+        logger.file = open(logger.baseName, logger.baseMode, bufSize = logger.bufSize)
+
+      writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
+      if level in {lvlError, lvlFatal}: flushFile(logger.file)
+      logger.curLine.inc
 
 # --------
 
@@ -323,10 +336,11 @@ proc getLogFilter*(): Level =
 
 when not defined(testing) and isMainModule:
   var L = newConsoleLogger()
-  var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
-  var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
+  when not defined(js):
+    var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
+    var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
+    addHandler(fL)
+    addHandler(rL)
   addHandler(L)
-  addHandler(fL)
-  addHandler(rL)
   for i in 0 .. 25:
     info("hello", i)