package aceboot::observability
import std.collection.*
/**
* MDC(Mapped Diagnostic Context):协程本地诊断上下文。
* 由 requestId() 中间件写入,Logger.format() 自动附加到每条日志。
* 无请求上下文时(启动日志、定时任务)getAll() 返回空数组,不影响正常输出。
*
* 生命周期:requestId() 中间件在 next() 前 set("requestId", id),
* finally 块中 clear()——保证协程复用时不泄漏上一请求的上下文。
*/
public class Mdc {
private static let holder = ThreadLocal<HashMap<String, String>>()
private init() {}
/** 设置当前协程的 MDC 键值。键不存在则新建,已存在则覆盖。 */
public static func set(key: String, value: String): Unit {
match (holder.get()) {
case Some(map) => map.add(key, value)
case None =>
let map = HashMap<String, String>()
map.add(key, value)
holder.set(map)
}
}
/** 读取当前协程的 MDC 值;无该键或无 MDC 上下文时返回 None。 */
public static func get(key: String): ?String {
match (holder.get()) {
case Some(map) => map.get(key)
case None => None
}
}
/**
* 返回当前协程所有 MDC 键值对的快照数组。
* Logger.format() 调用此方法将 MDC 字段附加到 JSON 输出末尾。
* 无请求上下文(或已 clear)时返回空数组,Logger 不会附加任何额外字段。
*/
public static func getAll(): Array<(String, String)> {
match (holder.get()) {
case Some(map) =>
let arr = ArrayList<(String, String)>()
for ((k, v) in map) {
arr.add((k, v))
}
arr.toArray()
case None => []
}
}
/** 删除当前协程中的指定 MDC 键。 */
public static func remove(key: String): Unit {
match (holder.get()) {
case Some(map) => map.remove(key)
case None => ()
}
}
/**
* 清除当前协程的全部 MDC 上下文。
* requestId() 中间件在 finally 块中调用,确保协程复用安全。
*/
public static func clear(): Unit {
holder.set(None)
}
}