Microsoft.AspNetCore.Hosting.Internal.WebHost 和 log4net.LogicalThreadContext.Properties["reques
Posted
技术标签:
【中文标题】Microsoft.AspNetCore.Hosting.Internal.WebHost 和 log4net.LogicalThreadContext.Properties["requestid"]【英文标题】:Microsoft.AspNetCore.Hosting.Internal.WebHost and log4net.LogicalThreadContext.Properties["requestid"] 【发布时间】:2018-09-29 22:10:14 【问题描述】:我使用 netcore2.0,并为中间件类中的每个请求设置 log4net.LogicalThreadContext 属性“requestid”以进行日志记录。
log4net.LogicalThreadContext.Properties["requestid"] = Guid.NewGuid().ToString("N");
但“Microsoft.AspNetCore.Hosting.Internal.WebHost”类在记录行时不显示此属性。
我不知道如何为“Microsoft.AspNetCore.Hosting.Internal.WebHost”设置 log4net.LogicalThreadContext.Propery["requestid"]。
我希望将所有请求日志从头到尾绑定。 有没有人有任何可能有帮助的见解?
问候!
更新:这里是代码
using Microsoft.Extensions.Logging;
...
public static ILoggerProvider Log4NetProvider;
public static void Main(string[] args)
#if DEBUG
Log4NetProvider = new Log4NetProvider("log4net.Debug.config", ((o,
exception) => exception.Message));
#else
Log4NetProvider = new Log4NetProvider("log4net.Release.config", ((o,
exception) => exception.Message));
#endif
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureLogging((hostingContext, logging) =>
logging.AddProvider(Log4NetProvider);
)
.ConfigureServices(services =>
services.AddAutofac();
)
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
在 Startup.cs 中 Configure(IApplicationBuilder app, IHostingEnvironment env) 我已经设置为第一件事。
app.UseMiddleware<Log4NetRequestIdMiddleware>();
public class Log4NetRequestIdMiddleware
private readonly RequestDelegate _next;
public Log4NetRequestIdMiddleware(RequestDelegate next)
_next = next;
public async Task Invoke(HttpContext context)
log4net.LogicalThreadContext.Properties["requestid"] = Guid.NewGuid().ToString("N");
await _next(context);
Log4net 配置文件>
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<file value="C:\log\applog.log" />
<rollingStyle value="Size"/>
<maxSizeRollBackups value="500"/>
<maximumFileSize value="5MB"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%utcdate|%-5level|%logger|%propertyrequestid| %message %exception%newline" />
</layout>
</appender>
<root>
<level value="ALL" />
<appender-ref ref="RollingFile" />
</root>
</log4net>
来自 Fileappender.log 的其他示例(粗体标记 RequestId)
2018-04-10 14:02:28,664|INFO|Microsoft.AspNetCore.Hosting.Internal.WebHost|(null)|请求开始 HTTP/1.1 GET http://localhost... 2018-04-10 14:02:28,956|信息| Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker|cfb2709e3b4f40559c365ecbb08a7746|执行动作方法 Controllers.HealtCheckStatusController.GetHealthCheckStatus 2018-04-10 14:02:29,486|信息| Microsoft.AspNetCore.Mvc.Internal.ObjectResultExecutor|cfb2709e3b4f40559c365ecbb08a7746|执行 ObjectResult,写入值 Microsoft.AspNetCore.Mvc.ControllerContext. 2018-04-10 14:02:29,510|信息| Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker|cfb2709e3b4f40559c365ecbb08a7746|在 564.464 毫秒内执行操作 Controllers.HealtCheckStatusController.GetHealthCheckStatus 2018-04-10 14:02:29,520|信息|Microsoft.AspNetCore.Hosting.Internal.WebHost|(null)|请求在 858.9575 毫秒内完成 200 应用程序/json;字符集=utf-8
【问题讨论】:
请发布您的代码。我刚刚使用我的管道的第一个中间件尝试了您的方案,它可以工作。 仍然无法重现。除了任何不清楚的地方张贴您的log4net config
和Log4NetProvider
。
嘿,抱歉耽搁了。发布 log4net 配置和不显示“requestId”的示例
没有更多的 Log4NetProvider 代码。这是一个 Microsoft.Extensions.Logging ILoggerProvider 实现。
【参考方案1】:
为什么WebHost
logger 不显示属性
WebHost
logger 记录两条消息 - 请求开始消息和请求完成消息。
请求开始消息看不到requestid
属性,因为WebHost
运行并在第一个中间件包含到Startup
类中设置requestid
属性的管道之前记录该消息。
请求完成的消息没有看到requestid
属性,因为(我猜)WebHost
记录器不在log4net.LogicalThreadContext
中。就像Log4NetRequestIdMiddleware
logger 不会看到 requestid
属性,如果它会在控制器操作中设置。
可能的解决方案
由于WebHost
记录器在Microsoft.AspNetCore.Hosting.Internal
命名空间的HostingApplicationDiagnostics
类的某个深处记录消息,因此没有任何明确的扩展点可以注入设置requestid
属性的代码。
所以,我认为您可以像 WebHost
logger 一样在中间件中记录信息:
public async Task Invoke(HttpContext context)
var logger = httpContext.RequestServices.GetRequiredService<ILogger<Log4NetRequestIdMiddleware>>();
log4net.LogicalThreadContext.Properties["requestid"] = Guid.NewGuid().ToString("N");
var request = context.Request;
string logMsg = string.Format(
CultureInfo.InvariantCulture,
"Request starting 0 1 2://3456 7 8",
request.Protocol,
request.Method,
request.Scheme,
request.Host.Value,
request.PathBase.Value,
request.Path.Value,
request.QueryString.Value,
request.ContentType,
request.ContentLength);
logger.LogDebug(logMsg);
await _next(context);
【讨论】:
感谢 Albert 对此进行调查。我想这是唯一的方法,我会使用它。问候!【参考方案2】:你可以看看这个 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1#logging-providers
创建自己的LogProvider,像这样清除日志提供者。
services.AddLogging(config =>
config.ClearProviders();
);
loggerFactory.AddLog4Net();
这篇文章讲述了如何创建一个 log4net Logger。 https://dotnetthoughts.net/how-to-use-log4net-with-aspnetcore-for-logging/
【讨论】:
以上是关于Microsoft.AspNetCore.Hosting.Internal.WebHost 和 log4net.LogicalThreadContext.Properties["reques的主要内容,如果未能解决你的问题,请参考以下文章