log4net.LogicalThreadContext.Properties无法与OwinMiddleware

时间:2016-03-09 22:05:05

标签: c# log4net log4net-appender

我正在尝试使用log4net.LogicalThreadContext在OwinMiddleware中存储一些数据,所以我可以稍后在ApiController中记录它,但它似乎不起作用。存储在log4net.LogicalThreadContext中的数据似乎不能在ApiController中使用。这是我的代码片段:

创建ApiMiddleWare以便将一些日志数据注入LogicalThreadContext.Properties [“logdata”]:

public class ApiMiddleWare : OwinMiddleware
{
    public ApiMiddleWare(OwinMiddleware next) : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {

        var loggers = new ConcurrentDictionary<string, object>();
        if (!loggers.ContainsKey("CorellationId"))
        {
            var correlationId = new[] {Guid.NewGuid().ToString().Replace("-", "")};
            loggers.TryAdd("CorellationId", correlationId[0]);
        }
        if (context.Request.Path.HasValue)
        {
            loggers.TryAdd("Route", context.Request.Uri.AbsoluteUri);
        }

        LogicalThreadContext.Properties["logdata"] = loggers;

        await Next.Invoke(context);
    }
}

然后ApiMiddleWare将在ServiceHost的Startup.cs中使用,如下所示:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Use<ApiMiddleWare>();
        Log.Configure();
    }

}

我创建了一个自定义RollingFileAppeanderEx来捕获在中间件中分配的日志数据并将其记录下来:

public class RollingFileAppenderEx: RollingFileAppender
{
    protected static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        NullValueHandling = NullValueHandling.Ignore,
        DateFormatHandling = DateFormatHandling.IsoDateFormat
    };
    protected override void Append(LoggingEvent loggingEvent)
    {
        if (FilterEvent(loggingEvent))
        {
            var logdata = loggingEvent.GetLoggingEventData();
            logdata.Message = GetLogData(loggingEvent);
            loggingEvent = new LoggingEvent(loggingEvent.GetType(), loggingEvent.Repository, logdata, loggingEvent.Fix);
            base.Append(loggingEvent);
        }

    }

    protected string GetLogData(LoggingEvent logEvent)
    {

        IDictionary<string, object> logData = new Dictionary<string, object>();
        var logD = logEvent.Properties["logdata"] as ConcurrentDictionary<string, object>;
        if logD != null)
        {
            foreach (var log in logD)
            {
                logData.Add(log.Key, log.Value);
            }
        }
        logData.Add("Message", logObject.Message);

        var logString = JsonConvert.SerializeObject(logData, JsonSettings);
        return logString;
    }

}

从ApiController,调用Info函数到log:

public class TestsController : ApiController
{
    private static readonly ILogger Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);  
    public string Get(int id)
    {
        Log.Info("Something");
        return id;
    }
}

这是我的问题:只有“Something”被写入日志。但是,CorellationId和Route不是。通过代码调试,我发现“logEvent.Properties [”logdata“]作为ConcurrentDictionary”在RollingFileAppenderEx中返回了可以为null的值。所以我有一个理论:似乎TestsController类不在同一个线程中,或者不是来自ApiMiddleWare的子线程。因此,存储在LogicalThreadContext中的数据不会一直传播。

如果有人可以帮助查看是否有办法执行此操作,或者我的代码中可能存在错误。我会很感激。感谢。

1 个答案:

答案 0 :(得分:1)

也许您必须致电loggingEvent.GetLoggingEventData()

我有:

public abstract class AwsVerboseLogsAppender : AppenderSkeleton
{
    // ...
    protected override void Append(LoggingEvent loggingEvent)
    {
        // ...
    }
    // ...
}

// ...

var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config");
var fileinfo = new FileInfo(path);
XmlConfigurator.Configure(fileinfo);
var log = LogManager.GetLogger(GetType());

LogicalThreadContext.Properties["Test"] = "MyValue";

log.Debug("test");

loggingEvent.PropertiesAppend为空。

但是,如果我拨打loggingEvent.GetLoggingEventData(),则"Test"MyValue会显示在loggingEvent.Properties内。所以也许你必须打电话给那个方法。