.NET Core的日志[4]:将日志写入EventLog
面向Windows的编程人员应该不会对Event Log感到陌生,以至于很多人提到日志,首先想到的就是EventLog。EventLog不仅仅记录了Windows系统自身针对各种事件的日志,我们的应用也可以利用提供的API将日志消息写到EventLog中。与EventLog相关的API都定义在System.Diagnostics.EventLog这个类型中,我们不仅仅可以利用它读取、写入和删除日志,还可以使用它来创建和删除Event Source。.NET Core的日志模型利用EventLogLogger实现了与EventLog的集成,不过EventLogLogger使用的是一个抽象化的EventLog。本文已经同步到《ASP.NET Core框架揭秘》之中]
目录
一、抽象化的EventLog
二、EventLogLogger
三、EventLogLoggerProvider
一、抽象化的EventLog
EventLogLogger定义在“Microsoft.Extensions.Logging.EventLog”这个NuGet包中。就目前这个版本来说,该NuGet包承载的程序集只适用于.NET Framework应用,换句话说,EventLogLogger仅仅提供针对Windows EventLog的支持。尽管如此,日志模型仍然通过一个接口对EventLog的相关操作进行了抽象。
ConsoleLogger采用IConsole接口对针对不同平台的控制台进行了抽象,EventLogLogger使用的抽象化EventLog通过IEventLog接口来表示。如下面的代码片段所示,IEventLog接口仅仅定义了一个唯一的方法WriteEntry来写日志,提供的参数用于指定日志的消息文本(message)、类型(type)、事件ID(eventID)以及类别(category)。为了避免单条日志包含过多的内容,IEventLog接口定义了一个只读属性MaxMessageSize来设置日志消息的文本允许的最大长度。
1: public interface IEventLog
2: {
3: void WriteEntry(string message, EventLogEntryType type, int eventID, short category);
4: int MaxMessageSize { get; }
5: }
6:
7: public enum EventLogEntryType
8: {
9: Error = 1,
10: Warning = 2,
11: Information = 4,
12: SuccessAudit = 8
13: FailureAudit = 16
14: }
EventLog记录下来的没条日志都具有一个通过枚举EventLogEntryType表示的类型,这个类型相当于日志的等级。对于定义在这个枚举中的五种类型,Error、Warning和Information与同名的日志等级具有相同的含义,而SuccessAudit和FailureAudit代表针对“审核(Audit)”事件的日志,它们分别代表针对“成功事件”和“失败事件”的审核。当EventLogLogger在利用EventLog写入日志的时候,会将指定的日志等级转化成EventLog的日志类型,转换规则很简单:针对Error、Warning和Information的日志等级转换成同名的EventLog日志类型,其他的等级则之间转换成Information类型。
具有如下定义的 WindowsEventLog是对IEventLog接口的默认实现者。一个WindowsEventLog实际上就是对一个EventLog对象的封装,后者通过DiagnosticsEventLog属性表示。这个封装的EventLog对象在构造函数通过指定相应参数的日志名称(logName)、机器名(machineName)和Event Source名称(sourceName)来创建。在实现的WriteEntry方法中,这个EventLog的WriteEntry被直接调用来完成日志的写入。WindowsEventLog的MaxMessageSize属性返回一个常量31839,日志消息文本不能超过这个长度。
1: public class WindowsEventLog : IEventLog
2: {
3: private const int MaximumMessageSize = 31839;
4:
5: public int MaxMessageSize
6: {
7: get { return MaximumMessageSize; }
8: }
9:
10: public System.Diagnostics.EventLog DiagnosticsEventLog { get; }
11:
12: public WindowsEventLog(string logName, string machineName, string sourceName)
13: {
14: DiagnosticsEventLog = new System.Diagnostics.EventLog(logName, machineName, sourceName);
15: }
16:
17: public void WriteEntry(string message, EventLogEntryType type, int eventID, short category)
18: {
19: DiagnosticsEventLog.WriteEntry(message, type, eventID, category);
20: }
21: }
二、EventLogLogger
日志模型利用EventLogLogger实现了与EventLog的整合。具体来说,一个EventLogLogger实际上是对EventLog对象的封装,它利用后者向EventLog写入日志。EventLogLogger类型具有如下的定义,我们可以看到它具有两个构造函数,除了提供Logger名称之外,其中一个构造函数具有一个类型为EventLogSettings的参数,这个封装的EventLog对象正式通过该参数提供的信息创建出来的。
1: public class EventLogLogger : ILogger
2: {
3: public EventLogLogger(string name);
4: public EventLogLogger(string name, EventLogSettings settings);
5:
6: public IDisposable BeginScope<TState>(TState state);
7: public bool IsEnabled(LogLevel logLevel);
8: public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
9: Func<TState, Exception, string> formatter);
10: }
11:
12: public class EventLogSettings
13: {
14: public IEventLog EventLog { get; set; }
15:
16: public string LogName { get; set; }
17: public string MachineName { get; set; }
18: public string SourceName { get; set; }
19:
20: public Func<string, LogLevel, bool> Filter { get; set; }
21: }
如上面的代码片段所示,我们可以利用EventLogSettings对象的EventLog属性向EventLogLogger提供一个具体的EventLog对象。如果这个属性为Null,EventLogLogger将会利用EventLogSettings的其他三个属性(LogName、MatcheName和SourceName)创建一个WindowsEventLog对象。除了这四个与创建或者提供EventLog对象相关的四个属性之外,EventLogSettings还具有另一个Func<string, LogLevel, bool>类型的属性Filter,它自然代表日志消息过滤器。
当EventLogLogger在利用EventLogSettings创建WindowsEventLog对象的时候,如果相关的属性(LogName、MatcheName和SourceName)在EventLogSettings对象中未作显式设置,它会采用预定义的默认值。具体来说这三者对应的默认值为“Application”[1]、“.”(代表本机)和“Application”。如果我们调用第一个构造函数重载,实际上内部会利用这些默认值创建一个WindowsEventLog对象。如果调用构造函数时连名称(name参数)都没有指定,那么类型名称(“EventLogLogger”)将被用来命名创建的Logger。
EventLogLogger和DebugLogger一样也不支持日志上下文范围,所以它的BeginScope<TState>方法和返回的对象其实毫无意义。EventLogSettings的Filter属性返回Func<string, LogLevel, bool>对象将被IsEnabled方法使用,如果个委托对象没有被显式提供,意味着这个方法总是返回True。当Log方法被调用的时候,它会采用与DebugLogger完全一致的方式来格式化最终的日志消息文本,所以针对异常的重复描述的问题依然存在。日志消息最终通过调用EventLog的WriteEntry方法被写到EventLog中,但是在这之前会检查格式化后的日志消息文本是否超过通过MaxMessageSize属性限制的长度,如果超过这个限制,日志消息将会被拆分并分多次写入EventLog。
三、EventLogLoggerProvider
EventLogLogger由对应的EventLogLoggerProvider来提供,下面的代码体现了这个类型完整的定义。我们可以调用如下所示的三个扩展方法AddEventLog来创建相应的EventLogLoggerProvider并将其注册到指定的LoggerFactory之上,我们可以通过这个方法指定用于提供或者辅助创建EventLog的EventLogSettings对象和最低日志等级。
1: public class EventLogLoggerProvider : ILoggerProvider, IDisposable
2: {
3: private readonly EventLogSettings _settings;
4: public EventLogLoggerProvider() : this(null)
5: {}
6:
7: public EventLogLoggerProvider(EventLogSettings settings)
8: {
9: _settings = settings;
10: }
11:
12: public ILogger CreateLogger(string name)
13: {
14: return new EventLogLogger(name, _settings ?? new EventLogSettings());
15: }
16:
17: public void Dispose()
18: {}
19: }
20:
21: public static class EventLoggerFactoryExtensions
22: {
23: public static ILoggerFactory AddEventLog(this ILoggerFactory factory);
24: public static ILoggerFactory AddEventLog(this ILoggerFactory factory, EventLogSettings settings);
25: public static ILoggerFactory AddEventLog(this ILoggerFactory factory, LogLevel minLevel);
26: }
我们同样通过一个简单的控制台应用来演示针对EventLog的日志记录。我们首选创建一个空的控制台应用,并在project.json中添加所需的依赖。由于针对EventLog的日志记录只适用于.NET Framework应用,所以我们仅仅为应用定义了一个针对.NET Framework 4.6.1(net461)的框架。
1: {
2: ...
3: "dependencies": {
4: "Microsoft.Extensions.DependencyInjection" : "1.0.0",
5: "Microsoft.Extensions.Logging" : "1.0.0",
6: "Microsoft.Extensions.Logging.EventLog" : "1.0.0"
7: },
8:
9: "frameworks": {
10: "net461": {
11: "frameworkAssemblies": {
12: "System.Runtime": {
13: "type": "build"
14: }
15: }
16: }
17: }
18: }
我们编写了下面这段程序来完成针对EventLog的日志记录。如下面的代码片段所示,我们首先为即将写入的日志创建了一个名为“Demo”的Event Source(它一般代表日志被写入的应用或者服务的名称)。接下来我们采用依赖注入的方式创建了一个LoggerFactory对象,并调用扩展方法AddEventLog创建了一个EventLoggerProvider对象并将其注册到LoggerFactory上。我们在调用这个AddEventLog方法时指定了一个EventLogSettings对象,并将其SourceName属性设置为“Demo”。我们最终利用这个LoggerFactory对象创建出对应的Logger,并利用它写入了一条等级为Error的日志。
1: public class Program
2: {
3: public static void Main(string[] args)
4: {
5: if(!EventLog.SourceExists("Demo"))
6: {
7: EventLog.CreateEventSource("Demo", "Application");
8: }
9:
10: new ServiceCollection()
11: .AddLogging()
12: .BuildServiceProvider()
13: .GetService<ILoggerFactory>()
14: .AddEventLog(new EventLogSettings { SourceName = "Demo" })
15: .CreateLogger<Program>()
16: .LogError("数据库连接失败(数据库:{ Database},用户名:{ User})", "TestDb", "sa");
17: }
18: }
由于上面这段程序涉及到Event Source查看和创建,所以需要在管理员权限下才能正常运行。程序运行后查看Event Viewer,我们将会看到被写入的这条日志消息。如图10所示,由于我们调用扩展方法AddEventLog时提供的EventLogSettings并没有显式指定EventLog名称,所以我们的日志默认会写入Application这个EventLog。
[1] Windows默认提供了三种EventLog,分别是Application、System和Security,应用产生的日志只能写到Application和System日志中,Security日志是只读的。除了这三种EventLog,我们还可以为应用创建独立的EventLog。
.NET Core的日志[1]:采用统一的模式记录日志
.NET Core的日志[2]:将日志写入控制台
.NET Core的日志[3]:将日志写入Debug窗口
.NET Core的日志[4]:利用EventLog写日志
.NET Core的日志[5]:利用TraceSource写日志
转载于:https://www.cnblogs.com/artech/p/logging-for-net-core-04.html
.NET Core的日志[4]:将日志写入EventLog相关推荐
- .NET Core的日志[2]:将日志输出到控制台
对于一个控制台应用,比如采用控制台应用作为宿主的ASP.NET Core应用,我们可以将记录的日志直接输出到控制台上.针对控制台的Logger是一个类型为ConsoleLogger的对象,Consol ...
- .Net Core with 微服务 - Seq 日志聚合
上一次我们介绍并演示了如果使用 Consul 做为我们微服务的注册中心,来实现服务的注册与发现.那么本次我们讲会演示如何做日志聚合.日志聚合比较常用的有 ELK 等,但是这次我想要介绍的是一款比较小众 ...
- .NET Core + K8S + Loki 玩转日志聚合
Grafana loki 1. Intro 最近在了解日志聚合系统,正好前几天看到一篇文章<用了日志系统新贵Loki,ELK突然不香了!>,所以就决定动手体验一下.本文就带大家快速了解下L ...
- Net Core平台灵活简单的日志记录框架NLog+Mysql组合初体验
Net Core平台灵活简单的日志记录框架NLog初体验 前几天分享的"[Net Core集成Exceptionless分布式日志功能以及全局异常过滤][https://www.cnblog ...
- Net Core平台灵活简单的日志记录框架NLog+SqlServer初体验
Net Core平台灵活简单的日志记录框架NLog+SqlServer初体验 前几天分享的"[Net Core平台灵活简单的日志记录框架NLog+Mysql组合初体验][http://www ...
- 【愚公系列】2022年12月 .NET CORE工具案例-PLG轻量级日志可视化服务
文章目录 前言 1.Serilog简介 2.Grafana简介 3.Loki是什么 一.Serilog对接Grafana轻量级日志可视化服务 1.Grafana部署 2.Loki部署 3.promta ...
- asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程...
最近在学习张善友老师的NanoFabric 框架的时了解到Exceptionless : https://exceptionless.com/ !因此学习了一下这个开源框架!下面对Exceptionl ...
- hbase 预写日志_HDInsight HBase 加速写入现已正式发布
HDInsight HBase 加速写入现已正式发布. 要点 Apache HBase 和 Phoenix 的写入性能提升多达 9 倍. 非常适合 Azure Data Lake Storage Ge ...
- asp.net core 多端口监听日志服务
1 配置多个端口监听 HostingAbstractionsWebHostBuilderExtensions. public static IWebHostBuilder UseUrls(this I ...
最新文章
- 为学Linux,我看了这些书
- AFNetworking 3.0 发送soap到webservice
- PHP实现图片压缩的两则实例(转)
- Windows平台基于RTMP实现一对一互动直播
- php面向对象有哪三种访问控制模式,第三节 访问控制的实现
- ggplot2作图详解:标尺(scale)设置
- Flutter之Binding简单梳理
- word转pdf公式乱码_MathType转换成pdf符号丢失或乱码怎么办
- SAS means 过程帮助
- 共享打印机服务器系统64位,win7系统64位和winXP 32位共享网络打印机的操作方法...
- Java使用策略模式实现聚石塔接口调用
- 我心中的超短系统之人气、情绪、大局观、仓控
- 关于java中判断一个点是否在一个长方形内和一个长方形是否包含另一个长方形或者两个相重叠的问题。
- 系统架构设计的一点思考
- JavaScript实现微信聊天烟花效果
- JavaScript 进阶篇的学习~
- Quaternion to angular velocity. 四元数 角速度
- C. Chocolate Bunny
- char* strlen()学习
- nodejs express搭建服务器(爬虫知乎精华帖,个人学习用)一 爬取所有话题类型
热门文章
- 企业网络推广方法浅析如何提高网站的点击率和访问量呢?
- 浅析网站开发的未来前景如何?
- 浅析企业网站建设潜在价值有哪些?
- 猜拳小程序c语言编程,无聊的时候写的猜拳小程序
- 计算机CPU哪家好,2019年电脑cpu排行榜_电脑CPU哪个好 电脑CPU排行榜2019
- 求助matlab分解质因数,Matlab
- ida android sign加密,最右sign-v2签名算法追踪及逆向还原
- Ciruy英雄谭 Chapter 1 序章
- 开发日记-20190702 关键词 读书笔记《Linux 系统管理技术手册(第二版)》DAY 8
- Deep Belief Network简介——本质上是在做逐层无监督学习,每次学习一层网络结构再逐步加深网络...