.NET Core中如何在应用启动后设置Application Insights连接字符串?
我在多个.NET Core 7项目中使用Application Insights将日志遥测数据发送至Azure,多数项目通过Azure Key Vault避免在应用中存储连接字符串。但我的IoT项目需求特殊:
- 设备为无人值守类型,不会托管在Azure环境,无法使用Azure Key Vault
- 采用TPM认证连接Azure IoT Hub,必须先完成Hub连接,才能通过设备孪生属性获取Application Insights的连接字符串,项目本身不存储任何密钥或连接字符串
- 连接Hub前仅需将日志记录到本地文本文件,无需向Azure发送遥测数据
想明确以下问题:
- 是否可以在启动时初始化Application Insights,之后再补充设置连接字符串?
- 有没有办法不在启动时初始化服务,等需要的时候再启用?
- 如果不在启动时注册服务,而是在业务逻辑中创建
TelemetryClient,发送大量日志会不会有性能问题?
附常规场景下的Program.cs代码示例:
// Configure the Azure Key Vault. We action this straight away in order we can use it to get // the instrumentation key needed for app insights, which we need to setup before configuring builder.Configuration.AddAzureKeyVault( new Uri($"https://{builder.Configuration["AzureKeyVaultConfig:KeyVaultName"]}.vault.azure.net/"), new DefaultAzureCredential()); // Create the connection string for App Insights. var appInsightConnectionString = "InstrumentationKey=" + builder.Configuration["ApplicationInsights:InstrumentationKey"] + ";IngestionEndpoint=" + builder.Configuration["ApplicationInsights:IngestionEndpoint"]; // ----- Configure Application Insights Telemetry ----- Microsoft.ApplicationInsights.AspNetCore.Extensions.ApplicationInsightsServiceOptions aiOptions = new(); aiOptions.ConnectionString = appInsightConnectionString; // See appInsightConnectionString at the top of the page. aiOptions.EnableQuickPulseMetricStream = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableQuickPulseMetricStream"); aiOptions.EnableEventCounterCollectionModule = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableEventCounterCollectionModule"); aiOptions.EnableAppServicesHeartbeatTelemetryModule = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableAppServicesHeartbeatTelemetryModule"); aiOptions.EnableAzureInstanceMetadataTelemetryModule = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableAzureInstanceMetadataTelemetryModule"); aiOptions.EnableDependencyTrackingTelemetryModule = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableDependencyTrackingTelemetryModule"); aiOptions.EnableEventCounterCollectionModule = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableEventCounterCollectionModule"); aiOptions.EnableAdaptiveSampling = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableAdaptiveSampling"); aiOptions.EnableHeartbeat = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableHeartbeat"); aiOptions.AddAutoCollectedMetricExtractor = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("AddAutoCollectedMetricExtractor"); // Web App Options aiOptions.EnableRequestTrackingTelemetryModule = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableRequestTrackingTelemetryModule"); aiOptions.EnableAuthenticationTrackingJavaScript = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableAuthenticationTrackingJavaScript"); aiOptions.EnableDiagnosticsTelemetryModule = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableDiagnosticsTelemetryModule"); aiOptions.EnableActiveTelemetryConfigurationSetup = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableActiveTelemetryConfigurationSetup"); // Build the serive with the options from above. //builder.Services.AddLogging(loggingBuilder => loggingBuilder.AddFilter<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("", LogLevel.Trace)); builder.Services.AddApplicationInsightsTelemetry(aiOptions);
解决方案1:延迟设置Application Insights连接字符串
可以在启动时先初始化Application Insights但不提供连接字符串,等从IoT Hub获取到连接字符串后,再更新全局配置。具体步骤如下:
1. 启动时初始化AI服务(无连接字符串)
在Program.cs中创建不带连接字符串的配置选项,完成服务注册:
// 初始化AI选项,暂不设置连接字符串 var aiOptions = new Microsoft.ApplicationInsights.AspNetCore.Extensions.ApplicationInsightsServiceOptions(); // 保留需要的其他配置项(如采样规则、模块开关等) aiOptions.EnableQuickPulseMetricStream = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableQuickPulseMetricStream"); aiOptions.EnableAdaptiveSampling = builder.Configuration.GetSection("ApplicationInsights").GetValue<bool>("EnableAdaptiveSampling"); // ...其他配置项保持不变 // 注册AI服务 builder.Services.AddApplicationInsightsTelemetry(aiOptions);
2. 获取连接字符串后更新全局配置
当从IoT Hub设备孪生拿到Application Insights连接字符串后,通过依赖注入获取全局TelemetryConfiguration实例并更新:
// 假设这是获取到连接字符串后的逻辑 var appInsightsConnStr = "从设备孪生属性中获取的连接字符串"; // 从服务容器获取全局配置实例 var telemetryConfig = app.Services.GetRequiredService<TelemetryConfiguration>(); // 更新连接字符串 telemetryConfig.ConnectionString = appInsightsConnStr;
这种方式复用了全局的TelemetryConfiguration,所有自动收集的遥测数据(如请求、依赖)以及通过DI获取的TelemetryClient都会自动使用新的连接字符串,无需重新创建实例,性能与常规场景一致。
解决方案2:延迟注册Application Insights服务
如果不想在启动时就初始化AI服务,可以先仅配置本地日志,等获取到连接字符串后再完成AI服务的注册。
1. 启动时仅配置本地日志
在Program.cs中只添加本地文件日志,暂不注册AI服务:
builder.Logging.AddFile("logs/{Date}.txt"); // 其他本地日志配置(如日志级别、格式等)
2. 调整启动流程:先获取连接字符串再构建服务
对于无人值守设备,可以调整启动顺序,先完成IoT Hub连接并拿到AI连接字符串,再配置并构建Host:
// 第一步:连接IoT Hub,获取Application Insights连接字符串 var appInsightsConnStr = await GetAppInsightsConnStrFromIoTHubAsync(); // 第二步:配置Host并注册AI服务 var builder = Host.CreateDefaultBuilder(args); builder.ConfigureLogging(logging => { logging.AddFile("logs/{Date}.txt"); // 添加AI日志提供器 logging.AddApplicationInsights(appInsightsConnStr); }); builder.ConfigureServices(services => { var aiOptions = new Microsoft.ApplicationInsights.AspNetCore.Extensions.ApplicationInsightsServiceOptions { ConnectionString = appInsightsConnStr, // 其他配置项 EnableQuickPulseMetricStream = true, EnableAdaptiveSampling = true }; services.AddApplicationInsightsTelemetry(aiOptions); // 注册其他业务服务 }); var host = builder.Build(); await host.RunAsync();
这种方式的优势是AI服务只有在拿到有效连接字符串后才会初始化,避免了启动时的空配置问题,完全适配无人值守设备的启动逻辑。
关于单独创建TelemetryClient的性能问题
如果不通过DI注册,而是每次创建新的TelemetryClient,确实会产生额外性能开销:每个实例都会创建独立的通道和配置,发送大量日志时会导致连接数增加、资源消耗上升。因此强烈推荐通过DI复用全局的TelemetryConfiguration和TelemetryClient,上述两种解决方案均基于全局实例复用,性能与常规场景一致。
内容的提问来源于stack exchange,提问作者OJB1

