summary refs log tree commit diff stats
path: root/lib/pure/includes
Commit message (Expand)AuthorAgeFilesLines
* change os.nim doc links to new style (#19102)Andrey Makarov2021-11-083-35/+34
* envPairs works in vm, nims (#18615)Timothee Cour2021-09-291-177/+188
* Remove tracking of environment from osenv.nim v2 (#18575)Timothee Cour2021-07-291-159/+78
* Replace calls to `putenv` with `setenv` (#18530)Caden Haustein2021-07-231-3/+8
* improve rendering of newOSError.additionalInfo (#18443)Timothee Cour2021-07-071-2/+3
* Use `.. warning::` (#17320)konsumlamm2021-03-101-5/+4
* use lowercase --define switches (#17283)flywind2021-03-071-1/+1
* https://github.com/nim-lang/Nim/pull/15826/files#r585368355 (#17233)Juan Carlos2021-03-031-2/+3
* use single backtick (#17141)flywind2021-02-213-12/+12
* Correct typo in osseps.nim (#16939)Rummskartoffel2021-02-041-1/+1
* Deprecate TaintedString (#15423)Juan Carlos2021-01-151-9/+9
* fixes #16359 [backport] (#16377)Andreas Rumpf2020-12-171-1/+1
* move decode_helpers to std/private (#16209)flywind2020-12-021-24/+0
* js -d:nodejs now supports osenv: `getEnv`, `putEnv`, `envPairs`, `delEnv`, `e...Timothee Cour2020-11-121-215/+251
* fix #14082, don't crash on incorrectly formatted input (#14977) [backport]Miran2020-07-171-0/+24
* forward type alignment information to seqs (#12430)Arne Döring2020-04-191-2/+1
* More fixes for Haiku (#13774)alaviss2020-03-271-0/+2
* miscellaneous bug fixes (#13291)Timothee Cour2020-01-301-1/+1
* Deleted misplaced separator (#13085) [backport]Teashrock2020-01-091-1/+0
* remove unused importsnarimiran2019-11-061-1/+2
* fixes #11807 (#11900)Andreas Rumpf2019-08-071-0/+5
* Fix #10630 - fix broken separators in nim doc (#11814)genotrance2019-07-241-95/+77
* os: confine osErrorMsg example to Linux (#11725)alaviss2019-07-131-1/+1
* [feature] Added os.delEnv; add delEnv support to nimscript too (#11466)Kaushal Modi2019-06-151-0/+31
* [bugfix] Fixes async IO operations stalling even after socket is closed. (#11...Dominik Picheta2019-06-121-3/+12
* Fix ospaths import error (#11150)genotrance2019-05-012-2/+2
* newruntime: progressAraq2019-04-011-1/+1
* update unicode.nim (#10921)Miran2019-03-311-0/+2016
* better docs: os (#10492)Miran2019-01-303-27/+77
* prevent index out of bounds error in oserr.nimKobi2019-01-191-1/+1
* Fix spelling errors (#10379)Federico Ceratto2019-01-191-2/+2
* [backport] fix documentation leak to `os.nim`[ci skip]narimiran2019-01-142-2/+2
* os.nim: big refactoring, use the new pathnorm that was extracted by compiler/...Araq2018-12-131-0/+130
* Merge pull request #9910 from nc-x/fix-semicolonAndreas Rumpf2018-12-111-1/+2
|\
| * Address CommentsNeelesh Chandola2018-12-111-0/+1
| * Fixes #9907Neelesh Chandola2018-12-091-1/+1
* | Merge async common into asyncdispatch.Dominik Picheta2018-12-071-211/+0
|/
* Make getEnv case insensitive on Windows (#9722)pgkos2018-11-161-1/+6
* deprecated ospaths (#9665)Andreas Rumpf2018-11-092-4/+4
* Convert *_family fields to cushortLemonBoy2018-09-191-2/+2
* add data.sysCommand when startProcessAuxSpawn raisesTimothee Cour2018-09-061-4/+4
* addresses issue #8391 show runtime context on some failed operations (#8393)Timothee Cour2018-07-231-1/+1
* Fixes #5880. (#7229)Dominik Picheta2018-07-101-1/+1
* remove deprecated stuff from the stdlib; introduce better deprecation warningsAraq2018-05-052-46/+2
* Fixes #4995. (#7157)Dominik Picheta2018-02-131-6/+16
* added a warning that the .deprecate statement is unreliable for routinesAndreas Rumpf2017-11-211-3/+0
* getEnv now supports a 'default' parameter; refs #6019Andreas Rumpf2017-10-301-2/+2
* another attempt to make travis and appveyor green againAndreas Rumpf2017-09-011-3/+3
* fix os.nim for WindowsAndreas Rumpf2017-09-011-0/+3
* refactor os.nim and ospaths.nimAndreas Rumpf2017-09-012-0/+291
/span>] = [ "DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE" ] defaultFmtStr* = "" ## default string between log level and message per logger verboseFmtStr* = "$date $time " 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 FileLogger* = ref object of Logger ## logger that writes the messages to a file f: 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... {.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger, PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].} proc substituteLog(frmt: string): string = ## converts $date to the current date ## converts $time to the current time ## converts $app to getAppFilename() ## converts result = newStringOfCap(frmt.len + 20) var i = 0 while i < frmt.len: if frmt[i] != '$': result.add(frmt[i]) inc(i) else: inc(i) var v = "" var app = getAppFilename() while frmt[i] in IdentChars: v.add(toLower(frmt[i])) inc(i) case v of "date": result.add(getDateStr()) of "time": result.add(getClockStr()) of "app": result.add(app) of "appdir": result.add(app.splitFile.dir) of "appname": result.add(app.splitFile.name) else: discard method log*(logger: Logger, level: Level, frmt: string, args: varargs[string, `$`]) {. raises: [Exception], tags: [TimeEffect, WriteIOEffect, ReadIOEffect].} = ## Override this method in custom loggers. Default implementation does ## nothing. discard method log*(logger: ConsoleLogger, level: Level, frmt: string, args: varargs[string, `$`]) = ## Logs to the console using ``logger`` only. if level >= logger.levelThreshold: writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr), frmt % args) method log*(logger: FileLogger, level: Level, frmt: string, args: varargs[string, `$`]) = ## Logs to a file using ``logger`` only. if level >= logger.levelThreshold: writeln(logger.f, LevelNames[level], " ", substituteLog(logger.fmtStr), frmt % args) proc defaultFilename*(): string = ## Returns the default filename for a logger. var (path, name, ext) = splitFile(getAppFilename()) result = changeFileExt(path / name, "log") proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger = ## Creates a new console logger. This logger logs to the console. new result result.fmtStr = fmtStr result.levelThreshold = levelThreshold proc newFileLogger*(filename = defaultFilename(), mode: FileMode = fmAppend, levelThreshold = lvlAll, fmtStr = defaultFmtStr): FileLogger = ## Creates a new file logger. This logger logs to a file. new(result) result.levelThreshold = levelThreshold result.f = open(filename, mode) result.fmtStr = fmtStr # ------ proc countLogLines(logger: RollingFileLogger): int = result = 0 for line in logger.f.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): 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. new(result) result.levelThreshold = levelThreshold result.fmtStr = fmtStr result.maxLines = maxLines result.f = open(filename, mode) 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, frmt: string, args: varargs[string, `$`]) = ## Logs to a file using rolling ``logger`` only. if level >= logger.levelThreshold: if logger.curLine >= logger.maxLines: logger.f.close() rotate(logger) logger.logFiles.inc logger.curLine = 0 logger.f = open(logger.baseName, logger.baseMode) writeln(logger.f, LevelNames[level], " ", frmt % args) logger.curLine.inc # -------- var level {.threadvar.}: Level ## global log filter var handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels proc logLoop(level: Level, frmt: string, args: varargs[string, `$`]) = for logger in items(handlers): if level >= logger.levelThreshold: log(logger, level, frmt, args) template log*(level: Level, frmt: string, args: varargs[string, `$`]) = ## Logs a message to all registered handlers at the given level. bind logLoop bind `%` bind logging.level if level >= logging.level: logLoop(level, frmt, args) template debug*(frmt: string, args: varargs[string, `$`]) = ## Logs a debug message to all registered handlers. log(lvlDebug, frmt, args) template info*(frmt: string, args: varargs[string, `$`]) = ## Logs an info message to all registered handlers. log(lvlInfo, frmt, args) template warn*(frmt: string, args: varargs[string, `$`]) = ## Logs a warning message to all registered handlers. log(lvlWarn, frmt, args) template error*(frmt: string, args: varargs[string, `$`]) = ## Logs an error message to all registered handlers. log(lvlError, frmt, args) template fatal*(frmt: string, args: varargs[string, `$`]) = ## Logs a fatal error message to all registered handlers. log(lvlFatal, frmt, args) proc addHandler*(handler: Logger) = ## Adds ``handler`` to the list of handlers. if handlers.isNil: handlers = @[] handlers.add(handler) proc getHandlers*(): seq[Logger] = ## Returns a list of all the registered handlers. return handlers proc setLogFilter*(lvl: Level) = ## Sets the global log filter. level = lvl proc getLogFilter*(): Level = ## Gets the global log filter. return level # -------------- when isMainModule: var L = newConsoleLogger() var fL = newFileLogger("test.log", fmtStr = verboseFmtStr) var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr) addHandler(L) addHandler(fL) addHandler(rL) for i in 0 .. 25: info("hello" & $i, [])