ITelemetryInitializer.Initialize 在控制台应用程序中将 Serilog 与 ApplicationInsights 一起使用时从未被调用

ITelemetryInitializer.Initialize never being called when using Serilog with ApplicationInsights in Console application

我在我的 .NET Core 3.1 控制台应用程序中按如下方式配置 DI:

services.AddSingleton<ITelemetryInitializer, TelemetryInitializer>();
services.AddApplicationInsightsTelemetryWorkerService(instrumentationKey);

appSettings.json 我有:

"Serilog": {
  "Using": [
    "Serilog.Sinks.Console",
    "Serilog.Sinks.ApplicationInsights"
  ],
  "MinimumLevel": "Information",
  "WriteTo": [
    {
      "Name": "Console",
      "Args": {
        "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}",
        "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
      }
    },
    {
      "Name": "ApplicationInsights",
      "Args": {
        "restrictedToMinimumLevel": "Information",
        "InstrumentationKey": "...",
        "telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights",
        "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}",
        "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
      }
    }
  ],
  "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ]
}

Serilog配置如下:

Host.CreateDefaultBuilder(args)
    .UseSerilog((hostingContext, loggerConfiguration) =>
        loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration)
    )
    .UseConsoleLifetime()
    .Build()
    .Run()

我的初始化器class:

public class TelemetryInitializer : ITelemetryInitializer
{
    public void Initialize(ITelemetry telemetry)
    {
        telemetry.Context.Cloud.RoleName = "something-something";
    }
}

然而,当我使用 ILogger 登录时,Initialize 方法 而不是 被调用。如果我直接解析 TelemetryClient 并使用它登录,Initialize 调用。

我是否缺少 Serilog 的某些配置?

这似乎是 Serilog.Sinks.ApplicationInsights 的一个小故障。当从配置 (code reference) 初始化接收器时,它会创建一个新的 TelemetryClient,在注册的 TelemetryInitializer 可以与之关联之前会导致活动 TelemetryConfiguration

要让 TelemetryInitilizer 注入 Active 配置,它需要在 Serilog 初始化 App Insights 接收器之前创建一次 TelemetryClient 实例。否则尊重它就太迟了,因为在内部 AddApplicationInsightsTelemetryWorkerService 注册 TelemetryClient 为单例。所以下面是我的工作代码,它只是在初始化 Serilog 的 loggerConfiguration 之前对 TelemetryClient 进行了虚拟解析。

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddApplicationInsightsTelemetryWorkerService(instrumentationKey);
                    services.AddSingleton<ITelemetryInitializer, TelemetryInitializer>();
                    services.AddHostedService<Worker>();
                })
                .UseSerilog((hostingContext, serviceProvider, loggerConfiguration) => {
                    serviceProvider.GetRequiredService<TelemetryClient>(); // just a dummy resolve
                    loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration);
                })
                .UseConsoleLifetime();
    }

选项 2 是创建自定义 TelemetryConverter,它可以更新所需的上下文而不是使用 Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter。这将消除对初始化程序的依赖。

选项 3 是切换到基于代码的设置而不是配置,这将允许您传递 TelemetryClientTelemetryConfiguration 实例,例如 https://github.com/serilog/serilog-sinks-applicationinsights#configuring。但这可能不像基于配置的方法那样具有声明性。