当在owin中间件中使用LogConext.PushProperty向所有日志(log)事件添加关联ID时,它只会添加到中间件中,但不会在登录控制器时添加,这是我所期望的.

下面是代码与问题再现https://github.com/mk0sojo/SerilogOwinBug. 它是ASP.NET MVC on .NET framework模板,更改了以下内容:

  • 添加Microsoft.Owin.Host.SystemWeb Nuget包以运行IIS中的OWIN中间件
  • 从Nuget添加Serlog和Serilog.Sinks.Trace
  • 在工程根目录下添加一个Startup.cs文件,文件内容如下:
using Microsoft.Owin;
using Owin;
using Serilog;

[assembly: OwinStartup(typeof(SerilogOwinBug.Startup))]

namespace SerilogOwinBug
{
    public class Startup
    {
        // Running the app produces the following log:
        // 2023-11-28 14:25:35Z [RequestId: 123] Starting middleware. URL: "/"
        // 2023-11-28 14:25:35Z [RequestId: ] Hello from Home Controller
        // 2023-11-28 14:25:37Z [RequestId: 123] Ending middleware. URL: "/"
        //
        // Expecting
        // 2023-11-28 14:25:35Z [RequestId: 123] Starting middleware. URL: "/"
        // 2023-11-28 14:25:35Z [RequestId: 123] Hello from Home Controller
        // 2023-11-28 14:25:37Z [RequestId: 123] Ending middleware. URL: "/"
        public Startup()
        {

            Log.Logger = new LoggerConfiguration()
                .Enrich.FromLogContext()
                .WriteTo.Trace(
                    outputTemplate: "{Timestamp:u} [RequestId: {RequestId}] {Message}"
                 )
                .CreateLogger();
        }
        public void Configuration(IAppBuilder app)
        {
            app.Use<SerilogMiddleware>();
        }
    }
}

  • 在项目根目录下添加SerilogMiddleware.cs:
using Microsoft.Owin;
using Serilog.Context;
using Serilog;
using System.Threading.Tasks;

namespace SerilogOwinBug
{
    public class SerilogMiddleware : OwinMiddleware
    {
        public SerilogMiddleware(OwinMiddleware next) : base(next)
        {

        }

        public override async Task Invoke(IOwinContext context)
        {
            using (LogContext.PushProperty("RequestId", "123"))
            {
                Log.Information("Starting middleware. URL: {URL}", context.Request.Path);
                await Next.Invoke(context);
                Log.Information("Ending middleware. URL: {URL}", context.Request.Path);
            }
        }
    }
}
  • 将一条日志(log)语句添加到HomeController.cs文件,使其如下所示:
using Serilog;
using System.Web.Mvc;

namespace SerilogOwinBug.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            Log.Information("Hello from Home Controller");
            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}
  • 运行应用程序并在Web浏览器中打开它.判断输出窗口中的日志(log).它看起来是这样的:
iisexpress.exe Information: 0 : 2023-11-28 14:25:35Z [RequestId: 123] Starting middleware. URL: "/"
iisexpress.exe Information: 0 : 2023-11-28 14:25:35Z [RequestId: ] Hello from Home Controller
...
iisexpress.exe Information: 0 : 2023-11-28 14:25:37Z [RequestId: 123] Ending middleware. URL: "/"

Expected behavior个 预计输出为:

iisexpress.exe Information: 0 : 2023-11-28 14:25:35Z [RequestId: 123] Starting middleware. URL: "/"
iisexpress.exe Information: 0 : 2023-11-28 14:25:35Z [RequestId: 123] Hello from Home Controller
...
iisexpress.exe Information: 0 : 2023-11-28 14:25:37Z [RequestId: 123] Ending middleware. URL: "/"

推荐答案

可能是复制品 How to add a request identifier to OWIN requests using Serilog?

你有没有试过添加

Enrich.FromLogContext()

到您的Serilog配置?

最新情况: 另一种 Select 是实现一个定制的LogEnricher类:

  1. 在SerilogMiddleware.Invoke(IOwinContext上下文)中,将请求id设置到请求中:

    HttpContext.Current.Items["RequestId"] = Guid.NewGuid().ToString();
    
  2. 创建一个LogEnricher类:

    public class LogEnricher : ILogEventEnricher
    
  3. 实现ILogEventEnricher.Enrich方法:

     public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
     {
       // get the request id
       string requestid = HttpContext.Current.Items[Constants.RequestId]?.ToString();
    
       // create the property
       var property = propertyFactory.CreateProperty("RequestId", requestid);
    
       // add property to event
       logEvent.AddOrUpdateProperty(property);
     }
    

.net相关问答推荐

我的Azure应用服务从哪里获取应用设置?

Msbuild try 构建 msbuild.exe 而不是我的 .csproj 文件

如何在选项卡中 Select Winforms NumericUpDown 中的所有文本?

您如何确定两个 HashSet 是否相等(按值,而不是按引用)?

将毫秒转换为人类可读的时间间隔

在 .NET C# 中存储加密密钥的最佳方式

.NET 4.0 中有内置的二叉搜索树吗?

简单委托(委托)与多播委托

Automapper:使用 ReverseMap() 和 ForMember() 进行双向映射

.NET 等价于旧的 vb left(string, length) 函数

迭代器和枚举器的区别

有没有像样的 C# 分析器?

为什么 C# 不推断我的泛型类型?

找不到库 hostpolicy.dll

如何从文件中删除单个属性(例如只读)?

了解 C# 中的协变和逆变接口

ValueTypes 如何从 Object (ReferenceType) 派生并且仍然是 ValueTypes?

在 Windows 窗体 C# 应用程序中拥有配置文件的最简单方法

将控制台输出镜像到文件

如何将 VB 项目转换为 C# 项目