// Tagged logging — categorize logs by module/feature tags
///|
pub(all) struct TagSet {
tags : Array[String]
}
///|
pub fn TagSet::new() -> TagSet {
TagSet::{ tags: [] }
}
///|
pub fn TagSet::add(self : TagSet, tag : String) -> TagSet {
let new_tags = self.tags.copy()
new_tags.push(tag)
TagSet::{ tags: new_tags }
}
///|
pub fn TagSet::has(self : TagSet, tag : String) -> Bool {
tag_in_set(self.tags, tag, 0)
}
///|
fn tag_in_set(tags : Array[String], target : String, idx : Int) -> Bool {
if idx >= tags.length() {
false
} else if tags[idx] == target {
true
} else {
tag_in_set(tags, target, idx + 1)
}
}
///|
pub fn TagSet::to_fields(self : TagSet) -> Array[(String, String)] {
tags_to_fields(self.tags, 0, [])
}
///|
fn tags_to_fields(
tags : Array[String],
idx : Int,
result : Array[(String, String)],
) -> Array[(String, String)] {
if idx >= tags.length() {
result
} else {
result.push(("tag", tags[idx]))
tags_to_fields(tags, idx + 1, result)
}
}
///|
pub fn TagSet::count(self : TagSet) -> Int {
self.tags.length()
}
// Tagged logger — wraps Logger with a TagSet for automatic tag attachment
///|
pub(all) struct TaggedLogger {
logger : Logger
tags : TagSet
}
///|
pub fn TaggedLogger::new(logger : Logger) -> TaggedLogger {
TaggedLogger::{ logger, tags: TagSet::new() }
}
///|
pub fn TaggedLogger::with_tag(
self : TaggedLogger,
tag : String,
) -> TaggedLogger {
TaggedLogger::{ ..self, tags: self.tags.add(tag) }
}
///|
pub fn TaggedLogger::info(
self : TaggedLogger,
msg : String,
fields : Array[(String, String)],
) -> TaggedLogger {
let merged = merge_fields(self.tags.to_fields(), fields)
let new_logger = self.logger.info(msg, merged)
TaggedLogger::{ ..self, logger: new_logger }
}
///|
fn merge_fields(
tag_fields : Array[(String, String)],
user_fields : Array[(String, String)],
) -> Array[(String, String)] {
append_fields(tag_fields, user_fields.copy(), 0)
}
///|
fn append_fields(
tag_fields : Array[(String, String)],
result : Array[(String, String)],
idx : Int,
) -> Array[(String, String)] {
if idx >= tag_fields.length() {
result
} else {
result.push(tag_fields[idx])
append_fields(tag_fields, result, idx + 1)
}
}
///|
pub fn TaggedLogger::warn(
self : TaggedLogger,
msg : String,
fields : Array[(String, String)],
) -> TaggedLogger {
let merged = merge_fields(self.tags.to_fields(), fields)
let new_logger = self.logger.warn(msg, merged)
TaggedLogger::{ ..self, logger: new_logger }
}
///|
pub fn TaggedLogger::error(
self : TaggedLogger,
msg : String,
fields : Array[(String, String)],
) -> TaggedLogger {
let merged = merge_fields(self.tags.to_fields(), fields)
let new_logger = self.logger.error(msg, merged)
TaggedLogger::{ ..self, logger: new_logger }
}
///|
pub fn TaggedLogger::get_logger(self : TaggedLogger) -> Logger {
self.logger
}