如何在C#中获取所有Windows事件日志(事件查看器日志)及其层次结构和友好名称的列表

时间:2016-06-06 16:21:25

标签: c# .net system.diagnostics etw event-viewer

我正试图从事件查看器中复制以下内容

enter image description here

我遇到了一些问题。首先,我得到的一些名字不是显示名称或友好名称。例如,对于“Microsoft Office Alerts”,我只是回到“OAlerts”。如何从“OAlerts”获得完整的“Microsoft Office Alerts”?

第二个问题是弄清楚层次结构。似乎我所能做的只是解析破折号,做一些最好的猜测。在API中似乎没有一种简单的方法可以解决这个问题。 GetLogNames只为您提供所有日志的平面列表

EventLogSession session = new EventLogSession();
List<string> logNames = new List<string>(session.GetLogNames());
foreach (string name in logNames)
{
   //EventLogConfiguration config = new EventLogConfiguration(name); //looks useful but doesn't give me any of the info i'm looking for.

   Console.WriteLine(name);
}         

1 个答案:

答案 0 :(得分:5)

此处的博客:The EventSource NuGet package and support for the Windows Event Log (Channel Support)有一个指向罕见EventSource User's Guide文档的链接,其中说明了这一点:

  

使用EventSourceAttribute的Name属性来提供   由ETW表示的ETW事件提供程序的描述性限定名称   你的活动来源。默认值是事件源的简称   类型,很容易导致冲突,因为ETW提供商名称共享   一个机器范围的命名空间。良好的提供者名称的示例   “<CompanyName>-<Product>-<Component>”。遵循这个3元素   约定将确保事件查看器在a中显示您的事件日志   逻辑文件夹层次结构:“Application and Services Logs/<CompanyName>/<Product>/<Component>“。

这往往表明破折号更像是一种约定而不是严格的要求(所以我相信你可以自己解析它)。请注意,博客仍然可以发表评论。

对于不匹配的名称,有一个未记录的 EvtIntGetClassicLogDisplayName 函数,可以获取事件查看器中显示的名称。以下是如何将它与会话和日志名称一起使用:

    static void Main(string[] args)
    {
        var session = new EventLogSession();
        foreach (string name in session.GetLogNames())
        {
            Console.WriteLine(GetDisplayName(session, name));
        }
    }

这是支持代码(因为它没有文档,使用风险自负,加上它似乎主要用于'OAlert'条目,所以我不确定它是否值得):

    public static string GetDisplayName(EventLogSession session, string logName)
    {
        var sb = new StringBuilder(512);
        int bufferUsed = 0;
        if (EvtIntGetClassicLogDisplayName(GetSessionHandle(session).DangerousGetHandle(), logName, 0, 0, sb.Capacity, sb, out bufferUsed))
            return sb.ToString();

        return logName;
    }

    private static SafeHandle GetSessionHandle(EventLogSession session)
    {
        return (SafeHandle)session.GetType().GetProperty("Handle", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(session);
    }

    [DllImport("wevtapi.dll", CharSet = CharSet.Unicode)]
    private static extern bool EvtIntGetClassicLogDisplayName(IntPtr session, [MarshalAs(UnmanagedType.LPWStr)] string logName, int locale, int flags, int bufferSize, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder displayName, out int bufferUsed);