Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何组织语义日志应用程序块的EventSources?_C#_Logging_Etw_Semantic Logging - Fatal编程技术网

C# 如何组织语义日志应用程序块的EventSources?

C# 如何组织语义日志应用程序块的EventSources?,c#,logging,etw,semantic-logging,C#,Logging,Etw,Semantic Logging,语义日志应用程序块(SLAB)对我很有吸引力,我希望在我正在编写的大型复合应用程序中使用它。要使用它,可以编写一个从“EventSource”派生的类,并在类中为每个要作为类型化事件记录的事件包含一个方法,而不是一个简单的字符串 像我这样的应用程序可能有数百个这样的事件。我可以有一个基于“EventSource”的类,只包含一个事件“SomethingOccessed”,并在努力和准确度范围的一个极端记录所有事件,我可以为我执行的每个操作都包含一个事件 在我看来,为不同的功能领域提供EventS

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

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

在我看来,为不同的功能领域提供EventSource衍生工具是一个好主意。应用程序本身几乎不了解业务逻辑;这一切都是由MEF插件模块提供的,因此我可以为bootsrapping、安全性、配置更改等提供事件源,并且任何插件模块都可以为它想要记录的任何事件定义事件源


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

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


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

这有点手工操作,因为注释太长。但是模板化和工厂服务怎么样

这样就不会改变,在应用程序启动时和加载插件后都会绑定所有内容

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
    }
}
接口可移植
{
无效报告(对象参数);
}
接口IKernel
{
T Get();
}
类EventSource2:EventSource
{
私人IKernel_工厂;
公共事件源2(IKernel工厂)
{
_工厂=工厂;
}
public void Report(object param=null),其中TReportable:IReportable
{
var reportable=_factory.Get();
可报告。报告(参数);
//…对EventSource执行您想要执行的操作
}
}
根据您的问题

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

我可以推断,在单个开发人员的上下文中,大型是指。在这种情况下,您可以从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);
  }
}
这样,您可以保持记录器组件的特定性,并在必要时自动将上下文信息添加到通用事件中。 另一种方法是在应用程序跟踪中使用,其中跟踪方法enter/leave、info、warning、error和EventSource派生类只知道这些事件。当您为每个跟踪条目添加类型名+方法名时,您可以在WPA中按名称空间过滤并按类分组,以查看您在做什么。示例如所示。 对于大型应用程序,您可以在计算机上签出该文件

C:\Windows\Microsoft.NET\Framework\v4.0.30319\CLR-ETW.man
您可以使用Windows SDK中的ecmangen.exe打开它,以获得一个漂亮的GUI来查看事件的结构。NET只定义了两个事件提供程序。许多事件通过关键字分组,以启用.NET的特定方面,例如GC、加载程序、异常等。。。。 这一点很重要,因为您可以在启用特定于提供程序的关键字时向其传递消息,以便仅启用大型提供程序的某些事件


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

不要将EventSource看作是应用程序中可能执行的所有日志事件的列表。请记住,可以通过使用关键字和详细程度/事件级别来过滤事件。您甚至可以进一步深入并使用操作码和任务。板的版本1.1支持ActivityID和RelatedActivityID。本周早些时候发布的2.0()版本现在支持进程和线程id

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

最后一件事。当我进行测试时,发现多个程序集记录到同一个文件中,因为它们使用相同的事件方法(因此使用相同的事件id、关键字、事件级别等),我觉得自己陷入了困境。我修改了代码,以传递调用程序集名称,在确定时,该名称现在用于筛选进程