首页 > 解决方案 > 使用 Serilog 登录到事件查看器时动态设置 EventID

问题描述

目前,我已将记录器设置为记录到事件查看器,如下所示:

 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 的任何想法?在实例化记录器时,我需要有这个动态并且不设置为一个值。

提前致谢

标签: c#loggingevent-logserilogevent-viewer

解决方案


我能够通过以下步骤解决这个问题:

在实例化记录器时添加以下内容:

.WriteTo.EventLog("SourceInEventViewer", 
    "AreaInEventViewer", 
    formatProvider: new EventLogFormatProvider(),
    eventIdProvider: new EventIdProvider(),
    manageEventSource: true,
    restrictedToMinimumLevel: LogEventLevel.Information)

将以下类添加到项目中

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");

推荐阅读