diff --git a/config.nims b/config.nims index d7ce9358..f176e809 100644 --- a/config.nims +++ b/config.nims @@ -66,4 +66,4 @@ switch("warning", "ObservableStores:off") # Too many false positives for "Warning: method has lock level , but another method has 0 [LockLevel]" switch("warning", "LockLevel:off") - +switch("define", "chronicles_sinks=textlines[dynamic],json[dynamic]") diff --git a/dagger.nim b/dagger.nim index edbf2b6f..3c7c574e 100644 --- a/dagger.nim +++ b/dagger.nim @@ -27,8 +27,8 @@ when isMainModule: when defined(posix): import system/ansi_c - let - config = DaggerConf.load() + let config = DaggerConf.load() + config.setupLogging() case config.cmd: of StartUpCommand.noCommand: diff --git a/dagger/conf.nim b/dagger/conf.nim index 049ff1d6..c99c0f93 100644 --- a/dagger/conf.nim +++ b/dagger/conf.nim @@ -12,9 +12,12 @@ import pkg/upraises push: {.upraises: [].} import std/os +import std/terminal import std/options +import std/typetraits import pkg/chronicles +import pkg/chronicles/topics_registry import pkg/confutils/defs import pkg/libp2p @@ -30,10 +33,26 @@ type noCommand, initNode + LogKind* = enum + Auto = "auto" + Colors = "colors" + NoColors = "nocolors" + Json = "json" + None = "none" + DaggerConf* = object logLevel* {. defaultValue: LogLevel.INFO - desc: "Sets the log level" }: LogLevel + desc: "Sets the log level", + name: "log-level" }: LogLevel + + logFormat* {. + hidden + desc: "Specifies what kind of logs should be written to stdout (auto, colors, nocolors, json)" + defaultValueDesc: "auto" + defaultValue: LogKind.Auto + name: "log-format" }: LogKind + dataDir* {. desc: "The directory where dagger will store configuration and data." @@ -99,3 +118,76 @@ proc defaultDataDir*(): string = func parseCmdArg*(T: type MultiAddress, input: TaintedString): T {.raises: [ValueError, LPError, Defect].} = MultiAddress.init($input).tryGet() + +# silly chronicles, colors is a compile-time property +proc stripAnsi(v: string): string = + var + res = newStringOfCap(v.len) + i: int + + while i < v.len: + let c = v[i] + if c == '\x1b': + var + x = i + 1 + found = false + + while x < v.len: # look for [..m + let c2 = v[x] + if x == i + 1: + if c2 != '[': + break + else: + if c2 in {'0'..'9'} + {';'}: + discard # keep looking + elif c2 == 'm': + i = x + 1 + found = true + break + else: + break + inc x + + if found: # skip adding c + continue + res.add c + inc i + + res + +proc setupLogging*(conf: DaggerConf) = + when defaultChroniclesStream.outputs.type.arity != 2: + warn "Logging configuration options not enabled in the current build" + else: + proc noOutput(logLevel: LogLevel, msg: LogOutputStr) = discard + proc writeAndFlush(f: File, msg: LogOutputStr) = + try: + f.write(msg) + f.flushFile() + except IOError as err: + logLoggingFailure(cstring(msg), err) + + proc stdoutFlush(logLevel: LogLevel, msg: LogOutputStr) = + writeAndFlush(stdout, msg) + + proc noColorsFlush(logLevel: LogLevel, msg: LogOutputStr) = + writeAndFlush(stdout, stripAnsi(msg)) + + defaultChroniclesStream.outputs[1].writer = noOutput + + defaultChroniclesStream.outputs[0].writer = + case conf.logFormat: + of LogKind.Auto: + if isatty(stdout): + stdoutFlush + else: + noColorsFlush + of LogKind.Colors: stdoutFlush + of LogKind.NoColors: noColorsFlush + of LogKind.Json: + defaultChroniclesStream.outputs[1].writer = stdoutFlush + noOutput + of LogKind.None: + noOutput + + setLogLevel(conf.logLevel)