2023-04-19 15:01:01 +00:00
|
|
|
# Nimbus Fluffy
|
2024-02-28 17:31:45 +00:00
|
|
|
# Copyright (c) 2023-2024 Status Research & Development GmbH
|
2023-04-19 15:01:01 +00:00
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
|
|
|
# Note:
|
|
|
|
# Code taken from nimbus-eth2/beacon_chain/nimbus_binary_common with minor
|
|
|
|
# adjustments. The write to file logic is removed as it never was an option
|
|
|
|
# in Fluffy.
|
|
|
|
|
|
|
|
{.push raises: [].}
|
|
|
|
|
|
|
|
import
|
|
|
|
std/[strutils, tables, terminal, typetraits],
|
2024-02-28 17:31:45 +00:00
|
|
|
pkg/chronicles,
|
|
|
|
pkg/chronicles/helpers,
|
|
|
|
chronicles/topics_registry,
|
2024-05-30 12:54:03 +00:00
|
|
|
pkg/results
|
2023-04-19 15:01:01 +00:00
|
|
|
|
|
|
|
export results
|
|
|
|
|
2024-02-28 17:31:45 +00:00
|
|
|
type StdoutLogKind* {.pure.} = enum
|
|
|
|
Auto = "auto"
|
|
|
|
Colors = "colors"
|
|
|
|
NoColors = "nocolors"
|
|
|
|
Json = "json"
|
|
|
|
None = "none"
|
2023-04-19 15:01:01 +00:00
|
|
|
|
|
|
|
# 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:
|
2024-02-28 17:31:45 +00:00
|
|
|
if c2 in {'0' .. '9'} + {';'}:
|
2023-04-19 15:01:01 +00:00
|
|
|
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 updateLogLevel(logLevel: string) {.raises: [ValueError].} =
|
|
|
|
# Updates log levels (without clearing old ones)
|
|
|
|
let directives = logLevel.split(";")
|
|
|
|
try:
|
|
|
|
setLogLevel(parseEnum[LogLevel](directives[0].capitalizeAscii()))
|
|
|
|
except ValueError:
|
2024-02-28 17:31:45 +00:00
|
|
|
raise (ref ValueError)(
|
|
|
|
msg: "Please specify one of TRACE, DEBUG, INFO, NOTICE, WARN, ERROR or FATAL"
|
|
|
|
)
|
2023-04-19 15:01:01 +00:00
|
|
|
|
|
|
|
if directives.len > 1:
|
2024-02-28 17:31:45 +00:00
|
|
|
for topicName, settings in parseTopicDirectives(directives[1 ..^ 1]):
|
2023-04-19 15:01:01 +00:00
|
|
|
if not setTopicState(topicName, settings.state, settings.logLevel):
|
|
|
|
warn "Unrecognized logging topic", topic = topicName
|
|
|
|
|
|
|
|
proc detectTTY(stdoutKind: StdoutLogKind): StdoutLogKind =
|
|
|
|
if stdoutKind == StdoutLogKind.Auto:
|
|
|
|
if isatty(stdout):
|
|
|
|
# On a TTY, let's be fancy
|
|
|
|
StdoutLogKind.Colors
|
|
|
|
else:
|
|
|
|
# When there's no TTY, we output no colors because this matches what
|
|
|
|
# released binaries were doing before auto-detection was around and
|
|
|
|
# looks decent in systemd-captured journals.
|
|
|
|
StdoutLogKind.NoColors
|
|
|
|
else:
|
|
|
|
stdoutKind
|
|
|
|
|
2024-02-28 17:31:45 +00:00
|
|
|
proc setupLogging*(logLevel: string, stdoutKind: StdoutLogKind) =
|
2023-04-19 15:01:01 +00:00
|
|
|
# In the cfg file for fluffy, we create two formats: textlines and json.
|
|
|
|
# Here, we either write those logs to an output, or not, depending on the
|
|
|
|
# given configuration.
|
|
|
|
# Arguably, if we don't use a format, chronicles should not create it.
|
|
|
|
|
|
|
|
when defaultChroniclesStream.outputs.type.arity != 2:
|
|
|
|
warn "Logging configuration options not enabled in the current build"
|
|
|
|
else:
|
|
|
|
# Naive approach where chronicles will form a string and we will discard
|
|
|
|
# it, even if it could have skipped the formatting phase
|
2024-02-28 17:31:45 +00:00
|
|
|
proc noOutput(logLevel: LogLevel, msg: LogOutputStr) =
|
|
|
|
discard
|
|
|
|
|
2023-04-19 15:01:01 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
let tmp = detectTTY(stdoutKind)
|
|
|
|
|
|
|
|
case tmp
|
2024-02-28 17:31:45 +00:00
|
|
|
of StdoutLogKind.Auto:
|
|
|
|
raiseAssert "checked in detectTTY"
|
2023-04-19 15:01:01 +00:00
|
|
|
of StdoutLogKind.Colors:
|
|
|
|
defaultChroniclesStream.outputs[0].writer = stdoutFlush
|
|
|
|
of StdoutLogKind.NoColors:
|
|
|
|
defaultChroniclesStream.outputs[0].writer = noColorsFlush
|
|
|
|
of StdoutLogKind.Json:
|
|
|
|
defaultChroniclesStream.outputs[0].writer = noOutput
|
|
|
|
|
|
|
|
let prevWriter = defaultChroniclesStream.outputs[1].writer
|
2024-02-28 17:31:45 +00:00
|
|
|
defaultChroniclesStream.outputs[1].writer = proc(
|
|
|
|
logLevel: LogLevel, msg: LogOutputStr
|
|
|
|
) =
|
|
|
|
stdoutFlush(logLevel, msg)
|
|
|
|
prevWriter(logLevel, msg)
|
2023-04-19 15:01:01 +00:00
|
|
|
of StdoutLogKind.None:
|
2024-02-28 17:31:45 +00:00
|
|
|
defaultChroniclesStream.outputs[0].writer = noOutput
|
2023-04-19 15:01:01 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
updateLogLevel(logLevel)
|
|
|
|
except ValueError as err:
|
|
|
|
try:
|
|
|
|
stderr.write "Invalid value for --log-level. " & err.msg
|
|
|
|
except IOError:
|
|
|
|
echo "Invalid value for --log-level. " & err.msg
|
|
|
|
quit 1
|