Merge branch 'master' of github.com:Araq/Nimrod

This commit is contained in:
Araq 2012-08-02 23:16:17 +02:00
commit e2359aba44
5 changed files with 123 additions and 53 deletions

View file

@ -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 =

View file

@ -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

View file

@ -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", [])

View file

@ -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.})

View file

@ -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: