如何为语义化日志应用程序块组织EventSources?

9
“语义日志应用程序块(SLAB)”对我来说非常吸引,我希望在我正在编写的大型组合应用程序中使用它。要使用它,需要编写一个继承自“EventSource”的类,并在该类中为每个要记录的事件包括一个方法,作为一个类型化的事件(与简单字符串不同)。
像我的应用程序这样的应用程序可能有数百个此类事件。我可以有一个基于“EventSource”的类,只有一个事件“SomethingHappened”,并通过它记录所有内容,在努力和精度谱的极端端点之一,也可以为每个操作定义一个事件。
对于不同的功能区域,使用“EventSource”派生类似乎是个好主意。该应用程序本身几乎没有任何业务逻辑;所有的业务逻辑都由MEF插件模块提供,因此我可以为引导、安全性、配置更改等设置事件源,任何插件模块都可以定义其想要记录的任何事件的事件源。
这是一个好策略,还是许多派生的日志记录器是不可取的应用程序特性?
4个回答

5
从您的问题中我可以看出,您希望在您正在编写的大型组合应用程序中使用它。在这种情况下,您可以从EventSource派生并将所有可能需要的事件添加到该类中。为每个组件应用程序创建一个额外的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中按类进行分组以查看您正在执行的操作。示例在Semantic Tracing For .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事件。这应该有助于找到自己的方式。重要的不是你如何确切地构造你的事件,而是在客户现场找到生产故障的真正测试。很可能需要进行几次迭代,直到找到正确的平衡,以记录/跟踪有助于诊断现场故障的相关信息。

1
不,整个团队大约有五名开发人员。我是唯一一个现在编写 WPF 的人,但另一个人正在包装200多个 Delphi 模块作为插件组件,然后我们三个人将开始将这些模块集转换为更适用的 WPF 组件。 - ProfK

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
    }
}

0

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

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


0
不要把EventSource看作是你的应用程序中可能执行的每个可能日志事件的列表。请记住,可以使用关键字和详细程度/事件级别来过滤事件。您甚至可以进一步深入并使用OpCodes和Tasks。 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、关键字、事件级别等)。我修改了我的代码,传递了调用程序集名称,该名称现在在过滤器处理中使用,以确定是否应写入日志消息(从配置文件设置)以及在哪里(基于程序集名称写入日志文件)。希望这能帮助到您!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接