using System; using System.Threading; namespace Aivfo.OperationLog { /// /// 进程内 traceId / parentId / operator / 设备上下文 透传(AsyncLocal,跨 async/线程切换)。 /// 对称 Java 的 Trace(TransmittableThreadLocal)。 /// public static class OperationLogContext { private static readonly AsyncLocal _traceId = new AsyncLocal(); private static readonly AsyncLocal _parentId = new AsyncLocal(); private static readonly AsyncLocal _operator = new AsyncLocal(); private static readonly AsyncLocal _houseSn = new AsyncLocal(); private static readonly AsyncLocal _wellSn = new AsyncLocal(); /// 当前 traceId(无则返回 null)。 public static string TraceId { get => _traceId.Value; set => _traceId.Value = value; } /// 当前 parentId。 public static string ParentId { get => _parentId.Value; set => _parentId.Value = value; } /// 当前操作者(登录用户)。可在登录后设置一次。 public static string Operator { get => _operator.Value; set => _operator.Value = value; } /// 当前舱号。 public static int? HouseSn { get => _houseSn.Value; set => _houseSn.Value = value; } /// 当前 well 号。 public static int? WellSn { get => _wellSn.Value; set => _wellSn.Value = value; } /// 生成一个新的 traceId(去横线的 Guid,紧凑唯一)。 public static string NewTraceId() { return Guid.NewGuid().ToString("N"); } /// /// 开启一次操作 scope:设置/继承 traceId,把当前 traceId 作为新 parentId。 /// 释放时恢复原值。用 using 包裹一次完整操作。 /// public static IDisposable BeginScope(string traceId = null) { var prevTrace = _traceId.Value; var prevParent = _parentId.Value; // 新 scope 的 parentId = 外层的 traceId(构成父子链);最外层为 null。 _parentId.Value = prevTrace; _traceId.Value = string.IsNullOrEmpty(traceId) ? (string.IsNullOrEmpty(prevTrace) ? NewTraceId() : prevTrace) : traceId; return new ScopeRestore(prevTrace, prevParent); } private sealed class ScopeRestore : IDisposable { private readonly string _prevTrace; private readonly string _prevParent; private bool _done; public ScopeRestore(string prevTrace, string prevParent) { _prevTrace = prevTrace; _prevParent = prevParent; } public void Dispose() { if (_done) return; _done = true; _traceId.Value = _prevTrace; _parentId.Value = _prevParent; } } } }