如何禁用Azure Functions默认Logger的Trace事件,保留Request/Dependency事件
Azure FunctionApp Trace日志重复发送至Application Insights问题处理
问题背景
在Azure FunctionApp中同时使用Serilog和默认Application Insights日志提供程序时,出现Trace日志重复发送至Application Insights的情况。当前服务集合包含两个日志提供程序:
- 默认Application Insights日志提供程序
- Serilog日志提供程序
若移除默认日志提供程序,虽能解决重复日志问题,但会导致Request、Dependency等遥测事件无法发送至Application Insights,且Serilog无法捕获这些事件。
核心疑问
- 能否仅禁用默认Application Insights日志提供程序的Trace事件,保留其他遥测事件的正常记录?
- 若上述方案不可行,能否让Serilog自身记录Request和Dependency事件?
已尝试操作
移除服务集合中的默认日志提供程序后,重复日志问题解决,但发现Function App依赖该提供程序发送Request和Dependency事件,移除后无法获取这类遥测数据。同时观察到配置中的部分键会自动启用默认日志提供程序,但目前只有默认提供程序能发送Request、Dependency事件。
Serilog注册代码
var telemetryConfiguration = new TelemetryConfiguration { ConnectionString = appSettings.application_insights_connection_string }; var logger = new LoggerConfiguration() .MinimumLevel.Debug() .WriteTo.Console() .Enrich.FromLogContext() .WriteTo.ApplicationInsights(telemetryConfiguration, TelemetryConverter.Traces) .CreateLogger(); builder.Services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(logger, dispose: true));
重复日志示例

