3

我正在尝试使用事件源 (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"
    }

这是我目前正在生成希望通过事件流处理的事件的方法。目前,这确实出现在应用程序洞察力中,但是我相信我的实现很糟糕,因为我在运行时在输出窗口中看到下面的消息。

Event 方法的参数与 WriteEvent 方法的参数不匹配。这可能会导致事件显示不正确。

    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);
 }`

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

非常感谢。

4

1 回答 1

6

这里有两个不同的问题。一个是您得到的错误,另一个是异常元数据的 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 属性具有 value Message = "{0} - {1}, {2}",但您只为方法提供了 2 个参数(字符串 operationType 和字符串 Shark)。因此错误。这就是为什么我将其更改为Message = "{0} - {1}"

有一些特定的规则可以让它工作。从文档

当您在 EventSource 派生类中实现标识为 ETW 事件的方法时。您必须调用基类 WriteEvent 方法,传递 EventId 和与已实现方法相同的参数

事件流配置

这里是最大的问题。该类EventSource不允许您使用WriteEvent. 这包括一个Exception. 从文档

如果事件有额外的数据,这些应该作为参数传递。目前仅允许将原始类型、日期时间和字符串与事件一起记录。

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

我想你有几个选择。

一种是使用 EventSource.Write 方法https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.write(v=vs.110).aspx如果您正在使用这应该很好用.NET Core,虽然老实说——我还没有测试过它。不幸的是,对于完整框架,框架中有一个错误会阻止 EventFlow 正确读取事件级别,因此如果您使用完整(桌面)框架,则不推荐使用这种方法。

第二种选择是使用不同的日志库(例如 Serilog),它允许您将任意对象传递到 EventFlow。

另一种选择是使用自定义 EventFlow 输入。这应该不像 AI 的自定义输出那么麻烦。我认为您甚至可以将它与您的 EventSource 集成,例如通过使 EventSource 实现 IObservable 并使用 [NonEvent] 方法来引发携带异常对象的事件。这样,您将只有一个日志 API,即您的 EventSource,供应用程序使用。

我的 2 美分

我的建议(我最终这样做了):忘记 EventSource 并使用另一个日志库。使用 EventSource 最好的部分是它具有结构化日志记录功能。我最终使用了具有此功能的SeriLog 。它确实支持将非原始类型写入日志。EventFlow 也支持将 SeriLog 作为输入,或者您可以为将数据发送到 Application Insights 的 SeriLog配置Application Insights (AI) 接收器。

如果您决定选择该选项,可以查看我的实现

于 2017-06-08T18:39:11.577 回答