1/** @Log.Context.Ambient — properties pushed for a stretch of work */2modulePuduLangLog.Context34importStd.SyncasSync5importPuduLangLog.Domain.CaptureasCapture6importPuduLangLog.EnricherasEnricher7importPuduLangLogasLog89/** @Log.Context.Stack — enrichers pushed and not yet popped */10exporttypeContext = { frames: Sync.Cell[Array[Enricher.Enricher]] }1112/** @Log.Context.Bookmark — the stack as it was before a push */13exporttypeBookmark = { frames: Array[Enricher.Enricher] }1415/// An empty context. Give each thread of work its own, or a clone of its parent's.16exportfncreate() -> Context {17let none: Array[Enricher.Enricher] = []18Context{frames: Sync.cell(none)}19}2021/// The enrichers currently pushed, oldest first.22fnframesOf(context: &Context) -> Array[Enricher.Enricher] {23matchSync.get(&context.frames) {24caseOk(frames) => frames25caseErr(_) => []26 }27}2829/// Pushes an enricher and answers the bookmark that pops it.30exportfnpush(context: &Context, frame: Enricher.Enricher) -> Bookmark {31let before = framesOf(context)32let _stored = Sync.set(&context.frames, before.push(frame))33Bookmark{frames: before}34}3536/// Pushes a property and answers the bookmark that pops it.37exportfnpushProperty(context: &Context, name: Str, held: Log.Value) -> Bookmark { push(context, Enricher.property(name, held)) }3839/// Pushes a destructured property and answers the bookmark that pops it.40exportfnpushDestructured(context: &Context, name: Str, held: Log.Value) -> Bookmark { push(context, Enricher.destructured(name, held)) }4142/// Puts the stack back as it was when the bookmark was taken.43exportfnrestore(context: &Context, bookmark: Bookmark) -> () {44let _stored = Sync.set(&context.frames, bookmark.frames)45}4647/// Runs an action with a property pushed, popping it afterwards.48exportfnusing[T](context: &Context, name: Str, held: Log.Value, action: fn() -> T) -> T {49let bookmark = pushProperty(context, name, held)50let result = action()51 restore(context, bookmark)52 result53}5455/// An independent context holding the same enrichers, for work started on another thread.56exportfnclone(context: &Context) -> Context { Context{frames: Sync.cell(framesOf(context))} }5758/// Empties the stack until the bookmark is restored.59exportfnsuspend(context: &Context) -> Bookmark {60let before = framesOf(context)61let none: Array[Enricher.Enricher] = []62let _stored = Sync.set(&context.frames, none)63Bookmark{frames: before}64}6566/// Empties the stack.67exportfnreset(context: &Context) -> () {68let _suspended = suspend(context)69}7071/// The enricher that applies the context's properties, the most recent first, so an inner push72/// wins over an outer one of the same name.73exportfnenricher(context: &Context) -> Enricher.Enricher {74let shared = *context75fn(event: Log.Event, policy: &Capture.Policy) -> Log.Event {76var current = event77for frame in framesOf(&shared).reverse() { current = frame(current, policy) }78 current79 }80}81