Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-log

Structured event logging for Pudu: message templates, enrichment, filtering, formatting, and sinks

0.1.0Apache-2.01

InstallClose

Console.pudu

Pudu64 lines2.5 KB

GitHub ↗
1/** @Log.Sinks.Console.Sink — events written to the terminal */2module PuduLangLog.Sinks.Console34import Std.Out as Out5import Std.Sync as Sync6import Std.Term as Term7import PuduLangLog.Constants.Names as Names8import PuduLangLog.Domain.Levels as Levels9import PuduLangLog.Domain.Output as Output10import PuduLangLog.Domain.Parser as Parser11import PuduLangLog as Log12import PuduLangLog.Sink as Sink13import PuduLangLog.Sinks.Theme as Theme1415/** @Log.Sinks.Console.Options — layout, colours, and error stream */16export type Options = {17  outputTemplate: Str,18  theme: Theme.Theme,19  colored: Bool,20  standardErrorFromLevel: Option[Log.Level],21  formatter: Option[fn(&Log.Event) -> Str]22}2324/// The console template, the literate theme when the terminal takes colour, and every event on25/// standard output.26export fn defaults() -> Options {27  Options{outputTemplate: Names.CONSOLE_TEMPLATE, theme: Theme.literate(), colored: Term.colorEnabled(), standardErrorFromLevel: None, formatter: None}28}2930/// The text written for an event: the formatter's text when one is set, and otherwise the output31/// template, painted with the theme when colour is on.32export fn render(options: &Options, event: &Log.Event) -> Str { textOf(options, &Parser.parse(options.outputTemplate), event) }3334/// The text written for an event through an already parsed output template.35fn textOf(options: &Options, parsed: &Log.Template, event: &Log.Event) -> Str {36  match options.formatter {37    case Some(formatter) => formatter(event)38    case None => Theme.paint(if options.colored { &options.theme } else { &Theme.none() }, &Output.render(parsed, event))39  }40}4142/// Whether an event goes to the error stream.43export fn toErrors(options: &Options, level: Log.Level) -> Bool {44  match options.standardErrorFromLevel {45    case Some(minimum) => Levels.passes(level, minimum)46    case None => false47  }48}4950/// A sink writing each event to standard output, or to standard error from the configured level.51/// Writes are serialized so lines from different threads never interleave.52export fn sink(options: Options) -> Sink.Sink {53  let parsed = Parser.parse(options.outputTemplate)54  let lock = Sync.mutex()55  Sink.of(fn(event: &Log.Event) -> Result[(), Str] {56      let text = textOf(&options, &parsed, event)57      let printer = if toErrors(&options, event.level) { Out.bare().toStream(Out.Errors) } else { Out.bare() }58      match Sync.withLock(&lock, fn() -> Result[(), Str] { Out.text(&printer, text) }) {59        case Ok(written) => written60        case Err(_) => Err("the console lock could not be taken")61      }62    })63}64