86 lines
2.8 KiB
C#
86 lines
2.8 KiB
C#
using System.Diagnostics;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.RateLimiting;
|
|
using Nexus.Api.Models;
|
|
using Nexus.Api.Observability;
|
|
|
|
namespace Nexus.Api.Controllers;
|
|
|
|
[Authorize]
|
|
[ApiController]
|
|
[Route("api/v1/telemetry/browser")]
|
|
[EnableRateLimiting("agents")]
|
|
public sealed class BrowserTelemetryController : ControllerBase
|
|
{
|
|
private static readonly HashSet<string> AllowedNames =
|
|
[
|
|
"CLS",
|
|
"FCP",
|
|
"INP",
|
|
"LCP",
|
|
"TTFB",
|
|
"board_content_visible",
|
|
"board_delta_painted",
|
|
"mutation_confirmed",
|
|
"agent_proposal_readback"
|
|
];
|
|
|
|
private static readonly HashSet<string> AllowedRatings =
|
|
["good", "needs-improvement", "poor", "custom"];
|
|
|
|
[HttpPost]
|
|
public IResult Record([FromBody] BrowserMetricRequest request)
|
|
{
|
|
if (!AllowedNames.Contains(request.Name))
|
|
return Results.ValidationProblem(new Dictionary<string, string[]>
|
|
{
|
|
["name"] = ["Unsupported browser metric."]
|
|
});
|
|
|
|
if (!double.IsFinite(request.Value) || request.Value < 0 || request.Value > 86_400_000)
|
|
return Results.ValidationProblem(new Dictionary<string, string[]>
|
|
{
|
|
["value"] = ["Metric value must be finite and within the accepted range."]
|
|
});
|
|
|
|
if (!AllowedRatings.Contains(request.Rating))
|
|
return Results.ValidationProblem(new Dictionary<string, string[]>
|
|
{
|
|
["rating"] = ["Unsupported metric rating."]
|
|
});
|
|
|
|
var route = NormalizeBoundedDimension(request.RouteName, "unknown", 80);
|
|
var liveMode = request.LiveMode is "live" or "polling" ? request.LiveMode : "unknown";
|
|
var navigationType = NormalizeBoundedDimension(request.NavigationType, "unknown", 40);
|
|
|
|
var tags = new TagList
|
|
{
|
|
{ "metric.name", request.Name },
|
|
{ "metric.rating", request.Rating },
|
|
{ "route.name", route },
|
|
{ "nexus.live_mode", liveMode },
|
|
{ "navigation.type", navigationType }
|
|
};
|
|
|
|
if (request.Name == "CLS")
|
|
NexusTelemetry.BrowserScore.Record(request.Value, tags);
|
|
else
|
|
NexusTelemetry.BrowserDuration.Record(request.Value, tags);
|
|
|
|
return Results.NoContent();
|
|
}
|
|
|
|
private static string NormalizeBoundedDimension(string? value, string fallback, int maxLength)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
return fallback;
|
|
|
|
var normalized = new string(value
|
|
.Where(character => char.IsAsciiLetterOrDigit(character) || character is ' ' or '_' or '-')
|
|
.Take(maxLength)
|
|
.ToArray());
|
|
return string.IsNullOrWhiteSpace(normalized) ? fallback : normalized;
|
|
}
|
|
}
|