如何在C#中遍历MDC所有条目?(适配slf4net场景)
问题
为了让Java与C#的日志配置保持一致,Java端已通过log4j配置自定义FileBeatLayout,将MDC中的所有内容以单条JSON字符串形式写入文件。但在C#中,由于slf4net的MDC遍历功能为内部实现,目前仅完成自定义Layout的基础框架,需要实现遍历MDC所有条目,输出和Java端一致的日志效果。
Java端参考实现
配置文件
<appender name="ELASTIC" class="ch.qos.logback.core.FileAppender"> ... <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="FileBeatLayout" /> </encoder> </appender>
MDC写入代码
MDC.Set("testIssue", testIssue.Replace("#", "-")); MDC.Set("testType", testType); MDC.Set("method", method.Name.ToLower()); MDC.Set("elapsedTime", elapsedTimeInNs.ToString()); MDC.Set("elapsedTimeUnit", "ns"); MDC.Set("platform", ".NET"); MDC.Set("platformVersion", Environment.Version.ToString()); MDC.Set("operatingSystem", $"{GetBaseOs()} {Environment.OSVersion.Version.Major}"); MDC.Set("jenkinsBuild", GetJenkinsBuildTagIfSet()); foreach (var version in testEnvironment.GetDependencyTreeDict()) { MDC.Set(version.Key, version.Value); } _logger.Info("[{0}] *{1}* {2}: {3} ns", testIssue, testType, method.Name, elapsedTimeInNs); log4net.ThreadContext.Properties["TIMING"] = "false"; MDC.Clear();
自定义Layout代码
public class FileBeatLayout extends LayoutBase<ILoggingEvent> { @Override public String doLayout(ILoggingEvent iLoggingEvent) { StringBuilder stringBuilder = new StringBuilder(); Map<String, String> map = iLoggingEvent.getMDCPropertyMap(); JSONObject jsonObject = new JSONObject(map); stringBuilder.append(jsonObject); return stringBuilder.toString().replaceAll("[\t \n]", "") + "\n"; }
C#端实现方案
在log4net中,MDC内容实际存储在ThreadContext.Properties中,可通过两种方式遍历所有条目,完成JSON序列化输出:
核心实现代码
先通过NuGet安装Newtonsoft.Json(或使用System.Text.Json),然后修改自定义Layout:
using log4net.Core; using log4net.Layout; using Newtonsoft.Json; using System.IO; using System.Collections; public class FileBeatLayout : LayoutSkeleton { public override void ActivateOptions() { // 无需额外初始化逻辑 } public override void Format(TextWriter writer, LoggingEvent loggingEvent) { var mdcDict = new Hashtable(); // 方式1:遍历日志事件关联的所有属性(含MDC) foreach (DictionaryEntry entry in loggingEvent.Properties) { mdcDict[entry.Key] = entry.Value; } // 方式2:直接遍历当前线程的MDC属性 // foreach (DictionaryEntry entry in (IDictionary)log4net.ThreadContext.Properties) // { // mdcDict[entry.Key] = entry.Value; // } // 序列化为JSON并移除空白字符,对齐Java端逻辑 string json = JsonConvert.SerializeObject(mdcDict); json = json.Replace("\t", "").Replace(" ", "").Replace("\n", ""); writer.WriteLine(json); } }
说明
- 两种遍历方式二选一:若需要日志事件关联的完整属性集合,用
loggingEvent.Properties;若仅需当前线程MDC内容,用ThreadContext.Properties JsonConvert.SerializeObject替代Java端JSONObject的序列化逻辑- 移除JSON中的空白字符,和Java端
replaceAll("[\t \n]", "")效果完全一致
内容的提问来源于stack exchange,提问作者Johan P
相关产品推荐
相关产品推荐

