Merge branch 'master' of github.com:Araq/Nimrod
This commit is contained in:
commit
e2359aba44
5 changed files with 123 additions and 53 deletions
|
|
@ -861,7 +861,8 @@ proc genMainProc(m: BModule) =
|
||||||
CommonMainBody & "}$n"
|
CommonMainBody & "}$n"
|
||||||
WinCDllMain =
|
WinCDllMain =
|
||||||
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
|
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
|
||||||
" LPVOID lpvReserved) {$n" & "\tNimMain();$n" &
|
" LPVOID lpvReserved) {$n" &
|
||||||
|
"\tif(fwdreason == DLL_PROCESS_ATTACH) NimMain();$n" &
|
||||||
"\treturn 1;$n" & "}$n"
|
"\treturn 1;$n" & "}$n"
|
||||||
PosixNimDllMain = WinNimDllMain
|
PosixNimDllMain = WinNimDllMain
|
||||||
PosixCDllMain =
|
PosixCDllMain =
|
||||||
|
|
|
||||||
|
|
@ -212,16 +212,22 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode =
|
||||||
result = newEmptyStrNode(n)
|
result = newEmptyStrNode(n)
|
||||||
|
|
||||||
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
proc processDynLib(c: PContext, n: PNode, sym: PSym) =
|
||||||
if (sym == nil) or (sym.kind == skModule):
|
if (sym == nil) or (sym.kind == skModule):
|
||||||
POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic,
|
POptionEntry(c.optionStack.tail).dynlib = getLib(c, libDynamic,
|
||||||
expectDynlibNode(c, n))
|
expectDynlibNode(c, n))
|
||||||
elif n.kind == nkExprColonExpr:
|
else:
|
||||||
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
|
if n.kind == nkExprColonExpr:
|
||||||
addToLib(lib, sym)
|
var lib = getLib(c, libDynamic, expectDynlibNode(c, n))
|
||||||
incl(sym.loc.flags, lfDynamicLib)
|
addToLib(lib, sym)
|
||||||
else:
|
incl(sym.loc.flags, lfDynamicLib)
|
||||||
incl(sym.loc.flags, lfExportLib)
|
else:
|
||||||
|
incl(sym.loc.flags, lfExportLib)
|
||||||
|
# since we'll be loading the dynlib symbols dynamically, we must use
|
||||||
|
# a calling convention that doesn't introduce custom name mangling
|
||||||
|
# cdecl is the default - the use can override this explicitly
|
||||||
|
if sym.typ.callConv == ccDefault:
|
||||||
|
sym.typ.callConv = ccCDecl
|
||||||
|
|
||||||
proc processNote(c: PContext, n: PNode) =
|
proc processNote(c: PContext, n: PNode) =
|
||||||
if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
|
if (n.kind == nkExprColonExpr) and (sonsLen(n) == 2) and
|
||||||
(n.sons[0].kind == nkBracketExpr) and
|
(n.sons[0].kind == nkBracketExpr) and
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
##
|
##
|
||||||
##
|
##
|
||||||
|
|
||||||
|
import strutils, os, times
|
||||||
|
|
||||||
type
|
type
|
||||||
TLevel* = enum ## logging level
|
TLevel* = enum ## logging level
|
||||||
lvlAll, ## all levels active
|
lvlAll, ## all levels active
|
||||||
|
|
@ -25,46 +27,39 @@ type
|
||||||
lvlInfo, ## info level (and any above) active
|
lvlInfo, ## info level (and any above) active
|
||||||
lvlWarn, ## warn level (and any above) active
|
lvlWarn, ## warn level (and any above) active
|
||||||
lvlError, ## error level (and any above) active
|
lvlError, ## error level (and any above) active
|
||||||
lvlFatal ## fatal level (and any above) active
|
lvlFatal, ## fatal level (and any above) active
|
||||||
|
lvlNone
|
||||||
|
|
||||||
const
|
const
|
||||||
LevelNames*: array [TLevel, string] = [
|
LevelNames*: array [TLevel, string] = [
|
||||||
"DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
|
"DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
defaultFmtStr = "" ## default string between log level and message per logger
|
||||||
|
verboseFmtStr = "$date $time "
|
||||||
|
|
||||||
type
|
type
|
||||||
TLogger* = object of TObject ## abstract logger; the base type of all loggers
|
TLogger* = object of TObject ## abstract logger; the base type of all loggers
|
||||||
levelThreshold*: TLevel ## only messages of level >= levelThreshold
|
levelThreshold*: TLevel ## only messages of level >= levelThreshold
|
||||||
## should be processed
|
## should be processed
|
||||||
|
fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc.
|
||||||
|
|
||||||
TConsoleLogger* = object of TLogger ## logger that writes the messages to the
|
TConsoleLogger* = object of TLogger ## logger that writes the messages to the
|
||||||
## console
|
## console
|
||||||
|
|
||||||
TFileLogger* = object of TLogger ## logger that writes the messages to a file
|
TFileLogger* = object of TLogger ## logger that writes the messages to a file
|
||||||
f: TFile
|
f: TFile
|
||||||
|
|
||||||
|
# TODO: implement rolling log, will produce filename.1, filename.2 etc.
|
||||||
TRollingFileLogger* = object of TFileLogger ## logger that writes the
|
TRollingFileLogger* = object of TFileLogger ## logger that writes the
|
||||||
## message to a file
|
## message to a file
|
||||||
maxlines: int # maximum number of lines
|
maxLines: int # maximum number of lines
|
||||||
lines: seq[string]
|
curLine : int
|
||||||
|
baseName: string # initial filename
|
||||||
|
logFiles: int # how many log files already created, e.g. basename.1, basename.2...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
method log*(L: ref TLogger, level: TLevel,
|
|
||||||
frmt: string, args: openArray[string]) =
|
|
||||||
## override this method in custom loggers. Default implementation does
|
|
||||||
## nothing.
|
|
||||||
nil
|
|
||||||
|
|
||||||
method log*(L: ref TConsoleLogger, level: TLevel,
|
|
||||||
frmt: string, args: openArray[string]) =
|
|
||||||
Writeln(stdout, LevelNames[level], " ", frmt % args)
|
|
||||||
|
|
||||||
method log*(L: ref TFileLogger, level: TLevel,
|
|
||||||
frmt: string, args: openArray[string]) =
|
|
||||||
Writeln(L.f, LevelNames[level], " ", frmt % args)
|
|
||||||
|
|
||||||
proc defaultFilename*(): string =
|
|
||||||
## returns the default filename for a logger
|
|
||||||
var (path, name, ext) = splitFile(getAppFilename())
|
|
||||||
result = changeFileExt(path / name & "_" & getDateStr(), "log")
|
|
||||||
|
|
||||||
proc substituteLog*(frmt: string): string =
|
proc substituteLog*(frmt: string): string =
|
||||||
## converts $date to the current date
|
## converts $date to the current date
|
||||||
|
|
@ -90,56 +85,126 @@ proc substituteLog*(frmt: string): string =
|
||||||
of "app": result.add(app)
|
of "app": result.add(app)
|
||||||
of "appdir": result.add(app.splitFile.dir)
|
of "appdir": result.add(app.splitFile.dir)
|
||||||
of "appname": result.add(app.splitFile.name)
|
of "appname": result.add(app.splitFile.name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
method log*(L: ref TLogger, level: TLevel,
|
||||||
|
frmt: string, args: openArray[string]) =
|
||||||
|
## override this method in custom loggers. Default implementation does
|
||||||
|
## nothing.
|
||||||
|
nil
|
||||||
|
|
||||||
|
method log*(L: ref TConsoleLogger, level: TLevel,
|
||||||
|
frmt: string, args: openArray[string]) =
|
||||||
|
Writeln(stdout, LevelNames[level], " ", substituteLog(L.fmtStr), frmt % args)
|
||||||
|
|
||||||
|
method log*(L: ref TFileLogger, level: TLevel,
|
||||||
|
frmt: string, args: openArray[string]) =
|
||||||
|
Writeln(L.f, LevelNames[level], " ", substituteLog(L.fmtStr), frmt % args)
|
||||||
|
|
||||||
|
proc defaultFilename*(): string =
|
||||||
|
## returns the default filename for a logger
|
||||||
|
var (path, name, ext) = splitFile(getAppFilename())
|
||||||
|
result = changeFileExt(path / name & "_" & getDateStr(), "log")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
proc newConsoleLogger*(levelThreshold = lvlAll) : ref TConsoleLogger =
|
||||||
|
new result
|
||||||
|
result.fmtStr = defaultFmtStr
|
||||||
|
result.levelThreshold = levelThreshold
|
||||||
|
|
||||||
proc newFileLogger*(filename = defaultFilename(),
|
proc newFileLogger*(filename = defaultFilename(),
|
||||||
mode: TFileMode = fmAppend,
|
mode: TFileMode = fmAppend,
|
||||||
levelThreshold = lvlNone): ref TFileLogger =
|
levelThreshold = lvlAll): ref TFileLogger =
|
||||||
new(result)
|
new(result)
|
||||||
result.levelThreshold = levelThreshold
|
result.levelThreshold = levelThreshold
|
||||||
result.f = open(filename, mode)
|
result.f = open(filename, mode)
|
||||||
|
result.fmtStr = defaultFmtStr
|
||||||
|
|
||||||
|
# ------
|
||||||
|
|
||||||
|
proc readLogLines(logger : ref TRollingFileLogger) = nil
|
||||||
|
#f.readLine # TODO read all lines, update curLine
|
||||||
|
|
||||||
|
|
||||||
proc newRollingFileLogger*(filename = defaultFilename(),
|
proc newRollingFileLogger*(filename = defaultFilename(),
|
||||||
mode: TFileMode = fmAppend,
|
mode: TFileMode = fmReadWrite,
|
||||||
levelThreshold = lvlNone,
|
levelThreshold = lvlAll,
|
||||||
maxLines = 1000): ref TFileLogger =
|
maxLines = 1000): ref TRollingFileLogger =
|
||||||
new(result)
|
new(result)
|
||||||
result.levelThreshold = levelThreshold
|
result.levelThreshold = levelThreshold
|
||||||
|
result.fmtStr = defaultFmtStr
|
||||||
result.maxLines = maxLines
|
result.maxLines = maxLines
|
||||||
result.f = open(filename, mode)
|
result.f = open(filename, mode)
|
||||||
|
result.curLine = 0
|
||||||
|
|
||||||
|
# TODO count all number files
|
||||||
|
# count lines in existing filename file
|
||||||
|
# if >= maxLines then rename to next numbered file and create new file
|
||||||
|
|
||||||
|
#if mode in {fmReadWrite, fmReadWriteExisting}:
|
||||||
|
# readLogLines(result)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
method log*(L: ref TRollingFileLogger, level: TLevel,
|
||||||
|
frmt: string, args: openArray[string]) =
|
||||||
|
# TODO
|
||||||
|
# if more than maxlines, then set cursor to zero
|
||||||
|
|
||||||
|
Writeln(L.f, LevelNames[level], " ", frmt % args)
|
||||||
|
|
||||||
|
# --------
|
||||||
|
|
||||||
var
|
var
|
||||||
level* = lvlNone
|
level* = lvlAll ## global log filter
|
||||||
handlers*: seq[ref TLogger] = @[]
|
handlers*: seq[ref TLogger] = @[] ## handlers with their own log levels
|
||||||
|
|
||||||
proc logLoop(level: TLevel, msg: string) =
|
proc logLoop(level: TLevel, frmt: string, args: openarray[string]) =
|
||||||
for logger in items(handlers):
|
for logger in items(handlers):
|
||||||
if level >= logger.levelThreshold:
|
if level >= logger.levelThreshold:
|
||||||
log(logger, level, msg)
|
log(logger, level, frmt, args)
|
||||||
|
|
||||||
template log*(level: TLevel, msg: string) =
|
template log*(level: TLevel, frmt: string, args: openarray[string]) =
|
||||||
## logs a message of the given level
|
## logs a message of the given level
|
||||||
bind logLoop
|
bind logLoop
|
||||||
|
bind `%`
|
||||||
|
bind logging.Level
|
||||||
|
|
||||||
if level >= logging.Level:
|
if level >= logging.Level:
|
||||||
logLoop(level, frmt, args)
|
logLoop(level, frmt, args)
|
||||||
|
|
||||||
template debug*(msg: string) =
|
template debug*(frmt: string, args: openarray[string]) =
|
||||||
## logs a debug message
|
## logs a debug message
|
||||||
log(lvlDebug, msg)
|
log(lvlDebug, frmt, args)
|
||||||
|
|
||||||
template info*(msg: string) =
|
template info*(frmt: string, args: openarray[string]) =
|
||||||
## logs an info message
|
## logs an info message
|
||||||
log(lvlInfo, msg)
|
log(lvlInfo, frmt, args)
|
||||||
|
|
||||||
template warn*(msg: string) =
|
template warn*(frmt: string, args: openarray[string]) =
|
||||||
## logs a warning message
|
## logs a warning message
|
||||||
log(lvlWarn, msg)
|
log(lvlWarn, frmt, args)
|
||||||
|
|
||||||
template error*(msg: string) =
|
template error*(frmt: string, args: openarray[string]) =
|
||||||
## logs an error message
|
## logs an error message
|
||||||
log(lvlError, msg)
|
log(lvlError, frmt, args)
|
||||||
|
|
||||||
template fatal*(msg: string) =
|
template fatal*(frmt: string, args: openarray[string]) =
|
||||||
## logs a fatal error message
|
## logs a fatal error message
|
||||||
log(lvlFatal, msg)
|
log(lvlFatal, frmt, args)
|
||||||
|
|
||||||
|
|
||||||
|
# --------------
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
var L = newConsoleLogger()
|
||||||
|
var fL = newFileLogger("test.log")
|
||||||
|
fL.fmtStr = verboseFmtStr
|
||||||
|
handlers.add(L)
|
||||||
|
handlers.add(fL)
|
||||||
|
info("hello", [])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1935,7 +1935,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
include "system/syslocks"
|
include "system/syslocks"
|
||||||
include "system/threads"
|
include "system/threads"
|
||||||
elif not defined(nogc):
|
elif not defined(nogc):
|
||||||
initStackBottom()
|
|
||||||
initGC()
|
initGC()
|
||||||
|
|
||||||
proc setControlCHook*(hook: proc () {.noconv.})
|
proc setControlCHook*(hook: proc () {.noconv.})
|
||||||
|
|
|
||||||
|
|
@ -203,7 +203,6 @@ when not defined(useNimRtl):
|
||||||
when not useStackMaskHack:
|
when not useStackMaskHack:
|
||||||
var mainThread: TGcThread
|
var mainThread: TGcThread
|
||||||
ThreadVarSetValue(globalsSlot, addr(mainThread))
|
ThreadVarSetValue(globalsSlot, addr(mainThread))
|
||||||
initStackBottom()
|
|
||||||
initGC()
|
initGC()
|
||||||
|
|
||||||
when emulatedThreadVars:
|
when emulatedThreadVars:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue