【问题标题】:How to add EventSource to a web application如何将 EventSource 添加到 Web 应用程序
【发布时间】:2017-03-31 15:30:00
【问题描述】:

我们终于在我们的服务结构集群中正确配置了 EventSource 和 ElasticSearch。现在我们有了想要将 EventSources 添加到与我们的服务结构应用程序交互的 Web 应用程序,以便我们可以在一个位置查看所有事件(应用程序日志)并通过 Kibana 过滤/查询。

我们的问题似乎与作为 exe 的服务结构应用程序和无状态的 .NET 4.6(不是 .net CORE)Web 应用程序之间的差异有关。在 service Fabric 中,我们将实例化管道的 using 语句放在 Program.cs 中并设置无限睡眠。

private static void Main()
{
        try
        {
            using (var diagnosticsPipeline = ServiceFabricDiagnosticPipelineFactory.CreatePipeline("CacheApp-CacheAPI-DiagnosticsPipeline"))
            {
                ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(Endpoint).Name);
                // Prevents this host process from terminating so services keeps running. 
                Thread.Sleep(Timeout.Infinite);
            }

如何在网络应用程序中执行此操作?这是我们用于 EventSource 的非 ServiceFabric 实现的管道代码。这就是我们正在使用的:

using (var pipeline = DiagnosticPipelineFactory.CreatePipeline("eventFlowConfig.json"))
    {
        IEnumerable ie = System.Diagnostics.Tracing.EventSource.GetSources();

        ServiceEventSource.Current.Message("initialize eventsource");

    } 

我们可以在 using 语句中看到管道并将事件发送到 ElasticSearch,但不能在它之外。所以问题是:

  1. 我们如何/在哪里放置 Web 应用程序的管道 using 语句?
  2. 我们是否需要在每次记录时实例化和销毁管道,或者是否有办法在无状态 Web 事件中重用该管道?这似乎会非常昂贵并且会损害性能。也许我们可以缓存管道?

这就是要点,如果您需要澄清,请告诉我。我看到很多用于客户端应用的 doco,但对于 Web 应用来说却不多。

谢谢, 格雷格

使用解决方案代码更新

DiagnosticPipeline 管道;

protected void Application_Start(Object sender, EventArgs e)
{
    try
    {
        pipeline = DiagnosticPipelineFactory.CreatePipeline("eventFlowConfig.json");   
        IEnumerable ie = System.Diagnostics.Tracing.EventSource.GetSources();
        AppEventSource.Current.Message("initialize eventsource");

    }
}

protected void Application_End(Object sender, EventArgs e)
{
    pipeline.Dispose();
}

【问题讨论】:

    标签: etw eventsource etw-eventsource


    【解决方案1】:

    假设 ASP.NET Core 初始化 EventFlow 管道的最简单方法是在 Program.cs Main() 方法中,例如:

    public static void Main(string[] args)
    {
        using (var pipeline = DiagnosticPipelineFactory.CreatePipeline("eventFlowConfig.json"))
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .UseApplicationInsights()
                .Build();
    
                host.Run();
        }
    }
    

    这利用了 host.Run() 将阻塞直到服务器关闭的事实,因此在接收和服务请求期间将存在管道。

    根据您使用的 Web 框架,情况可能会有所不同。例如。如果您使用的提供“设置”和“清理”挂钩,您可以在设置阶段创建一个诊断管道(并将对它的引用存储在某个成员变量中),然后在清理阶段处理它。例如,在 ASP.NET 经典中,您可以将代码放入 global.asax.cs 并利用 Application_OnStartApplication_OnEnd 方法。详情请见Application Instances, Application Events, and Application State in ASP.NET

    正如您所说,每次处理请求时都创建一个管道实例效率很低。确实没有充分的理由这样做。

    【讨论】:

    • 谢谢,但这不是 .net CORE,它是托管在 IIS 中的较旧的 Web 表单应用程序。在这些应用程序中没有“主要”。我可以使用 global.asax 吗? ——
    • 是的,global.asax 是我会尝试的。我在原始答案中添加了一些细节。
    • 那么我们就不会使用 using 语句了吗? Application_Start 有点像我们的 using 语句,我们将变量直接放入 on Start? var pipeline = DiagnosticPipelineFactory.CreatePipeline("eventFlowConfig.json");然后处理变量 Application_End。现在试试看
    • 呜呼!!!这行得通。我必须在 application_start 上方创建一个全局变量,然后将管道分配给该全局变量。然后我可以在不同的页面上使用管道。我在 application_end 事件中调用管道对象的 dispose 方法。