You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:20:47