使用 Serilog 登录到事件查看器时动态设置 EventID
Dynamically set EventID when logging to Event Viewer using Serilog
目前,我已经将我的记录器设置为像这样记录到事件查看器:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.EventLog("MySource", "EventViewerArea")
.CreateLogger();
当我登录时,我使用以下命令:
_logger.LogWarning(logText);
看起来好像我可以将 EventId 传递给 LogWarning 方法,所以我想在 运行 LogWarning/LogInformation 方法时设置它:
_logger.LogWarning(9876, logText);
但这不会覆盖事件查看器条目中的事件 ID。关于如何在记录时动态设置此 EventId 的任何想法?在实例化记录器时,我需要有这个动态而不是设置为一个值。
提前致谢
如果您查看 event log sink 的源代码,您会发现它使用 EventIdHashProvider
通过散列事件消息来生成唯一 ID。
您可以做的是在配置接收器时提供 IEventIdProvider
接口的实现,如下所示(这是 eventIdProvider: new CustomEventIdProvider()
添加的):
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.EventLog("MySource", "EventViewerArea", eventIdProvider: new CustomEventIdProvider())
.CreateLogger();
.LogWarnning()
来自 Microsoft.Extensions.Logging
。它实际上接受 EventId strcut,它具有来自 int.
的隐式转换
但是正如您所看到的,这个 id 从未在接收器中使用过。 EventId 用于轻松跟踪事件的身份,但我不确定是否有任何接收器正在重复使用此 ID ... EventLog
接收器没有。
我能够通过以下步骤解决此问题:
在实例化记录器时添加以下内容:
.WriteTo.EventLog("SourceInEventViewer",
"AreaInEventViewer",
formatProvider: new EventLogFormatProvider(),
eventIdProvider: new EventIdProvider(),
manageEventSource: true,
restrictedToMinimumLevel: LogEventLevel.Information)
将以下class添加到项目
using Newtonsoft.Json.Linq;
using Serilog.Events;
using Serilog.Sinks.EventLog;
using System;
using System.Linq;
namespace IndependentFile.Extensions
{
public class LoggerSetupExtensions
{
public class EventLogFormatProvider : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
return formatType == typeof(ICustomFormatter) ? this : null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
return arg.ToString();
}
}
public class EventIdProvider : IEventIdProvider
{
public ushort ComputeEventId(LogEvent logEvent)
{
var eventTypeProp = logEvent.Properties.FirstOrDefault(prop => prop.Key == "EventId");
if (eventTypeProp.Value == null)
{
return (ushort)LogValuesEnum.Unknown;
}
try
{
var val = eventTypeProp.Value;
string eventType = eventTypeProp.Value.ToString();
//this is not the right way to parse the logEventPropertyValue
var parseEventType = JObject.Parse(eventType);
var eventIdInt = parseEventType["Id"].ToString();
if (eventType == null) return (int)LogValuesEnum.Unknown;
var tryParseEventId = Enum.TryParse<LogValuesEnum>(eventIdInt, ignoreCase: true, out var res);
if (tryParseEventId)
{
return (ushort)res;
}
return (ushort)LogValuesEnum.Unknown;
}
catch(Exception exc)
{
return (ushort)LogValuesEnum.Unknown;
}
}
}
}
}
现在您可以使用日志并将您的事件 ID 传递给它:
_logger.LogInformation(LogValuesEnum.MyEnumVal, "My log message");
目前,我已经将我的记录器设置为像这样记录到事件查看器:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.EventLog("MySource", "EventViewerArea")
.CreateLogger();
当我登录时,我使用以下命令:
_logger.LogWarning(logText);
看起来好像我可以将 EventId 传递给 LogWarning 方法,所以我想在 运行 LogWarning/LogInformation 方法时设置它:
_logger.LogWarning(9876, logText);
但这不会覆盖事件查看器条目中的事件 ID。关于如何在记录时动态设置此 EventId 的任何想法?在实例化记录器时,我需要有这个动态而不是设置为一个值。
提前致谢
如果您查看 event log sink 的源代码,您会发现它使用 EventIdHashProvider
通过散列事件消息来生成唯一 ID。
您可以做的是在配置接收器时提供 IEventIdProvider
接口的实现,如下所示(这是 eventIdProvider: new CustomEventIdProvider()
添加的):
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.EventLog("MySource", "EventViewerArea", eventIdProvider: new CustomEventIdProvider())
.CreateLogger();
.LogWarnning()
来自 Microsoft.Extensions.Logging
。它实际上接受 EventId strcut,它具有来自 int.
的隐式转换
但是正如您所看到的,这个 id 从未在接收器中使用过。 EventId 用于轻松跟踪事件的身份,但我不确定是否有任何接收器正在重复使用此 ID ... EventLog
接收器没有。
我能够通过以下步骤解决此问题:
在实例化记录器时添加以下内容:
.WriteTo.EventLog("SourceInEventViewer",
"AreaInEventViewer",
formatProvider: new EventLogFormatProvider(),
eventIdProvider: new EventIdProvider(),
manageEventSource: true,
restrictedToMinimumLevel: LogEventLevel.Information)
将以下class添加到项目
using Newtonsoft.Json.Linq;
using Serilog.Events;
using Serilog.Sinks.EventLog;
using System;
using System.Linq;
namespace IndependentFile.Extensions
{
public class LoggerSetupExtensions
{
public class EventLogFormatProvider : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
return formatType == typeof(ICustomFormatter) ? this : null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
return arg.ToString();
}
}
public class EventIdProvider : IEventIdProvider
{
public ushort ComputeEventId(LogEvent logEvent)
{
var eventTypeProp = logEvent.Properties.FirstOrDefault(prop => prop.Key == "EventId");
if (eventTypeProp.Value == null)
{
return (ushort)LogValuesEnum.Unknown;
}
try
{
var val = eventTypeProp.Value;
string eventType = eventTypeProp.Value.ToString();
//this is not the right way to parse the logEventPropertyValue
var parseEventType = JObject.Parse(eventType);
var eventIdInt = parseEventType["Id"].ToString();
if (eventType == null) return (int)LogValuesEnum.Unknown;
var tryParseEventId = Enum.TryParse<LogValuesEnum>(eventIdInt, ignoreCase: true, out var res);
if (tryParseEventId)
{
return (ushort)res;
}
return (ushort)LogValuesEnum.Unknown;
}
catch(Exception exc)
{
return (ushort)LogValuesEnum.Unknown;
}
}
}
}
}
现在您可以使用日志并将您的事件 ID 传递给它:
_logger.LogInformation(LogValuesEnum.MyEnumVal, "My log message");