
Telemetry.pudu
Pudu107 lines3.6 KB
1/** @Resilience.Telemetry.Seam — events strategies report while executing */2module PuduLangResilience.Telemetry34import Std.Option as Option5import PuduLangResilience.Context as Context67/** @Resilience.Telemetry.Severity — how much an event matters */8export type Severity = Silent | Debug | Information | Warning | Error | Critical910/** @Resilience.Telemetry.Source — the pipeline and strategy reporting */11export type Source = { pipelineName: Option[Str], pipelineInstance: Option[Str], strategyName: Option[Str] }1213/** @Resilience.Telemetry.Detail — what each kind of event measured */14export type Detail15 = Executing16 | Executed(Int)17 | Attempted(Int, Int, Bool)18 | Retrying(Int, Int)19 | Opened(Int, Bool)20 | Closed(Bool)21 | HalfOpened22 | FellBack23 | Hedged(Int)24 | TimeoutElapsed(Int)25 | Rejected(Option[Int])26 | FaultInjected27 | OutcomeInjected28 | LatencyInjected(Int)29 | BehaviorInjected3031/** @Resilience.Telemetry.Event — one reported occurrence */32export type Event = {33 name: Str,34 severity: Severity,35 source: Source,36 operationKey: Option[Str],37 outcome: Option[Str],38 detail: Detail39}4041/** @Resilience.Telemetry.Listener — receives every reported event */42export type Listener = fn(Event) -> ()4344/** @Resilience.Telemetry.Reporter — where one strategy's events go */45export type Reporter = { source: Source, emit: fn(Event) -> () }46474849export fn reporter(source: Source, listeners: &Array[Listener], severityOf: &Option[fn(Event) -> Severity]) -> Reporter {50 let targets = *listeners51 let override = *severityOf52 Reporter{source: source, emit: fn(event: Event) -> () {53 let graded = match override {54 case Some(grade) => Event{..event, severity: grade(event)}55 case None => event56 }57 if graded.severity != Silent {58 for listener in targets { listener(graded) }59 }60 } }61}626364export fn silent() -> Reporter {65 Reporter{source: Source{pipelineName: None, pipelineInstance: None, strategyName: None}, emit: fn(_event: Event) -> () { () }}66}676869export fn forStrategy(base: &Reporter, strategyName: Option[Str]) -> Reporter {70 Reporter{..*base, source: Source{..base.source, strategyName: strategyName}}71}727374export fn report(target: &Reporter, context: &Context.Context, name: Str, severity: Severity, outcome: Option[Str], detail: Detail) -> () {75 (target.emit)(Event{name: name, severity: severity, source: target.source, operationKey: context.operationKey, outcome: outcome, detail: detail})76}777879export fn severityName(value: &Severity) -> Str {80 match value {81 case Silent => "Silent"82 case Debug => "Debug"83 case Information => "Information"84 case Warning => "Warning"85 case Error => "Error"86 case Critical => "Critical"87 }88}899091export fn rank(value: &Severity) -> Int {92 match value {93 case Silent => 094 case Debug => 195 case Information => 296 case Warning => 397 case Error => 498 case Critical => 599 }100}101102103export fn sourceName(value: &Source) -> Str {104 let parts = Option.toArray(value.pipelineName).concat(Option.toArray(value.pipelineInstance)).concat(Option.toArray(value.strategyName))105 if parts.isEmpty() { "(unnamed)" } else { parts.join("/") }106}107