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

Expressions.pudu

Pudu70 lines3.0 KB

GitHub ↗
1/** @Log.Expressions.Facade — filter expressions and expression templates */2module PuduLangLog.Expressions34import PuduLangLog.Clock as Clock5import PuduLangLog.Domain.Capture as Capture6import PuduLangLog.Domain.Properties as Properties7import PuduLangLog.Enricher as Enricher8import PuduLangLog.Expressions.Evaluator as Evaluator9import PuduLangLog.Expressions.Functions as Functions10import PuduLangLog.Expressions.Parser as Parser11import PuduLangLog.Expressions.Syntax as Syntax12import PuduLangLog.Expressions.Template as Template13import PuduLangLog.Expressions.Values as Values14import PuduLangLog as Log1516/** @Log.Expressions.Compiled — a parsed expression and its text */17export type Compiled = { text: Str, expression: Syntax.Expression }1819/// The expression the text denotes, or why it could not be read, including a call to an unknown20/// function.21export fn compile(text: Str) -> Result[Compiled, Str] {22  let expression = Parser.parse(text) ?23  for name in Syntax.callsIn(&expression) {24    if !Functions.isKnown(name) { return Err("unknown function `" + name + "`") }25  }26  Ok(Compiled{text: text, expression: expression})27}2829/// The value of a compiled expression for an event, or none when it is undefined.30export fn evaluate(compiled: &Compiled, event: &Log.Event) -> Option[Log.Value] {31  Evaluator.evaluate(&compiled.expression, &Evaluator.scopeOf(event, Clock.system()()))32}3334/// A predicate true for the events that make the expression the boolean `true`, for filters,35/// conditional sinks, and conditional enrichers.36export fn predicate(text: Str) -> Result[fn(&Log.Event) -> Bool, Str] {37  let compiled = compile(text) ?38  Ok(fn(event: &Log.Event) -> Bool { Values.isTrue(&evaluate(&compiled, event)) })39}4041/// An enricher adding a property whose value is the expression evaluated for each event, unless42/// the event already has the property or the expression is undefined for it.43export fn computed(name: Str, text: Str) -> Result[Enricher.Enricher, Str] {44  let compiled = compile(text) ?45  Ok(fn(event: Log.Event, policy: &Capture.Policy) -> Log.Event {46      if Properties.has(&event.properties, name) { return event }47      match evaluate(&compiled, &event) {48        case Some(held) => Log.Event{..event, properties: event.properties.push(Log.Property{name: name, value: Capture.capture(policy, &held, Log.Destructure)})}49        case None => event50      }51    })52}5354/// A formatter writing each event through an expression template of holes `{expression:format}`55/// and the directives `#if`, `#else if`, `#else`, `#each … in …`, `#delimit`, and `#end`.56export fn template(text: Str) -> Result[Log.Formatter, Str] {57  let nodes = Template.parse(text) ?58  var referenced: Array[Str] = []59  for expression in Template.expressionsIn(&nodes) {60    for name in Syntax.callsIn(&expression) {61      if !Functions.isKnown(name) { return Err("unknown function `" + name + "`") }62    }63    referenced = referenced.concat(Syntax.namesIn(&expression))64  }65  Ok(fn(event: &Log.Event) -> Str {66      let within = Evaluator.Scope{..Evaluator.scopeOf(event, Clock.system()()), referenced: referenced}67      Template.render(&nodes, &within)68    })69}70