
Output.pudu
Pudu88 lines3.8 KB
1/** @Log.Domain.Output.Module — output templates rendered from events */2module PuduLangLog.Domain.Output34import Std.List as List5import PuduLangLog.Domain.Display as Display6import PuduLangLog.Domain.Levels as Levels7import PuduLangLog.Domain.Padding as Padding8import PuduLangLog.Domain.Properties as Properties9import PuduLangLog as Log101112export const NEW_LINE: Str = "\n"1314151617export fn render(output: &Log.Template, event: &Log.Event) -> Array[Display.Piece] {18 var pieces: Array[Display.Piece] = []19 for token in output.tokens {20 match token {21 case Log.Literal(text) => { pieces = pieces.push(Display.Piece{style: Display.Tertiary, text: text}) }22 case Log.Placeholder(hole) => { pieces = pieces.concat(Display.aligned(&part(output, &hole, event), &hole.alignment)) }23 }24 }25 pieces26}272829fn part(output: &Log.Template, hole: &Log.Hole, event: &Log.Event) -> Array[Display.Piece] {30 match hole.name {31 case "Level" => [Display.Piece{style: Display.LevelStyle(event.level), text: Levels.moniker(event.level, &hole.format)}]32 case "Message" => Display.message(&event.template, &event.properties, &hole.format)33 case "Timestamp" => [secondary(Display.scalar(&Log.Moment(event.timestamp), &hole.format).text)]34 case "UtcTimestamp" => [secondary(Display.scalar(&Log.Moment(Log.Timestamp{..event.timestamp, offset: 0}), &hole.format).text)]35 case "NewLine" => [plain(NEW_LINE)]36 case "Exception" => failure(&event.failure)37 case "TraceId" => [plain(optional(&event.traceId))]38 case "SpanId" => [plain(optional(&event.spanId))]39 case "Properties" => properties(output, event, &hole.format)40 case name => match Properties.find(&event.properties, name) {41 case Some(Log.Scalar(Log.Text(text))) => [Display.Piece{style: Display.StringStyle, text: Padding.cased(text, &hole.format)}]42 case Some(found) => Display.value(&found, &hole.format)43 case None => []44 }45 }46}474849fn plain(text: Str) -> Display.Piece { Display.Piece{style: Display.Plain, text: text} }505152fn secondary(text: Str) -> Display.Piece { Display.Piece{style: Display.Secondary, text: text} }535455fn optional(text: &Option[Str]) -> Str {56 match text {57 case Some(given) => given58 case None => ""59 }60}61626364fn failure(problem: &Option[Log.Failure]) -> Array[Display.Piece] {65 let found = match problem {66 case Some(given) => given67 case None => { return [] }68 }69 Display.failure(&found).split("\n").map(|line: Str| if line.startsWith(" at ") { secondary(line + NEW_LINE) } else { plain(line + NEW_LINE) })70}71727374fn properties(output: &Log.Template, event: &Log.Event, format: &Option[Str]) -> Array[Display.Piece] {75 let rest = event.properties.filter(|property: Log.Property| !mentions(&event.template, property.name) && !mentions(output, property.name))76 let shape = Log.Structure(Log.Structure{tag: None, properties: rest})77 let asJson = match format {78 case Some(given) => given.contains("j")79 case None => false80 }81 if asJson { [Display.json(&shape)] } else { Display.value(&shape, &None) }82}838485fn mentions(template: &Log.Template, name: Str) -> Bool {86 List.any(&template.holes, |hole: Log.Hole| hole.name == name)87}88