WIP support for user-defined record types
This commit is contained in:
parent
c7f2d2228c
commit
c91207357c
|
@ -8,9 +8,9 @@ export
|
|||
template chroniclesLexScopeIMPL* =
|
||||
0 # scope revision number
|
||||
|
||||
macro mergeScopes(scopes: typed, newBindings: untyped): untyped =
|
||||
macro mergeScopes(prevScopes: typed, newBindings: untyped): untyped =
|
||||
var
|
||||
bestScope = scopes.lastScopeHolder
|
||||
bestScope = prevScopes.lastScopeHolder
|
||||
bestScopeRev = bestScope.scopeRevision
|
||||
|
||||
var finalBindings = initTable[string, NimNode]()
|
||||
|
@ -20,12 +20,18 @@ macro mergeScopes(scopes: typed, newBindings: untyped): untyped =
|
|||
for k, v in assignments(newBindings):
|
||||
finalBindings[k] = v
|
||||
|
||||
result = newStmtList()
|
||||
|
||||
var newScopeDefinition = newStmtList(newLit(bestScopeRev + 1))
|
||||
|
||||
for k, v in finalBindings:
|
||||
newScopeDefinition.add newAssignment(newIdentNode(k), v)
|
||||
if k == "stream":
|
||||
let streamId = newIdentNode($v)
|
||||
result.add quote do:
|
||||
template chroniclesActiveStreamIMPL: typedesc = `streamId`
|
||||
else:
|
||||
newScopeDefinition.add newAssignment(newIdentNode(k), v)
|
||||
|
||||
result = quote:
|
||||
result.add quote do:
|
||||
template chroniclesLexScopeIMPL = `newScopeDefinition`
|
||||
|
||||
template logScope*(newBindings: untyped) {.dirty.} =
|
||||
|
@ -37,10 +43,10 @@ template dynamicLogScope*(bindings: varargs[untyped]) {.dirty.} =
|
|||
bind bindSym, brForceOpen
|
||||
dynamicLogScopeIMPL(bindSym("chroniclesLexScopeIMPL", brForceOpen), bindings)
|
||||
|
||||
macro logImpl(severity: LogLevel, scopes: typed,
|
||||
macro logImpl(activeStream: typed, severity: LogLevel, scopes: typed,
|
||||
logStmtBindings: varargs[untyped]): untyped =
|
||||
if not loggingEnabled: return
|
||||
|
||||
|
||||
let lexicalBindings = scopes.finalLexicalBindings
|
||||
var finalBindings = initOrderedTable[string, NimNode]()
|
||||
|
||||
|
@ -95,7 +101,10 @@ macro logImpl(severity: LogLevel, scopes: typed,
|
|||
|
||||
template log*(severity: LogLevel, props: varargs[untyped]) {.dirty.} =
|
||||
bind logImpl, bindSym, brForceOpen
|
||||
logImpl(severity, bindSym("chroniclesLexScopeIMPL", brForceOpen), props)
|
||||
logImpl(chroniclesActiveStreamIMPL(),
|
||||
severity,
|
||||
bindSym("chroniclesLexScopeIMPL", brForceOpen),
|
||||
props)
|
||||
|
||||
template logFn(name, severity) =
|
||||
template `name`*(props: varargs[untyped]) =
|
||||
|
|
|
@ -36,7 +36,7 @@ proc selectOutputType(dst: LogDestination): NimNode =
|
|||
of toSysLog: bnd"SysLogOutput"
|
||||
of toFile: newTree(nnkBracketExpr, bnd"FileOutput", newLit(dst.outputId))
|
||||
|
||||
proc selectRecordType(s: StreamSpec, sinkIdx: int): NimNode =
|
||||
proc selectRecordType(sink: SinkSpec): NimNode =
|
||||
# This proc translates the SinkSpecs loaded in the `options` module
|
||||
# to their corresponding LogRecord types.
|
||||
#
|
||||
|
@ -48,8 +48,6 @@ proc selectRecordType(s: StreamSpec, sinkIdx: int): NimNode =
|
|||
# BufferedOutput[(Output1, Output2, ...)]
|
||||
#
|
||||
|
||||
let sink = s.sinks[sinkIdx]
|
||||
|
||||
# Determine the head symbol of the instantiation
|
||||
let recordType = case sink.format
|
||||
of json: bnd"JsonRecord"
|
||||
|
@ -303,27 +301,49 @@ template flushRecord*(r: var JsonRecord) =
|
|||
# configured output stream.
|
||||
#
|
||||
|
||||
proc createCompositeLogRecord(s: StreamSpec): NimNode =
|
||||
if s.sinks.len > 1:
|
||||
proc createCompositeLogRecord(sinks: seq[SinkSpec]): NimNode =
|
||||
if sinks.len > 1:
|
||||
result = newTree(nnkPar)
|
||||
for i in 0 ..< s.sinks.len:
|
||||
result.add s.selectRecordType(i)
|
||||
for i in 0 ..< sinks.len:
|
||||
result.add selectRecordType(sinks[i])
|
||||
else:
|
||||
result = s.selectRecordType(0)
|
||||
result = selectRecordType(sinks[0])
|
||||
|
||||
template recordTypeName*(s: StreamSpec): string =
|
||||
s.name & "LogRecord"
|
||||
|
||||
import dynamic_scope_types
|
||||
|
||||
template createStreamSymbol(name: untyped, RecordType: typedesc) =
|
||||
type `name` {.inject.} = object
|
||||
|
||||
template chroniclesLogRecordTypeIMPL*(T: type `name`): typedesc = RecordType
|
||||
template chroniclesSinksCountIMPL*(T: type `name`): int = 1
|
||||
|
||||
var rootDynScope {.threadvar.}: ptr BindingsFrame[RecordType]
|
||||
template tlsSlot*(T: type RecordType): auto = rootDynScope
|
||||
|
||||
macro customLogStream*(streamDef: untyped): untyped =
|
||||
syntaxCheckStreamExpr streamDef
|
||||
return newCall(bindSym"createStreamSymbol", streamDef[0], streamDef[1])
|
||||
|
||||
macro logStream*(streamDef: untyped): untyped =
|
||||
syntaxCheckStreamExpr streamDef
|
||||
let streamSinks = sinkSpecsFromNode(streamDef)
|
||||
return newCall(bindSym"createStreamSymbol",
|
||||
streamDef[0],
|
||||
createCompositeLogRecord(streamSinks))
|
||||
|
||||
macro createStreamRecordTypes: untyped =
|
||||
result = newStmtList()
|
||||
|
||||
for s in config.streams:
|
||||
for i in 0 ..< config.streams.len:
|
||||
let
|
||||
s = config.streams[i]
|
||||
streamName = newIdentNode(s.name)
|
||||
typeName = newIdentNode(s.recordTypeName)
|
||||
tlsSlot = newIdentNode($typeName & "TlsSlot")
|
||||
typeDef = createCompositeLogRecord(s)
|
||||
typeDef = createCompositeLogRecord(s.sinks)
|
||||
|
||||
result.add quote do:
|
||||
type `typeName`* = `typeDef`
|
||||
|
@ -344,6 +364,12 @@ macro createStreamRecordTypes: untyped =
|
|||
template flushRecord*(r: var `typeName`) =
|
||||
for f in r.fields: flushRecord(f)
|
||||
|
||||
createStreamSymbol(`streamName`, `typeName`)
|
||||
|
||||
if i == 0:
|
||||
result.add quote do:
|
||||
template chroniclesActiveStreamIMPL*: typedesc = `streamName`
|
||||
|
||||
createStreamRecordTypes()
|
||||
|
||||
#
|
||||
|
|
|
@ -142,7 +142,12 @@ const
|
|||
defaultColorScheme = when handleYesNoOption(chronicles_colors): AnsiColors
|
||||
else: NoColors
|
||||
|
||||
proc sinkSpecsFromNode(streamNode: NimNode): seq[SinkSpec] =
|
||||
proc syntaxCheckStreamExpr*(n: NimNode) =
|
||||
if n.kind != nnkBracketExpr or n[0].kind != nnkIdent:
|
||||
error &"Invalid stream definition. " &
|
||||
"Please use a bracket expressions such as 'stream_name[sinks_list]'."
|
||||
|
||||
proc sinkSpecsFromNode*(streamNode: NimNode): seq[SinkSpec] =
|
||||
newSeq(result, 0)
|
||||
for i in 1 ..< streamNode.len:
|
||||
let n = streamNode[i]
|
||||
|
@ -163,10 +168,7 @@ proc parseStreamsSpec(spec: string): Configuration {.compileTime.} =
|
|||
newSeq(result.streams, 0)
|
||||
var specNodes = parseExpr "(" & spec.replace("\\", "/") & ")"
|
||||
for n in specNodes:
|
||||
if n.kind != nnkBracketExpr or n[0].kind != nnkIdent:
|
||||
error &"Invalid stream definition. " &
|
||||
"Please use a bracket expressions such as 'stream_name[sinks_list]'."
|
||||
|
||||
syntaxCheckStreamExpr(n)
|
||||
let streamName = $n[0]
|
||||
for prev in result.streams:
|
||||
if prev.name == streamName:
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import
|
||||
chronicles
|
||||
|
||||
type
|
||||
MyRecord = object
|
||||
|
||||
template initLogRecord*(r: var MyRecord, lvl: LogLevel, name: string) =
|
||||
stdout.write "[", lvl, "] ", name, ": "
|
||||
|
||||
template setPropertyImpl(r: var MyRecord, key: string, val: auto) =
|
||||
stdout.write key, "=", val
|
||||
|
||||
template setFirstProperty*(r: var MyRecord, key: string, val: auto) =
|
||||
stdout.write " ("
|
||||
setPropertyImpl(r, key, val)
|
||||
|
||||
template setProperty*(r: var MyRecord, key: string, val: auto) =
|
||||
stdout.write ", "
|
||||
setPropertyImpl(r, key, val)
|
||||
|
||||
template flushRecord*(r: var MyRecord) =
|
||||
stdout.write ")\n"
|
||||
|
||||
customLogStream myStream[MyRecord]
|
||||
|
||||
logScope:
|
||||
stream = "myStream"
|
||||
|
||||
info "test"
|
||||
# myStream.info "info panel"
|
||||
|
Loading…
Reference in New Issue