Initial implementation.
This commit is contained in:
commit
742d47ba53
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# ignore vim swap files
|
||||
.*.sw?
|
||||
|
||||
# ignore built binary
|
||||
/slfmt
|
14
slfmt.nimble
Normal file
14
slfmt.nimble
Normal file
@ -0,0 +1,14 @@
|
||||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Jonathan Bernard"
|
||||
description = "Small utility to pretty-print strucutured logs."
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["slfmt"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 2.2.0"
|
||||
requires "timeutils"
|
80
src/slfmt.nim
Normal file
80
src/slfmt.nim
Normal file
@ -0,0 +1,80 @@
|
||||
import std/[json, sequtils, streams, strutils, terminal, times]
|
||||
import timeutils
|
||||
#import docopt
|
||||
|
||||
const VERSION = "0.1.0"
|
||||
|
||||
# const USAGE = """Usage:
|
||||
# slfmt
|
||||
#
|
||||
# Options:
|
||||
#
|
||||
# -h, --help Print this usage and help information
|
||||
|
||||
const fieldDisplayOrder = @[
|
||||
"scope", "level", "ts", "code", "sid", "sub", "msg", "err", "stack", "method", "args"]
|
||||
|
||||
func decorate(
|
||||
s: string,
|
||||
fg = fgDefault,
|
||||
style: set[Style] = {}): string =
|
||||
|
||||
result = ""
|
||||
|
||||
if style != {}:
|
||||
result &= toSeq(items(style)).mapIt(ansiStyleCode(it)).join("")
|
||||
|
||||
if fg != fgDefault: result &= ansiForegroundColorCode(fg)
|
||||
|
||||
result &= s & ansiResetCode
|
||||
|
||||
|
||||
proc formatField(name: string, value: JsonNode): string =
|
||||
result = decorate(name, fgCyan) & ":" & " ".repeat(max(1, 10 - name.len))
|
||||
|
||||
var strVal: string = ""
|
||||
case name:
|
||||
of "ts":
|
||||
let dt = parseIso8601(value.getStr)
|
||||
strVal = decorate(dt.local.formatIso8601 & " (local) ", fgBlue, {styleBright}) &
|
||||
dt.utc.formatIso8601 & " (UTC)"
|
||||
of "sid", "sub": strVal = decorate(value.getStr, fgGreen)
|
||||
of "err": strVal = decorate(value.getStr, fgRed)
|
||||
of "msg": strVal = decorate(value.getStr, fgYellow)
|
||||
of "stack": strVal = decorate(value.getStr, fgBlack, {styleBright})
|
||||
else: strVal = pretty(value)
|
||||
|
||||
let valLines = splitLines(strVal)
|
||||
if name.len > 10 or strVal.len + 16 > terminalWidth() or valLines.len > 1:
|
||||
result &= "\n" & valLines.mapIt(" " & it).join("\n") & "\n"
|
||||
else: result &= strVal & "\n"
|
||||
|
||||
proc prettyPrintFormat(logLine: string): string =
|
||||
try:
|
||||
var logJson = parseJson(logLine)
|
||||
|
||||
result = '-'.repeat(terminalWidth())
|
||||
|
||||
# Print the known fields in order first
|
||||
for f in fieldDisplayOrder:
|
||||
if logJson.hasKey(f):
|
||||
result &= formatField(f, logJson[f])
|
||||
logJson.delete(f)
|
||||
|
||||
# Print the rest of the fields
|
||||
for (key, val) in pairs(logJson): result &= formatField(key, val)
|
||||
|
||||
result &= "\n"
|
||||
|
||||
except ValueError, JsonParsingError:
|
||||
result = logLine
|
||||
|
||||
when isMainModule:
|
||||
try:
|
||||
var line: string = ""
|
||||
let sin = newFileStream(stdin)
|
||||
while(sin.readLine(line)): stdout.writeLine(prettyPrintFormat(line))
|
||||
except:
|
||||
stderr.writeLine("slfmt - FATAL: " & getCurrentExceptionMsg())
|
||||
stderr.writeLine(getCurrentException().getStackTrace())
|
||||
quit(QuitFailure)
|
Loading…
x
Reference in New Issue
Block a user