You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何禁用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无法捕获这些事件。

核心疑问

  1. 能否仅禁用默认Application Insights日志提供程序的Trace事件,保留其他遥测事件的正常记录?
  2. 若上述方案不可行,能否让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事件

可以通过日志过滤规则实现,无需移除默认提供程序,两种配置方式可选:

  1. 代码层面配置
    在注册日志服务时,添加过滤规则,让默认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);
});
  1. 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实现,两种方式可选:

  1. 手动发送遥测
    通过依赖注入获取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);
        }
    }
}
  1. 自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 07:27:01