日志系统
日志系统
1、什么是日志
日志(logging
)是程序运行中的“黑匣子”,在程序出现问题以后,我们可以通过分析日志来查找问题。
在.Net core
中日志可以被记录到控制台,同时还可以使用第三方提供的程序将日志记录到文件,日志服务器等。
日志的级别:
NLog
,Log4Net
1 | Critical:最高级别,生死攸关,系统即将崩溃。 |
级别的使用情况,可以根据个人的具体情况来确定使用。
例如:系统正在链接数据库,可以使用Information
,记录链接这一过程,假设这里我们最多链接3次,但是第一次没有链接成功,这里可以使用Warning
,表示可能会出现问题,如果最后一次链接也没有成功,可以使用Error
,表示数据库彻底链接失败.
2、日志的基本使用
在这一小结中,我们看一下怎样将日志输出到控制台中。
第一步:需要安装的包:
1 | Install-Package Microsoft.Extensions.Logging // 这是日志系统的核心包,不管是将日志输出到控制台还是文件等,都需要安装 |
第二步:DI
注入
1 | ServiceCollection services = new ServiceCollection(); |
在上面的代码中,通过调用AddLogging
这个方法将与日志有关的服务注入到容器中,在该方法的中,又调用了AddConsole
方法,表示将日志信息输出到控制台中。
第三步:使用泛型的ILogger
接口从容器中获取一个用于输出日志的对象,泛型类型一般用当前的类,这样在输出日志的时候默认会把当前类名输出,这样便于我们定义某一条输出信息来自哪个类。注意:在注入ILogger
服务的时候,不能使用非泛型的ILogger
接口,否则是获取不到服务的。
1 | var logger=sp.GetRequiredService<ILogger<Program>>(); |
在ILogger
中有LogTrace,LogDebug,LogInformation,LogWarning,LogError,LogCritical
这个6个方法用于输出不同严重性级别的消息(严重性级别依次提高)。
例如:就像我们前面提到的,需要链接数据,但是如果3次没有链接成功,则不在进行链接。
开始进行链接,这样的信息就用LogInformation
,而出现了“第一次链接失败,准备进行第二次数据库的链接”,这时候可以使用LogWarning
.
如果3次都链接失败
,这时候就可以使用LogError
记录相应的错误信息。
完整代码如下所示:
1 | using Microsoft.Extensions.DependencyInjection; |
通过上面的代码,可以看到日志在输出的时候可以采用占位符的格式,同时在程序遇到异常的时候,我们还可以把异常的对象信息作为参数传递给LogError
方法,这样在输出信息中就可以看到异常的堆栈信息。
问题:在上面的代码中,我们是直接在Program.cs
类中进行演示的,但是这里有一个新的需求,就是我们需要再TestLog.cs
这个类中进行日志的记录,应该怎样做?
在项目中创建TestLog.cs
这个类
1 | using Microsoft.Extensions.Logging; |
在上面的代码中,是在TestLog
这个构造函数中,注入了ILogger
这个泛型接口,注意:这里的泛型类型是当前的类也就是TestLog
.
下面在ConnectSql
这个方法中进行日志的记录。
下面返回到Program.cs
类中,进行代码的修改,如下所示:
1 | using ConsoleApp; |
在上面的代码中,通过AddScoped
方法将TestLog
注入到DI
容器中,这样TestLog
类中的ILogger
泛型接口也完成了注入。
下面在通过GetRequiredService
方法,从DI
容器中获取TestLog
的实例,完成对ConnectSql
方法的调用。
进行代码的测试。
当然,这里我们也可以设置日志的级别。
1 | ServiceCollection services = new ServiceCollection(); |
运行以上程序,只是输出了Error
错误信息,警告等信息没有在控制台中输出。
3、NLog
基本使用
在前面的课程中,我们是将日志信息输出到控制台中,将日志信息输出到控制台中的问题是:
控制台中展示的信息的长度是有一定的限制的,当信息展示的比较多以后,以前的日志信息就无法展示了,同时控制台中的日志不是持久化保存的,当控制台不小心关掉了以后,日志信息就没有了。
而且,相对于控制台的展示,开发人员和运维人员更喜欢文本格式的日志文件,而且分发起来比较方便。
在.Net Core
中并没有内置的文本文件日志提供程序,我们需要使用第三方的日志提供程序。
常用的第三方日志提供程序有Log4Net,NLog,Serilog
.
这里我们讲解的是NLog
,它的使用比较简单,功能也比较强大。
将日志信息写到文件中要注意的问题:
第一:一般情况下日志文件名称会按照日期进行区分。
方便定位问题。
第二:限制日志文件的总个数
日志文件特别多,导致磁盘被占满,处理方式,可以限制日志文件的总个数,例如:限制200个日志文件,当到了200个以后,在有新的日志文件,可以将旧的删除掉,因为当问题解决了以后,以前的日志文件没有什么用了。
第三:限制单个日志文件的大小,日志文件不要太大,查找不方便。
NLog
使用的基本步骤:
第一:安装需要的包:
1 | Install-Package Microsoft.Extensions.Logging // 这是日志系统的核心包,不管是将日志输出到控制台还是文件等,都需要安装 |
第二:需要在项目跟目录下面创建nlog.config
配置文件(同时这里也要选择“如果较新则复制”)。注意文件名的大小写。当然,这里也可以修改成其他的名称,但是需要单独的配置,比较麻烦。约定大于配置。
第三部:增加logBuilder.AddNLog( )
当在项目的跟目录下面创建好了nlog.config
这个配置文件以后,可以将官网的配置拷贝到该文件中。
官网地址:https://github.com/NLog/NLog/wiki/Getting-started-with-.NET-Core-2---Console-application
这个配置针对的是控制台的程序,如果针对的是网站项目,配置不太一样,具体参考官网。
1 |
|
以上就是默认从官网中拷贝的配置。注意:这里把配置文件中默认的磁盘
盘符删除了,由于选择了较新则复制
,程序启动以后,对应的日志文件会被拷贝到程序的运行目录中bin\Debug\net7.0
。
下面修改Program.cs
文件中的代码,如下所示:
1 | using ConsoleApp; |
在AddLogging
方法中增加了logBuilder.AddNLog();
.
同时为了将错误的堆栈信息记录到日志文件中,我们将TestLog.cs
类中的代码也做了简单的修改。
1 | public void ConnectSql() |
运行程序,在控制台中打印的错误信息不一样了,同时在bin\Debug\net7.0
目录中有了记录错误信息的日志文件console-example.log
以上就是NLog
的基本使用。
下面对配置文件做一个简单的说明:
1 |
|
autoReload
:”修改日志配置文件后是否允许自动加载,而无需重启启动程序,这里设置为true,表示日志修改了,无需重新启动程序”。
internalLogLevel
:”把NLog
这个日志程序内部的调试和异常信息写到当前属性指定的文件,也就是console-example-internal.log
“
internalLogLevel
:指定的是NLog
这个程序内部的日志级别。当然,这里我们可以将其关闭,把该属性的值设置为off
.
如果这里设置了off
以后,我们可以把console-example-internal.log
这个日志文件删除掉,然后再重新运行程序,发现就不会再创建该文件了。也就是,不需要再记录NLog
这个程序的内部日志信息了。
targets
:表示日志文件输出的位置。
其中的每个target
,表示对每个输出格式进行限制。
xsi:type=File
表示输出到文件,fileName
表示输出的日志文件名。layout
表示日志信息在文件中的格式。
格式
:longdate
:表示日期,level
:表示日志的级别,message
:表示日志的信息,重点关注这几项配置,其他的可以查询文档。
rules
指定日志的输出规则,这里的writeTo
表示日志具体输出的形式,这里的writeTo
的取值是logfile,logconsole
,表示日志可以输出到文件,也可以输出到控制台(也就是上面target
中name
属性的值)。minlevel
表示了日志的最低级别。这里的name
取值为*
号,表示所有的日志信息都输出到logfile,logconsole
.
以上就是Nlog
的基本使用。
4、NLog
深入
这里先来简单说两个概念,一个是日志的分类,另外一个是日志的过滤。
这两个概念,在其他的日志程序中也是存在的。
日志分类:在上一小结中,我们是将所有级别的日志信息都写到一个文件中了,例如·:“Debug”,Warning,Error
等。其实我们可以对不同的级别进行分类,例如:Debug
的都写到一个文件中,Error
的写到一个文件中,这样查找起来也方便。
或者,也可以根据我们项目的模块来进行分类,例如,针对登录注册模块,有单独的日志文件,针对商品管理模块有单独的日志文件,这样结构非常清晰,查找方便。
日志过滤:项目不同阶段(比如,项目刚上线和项目稳定以后)需要记录的日志内容是不同的,例如:项目刚上线的时候,问题可能比较多,这时候,需要将日志的Debug,Warning
等都记录下来,但是当项目运行了一段时间后,比较稳定了,这时候,Debug
的日志信息我们就不需要了,只想保存Warning和Error
,这样也减少了日志文件的大小。
下面,我们看一下具体的实现:
首先在项目中在创建一个类FileLog.cs
,该类的代码如下所示:
1 | using ConsoleApp; |
注意:在上面的代码中,我们将命名空间修改成了SystemFile
,目的就是用来表示一个新的模块。
方法名称修改成了ReadFileInfo
,其他的内容与前面的案例是一样的。
下面再来看一下Program.cs
文件中的代码修改,如下所示:
1 | using ConsoleApp; |
在上面的代码中,我们将FileLog注入到了DI容器中
,并且通过GetRequiredService
方法从容器
中获取了FileLog
类的实例,完成了ReadFileInfo
方法的调用。
下面看一下nlog.config
配置文件中的配置信息的修改,如下所示:
1 |
|
在上面的配置中,我们先修改了第一个target
,这里我们让以前TestLog
类中的信息记录到了logs
目录下面以log-日期
为命名的日志文件中。
下面我们又添加了一个新的target
项,在该项中,指定的name
是sysFileLog
,目的是将SystemFile
命名空间下的FileLog
类中的
信息记录到logs
目录以sysFile-日期
命名的日志文件中。
当然,要想满足以上的要求,需要修改rules
中的配置。
第一项logger
中指定的name
取值是*
,表示任何类或者是模块中的日志信息都会执行logconsole
这个target
,这样都会将日志信息打印在控制台中。并且指定的日志级别最小是Warn
,最高的日志级别是Fatal
,这些级别是ILog
自已定义的,对应着.net
中的`Warning,Critical.一会我们可以在控制台中重点看一下输出的日志的级别
第二项logger
,指定的name
是SystemFile.*
,表示SystemFile
这个命名空间下的类出错的信息都会执行sysFileLog
这个target
.
同时这里指定了final
取值为true
,表示如果匹配上了这个logger
,就不会再执行后面的logger
项。
讲解到这,我们就明白了,针对SystemFile
这个命名空间下类出错的这些日志信息,不仅会展示在控制台中,也会写到以sysFile-
为前缀的文件中。
第三项logger
,指定的name
也是*
,表示的是任何类或者模块中的日志信息都会执行logfile
这个target
.但是问题是在第二项中,我们指定的logger
的name
属性的取值是SystemFile.*
,并且对应的final
属性的值是true
,也就是说,SystemFile
这个命名空间下的FileLog
类中如果出错了,对应的日志信息,不会执行logfile
这个target
,执行的是sysFileLog
这个target
.总结一句话就是:当把final
设置为true
以后,如果匹配到了这个logger
,就不会继续向下匹配其他的logger
了。
讲解到这,我们也明白了,针对当前我们所创建的项目,只有TestLog.cs
这个类中出错的日志信息才会执行logfile
这个target
.
这样在logs
目录下面会以log-日期
形式的文件来保存TestLog.cs
这个类中出错的日志信息。
下面运行程序,先看一下控制台中的输出(可以看到在控制台中Info
的日志信息没有输出,这里已经被ILog
给过滤掉了),然后看一下
bin\Debug\net7.0目录下的
logs`目录。
下面再来看两个配置:archiveAboveSize
和maxArchiveFiles
``
archiveAboveSize
:表示单个日志文件超过多少字节把日志存档
,也就是规定单个日志文件是多大,单位是字节
,通过该属性可以避免单个文件太大的情况。
maxArchiveFiles
:规定日志文件的个数,如果不设定该属性,则日志文件的数量会一直增加,如果设置了该属性,则最多保存该属性指定数量的日志文件个数,旧的会被删除掉。
下面进行测试:
1 | <target xsi:type="File" name="sysFileLog" fileName="logs/sysFile-${shortdate}.log" archiveAboveSize="10000" |
可以看到,在第二个target
中,我们指定的archiveAboveSize
属性的取值是10000
字节,同时maxArchiveFiles
属性的值是3,也就是保存三个日志文件。
返回到Program.cs
文件中修改测试代码,如下所示:
1 | using (var sp = services.BuildServiceProvider()) |
这里,我们是写一个循环,然后不断的调用相应的测试方法来向文件中写日志。
然后查看bin\Debug\net7.0\logs
目录中的日志文件的变化情况。
当然,这两个属性的取值根据实际情况自己来确定。
总结:NLog
部分功能与.net
中自带的日志管理有一定的重复,例如:分类,分级等,所以为了避免发生冲突,如果使用了NLog
,建议不要在配置.net
中的分级等。
所以这里,我们需要将Program.cs
文件中的设置分级的代码注释掉,如下所示:
1 | services.AddLogging(logBuilder => |
NLog
的官方网站
http://nlog-project.org/config/
通过官网,可以看到NLog
不仅可以将日志 输出的文件,数据库,还可以发送邮件等等。
大家可以根据自己的情况,查看相应的文档来进行学习。