.netcore3.1使用log4net/nlog记录日志
.netcore3.1与2.x之间很是有不少差异的。本来想通过ctrl+c,ctrl+v将在2.2中实现的简单日志记录搬到.netcore3.1项目上,才发现姿势不对。所以在此做个简单的记录。
使用log4net
第一步、在对应项目中引入Microsoft.Extensions.Logging.Log4Net.AspNetCore
第二步、创建log4net.config文件(详细的配置说明请参照其官方文档),配置好日志参数。并将改文件设置成【始终复制】或者【如果较新则复制】
log4net.config文件内容示例
<?xml version="1.0" encoding="utf-8"?> <log4net> <!-- Define some output appenders --> <appender name="rollingAppender" type="log4net.Appender.RollingFileAppender"> <file value="log\log.txt" /> <!--追加日志内容--> <appendToFile value="true" /> <!--防止多线程时不能写Log,官方说线程非安全--> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <!--可以为:Once|Size|Date|Composite--> <!--Composite为Size和Date的组合--> <rollingStyle value="Composite" /> <!--当备份文件时,为文件名加的后缀--> <datePattern value="yyyyMMdd.txt" /> <!--日志最大个数,都是最新的--> <!--rollingStyle节点为Size时,只能有value个日志--> <!--rollingStyle节点为Composite时,每天有value个日志--> <maxSizeRollBackups value="20" /> <!--可用的单位:KB|MB|GB--> <maximumFileSize value="5MB" /> <!--置为true,当前最新日志文件名永远为file节中的名字--> <staticLogFileName value="true" /> <!--输出级别在INFO和ERROR之间的日志--> <!--过滤级别 FATAL > ERROR > WARN > INFO > DEBUG--> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="WARN" /> <param name="LevelMax" value="FATAL" /> </filter> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/> </layout> </appender> <root> <priority value="ALL"/> <level value="ALL"/> <appender-ref ref="rollingAppender" /> </root> </log4net>
第三步、代码注入log4net
修改program.cs代码注入log4net
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging((context, logBuilder) => { logBuilder.AddFilter("System", LogLevel.Warning); logBuilder.AddFilter("Microsoft", LogLevel.Warning); logBuilder.AddLog4Net(); //注入log4net }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
再修改startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env , ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } // app.UseHttpsRedirection(); #region 添加log4net loggerFactory.AddLog4Net(); #endregion app.UseRouting(); ...... }
测试
[Route("api/[controller]")] [ApiController] public class TestLoggerController : ControllerBase { private readonly ILogger<TestLoggerController> _logger; public TestLoggerController(ILogger<TestLoggerController> logger) { this._logger = logger; } [HttpPost("testWriteLogException")] public void TestWriteLogException() { _logger.LogError("这是一个简单日志测试"); } }
结果
------------------------------------
使用NLog
第一步,项目中引入NLog.Web.AspNetCore
第二步、创建nlog.config文件(详细的配置说明请参照NLog官方文档),配置好日志参数。并将改文件设置成【始终复制】或者【如果较新则复制】
nlog.config文件示例
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogLevel="Off" internalLogFile="d:\temp\internal-nlog.txt"> <!-- enable asp.net core layout renderers --> <extensions> <add assembly="NLog.Web.AspNetCore"/> </extensions> <!-- the targets to write to --> <targets> <!-- write logs to file --> <target xsi:type="File" name="allfile" fileName="${basedir}/logs/${shortdate}.log" layout="${longdate} ${level:uppercase=true} ${event-context:item=Action} ${message} ${event-context:item=Amount} ${stacktrace} ${newline} ${exception:format=tostring} ${newline}" /> <!-- another file log, only own logs. Uses some ASP.NET core renderers --> <target xsi:type="Debugger" name="debugger" layout="${date:format=HH\:mm\:ss.fff}: ${message}" /> </targets> <!-- rules to map from logger name to target --> <rules> <!--Skip non-critical Microsoft logs and so log only own logs--> <!--<logger name="Microsoft.*" maxlevel="Error" final="true" />--> <logger name="*" minlevel="Debug" writeTo="allfile" /> <!--<logger name="*" minlevel="Info" writeTo="allfile" />--> </rules> </nlog>
第三步、代码中注入NLog
只需修改program.cs
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }).UseNLog();// 注入nlog
测试
[Route("api/[controller]")] [ApiController] public class TestLoggerController : ControllerBase { private readonly ILogger<TestLoggerController> _logger; public TestLoggerController(ILogger<TestLoggerController> logger) { this._logger = logger; } [HttpPost("testWriteLogException")] public void TestWriteLogException() { _logger.LogError("这是一个简单日志测试-----NLog"); } }
结果
-----------------------------------------
附,配置全局异常过滤
程序在运行中避免会出现各种异常,而我们不可能在所有地方都进行try..catch捕获异常记录日志。这时我们可以定义全局异常捕获并记录日志。
在netcore中我们只需要定义对应的异常过滤类(其必须继承自ExceptionFilterAttribute或者是实现接口IExceptionFilter;ExceptionFilterAttribute实现了接口IExceptionFilter),并在程序中进行注入异常过滤即可(日志的记录还是要依赖具体的实现,可以是log4net、NLog或者其他)。
以下定义了GlobalExceptionFilter
public class GlobalExceptionFilter : ExceptionFilterAttribute { private readonly ILogger<GlobalExceptionFilter> _logger; public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger) { _logger = logger; } public override void OnException(ExceptionContext context) { var operation = context.HttpContext.Request.RouteValues["controller"] + "/" + context.HttpContext.Request.RouteValues["action"]; _logger.LogError(context.Exception,$"{operation} Exception:" + context.Exception.Message); //记录错误日志 //拦截处理 if (!context.ExceptionHandled) { context.Result = new JsonResult(new { status = false, msg ="系统内部错误:"+ context.Exception.Message }); context.ExceptionHandled = true; } } }
修改startup.cs添加异常过滤
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddMvc(p => { p.Filters.Add(typeof(GlobalExceptionFilter)); //添加异常过滤 }); .... }
示例
[Route("api/[controller]")] [ApiController] public class TestLoggerController : ControllerBase { private readonly ILogger<TestLoggerController> _logger; public TestLoggerController(ILogger<TestLoggerController> logger) { this._logger = logger; } [HttpPost("testWriteLogException")] public void TestWriteLogException() { throw new Exception("这是没有捕获的异常"); } }
结果
-----------------------------------------