feat(metrics): Add new histograms for chunk latency, results, and sources in AdvisoryAiMetrics
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

feat(telemetry): Record chunk latency, result count, and source count in AdvisoryAiTelemetry

fix(endpoint): Include telemetry source count in advisory chunks endpoint response

test(metrics): Enhance WebServiceEndpointsTests to validate new metrics for chunk latency, results, and sources

refactor(tests): Update test utilities for Deno language analyzer tests

chore(tests): Add performance tests for AdvisoryGuardrail with scenarios and blocked phrases

docs: Archive Sprint 137 design document for scanner and surface enhancements
This commit is contained in:
master
2025-11-10 22:26:43 +02:00
parent 56c687253f
commit b059bc7675
22 changed files with 427 additions and 37 deletions

View File

@@ -24,6 +24,21 @@ internal static class AdvisoryAiMetrics
unit: "count",
description: "Number of advisory chunk segments blocked by guardrails.");
internal static readonly Histogram<double> ChunkLatencyHistogram = Meter.CreateHistogram<double>(
"advisory_ai_chunk_latency_milliseconds",
unit: "ms",
description: "Elapsed time required to assemble advisory chunks.");
internal static readonly Histogram<long> ChunkResultHistogram = Meter.CreateHistogram<long>(
"advisory_ai_chunk_segments",
unit: "chunks",
description: "Number of chunk segments returned to the caller per request.");
internal static readonly Histogram<long> ChunkSourceHistogram = Meter.CreateHistogram<long>(
"advisory_ai_chunk_sources",
unit: "sources",
description: "Number of advisory sources contributing to a chunk response.");
internal static KeyValuePair<string, object?>[] BuildChunkRequestTags(string tenant, string result, bool truncated, bool cacheHit)
=> new[]
{
@@ -33,6 +48,30 @@ internal static class AdvisoryAiMetrics
CreateTag("cache", cacheHit ? "hit" : "miss"),
};
internal static KeyValuePair<string, object?>[] BuildLatencyTags(string tenant, string result, bool truncated, bool cacheHit)
=> new[]
{
CreateTag("tenant", tenant),
CreateTag("result", result),
CreateTag("truncated", BoolToString(truncated)),
CreateTag("cache", cacheHit ? "hit" : "miss"),
};
internal static KeyValuePair<string, object?>[] BuildChunkResultTags(string tenant, string result, bool truncated)
=> new[]
{
CreateTag("tenant", tenant),
CreateTag("result", result),
CreateTag("truncated", BoolToString(truncated)),
};
internal static KeyValuePair<string, object?>[] BuildSourceTags(string tenant, string result)
=> new[]
{
CreateTag("tenant", tenant),
CreateTag("result", result)
};
internal static KeyValuePair<string, object?>[] BuildCacheTags(string tenant, string outcome)
=> new[]
{

View File

@@ -913,6 +913,7 @@ var advisoryChunksEndpoint = app.MapGet("/advisories/{advisoryKey}/chunks", asyn
buildResult.Response.Truncated,
cacheHit,
observations.Length,
buildResult.Telemetry.SourceCount,
buildResult.Response.Chunks.Count,
duration,
guardrailCounts));

View File

@@ -33,6 +33,18 @@ internal sealed class AdvisoryAiTelemetry : IAdvisoryAiTelemetry
AdvisoryAiMetrics.ChunkRequestCounter.Add(1,
AdvisoryAiMetrics.BuildChunkRequestTags(tenant, result, telemetry.Truncated, telemetry.CacheHit));
AdvisoryAiMetrics.ChunkLatencyHistogram.Record(
telemetry.Duration.TotalMilliseconds,
AdvisoryAiMetrics.BuildLatencyTags(tenant, result, telemetry.Truncated, telemetry.CacheHit));
AdvisoryAiMetrics.ChunkResultHistogram.Record(
telemetry.ChunkCount,
AdvisoryAiMetrics.BuildChunkResultTags(tenant, result, telemetry.Truncated));
AdvisoryAiMetrics.ChunkSourceHistogram.Record(
telemetry.SourceCount,
AdvisoryAiMetrics.BuildSourceTags(tenant, result));
if (telemetry.CacheHit)
{
AdvisoryAiMetrics.ChunkCacheHitCounter.Add(1,
@@ -56,13 +68,15 @@ internal sealed class AdvisoryAiTelemetry : IAdvisoryAiTelemetry
}
_logger.LogInformation(
"Advisory chunk request for tenant {Tenant} key {Key} returned {Chunks} chunks across {Sources} sources (truncated: {Truncated}, cacheHit: {CacheHit}, durationMs: {Duration}).",
"Advisory chunk request for tenant {Tenant} key {Key} returned {Chunks} chunks across {Sources} sources (observationsLoaded: {Observations}, truncated: {Truncated}, cacheHit: {CacheHit}, guardrailBlocks: {GuardrailBlocks}, durationMs: {Duration}).",
tenant,
telemetry.AdvisoryKey,
telemetry.ChunkCount,
telemetry.SourceCount,
telemetry.ObservationCount,
telemetry.Truncated,
telemetry.CacheHit,
telemetry.TotalGuardrailBlocks,
telemetry.Duration.TotalMilliseconds.ToString("F2", CultureInfo.InvariantCulture));
}
@@ -118,6 +132,7 @@ internal sealed record AdvisoryAiChunkRequestTelemetry(
bool Truncated,
bool CacheHit,
int ObservationCount,
int SourceCount,
int ChunkCount,
TimeSpan Duration,
IReadOnlyDictionary<AdvisoryChunkGuardrailReason, int> GuardrailCounts)