feat: Enhance telemetry metrics recording with sealed mode tagging

This commit is contained in:
StellaOps Bot
2025-12-05 01:00:29 +02:00
parent 175b750e29
commit 0de3c8a3f0
4 changed files with 152 additions and 27 deletions

View File

@@ -0,0 +1,132 @@
using System.Text.Json;
namespace StellaOps.Microservice;
/// <summary>
/// Adapts typed endpoint handlers to the raw endpoint interface.
/// </summary>
public static class TypedEndpointAdapter
{
private static readonly JsonSerializerOptions DefaultJsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true
};
/// <summary>
/// Creates a raw handler function from a typed endpoint with request and response.
/// </summary>
/// <typeparam name="TRequest">The request type.</typeparam>
/// <typeparam name="TResponse">The response type.</typeparam>
/// <param name="handler">The typed handler.</param>
/// <param name="jsonOptions">Optional JSON serialization options.</param>
/// <returns>A raw handler function.</returns>
public static Func<RawRequestContext, CancellationToken, Task<RawResponse>> Adapt<TRequest, TResponse>(
IStellaEndpoint<TRequest, TResponse> handler,
JsonSerializerOptions? jsonOptions = null)
{
var options = jsonOptions ?? DefaultJsonOptions;
return async (context, cancellationToken) =>
{
try
{
// Deserialize request
TRequest? request;
if (context.Body == Stream.Null || context.Body.Length == 0)
{
request = default;
}
else
{
request = await JsonSerializer.DeserializeAsync<TRequest>(
context.Body,
options,
cancellationToken);
}
if (request is null)
{
return RawResponse.BadRequest("Invalid request body");
}
// Call handler
var response = await handler.HandleAsync(request, cancellationToken);
// Serialize response
return SerializeResponse(response, options);
}
catch (JsonException ex)
{
return RawResponse.BadRequest($"Invalid JSON: {ex.Message}");
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
return RawResponse.InternalError(ex.Message);
}
};
}
/// <summary>
/// Creates a raw handler function from a typed endpoint with response only.
/// </summary>
/// <typeparam name="TResponse">The response type.</typeparam>
/// <param name="handler">The typed handler.</param>
/// <param name="jsonOptions">Optional JSON serialization options.</param>
/// <returns>A raw handler function.</returns>
public static Func<RawRequestContext, CancellationToken, Task<RawResponse>> Adapt<TResponse>(
IStellaEndpoint<TResponse> handler,
JsonSerializerOptions? jsonOptions = null)
{
var options = jsonOptions ?? DefaultJsonOptions;
return async (context, cancellationToken) =>
{
try
{
// Call handler
var response = await handler.HandleAsync(cancellationToken);
// Serialize response
return SerializeResponse(response, options);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
return RawResponse.InternalError(ex.Message);
}
};
}
/// <summary>
/// Creates a raw handler function from a raw endpoint.
/// </summary>
/// <param name="handler">The raw handler.</param>
/// <returns>A raw handler function.</returns>
public static Func<RawRequestContext, CancellationToken, Task<RawResponse>> Adapt(
IRawStellaEndpoint handler)
{
return handler.HandleAsync;
}
private static RawResponse SerializeResponse<TResponse>(TResponse response, JsonSerializerOptions options)
{
var json = JsonSerializer.SerializeToUtf8Bytes(response, options);
var headers = new HeaderCollection();
headers.Set("Content-Type", "application/json; charset=utf-8");
return new RawResponse
{
StatusCode = 200,
Headers = headers,
Body = new MemoryStream(json)
};
}
}