Azure Functions日志写入Application Insights问题咨询
Azure Function 接入 Application Insights 问题排查
测试代码与基础配置
验证场景使用的函数代码如下:
public class AzureAppInsightsExplore { private readonly ILogger<AzureAppInsightsExplore> logger; public AzureAppInsightsExplore(ILogger<AzureAppInsightsExplore> logger) { this.logger = logger; } [FunctionName("AzureAppInsightsExplore")] public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { logger.LogInformation("C# HTTP trigger function processed a request."); int a = 0, b = 0; // 触发未处理除零异常 int c = a / b; return new OkObjectResult(string.Empty); } }
对应host.json配置:
{ "version": "2.0", "logging": { "applicationInsights": { "samplingSettings": { "isEnabled": true, "excludedTypes": "Request" } } } }
问题1:未处理异常在Application Insights中重复记录两次
这是In-process托管模型Azure Function的已知默认行为,不是配置错误:
- Functions运行时本身在函数执行管道层会捕获所有逃逸的未处理异常,自动生成1条错误日志
- Application Insights SDK默认开启自动异常收集,会从AppDomain未处理异常事件中再抓1次同一条异常,最终就出现两条重复记录
解决方式二选一即可:
- 代码内加
try/catch块手动捕获异常,用logger.LogError主动记录,不要让异常逃逸到外层自动捕获逻辑 - 在host.json的applicationInsights配置节点下加
"enableAutoCollectExceptions": false,关闭SDK层的自动异常收集,只保留Functions运行时记录的单条异常即可。
问题2:构造函数注入的ILogger与Run方法参数的ILogger差异
二者核心功能没有区别,最终都会把日志写入同一个Application Insights实例,唯一差异是日志附带的Category属性和适用场景不同:
- 构造函数注入的
ILogger<ClassName>,日志Category固定为类的完整名,适合在构造函数、类的自定义通用方法中复用,不需要依赖函数执行上下文 - Run方法参数传入的
ILogger是Functions运行时针对单次函数执行生成的,Category固定为Function.<函数名>,会自动附带当前执行的InvocationId、触发源、函数实例ID等上下文信息,不需要手动埋点
日常写业务逻辑优先用方法参数传入的ILogger即可,省掉注入步骤,自带的上下文信息排障时更实用;只有需要在函数执行方法外写日志的时候,才需要注入类级别的ILogger。
问题3:Trace表存在大量非业务写入的冗余日志,如何过滤
Trace表中默认会混入Functions运行时、WebJobs SDK、依赖组件输出的系统日志,默认日志级别为Information,不需要修改代码,直接在host.json中配置日志级别过滤规则即可,只保留业务相关的日志输出:
{ "version": "2.0", "logging": { "logLevel": { "Default": "Warning", // 全局默认只记录Warning及以上级别日志,屏蔽所有系统默认的Information级日志 "AzureAppInsightsExplore": "Information", // 业务类日志保留Information级别 "Function.AzureAppInsightsExplore": "Information" // 函数执行类别的日志(即Run参数ILogger写入的日志)保留Information级别 }, "applicationInsights": { "samplingSettings": { "isEnabled": true, "excludedTypes": "Request" } } } }
如果还有零散的冗余日志,可以查询Trace表中冗余条目的customDimensions.Category字段,把对应的类别名加到logLevel配置中,将级别设为Warning/Error即可屏蔽。这种配置方式是性能损耗最低的过滤方案,不需要额外写自定义日志处理器。
问题4:自定义日志在Live Metrics可见,但Trace表长时间查询不到
这个问题是日志通道的机制差异导致的,按以下优先级排查即可:
- 先排查采样规则:当前开启的采样虽然排除了Request类型,但Trace日志默认参与采样。Live Metrics走独立的实时通道,完全不走采样逻辑,所以能看到全量日志;但持久化到Trace表的日志会被采样逻辑按比例丢弃。可以临时把
samplingSettings.isEnabled设为false关闭采样测试,如果关闭后日志正常入库,就调整采样比例,或者把Trace也加入excludedTypes不参与采样即可。 - 排查日志缓冲区刷新问题:普通持久化日志走SDK的批量发送通道,默认攒满500条或者等30秒才会发往后端,如果你用的是构造函数注入的类级别ILogger,在消费计划下函数执行完被回收时,缓冲区可能没来得及刷新就被释放,导致日志丢失。换成Run方法参数传入的ILogger写日志即可,这个实例在函数执行完成后运行时会主动触发缓冲区刷新,不会丢日志。
- 排查过滤规则冲突:检查函数应用的应用设置、Azure门户的函数诊断配置中是否有覆盖host.json的日志级别规则,把Information级别的业务日志拦截了——这类拦截规则只作用于持久化通道,不会影响Live Metrics的实时传输。
- 排查后端摄入延迟:如果你用的是工作区集成型Application Insights,日志最终会写入关联的Log Analytics工作区,极端情况下摄入延迟可能达到15分钟,如果超过20分钟还查不到再排除这个可能性,同时检查工作区是否配置了数据收集规则,主动丢弃了Information级别的Trace日志。
内容的提问来源于stack exchange,提问作者JackFrost
相关产品推荐
相关产品推荐

