ASP.NET Core:ASP.NET Core中使用NLog记录日志
一、前言
在所有的应用程序中,日志功能是不可或缺的模块,我们可以根据日志信息进行调试、查看产生的错误信息,在ASP.NET Core中我们可以使用log4net或者NLog日志组件来实现记录日志的功能,这里讲解如何在ASP.NET Core中使用NLog。
这里采用的是.NET Core 3.1创建应用程序。
那么什么是NLog呢?
NLog是一个基于.NET平台编写的类库,我们可以使用NLog在应用程序中添加即为完善的跟踪调试代码。
NLog是一个简单灵活的.NET日志记录类库。通过使用NLog,我们可以在任何一种.NET语言中输出带有上下文的调试诊断信息,根据个人的爱好配置其输出的样式,然后发送到一个或多个输出目标(target)中。
NLog的API非常类似于log4net,且配置方式非常简单。NLog使用路由表进行配置,这样就让NLog的配置文件非常容易阅读,并便于今后维护。
NLog遵循BSD license,即允许商业应用且完全开放源代码。任何人都可以免费使用并对其进行测试,然后通过邮件列表反馈问题以及建议。
NLog支持.NET、C/C++以及COM组件,因此我们的程序、组件、包括用C++/COM编写的遗留模块都可以通过同一个路由引擎将信息发送至NLog中。
简单来说,NLog就是用来记录项目日志的组件。
二、使用NLog
首先我们创建一个WebAPI的项目:
1、引入NLog
直接在NuGet里面搜索NLog.Web.AspNetCore,然后进行安装即可,如下图所示:
安装完成以后在依赖项里面就可以看到了:
修改Program类,在里面配置使用NLog,代码如下所示:
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Hosting;
- using NLog.Web;
- namespace NLogDemo
- {
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup<Startup>();
- })
- // 配置使用NLog
- .UseNLog();
- }
- }
2、添加配置文件
右键添加新建项,然后选择Web配置文件,命名为nlog.config如下图所示:
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"
- throwConfigExceptions="true"
- internalLogLevel="info"
- internalLogFile="E:\log\internal-nlog.txt">
- <!--autoReload:修改后自动加载,可能会有延迟-->
- <!--throwConfigExceptions:NLog日志系统抛出异常-->
- <!--internalLogLevel:内部日志的级别-->
- <!--internalLogFile:内部日志保存路径,日志的内容大概就是NLog的版本信息,配置文件的地址等等-->
- <!--输出日志的配置,用于rules读取-->
- <targets>
- <!--write logs to file-->
- <!--将日志写入文件中,fileName可以指定日志生成的路径-->
- <target xsi:type="File" name="allfile" fileName="D:\Log\nlog-all-${shortdate}.log"
- layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
- <!--同样是将文件写入日志中,写入的内容有所差别,差别在layout属性中体现。写入日志的数量有差别,差别在路由逻辑中体现-->
- <target xsi:type="File" name="ownFile-web" fileName="D:\Log\nlog-my-${shortdate}.log"
- layout="${longdate}|${logger}|${uppercase:${level}}|${message} ${exception}" />
- <target xsi:type="Null" name="blackhole" />
- </targets>
- <rules>
- <!--路由顺序会对日志打印产生影响。路由匹配逻辑为顺序匹配。-->
- <!--All logs, including from Microsoft-->
- <logger name="*" minlevel="Trace" writeTo="allfile" />
- <!--Skip Microsoft logs and so log only own logs-->
- <!--以Microsoft打头的日志将进入此路由,由于此路由没有writeTo属性,所有会被忽略-->
- <!--且此路由设置了final,所以当此路由被匹配到时。不会再匹配此路由下面的路由。未匹配到此路由时才会继续匹配下一个路由-->
- <logger name="Microsoft.*" minlevel="Trace" final="true" />
- <!--上方已经过滤了所有Microsoft.*的日志,所以此处的日志只会打印除Microsoft.*外的日志-->
- <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
- </rules>
- </nlog>
添加完配置文件以后,我们还需要修改配置文件的属性,设置为始终复制,如下图所示:
3、在控制器中使用
通过上面的步骤,我们已经完成NLog的配置,接下来我们就可以在控制器中使用了,通过构造函数注入的方式实现注入。控制器代码如下:
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.Extensions.Logging;
- namespace NLogDemo.Controllers
- {
- [Route("api/[controller]")]
- [ApiController]
- public class NLogTestController : ControllerBase
- {
- private readonly ILogger<NLogTestController> _logger;
- public NLogTestController(ILogger<NLogTestController> logger)
- {
- _logger = logger;
- }
- [HttpGet]
- public IActionResult Get()
- {
- _logger.LogError("这是错误信息");
- _logger.LogDebug("这是调试信息");
- _logger.LogInformation("这是提示信息");
- return Ok();
- }
- }
- }
运行程序,访问nlogtest控制器,然后查看是否有日志生成:
我们在nlog.config里面配置的文件路径是D:\Log,从上面的截图中看到,有日志生成了 。这里生成了两个日志文件,这是因为我们在nlog.config里面配置的日志级别不同。日志内容如下:
可以看到,启动过程中的Microsoft日志也输出了,如果不想输出Microsoft日志,修改nlog.config里rules节点下面的路径规则顺序即可。
4、读取指定位置的配置文件
上面的例子中,我们是直接在项目的根目录下面添加的nlog.config文件,有时候我们想把程序里面的配置文件都放到单独的文件夹里面,这样方便管理,那么该如何设置让程序读取指定位置的nlog.config文件呢?看下面的例子。
新建一个文件夹,命名为XmlConfig,然后把nlog.config文件移到到XmlConfig文件夹下面,移到后的结构如下图所示:
然后修改Program文件,在程序里面设置读取XmlConfig文件夹下面的nlog.config文件,代码如下:
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Hosting;
- using NLog.Web;
- namespace NLogDemo
- {
- public class Program
- {
- public static void Main(string[] args)
- {
- // 设置读取指定位置的nlog.config文件
- NLogBuilder.ConfigureNLog("XmlConfig/nlog.config");
- CreateHostBuilder(args).Build().Run();
- }
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup<Startup>();
- })
- // 配置使用NLog
- .UseNLog();
- }
- }
这样就可以读取XmlConfig文件夹下面的配置文件了。
5、封装
上面的例子中,最后输出的日志格式是根据nlog.config配置文件里面的layout样式输出的,有时候输出的内容可能不满足我们的需求,我们可以对程序中的日志功能模块进行封装,输出我们自己定义的日志格式。
在解决方案中添加一个类库,命名为Nlog.Framework,然后在类库中添加一个Log文件夹,把所有Log相关的文件都放到该文件夹下,添加后的项目结构如下图所示:
添加LogMessage类,里面是要记录的一些信息属性字段:
- using System;
- namespace Nlog.Framework.Log
- {
- /// <summary>
- /// 日志消息
- /// </summary>
- public class LogMessage
- {
- /// <summary>
- /// IP
- /// </summary>
- public string IpAddress { get; set; }
- /// <summary>
- /// 操作人
- /// </summary>
- public string OperationName { get; set; }
- /// <summary>
- /// 操作时间
- /// </summary>
- public DateTime OperationTime { get; set; }
- /// <summary>
- /// 日志信息
- /// </summary>
- public string LogInfo { get; set; }
- /// <summary>
- /// 跟踪信息
- /// </summary>
- public string StackTrace { get; set; }
- }
- }
添加一个格式化类,用来格式化日志输出内容:
- using System.Text;
- namespace Nlog.Framework.Log
- {
- /// <summary>
- /// 格式化输出样式
- /// </summary>
- public class LogFormat
- {
- public static string ErrorFormat(LogMessage logMessage)
- {
- StringBuilder strInfo = new StringBuilder();
- strInfo.Append("1. 操作时间: " + logMessage.OperationTime +" \r\n");
- strInfo.Append("2. 操作人: " + logMessage.OperationName + " \r\n");
- strInfo.Append("3. Ip : " + logMessage.IpAddress +"\r\n");
- strInfo.Append("4. 错误内容: " + logMessage.LogInfo + "\r\n");
- strInfo.Append("5. 跟踪: " + logMessage.StackTrace + "\r\n");
- strInfo.Append("-----------------------------------------------------------------------------------------------------------------------------\r\n");
- return strInfo.ToString();
- }
- }
- }
这里使用依赖注入的方式,所以我们首先定义一个接口,代码如下:
- using System;
- namespace Nlog.Framework.Log
- {
- public interface INLogHelper
- {
- void LogError(Exception ex);
- }
- }
然后定义接口的实现类,代码如下:
- using Microsoft.AspNetCore.Http;
- using Microsoft.Extensions.Logging;
- using System;
- namespace Nlog.Framework.Log
- {
- public class NLogHelper : INLogHelper
- {
- //public static Logger logger { get; private set; }
- private readonly IHttpContextAccessor _httpContextAccessor;
- private readonly ILogger<NLogHelper> _logger;
- public NLogHelper(IHttpContextAccessor httpContextAccessor, ILogger<NLogHelper> logger)
- {
- _httpContextAccessor = httpContextAccessor;
- _logger = logger;
- }
- public void LogError(Exception ex)
- {
- LogMessage logMessage = new LogMessage();
- logMessage.IpAddress = _httpContextAccessor.HttpContext.Request.Host.Host;
- if (ex.InnerException != null)
- logMessage.LogInfo = ex.InnerException.Message;
- else
- logMessage.LogInfo = ex.Message;
- logMessage.StackTrace = ex.StackTrace;
- logMessage.OperationTime = DateTime.Now;
- logMessage.OperationName = "admin";
- _logger.LogError(LogFormat.ErrorFormat(logMessage));
- }
- }
- }
为了演示效果,我们添加一个全局异常过滤器,代码如下:
- using Microsoft.AspNetCore.Mvc.Filters;
- using Nlog.Framework.Log;
- using System.Threading.Tasks;
- namespace NLogDemo.Filter
- {
- /// <summary>
- /// 异步版本自定义全局异常过滤器
- /// </summary>
- public class CustomerGlobalExceptionFilterAsync : IAsyncExceptionFilter
- {
- private readonly INLogHelper _logHelper;
- public CustomerGlobalExceptionFilterAsync(INLogHelper logHelper)
- {
- _logHelper = logHelper;
- }
- /// <summary>
- /// 重新OnExceptionAsync方法
- /// </summary>
- /// <param name="context">异常信息</param>
- /// <returns></returns>
- public Task OnExceptionAsync(ExceptionContext context)
- {
- // 如果异常没有被处理,则进行处理
- if (context.ExceptionHandled == false)
- {
- // 记录错误信息
- _logHelper.LogError(context.Exception);
- // 设置为true,表示异常已经被处理了,其它捕获异常的地方就不会再处理了
- context.ExceptionHandled = true;
- }
- return Task.CompletedTask;
- }
- }
- }
接着添加一个控制器,在控制器里面模拟发生错误的操作,代码如下:
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.Extensions.Logging;
- namespace NLogDemo.Controllers
- {
- [Route("api/[controller]")]
- [ApiController]
- public class ValuesController : ControllerBase
- {
- /// <summary>
- /// 日志
- /// </summary>
- private readonly ILogger<ValuesController> _logger;
- public ValuesController(ILogger<ValuesController> logger)
- {
- _logger = logger;
- }
- [HttpGet]
- public IActionResult Test()
- {
- _logger.LogError("测试封装日志");
- int i = 0;
- int result = 10 / i;
- return Ok();
- }
- }
- }
修改Program类:
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Hosting;
- using NLog;
- using NLog.Web;
- using System;
- namespace NLogDemo
- {
- public class Program
- {
- public static void Main(string[] args)
- {
- // 读取指定位置的配置文件
- var logger = NLogBuilder.ConfigureNLog("XmlConfig/nlog.config").GetCurrentClassLogger();
- try
- {
- logger.Info("Init Main");
- CreateHostBuilder(args).Build().Run();
- }
- catch (Exception ex)
- {
- logger.Error(ex, "Stopped program because of exception");
- }
- finally
- {
- LogManager.Shutdown();
- }
- }
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup<Startup>();
- })
- // 配置使用NLog
- .UseNLog();
- }
- }
最后在Startup类里面注入:
- public void ConfigureServices(IServiceCollection services)
- {
- #region 添加异常处理过滤器
- services.AddControllers(options => options.Filters.Add(typeof(CustomerGlobalExceptionFilterAsync)));
- #endregion
- services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
- services.AddSingleton<INLogHelper, NLogHelper>();
- // NLogHelper.LoadLogger();
- services.AddControllers();
- }
这样就完成了一个简单的封装,运行程序,访问value控制器测试:
上面的例子中,只是封装了Error,如果是其他级别的日志,可以自己封装。
GitHub地址:https://github.com/jxl1024/NLog
ASP.NET Core:ASP.NET Core中使用NLog记录日志的更多相关文章
- Asp.Net Core中使用NLog记录日志
2019/10/28, Asp.Net Core 3.0, NLog 4.6.7, NLog.Web.AspNetCore 4.9.0 摘要:NLog在asp.net网站中的使用,NLog日志写入数据 ...
- 在.net core web 项目中使用Nlog记录日志
第1步,添加NLog.Web.AspNetCore包引用 方法1 在项目上右击“依赖项”---“管理Nuget程序包(N)…”,然后在浏览对话框中输入“NLog.Web.AspNetCore”查找包, ...
- .NET中使用NLog记录日志
以前小编记录日志使用的是Log4Net,虽然好用但和NLog比起来稍显复杂.下面小编就和大伙分享一下NLog的使用方式. 引用NLog.Config 在使用NLog之前,我们要首先添加对NLog.Co ...
- ASP.NET Core中使用Graylog记录日志
以下基于.NET Core 2.1 定义GrayLog日志记录中间件: 中间件代码: public class GrayLogMiddleware { private readonly Request ...
- 【ASP.NET Core】EF Core - “影子属性” 深入浅出经典面试题:从浏览器中输入URL到页面加载发生了什么 - Part 1
[ASP.NET Core]EF Core - “影子属性” 有朋友说老周近来博客更新较慢,确实有些慢,因为有些 bug 要研究,另外就是老周把部分内容转到直播上面,所以写博客的内容减少了一点. ...
- 在ASP.NET Core的startup类中如何使用MemoryCache
问: 下面的代码,在ASP.NET Core的startup类中创建了一个MemoryCache并且存储了三个键值“entryA”,“entryB”,“entryC”,之后想在Controller中再 ...
- ASP.NET Core 3.0 WebApi中使用Swagger生成API文档简介
参考地址,官网:https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/getting-started-with-swashbuckle?view ...
- 从ASP.Net Core Web Api模板中移除MVC Razor依赖项
前言 :本篇文章,我将会介绍如何在不包括MVC / Razor功能和包的情况下,添加最少的依赖项到ASP.NET Core Web API项目中. 一.MVC VS WebApi (1)在ASP. ...
- ASP.NET Core在 .NET Core 3.1 Preview 1中的更新
.NET Core 3.1 Preview 1现在可用.此版本主要侧重于错误修复,但同时也包含一些新功能. 这是此版本的ASP.NET Core的新增功能: 对Razor components的部分类 ...
随机推荐
- Docker以过时,看Containerd怎样一统天下
Docker作为非常流行的容器技术,之前经常有文章说它被K8S弃用了,取而代之的是另一种容器技术containerd!其实containerd只是从Docker中分离出来的底层容器运行时,使用起来和D ...
- IO编程之对象序列化
对象序列化的目标是将对象保存在磁盘中或者允许在网络中直接传输对象.对象序列化机制循序把内存中的java对象转换成平台无关的二进制流,从而允许把这种二进制流持久的保存在磁盘上,通过网络将这种二进制流传输 ...
- 【LeetCode】144. 二叉树的前序遍历
144. 二叉树的前序遍历 知识点:二叉树:递归:Morris遍历 题目描述 给你二叉树的根节点 root ,返回它节点值的 前序 遍历. 示例 输入:root = [1,null,2,3] 输出:[ ...
- MySQL问题定位-性能优化之我见
前言 首先任何一个数据库不是独立存在的,也不是凭空想象决定出来的. 数据库的架构离不开应用的场景.所以,为了解决某些深入的问题,首先你得掌握数据库的原理与架构.原理掌握得越深入,越能帮助你定位复杂与隐 ...
- 什么是EL表达式,以及作用
1.概念 EL(Expression Language) 是为了使JSP写起来更加简单.减少java代码,便于开发和维护. 2.语法 格式都是以"${}"表示. 3.与运算符 EL ...
- UnitTest + HTMLTestRunner
#导入HTMLTestRunner类 from unitTest.tools1.HTMLTestRunner import HTMLTestRunner import unittest discove ...
- odoo检查规则
@api.multidef button_cancel(self): for move in self: if not move.journal_id.update_posted: raise Use ...
- 利用C++11可变模板,封装调用dll导出函数
起因 开发中经常需要动态调用一些导出函数,试着利用C++11特性封装一下 尝试 常规使用 typedef int WINAPI (*TMessageBoxA)(HWND hWnd,LPCSTR lpT ...
- python3中的缺省参数和global
关于py中缺省参数: 在声明函数的时候对某些参数(一个或多个)进行赋值,在你调用的时候无需在实参列表中体现该参数,但是在执行的时候会默认加上这个已经在形参中定义好的参数. 但是,缺省参数必须放在最后, ...
- 构建后端第1篇之---springcloud项目依赖分析
张艳涛写于2021-2-2日 springcloud是springboot工程+cloud依赖,从这个角度来分析,使用springcloud实际上就是添加springcloud的某个以来比如eurek ...