在 EventSource 中使用 System.Exception 对象

Using a System.Exception Object in EventSource

我正在尝试使用事件源 (Microsoft.Diagnostics.EventFlow.Inputs.EventSource) 创建一个事件,该事件由事件流 (Microsoft.Diagnostic.EventFlow) 处理并且其输出传递给 Application Insights (Microsoft.Diagnostics.EventFlow.Outputs.ApplicationInsights) 进行分析。

事件流库似乎要求我将完整的 System.Exception 对象传递给事件流,以便在 Application Insights 中将其成功归类为异常事件。

这是我在事件流中为异常使用的过滤器:

    {
      "type": "metadata",
      "metadata": "exception",
      "include": "EventId == 21",
      "exceptionProperty": "shark"
    }

这是我目前正在生成我希望使用事件流处理的事件的方法。目前这确实出现在 application insights 中,但是我相信我实施得不好,因为我在运行时的输出 window 中看到下面的消息。

The parameters to the Event method do not match the parameters to the WriteEvent method. This may cause the event to be displayed incorrectly.

    private const int TestExceptionEventId = 21;
    [NonEvent]
    public void TestException(string operationType, Exception ex)
    {
        string shark = ex.ToString();
        TestException(operationType, shark);
        WriteEvent(TestExceptionEventId, operationType, ex);
    }

    [Event(TestExceptionEventId, Level = EventLevel.Error, Message = "{0} - {1}, {2}", Keywords = Keywords.Exception)]
    public void TestException(string operationType, string shark)
    {

    }

这是触发记录事件的方法:

 //EXCEPTION
 //id = 21
 try
 {
     int value = 1 / int.Parse("0");
 }
 catch (DivideByZeroException exception)
 {
     //id = 21
     _eventSource.TestException("hello", exception);
 }`

任何人都可以清楚地说明实现这个的正确方法以及通过事件流传递 System.Exception 对象到 Application Insights 的正确方法是什么。

非常感谢。

这里有两个不同的问题。一个是您收到的错误,另一个是异常元数据的 EventFlow 配置。我会解决这两个问题。

错误

[Event] 属性修饰的方法是应该调用 WriteEvent 的方法。例如:

private const int TestExceptionEventId = 21;

[NonEvent]
public void TestException(string operationType, Exception ex)
{
    string shark = ex.ToString();
    TestException(operationType, shark);
}

[Event(TestExceptionEventId, Level = EventLevel.Error, Message = "{0} - {1}", Keywords = Keywords.Exception)]
public void TestException(string operationType, string shark)
{
    WriteEvent(TestExceptionEventId, operationType, shark);
}

注意:您的原始消息 属性 具有值 Message = "{0} - {1}, {2}",但您仅向该方法提供了 2 个参数(字符串 operationType 和字符串 shark)。因此错误。这就是为什么我将其更改为 Message = "{0} - {1}"

有一些特定的规则才能使其正常工作。来自 docs:

When you implement a method that is identified as an ETW event in an EventSource-derived class. You must call the base class WriteEvent method passing the EventId and the same arguments as the implemented method

EventFlow 配置

这里是最大的问题。 EventSource class 不允许您使用 WriteEvent 编写非基元。其中包括 Exception。来自 docs:

If the event has additional data, these should be passed as arguments. Currently only primitive types, DateTime, and string are allowed to be logged with the event.

GitHub 存储库中有一个 issue 概述了您的可能性:

I think you have a few options.

One is to use EventSource.Write method https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.write(v=vs.110).aspx This should work well if you are using .NET Core, although I will be honest--I haven't tested it. Unfortunately with full framework there is a bug in the framework that prevents EventFlow from reading the event level correctly, so it is not a recommended way if you are using full (desktop) framework.

Second option is to use a different logging library (e.g. Serilog) that allows you to pass arbitrary objects into EventFlow.

Yet another option is to use custom EventFlow input. That should be not nearly as troublesome as a custom output for AI. I think you could even integrate it with your EventSource e.g. by making the EventSource implement IObservable and using [NonEvent] methods to raise events that carry exception objects. This way you will have just one logging API, your EventSource, for the application to use.

我的2美分

我的建议(我最终这样做了):忘记 EventSource 并使用另一个日志记录库。使用 EventSource 最好的部分是它具有结构化日志记录这一事实。我最终使用 SeriLog that features this as well. It does support non-primitive types to be written to the log. EventFlow supports SeriLog as an input as well or you can configure the Application Insights (AI) sink 将数据发送到 Application Insights 的 SeriLog。

如果您决定选择该选项,您可以查看 my implementation