LevelSwitch.md
PuduLangLog.LevelSwitch
type: module path: "@root/src/PuduLangLog/LevelSwitch.pudu" fidelity: Active grammar: "[[grammar/pudu]]" depth_score: 0.5 depth_status: MEDIUM tags: [module] aliases: [PuduLangLog.LevelSwitch]
Purpose
A [[domain/Level|minimum level]] shared by loggers, sinks, and enrichers and changed while the program runs, with listeners told of each change.
Interface
Signatures
export type LevelSwitch = { current: Sync.Cell[Log.Level], lock: Sync.Mutex, listeners: Sync.Cell[Array[fn(Log.Level, Log.Level) -> ()]] }
export fn create(initial: Log.Level) -> LevelSwitch
export fn level(control: &LevelSwitch) -> Log.Level
export fn allows(control: &LevelSwitch, candidate: Log.Level) -> Bool
export fn set(control: &LevelSwitch, next: Log.Level) -> ()
export fn onChange(control: &LevelSwitch, listener: fn(Log.Level, Log.Level) -> ()) -> ()Linkage
- Requires: [[src/PuduLangLog]], [[src/PuduLangLog/Domain/Levels]],
Std.Sync. - Consumed by: [[src/PuduLangLog/Configuration]], [[src/PuduLangLog/Pipeline]], [[src/PuduLangLog/Sink]], [[src/PuduLangLog/Enricher]], and settings.
Algorithm
- The level lives in a cell;
setcompares and stores under the switch's lock. - When the level changed, every listener is called with the old and new levels after the lock is released.
Negative Logic (Prohibited Paths)
- Setting the level it already has calls no listener.
Edge Cases
- A listener that sets the switch again runs after the first change is stored, so no lock is held twice.
Depth
DEPTH 0.5 (MEDIUM). Tested by test/PuduLangLog/LoggerTest.
Grill Log
- Q: Why call listeners outside the lock? A: A listener may log or change the switch; holding the lock would deadlock it. _Rejected:_ calling inside the lock.
Referenced by
[[domain/Level]] · [[src/PuduLangLog/_MOC]] · [[src/PuduLangLog/Configuration]] · [[src/PuduLangLog/Enricher]] · [[src/PuduLangLog/Pipeline]] · [[src/PuduLangLog/Settings]] · [[src/PuduLangLog/Sink]]
