/ chronicles / formats.nim
formats.nim
1 ## Module that separately can be imported by projects wanting to provide custom 2 ## chronicles formatting for their types without importing the full chronicles 3 ## library. 4 5 import std/strformat, stew/shims/macros 6 7 template chroniclesFormatItIMPL*(value: auto): auto = 8 # By default, values are passed as-is to the log output 9 value 10 11 template formatIt*(T: type, body: untyped) {.dirty.} = 12 template chroniclesFormatItIMPL*(it: T): auto = 13 body 14 15 # enabled: SinksBitMask 16 template chroniclesExpandItIMPL*[RecordType: tuple]( 17 record: RecordType, field: static string, value: auto, enabled: auto 18 ) = 19 mixin setProperty, chroniclesFormatItIMPL 20 setProperty(record, field, chroniclesFormatItIMPL(value), enabled) 21 22 template chroniclesExpandItIMPL*[RecordType]( 23 record: RecordType, field: static string, value: auto 24 ) = 25 mixin setProperty, chroniclesFormatItIMPL 26 setProperty(record, field, chroniclesFormatItIMPL(value)) 27 28 macro expandIt*(T: type, expandedProps: untyped): untyped = 29 let 30 chroniclesFormatItIMPL = bindSym("chroniclesFormatItIMPL", brForceOpen) 31 record = ident "record" 32 it = ident "it" 33 it_name = ident "it_name" 34 enabled = ident "enabled" 35 setPropertyTupleCalls = newStmtList() 36 setPropertyCalls = newStmtList() 37 38 for prop in expandedProps: 39 if prop.kind != nnkAsgn: 40 error "An `expandIt` definition should consist only of key-value assignments", 41 prop 42 43 var key = prop[0] 44 let value = prop[1] 45 case key.kind 46 of nnkAccQuoted: 47 proc toStrLit(n: NimNode): NimNode = 48 let nAsStr = $n 49 if nAsStr == "it": 50 it_name 51 else: 52 newLit(nAsStr) 53 54 if key.len < 2: 55 key = key.toStrLit 56 else: 57 var concatCall = infix(key[0].toStrLit, "&", key[1].toStrLit) 58 for i in 2 ..< key.len: 59 concatCall = infix(concatCall, "&", key[i].toStrLit) 60 key = newTree(nnkStaticExpr, concatCall) 61 of nnkIdent, nnkSym: 62 key = newLit($key) 63 else: 64 error &"Unexpected AST kind for an `expandIt` key: {key.kind} ", key 65 66 setPropertyCalls.add newCall( 67 "setProperty", record, key, newCall(chroniclesFormatItIMPL, value) 68 ) 69 setPropertyTupleCalls.add newCall( 70 "setProperty", record, key, newCall(chroniclesFormatItIMPL, value), enabled 71 ) 72 73 # Both single- and multisink expanders are added here - the tradeoff would be 74 # to import ./options and check if runtime filtering is enabled and skip the 75 # latter if not 76 result = quote: 77 template chroniclesExpandItIMPL*[RecordType: tuple]( 78 `record`: RecordType, `it_name`: static string, `it`: `T`, `enabled`: auto 79 ) = 80 mixin setProperty, chroniclesFormatItIMPL 81 `setPropertyTupleCalls` 82 83 template chroniclesExpandItIMPL*( 84 `record`: auto, `it_name`: static string, `it`: `T` 85 ) = 86 mixin setProperty, chroniclesFormatItIMPL 87 `setPropertyCalls` 88 89 when defined(debugLogImpl): 90 echo result.repr