Application Insights请求条目丢失:自定义维度数据超限排查
我实现了一个中间件遥测处理器,用于在请求执行完成后,将响应体中的关键数据存入Application Insights的自定义维度字段,以便通过Grafana等第三方工具分析响应。
核心代码实现如下:
ResponseBodyHandler与TelemetryPropertyHandler
public class ResponseBodyHandler : IResponseBodyHandler { private readonly ITelemetryPropertyHandler _telemetryPropertyHandler = new TelemetryPropertyHandler(); public void TransformResponseBodyDataToTelemetryData(RequestTelemetry requestTelemetry, string responseBody) { SuccessResponse<List<Booking>> result = null; try { result = JsonConvert.DeserializeObject<SuccessResponse<List<Booking>>>(responseBody); } catch (Exception e) { Log.Error("Telemetry response handler, failure to deserialize response body: " + e.Message); return; } _telemetryPropertyHandler.CreateTelemetryProperties(requestTelemetry, result); } } public class TelemetryPropertyHandler : ITelemetryPropertyHandler { private readonly ILabelHandler _labelHandler = new LabelHandler(); public void CreateTelemetryProperties(RequestTelemetry requestTelemetry, SuccessResponse<List<Booking>> result) { Header bookingHeader = result?.SuccessObject?.FirstOrDefault()?.BookingHeader; requestTelemetry?.Properties.Add("ResponseClientId", "" + bookingHeader?.ConsigneeNumber); Line line = bookingHeader?.Lines.FirstOrDefault(); requestTelemetry?.Properties.Add("ResponseProductId", "" + line?.PurchaseProductID); requestTelemetry?.Properties.Add("ResponseCarrierId", "" + line?.SubCarrierID); _labelHandler.HandleLabel(requestTelemetry, bookingHeader); requestTelemetry?.Properties.Add("ResponseBody", JsonConvert.SerializeObject(result)); } }
在_labelHandler.HandleLabel方法中,我提取了Base64编码的图片,将其按8192字符分块,以"Image index 0 .. N"为键添加到Properties中。调试时代码正常运行,但Application Insights中的整个请求条目消失,并非仅自定义维度缺失。我推测这是数据大小超限导致,但未找到相关限制文档。
当仅将图片截断为单个属性存储时,代码可正常工作,但此方式无法完整存储图片数据。相关代码如下:
LabelHandler与Base64Splitter
public class LabelHandler : ILabelHandler { private readonly IBase64Splitter _base64Splitter = new Base64Splitter(); public void HandleLabel(RequestTelemetry requestTelemetry, Header bookingHeader) { Label label = bookingHeader?.Labels.FirstOrDefault(); IEnumerable<List<char>> splitBase64String = _base64Splitter.SplitList(label?.Base64.ToList()); if (splitBase64String != null) { bool imageHandlingWorked = true; try { int index = 0; foreach (List<char> chunkOfImageString in splitBase64String) { string dictionaryKey = $"Image index {index}"; string chunkData = new string(chunkOfImageString.ToArray()); requestTelemetry?.Properties.Add(dictionaryKey, chunkData); index++; } } catch (Exception e) { imageHandlingWorked = false; Log.Error("Error trying to store label in chunks: " + e.Message); } if (imageHandlingWorked && label != null) { label.Base64 = ""; } } } }
public class Base64Splitter : IBase64Splitter { private const int ChunkSize = 8192; public IEnumerable<List<T>> SplitList<T>(List<T> originalList) { for (var i = 0; i < originalList.Count; i += ChunkSize) yield return originalList.GetRange(i, Math.Min(ChunkSize, originalList.Count - i)); } }
请问我违反了什么规则?是否需要截断图片数据,或是存在其他问题?
你遇到的问题是Application Insights的单条遥测数据大小限制导致的:
核心限制:Application Insights中每个遥测条目(比如
RequestTelemetry)的总大小上限为64KB。这个大小包含遥测的所有字段:请求基本信息、自定义Properties、上下文数据等。当你把Base64图片分块存入Properties后,加上ResponseBody等其他属性,整个遥测的总大小超过了64KB,导致Application Insights直接丢弃了这条遥测,而不是仅忽略超限的属性。单块截断能工作的原因:当你只存截断后的单块图片数据时,整个遥测的总大小控制在了64KB以内,所以能正常被接收和存储。
解决方案
方案1:截断图片数据(快速妥协)
如果必须在自定义维度中保留图片相关数据,可以只存储Base64字符串的前N个字符(比如前4KB),确保整个遥测的总大小不超过64KB。但这种方式无法保留完整图片,仅适合需要预览或标识的场景。
方案2:避免在自定义维度存储大文件(推荐)
Application Insights的自定义维度设计初衷是存储小体积的元数据(比如ID、状态码、简短标识),而非大二进制/Base64数据。正确的做法是:
- 将Base64图片解码后存储到Blob存储;
- 在
RequestTelemetry的自定义维度中仅存储该Blob的访问URL或唯一标识; - 当Grafana需要查看图片时,通过这个URL去Blob存储中获取完整数据。
方案3:提前校验遥测大小
在添加属性前,手动计算当前RequestTelemetry的序列化大小,避免超限。可以通过将遥测序列化为JSON后计算字节数的方式判断,如果即将超过64KB,就跳过图片数据的存储。
内容的提问来源于stack exchange,提问作者Morten Bork

