Saltar al contenido principal

Trazado Distribuido

Vali-Mediator crea un Activity (span de OpenTelemetry) para cada solicitud, notificación y comando fire-and-forget.

ActivitySource

// Acceder al source directamente
var source = ValiMediatorDiagnostics.ActivitySource;
// Nombre: "Vali-Mediator"
// Versión: "2.0.0"

Configuración con OpenTelemetry

builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing
.SetResourceBuilder(ResourceBuilder.CreateDefault()
.AddService("MiApp", serviceVersion: "1.0.0"))
// Escuchar spans de Vali-Mediator
.AddSource("Vali-Mediator")
// Exportar a Jaeger
.AddJaegerExporter(opts =>
{
opts.AgentHost = "localhost";
opts.AgentPort = 6831;
})
// O a Zipkin
.AddZipkinExporter(opts =>
{
opts.Endpoint = new Uri("http://localhost:9411/api/v2/spans");
})
// O a OTLP (Grafana, Tempo, etc.)
.AddOtlpExporter();
});

Tags del Activity

TagValor
mediator.request.typeNombre completo del tipo de solicitud
mediator.handler.typeNombre completo del tipo del handler
mediator.request.successtrue / false
mediator.request.error_typeValor de ErrorType (si falló)
mediator.request.duration_msDuración en milisegundos

Crear Activities Hijo

public class GetProductHandler : IRequestHandler<GetProductQuery, Result<ProductDto>>
{
private static readonly ActivitySource Source = new("MiApp.Handlers");

public async Task<Result<ProductDto>> Handle(GetProductQuery req, CancellationToken ct)
{
using var activity = Source.StartActivity("GetProduct.ConsultaDB");
activity?.SetTag("product.id", req.ProductId.ToString());

var product = await _repository.GetByIdAsync(req.ProductId, ct);

activity?.SetTag("product.found", product is not null);

if (product is null)
return Result<ProductDto>.Fail("No encontrado.", ErrorType.NotFound);

return Result<ProductDto>.Ok(product.ToDto());
}
}