在 EventSource 中使用 System.Exception 对象



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

事件流库似乎要求我将完整的 System.Exception 对象传递给事件流,以便将其成功分类为应用程序见解中的异常事件。

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

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

以下是我当前生成事件的方法,我希望通过事件流处理该事件。目前,这确实出现在应用程序见解中,但是我认为我的实现效果很差,因为我在运行时在输出窗口中看到下面的消息。

事件方法的参数

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

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 对象并传递到应用程序见解的正确方法。

非常感谢。

这里有两个单独的问题。一个是您收到的错误,另一个是异常元数据的事件流配置。我将讨论这两个问题。

错误

使用[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 属性的值为Message = "{0} - {1}, {2}",但您只为该方法提供了 2 个参数(字符串操作类型和字符串鲨鱼)。因此错误。这就是为什么我把它改成Message = "{0} - {1}"

为了使它工作,有一些特定的规则。从文档中:

在事件源派生类中实现标识为 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中。

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

我的2美分

我的建议(我最终做到了):忘记 EventSource 并使用另一个日志记录库。使用事件源最好的部分是它具有结构化日志记录功能。我最终使用了具有此功能的SeriLog。它支持将非基元类型写入日志。EventFlow 也支持 SeriLog 作为输入,或者你可以为 SeriLog 配置应用程序见解 (AI) 接收器,将数据发送到应用程序见解。

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

最新更新