OperationLogContext.cs 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. using System;
  2. using System.Threading;
  3. namespace Aivfo.OperationLog
  4. {
  5. /// <summary>
  6. /// 进程内 traceId / parentId / operator / 设备上下文 透传(AsyncLocal,跨 async/线程切换)。
  7. /// 对称 Java 的 Trace(TransmittableThreadLocal)。
  8. /// </summary>
  9. public static class OperationLogContext
  10. {
  11. private static readonly AsyncLocal<string> _traceId = new AsyncLocal<string>();
  12. private static readonly AsyncLocal<string> _parentId = new AsyncLocal<string>();
  13. private static readonly AsyncLocal<string> _operator = new AsyncLocal<string>();
  14. private static readonly AsyncLocal<int?> _houseSn = new AsyncLocal<int?>();
  15. private static readonly AsyncLocal<int?> _wellSn = new AsyncLocal<int?>();
  16. /// <summary>当前 traceId(无则返回 null)。</summary>
  17. public static string TraceId
  18. {
  19. get => _traceId.Value;
  20. set => _traceId.Value = value;
  21. }
  22. /// <summary>当前 parentId。</summary>
  23. public static string ParentId
  24. {
  25. get => _parentId.Value;
  26. set => _parentId.Value = value;
  27. }
  28. /// <summary>当前操作者(登录用户)。可在登录后设置一次。</summary>
  29. public static string Operator
  30. {
  31. get => _operator.Value;
  32. set => _operator.Value = value;
  33. }
  34. /// <summary>当前舱号。</summary>
  35. public static int? HouseSn
  36. {
  37. get => _houseSn.Value;
  38. set => _houseSn.Value = value;
  39. }
  40. /// <summary>当前 well 号。</summary>
  41. public static int? WellSn
  42. {
  43. get => _wellSn.Value;
  44. set => _wellSn.Value = value;
  45. }
  46. /// <summary>生成一个新的 traceId(去横线的 Guid,紧凑唯一)。</summary>
  47. public static string NewTraceId()
  48. {
  49. return Guid.NewGuid().ToString("N");
  50. }
  51. /// <summary>
  52. /// 开启一次操作 scope:设置/继承 traceId,把当前 traceId 作为新 parentId。
  53. /// 释放时恢复原值。用 using 包裹一次完整操作。
  54. /// </summary>
  55. public static IDisposable BeginScope(string traceId = null)
  56. {
  57. var prevTrace = _traceId.Value;
  58. var prevParent = _parentId.Value;
  59. // 新 scope 的 parentId = 外层的 traceId(构成父子链);最外层为 null。
  60. _parentId.Value = prevTrace;
  61. _traceId.Value = string.IsNullOrEmpty(traceId)
  62. ? (string.IsNullOrEmpty(prevTrace) ? NewTraceId() : prevTrace)
  63. : traceId;
  64. return new ScopeRestore(prevTrace, prevParent);
  65. }
  66. private sealed class ScopeRestore : IDisposable
  67. {
  68. private readonly string _prevTrace;
  69. private readonly string _prevParent;
  70. private bool _done;
  71. public ScopeRestore(string prevTrace, string prevParent)
  72. {
  73. _prevTrace = prevTrace;
  74. _prevParent = prevParent;
  75. }
  76. public void Dispose()
  77. {
  78. if (_done) return;
  79. _done = true;
  80. _traceId.Value = _prevTrace;
  81. _parentId.Value = _prevParent;
  82. }
  83. }
  84. }
  85. }