第一条日志原始数据:
{ "name": "AppTraces", "time": "2023-10-17T00:37:50.5456099Z", "iKey": "25f0502c-1ad4-4f1d-bee2-f916bf75e51e", "tags": { "ai.cloud.roleInstance": "A0F00Z5Z220400C", "ai.location.ip": "0.0.0.0", "ai.internal.sdkVersion": "azurefunctionscoretools: 4.0.5413", "ai.internal.nodeName": "A0F00Z5Z220400C" }, "data": { "baseType": "MessageData", "baseData": { "ver": 2, "message": "Using the default storage provider: AzureStorage.", "severityLevel": "Information", "properties": { "HostInstanceId": "cc60e187-b5ae-4be8-a7b6-3bac2c17b77e", "Category": "Host.Triggers.DurableTask", "prop__{OriginalFormat}": "Using the default storage provider: AzureStorage.", "ProcessId": "29300", "LogLevel": "Information" } } } }
第二条日志原始数据:
{ "name": "AppTraces", "time": "2023-10-17T00:37:50.5546176Z", "iKey": "25f0502c-1ad4-4f1d-bee2-f916bf75e51e", "tags": { "ai.cloud.roleInstance": "A0F00Z5Z220400C", "ai.internal.sdkVersion": "dotnetc:2.21.0-429" }, "data": { "baseType": "MessageData", "baseData": { "ver": 2, "message": "Using the default storage provider: AzureStorage.", "severityLevel": "Information", "properties": { "MessageTemplate": "Using the default storage provider: AzureStorage.", "SourceContext": "Host.Triggers.DurableTask" } } } }
解决方案建议
针对疑问1:禁用默认AI日志提供程序的Trace事件
可以通过日志过滤规则实现,无需移除默认提供程序,两种配置方式可选:
- 代码层面配置
在注册日志服务时,添加过滤规则,让默认Application Insights日志提供程序不处理Trace级别日志,同时保留遥测收集能力:
builder.Services.AddLogging(loggingBuilder => { loggingBuilder.AddSerilog(logger, dispose: true); // 添加默认AI日志提供程序 loggingBuilder.AddApplicationInsights(telemetryConfiguration); // 过滤所有类别的Trace日志 loggingBuilder.AddFilter<ApplicationInsightsLoggerProvider>("", LogLevel.None); // 按需保留特定类别的非Trace日志(如业务需要) loggingBuilder.AddFilter<ApplicationInsightsLoggerProvider>("Microsoft", LogLevel.Information); });
- host.json配置
在host.json中添加日志过滤规则,直接限制默认AI日志提供程序的日志输出:
{ "logging": { "logLevel": { "Default": "Information", "Microsoft.ApplicationInsights.AspNetCore.Logging.ApplicationInsightsLoggerProvider": { "Default": "None" } } } }
此配置会让默认AI日志提供程序不再发送ILogger生成的Trace日志,但不会影响自动收集的Request、Dependency等遥测事件。
针对疑问2:让Serilog记录Request和Dependency事件
Serilog本身专注处理日志消息,若要捕获Request和Dependency这类遥测事件,需结合Application Insights的TelemetryClient实现,两种方式可选:
- 手动发送遥测
通过依赖注入获取TelemetryClient,在Function关键节点手动发送Request/Dependency遥测:
public class MyFunction { private readonly TelemetryClient _telemetryClient; private readonly ILogger<MyFunction> _logger; public MyFunction(TelemetryClient telemetryClient, ILogger<MyFunction> logger) { _telemetryClient = telemetryClient; _logger = logger; } [FunctionName("MyFunction")] public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req) { // 记录Request遥测 var requestTelemetry = new RequestTelemetry { Name = req.Path }; var operation = _telemetryClient.StartOperation(requestTelemetry); try { _logger.LogInformation("Function executed"); // 模拟记录Dependency遥测 var dependencyTelemetry = new DependencyTelemetry { Name = "SampleDependency", Target = "sample-target", Data = "sample-data", Duration = TimeSpan.FromMilliseconds(100), Success = true }; _telemetryClient.TrackDependency(dependencyTelemetry); return new OkObjectResult("Success"); } catch (Exception ex) { operation.Telemetry.Success = false; _telemetryClient.TrackException(ex); throw; } finally { _telemetryClient.StopOperation(operation); } } }
- 自定义Serilog遥测转换器
使用Serilog.Sinks.ApplicationInsights的自定义转换器,将带特定标记的日志转换为Request/Dependency遥测:
public class CustomTelemetryConverter : ITelemetryConverter { public IEnumerable<ITelemetry> Convert(LogEvent logEvent, IFormatProvider formatProvider) { if (logEvent.Properties.TryGetValue("RequestName", out var requestName)) { var requestTelemetry = new RequestTelemetry { Name = requestName.ToString().Trim('"'), Duration = logEvent.Properties.TryGetValue("Duration", out var duration) ? TimeSpan.Parse(duration.ToString().Trim('"')) : TimeSpan.Zero, Success = logEvent.Properties.TryGetValue("Success", out var success) ? bool.Parse(success.ToString().Trim('"')) : true }; yield return requestTelemetry; } else if (logEvent.Properties.TryGetValue("DependencyName", out var dependencyName)) { var dependencyTelemetry = new DependencyTelemetry { Name = dependencyName.ToString().Trim('"'), Target = logEvent.Properties.TryGetValue("Target", out var target) ? target.ToString().Trim('"') : "", Duration = logEvent.Properties.TryGetValue("Duration", out var duration) ? TimeSpan.Parse(duration.ToString().Trim('"')) : TimeSpan.Zero, Success = logEvent.Properties.TryGetValue("Success", out var success) ? bool.Parse(success.ToString().Trim('"')) : true }; yield return dependencyTelemetry; } else { // 默认转换为Trace遥测 yield return new TraceTelemetry(logEvent.RenderMessage(formatProvider), ConvertSeverityLevel(logEvent.Level)); } } private SeverityLevel ConvertSeverityLevel(LogEventLevel level) { return level switch { LogEventLevel.Verbose => SeverityLevel.Verbose, LogEventLevel.Debug => SeverityLevel.Verbose, LogEventLevel.Information => SeverityLevel.Information, LogEventLevel.Warning => SeverityLevel.Warning, LogEventLevel.Error => SeverityLevel.Error, LogEventLevel.Fatal => SeverityLevel.Critical, _ => SeverityLevel.Information }; } }
然后在Serilog配置中使用该转换器:
.WriteTo.ApplicationInsights(telemetryConfiguration, new CustomTelemetryConverter())
使用时只需在日志中添加对应属性,即可触发遥测转换:
_logger.LogInformation( "Request processed {RequestName} with duration {Duration}", "/api/myfunction", TimeSpan.FromMilliseconds(200));
内容的提问来源于stack exchange,提问作者ifg43
相关产品推荐
相关产品推荐

