如何通过 AppSettings 设置 Application Insights for Serilog 的遥测配置

Vin*_*ter 13 .net c# serilog azure-application-insights asp.net-core

对于我的 ASP.NET 5 Web 项目,我想通过 Serilog 登录到 Application Insights。现在我终于把一切都搞定了,但我不敢相信这是他们要走的路。我希望你能帮助我改进它。

我看到的主要问题是 Application Insights 的 Instrumentation Key 都是在 appsettings.json 的 Serilog 和 ApplicationInsights 部分中配置的。我希望 Serilog 使用默认/活动客户端(和配置),但它似乎根据自己的配置创建第二个客户端。

https://github.com/serilog/serilog-sinks-applicationinsights上的文档说:

如上所述,您还可以传递检测密钥,但不鼓励这样做

如果我从 appsettings.json 的 Serilog 部分中删除 InstrumentationKey 设置,它不会再将任何 Serilog 语句记录到 Application Insights。为了解决这个问题,我看到你可以使用.WriteTo.ApplicationInsights(TelemetryConfiguration.Active, TelemetryConverter.Traces),但我不想要硬编码配置,更喜欢通过 appsettings.json 来完成。另外,我担心有两个客户端/配置,不会提供最佳性能。

现在,有没有什么方法可以通过 appsettings.json 进行配置,而不必复制检测密钥?

程序.cs

public static void Main(string[] args)
{
    LoggingExtensions.SetupLoggerConfiguration(AppName, AppVersion);

    try
    {
        Log.Information("Starting web host for {0}", AppName);
        CreateHostBuilder(args).Build().Run();
    }
    catch (Exception ex)
    {
        Log.Fatal(ex, "Host terminated unexpectedly");
    }
    finally
    {
        Log.CloseAndFlush();
    }
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseSerilog((hostBuilderContext, loggerConfiguration) =>
        {
            loggerConfiguration.ConfigureBaseLogging(
                hostBuilderContext.Configuration, AppName, AppVersion);
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

public static string AppName => typeof(Program).Assembly.GetName().Name;
public static Version AppVersion => typeof(Program).Assembly.GetName().Version;
Run Code Online (Sandbox Code Playgroud)

启动.cs

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddApplicationInsightsTelemetry(Configuration["APPINSIGHTS_CONNECTIONSTRING"]);
    ...
}
Run Code Online (Sandbox Code Playgroud)

日志扩展.cs

internal static void SetupLoggerConfiguration(string appName, Version appVersion)
{
    var configuration = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json")
        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true)
        .Build();
    
    Log.Logger = new LoggerConfiguration()
        .ConfigureBaseLogging(configuration, appName, appVersion)
        .CreateLogger();
}

internal static LoggerConfiguration ConfigureBaseLogging(
    this LoggerConfiguration loggerConfiguration,
    IConfiguration configuration,
    string appName,
    Version appVersion
)
{
    loggerConfiguration
        .ReadFrom.Configuration(configuration)
        .Enrich.WithProperty("ApplicationVersion", appVersion.ToString())
        .Enrich.WithProperty("ApplicationName", appName);

    return loggerConfiguration;
}
Run Code Online (Sandbox Code Playgroud)

HomeController.cs

private readonly ILogger<HomeController> _logger;

public HomeController(ILogger<HomeController> logger)
{
    _logger = logger;
}

public ActionResult Index()
{
    _logger.LogInformation("Home page visit");
    return View();
}
Run Code Online (Sandbox Code Playgroud)

应用程序设置.json

{
  "Serilog": {
    "Using": [
      "Serilog.Sinks.Console",
      "Serilog.Sinks.ApplicationInsights"
    ],
    "MinimumLevel": {
      "Default": "Information"
    },
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
        }
      },
      {
        "Name": "ApplicationInsights",
        "Args": {
          "restrictedToMinimumLevel": "Information",
          "instrumentationKey": "xxx",
          "telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights"
        }
      }
    ],
    "Enrich": [
      "FromLogContext",
      "WithMachineName",
      "WithThreadId"
    ]
  },
  "ApplicationInsights": {
    "ConnectionString": "InstrumentationKey=xxx;IngestionEndpoint=https://xxx.in.applicationinsights.azure.com/"
  }
}
Run Code Online (Sandbox Code Playgroud)

更新1

似乎 ApplicationInsights 接收器依赖于TelemetryConfiguration.Active已弃用的并且可能未在 .NET 5 中设置的。 https://github.com/serilog/serilog-sinks-applicationinsights/issues/141

目前,我使用了https://github.com/serilog/serilog-sinks-applicationinsights/issues/121#issuecomment-798849183的解决方案,但是如果有人有更好的解决方案,请告诉我!

更新2

现在在https://github.com/serilog/serilog-sinks-applicationinsights/issues/156找到了更好的解决方案 可以通过在startup.csTelemetryConfiguration.Active中设置此选项来使用 已弃用的解决方案:

services.AddApplicationInsightsTelemetry(opt => opt.EnableActiveTelemetryConfigurationSetup = true);
// No need to set InstrumentationKey here as you can do this by setting 
// { "ApplicationInsights": { "InstrumentationKey": "xxx" } }
// in appsettings.json
Run Code Online (Sandbox Code Playgroud)

还要在Program.cs顶部添加以下内容,如https://nblumhardt.com/2020/10/bootstrap-logger/中所述

Log.Logger = new LoggerConfiguration()
                .WriteTo.Console()
                .CreateBootstrapLogger();
Run Code Online (Sandbox Code Playgroud)