9

语义日志应用程序块 (SLAB) 对我非常有吸引力,我希望在我正在编写的大型复合应用程序中使用它。要使用它,需要编写一个派生自“EventSource”的类,并在类中为他们想要记录为类型事件的每个事件包含一个方法,而不是简单的字符串。

像我这样的应用程序可能有数百个这样的事件。我可以有一个基于“EventSource”的类,其中只有一个事件“SomethingHappened”,并通过它记录所有内容,在努力和准确度范围的一个极端,我可以为我执行的每个操作都有一个事件。

在我看来,为不同的功能领域提供 EventSource 衍生产品是个好主意。该应用程序本身对业务逻辑知之甚少;这些都是由 MEF 插件模块提供的,所以我可以有用于引导、安全、配置更改等的事件源,并且任何插件模块都可以为它想要记录的任何事件定义一个事件源。

这是一个好的策略,还是许多EventSource派生记录器是不受欢迎的应用程序功能?

4

4 回答 4

5

从你的问题

...我希望在我正在编写的大型复合应用程序中使用它...

我可以推断出大是指在单个开发人员的上下文中。在这种情况下,您可以从 EventSource 派生并将您可能想要的所有事件添加到该类中。为复合应用程序的每个部分创建一个额外的 EventSource 派生类没有多大意义,因为它会污染已经注册了 2K 提供程序的事件源注册数据库。除此之外,如果您需要记住 20 个您需要启用的 guid,以便通过多个层遵循您的应用程序逻辑,则很难为您的应用程序启用日志记录。

一个折衷方案是在您的 EventSource 类中定义一些通用事件,例如

public void WriteViolation(string Subsystem, string Message, string Context)

您在组件中的每个组件都有一个记录器类

public static class NetworkLogger
{
   public static void Violation(string message)
   {
      GenericSource.Instance.Violation("Network", message, NetworkContext.Current);
   }
}

public static class DatabaseLogger
{
  public static void Violation(string message)
  {
      GenericSource.Instance.Violation("Database", message, DBContext.Current);
  }
}

这样,您可以保持记录器组件的特定性,并且可以在必要时自动将上下文信息添加到通用事件中。另一种方法是在您的应用程序跟踪中使用您的跟踪方法进入/离开、信息、警告、错误,而您的 EventSource 派生类只知道这些事件。当您为每个跟踪条目添加类型名称 + 方法名称时,您可以在 WPA 中按命名空间和按类进行过滤,以查看您在做什么。.NET 4.0 的语义跟踪中显示了一个示例。对于大型应用程序,您可以在您的机器上签出文件

C:\Windows\Microsoft.NET\Framework\v4.0.30319\CLR-ETW.man

您可以使用 Windows SDK 中的 ecmangen.exe 打开它,以获得一个不错的 GUI 来查看事件的结构。.NET 只定义了两个事件提供程序。许多事件通过关键字分组,以启用 .NET 的特定方面,例如 GC、Loader、Exceptions,...。这很重要,因为您可以在启用提供程序特定关键字时传递给它以仅启用大型提供程序的某些事件.

您还可以查看 Microsoft.Windows.ApplicationServer.Applications.45.man 以了解 Workflow 人员如何看待 ETW 事件。这应该有助于找到自己的方式。与您如何准确地构建事件无关,因为真正的测试是在客户站点发现生产错误。您很有可能需要进行多次迭代,直到找到正确的平衡点来记录/跟踪有助于诊断现场故障的相关信息。

于 2014-04-11T19:46:41.277 回答
1

这有点挥手,因为它太长了,无法发表评论。但是模板和工厂服务怎么样?

然后这不会改变,您在应用程序启动和加载插件后绑定所有内容。

interface IReportable
{
    void Report(object param);
}

interface IKernel
{
    T Get<T>();
}

class EventSource2 : EventSource
{
    private IKernel _factory;

    public EventSource2(IKernel factory)
    {
        _factory = factory;
    }

    public void Report<TReportable>(object param = null) where TReportable : IReportable
    {
        var reportable = _factory.Get<TReportable>();

        reportable.Report(param);

        //... Do what you want to do with EventSource
    }
}
于 2014-04-11T19:01:50.967 回答
0

将事件逻辑分组到不同的较小提供程序(EventSource 类)中,而不是到 1 个大文件中。

这样做的好处是您可以仅在特殊情况下为您关心的提供者启用事件。

于 2014-04-11T18:50:10.190 回答
0

不要将 EventSource 视为您可能在应用程序中执行的每个可能的日志事件的列表。请记住,有一些方法可以使用关键字和详细程度/事件级别来过滤您的事件。您甚至可以进一步深入并使用操作码和任务。SLAB 1.1 版支持 ActivityID 和 RelatedActivityID。本周早些时候发布的2.0 版 ( https://slab.codeplex.com/wikipage?title=SLAB2.0ReleaseNotes&version=2 ) 现在支持进程和线程 ID。

举个例子,我有一个非常小的 EventSource 派生类,并有 StartLog、LogStatus、StopLogging、LogError、LogDebug 和 CreateDump 的方法,前三个使用相同的事件级别,但由于格式不同而使用不同的事件 ID,其余的那些使用不同的事件级别,所以我不会调试或创建转储,除非我使用配置文件设置动态启用它。关键是我可以使用来自 asp.net 站点以及类库或控制台应用程序的相同方法。不要忘记这仅定义了日志记录事件。您仍然必须让接收器订阅该事件,从而为您提供更多可能性。您可以将调试消息发送到文件,将错误消息发送到数据库和/或电子邮件。可能性是无止境。

最后一件事。当我进行测试时,我以为我把自己画到了一个角落,发现多个程序集正在记录到同一个文件,因为它们使用相同的事件方法(因此相同的事件 ID、关键字、事件级别等)。我修改了我的代码以传递调用程序集名称,该名称现在在确定是否应写入日志消息(来自配置文件设置)和写入位置(基于程序集名称的日志文件)时用于过滤进程。希望这可以帮助!

于 2014-07-08T17:14:11.997 回答