CodeGym /Cursos /C# SELF /Monitorización del rendimiento y recopilación de métricas...

Monitorización del rendimiento y recopilación de métricas

C# SELF
Nivel 64 , Lección 3
Disponible

1. Introducción

Imagina que eres el administrador de un sitio y cada día te llegan mil usuarios. En los logs ves que todo funciona, casi no hay errores (a lo sumo alguien olvida la contraseña o falla el captcha de vez en cuando). «¡Todo perfecto!» — piensas.

Y de repente alguien escribe al soporte: el sitio va muy lento, las páginas tardan 10 segundos en cargar. Revisas los logs — ¡no hay errores! ¿Genial? No, porque los logs cuentan qué pasó (o no pasó), pero no dicen qué tan rápido o lento ocurrió, cuántos recursos se necesitaron, ni cómo cambió ese comportamiento con el aumento de carga.

Aquí entran en escena las métricas — características medibles del funcionamiento de la aplicación. No es solo el número de errores, sino el tiempo medio de respuesta, el volumen de memoria consumida, las peticiones por segundo y otros indicadores con los que se juzga la salud del sistema.

Comparación:
Logs — son "qué pasó".
Métricas — son "qué tan bien/mal funciona el sistema".
Trazas — son "por qué el sistema funciona así (en detalle)".

¿Qué tipos de métricas hay y qué conviene recopilar?

Tipos principales de métricas:

Tipo de métrica Ejemplo Para qué sirve
Counters (Contadores) Número de peticiones, errores, fallos Tendencias, alertas, carga
Histograms Tiempo de respuesta, tamaño de paquete Distribución de valores, percentiles
Gauges Uso de memoria, CPU Estado actual del recurso
Sum Volumen total de datos, bytes Volumen total de operaciones en un periodo

Ejemplos:

  • El tiempo medio y el percentil 95 de respuesta a una GET.
  • El número de usuarios online ahora mismo.
  • Uso de memoria (Private Bytes, Working Set).
  • Frecuencia de errores tipo 500/503.
  • Consultas a la BD por minuto.

Estos indicadores permiten no solo encontrar problemas, sino también prevenirlos — un aumento de carga en el servidor o un crecimiento gradual del tiempo de respuesta pueden avisar de fallos futuros.

2. Cómo funciona la recopilación de métricas en .NET y el ecosistema OpenTelemetry

Arquitectura general

En el .NET moderno (desde .NET 6, y especialmente en .NET 8/9) existe un sistema estándar de recopilación de métricas basado en OpenTelemetry.

Así es como funciona:

  1. El código de la aplicación llama a métodos para incrementar contadores, registrar gauges, y escribir histogramas.
  2. El SDK de OpenTelemetry Metrics recoge esas métricas (en memoria) y las envía periódicamente.
  3. El exportador de métricas las transmite al sistema de monitorización elegido (Prometheus, Application Insights, Grafana Cloud, Datadog, etc.).
  4. El backend de monitorización agrega, almacena, visualiza, crea alertas y dashboards.
Esquema simplificado:

[Tu aplicación] 
       ⬇ 
 [Recopilación de métricas (OpenTelemetry SDK)]
       ⬇
 [Exportador de métricas (Prometheus, AI, Datadog, ...)]
       ⬇
 [Sistema de monitorización/dashboards/alertas]

3. Práctica: Fundamentos de trabajo con métricas en C#

Métricas internas simples: System.Diagnostics.Metrics

.NET ofrece un mecanismo incorporado para métricas — System.Diagnostics.Metrics.

Jugadores principales: Meter, Counter<T>, Histogram<T>, ObservableGauge<T>.

Ejemplo: contador de visitas a la página


// Creamos un Meter (normalmente uno por toda la aplicación)
using System.Diagnostics.Metrics;

static Meter meter = new Meter("MyCompany.MyApp", "1.0");

// Registramos el contador
static Counter<long> homePageVisits = meter.CreateCounter<long>("HomePageVisits");

// En algún lugar del controlador o servicio...
public void HomePageRequested()
{
    homePageVisits.Add(1);
    // El resto del código que maneja la página
}

Comentarios:

  • Meter — es la "fábrica" de métricas, con un nombre único (espacio de nombres de la aplicación/compañía).
  • CreateCounter<long> — crea el contador; se incrementa con Add(1).

Ejemplo: medir el tiempo de respuesta


static Histogram<double> pageLoadTime = meter.CreateHistogram<double>("PageLoadTimeMs");

// En el handler de la petición:
public void OnRequest()
{
    var stopwatch = System.Diagnostics.Stopwatch.StartNew();

    // ...aquí va la propia petición...

    stopwatch.Stop();
    pageLoadTime.Record(stopwatch.Elapsed.TotalMilliseconds);
}

Recopilar gauges para valores dinámicos

Un gauge es una métrica que cambia con el tiempo: número de usuarios conectados, volumen de memoria actual, etc.


static ObservableGauge<int> onlineUserGauge = meter.CreateObservableGauge(
    "OnlineUsers", 
    () => GetOnlineUserCount());

// Donde GetOnlineUserCount - método que devuelve el valor actual
static int GetOnlineUserCount()
{
    // Aquí debería ir tu lógica real!
    return ActiveUserList.Count;
}

En el mundo real todo esto funciona de forma asíncrona: la aplicación reporta valores de métricas y el exportador los recoge y los expone (por ejemplo, Prometheus scrapea el endpoint "/metrics").

Añadir métricas en una aplicación ASP.NET Core moderna

Para ASP.NET Core muchas cosas están listas para usar. Basta con añadir el paquete OpenTelemetry.Instrumentation.AspNetCore y aparecerán métricas de HTTP, tiempos de respuesta, número de errores, etc.

Ejemplo de configuración en Program.cs:


using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenTelemetry()
    .WithMetrics(metrics =>
    {
        metrics
            .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MyApp"))
            .AddAspNetCoreInstrumentation() // métricas HTTP
            .AddRuntimeInstrumentation()    // métricas del runtime .NET CLR
            .AddProcessInstrumentation()    // CPU/memoria del proceso
            .AddMeter("MyCompany.MyApp")    // tus métricas
            .AddPrometheusExporter();       // exportar a Prometheus
    });

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Ahora tu aplicación expondrá métricas en /metrics, que Prometheus u otros sistemas pueden scrappear.

4. Ejemplos prácticos de uso de métricas

Monitorización del rendimiento en proyectos reales

Conectamos métricas para saber:

  • Cuál es el RPS medio y máximo (requests per second) que aguanta la API?
  • Dónde están los "cuellos de botella": un endpoint responde en 300 ms y otro en 2000 ms?
  • Cuánto tiempo se pasa en llamadas a la BD? (añadimos nuestros histogramas)

Ejemplo: controlar el tiempo de respuesta a la base de datos


static Histogram<double> dbQueryDuration = meter.CreateHistogram<double>("DbQueryDurationMs");

public async Task<List<Product>> GetProductsAsync()
{
    var sw = Stopwatch.StartNew();
    var result = await _db.Products.ToListAsync();
    sw.Stop();
    dbQueryDuration.Record(sw.Elapsed.TotalMilliseconds);
    return result;
}

Ejemplo: contar errores


static Counter<long> apiErrors = meter.CreateCounter<long>("ApiErrors");

public IActionResult SomeEndpoint()
{
    try
    {
        // alguna acción
        return Ok();
    }
    catch (Exception)
    {
        apiErrors.Add(1);
        throw;
    }
}

Trabajar con labels (tags) para métricas

Es importante agrupar datos por atributos útiles: endpoint, tipo de error, tipo de usuario, etc.


homePageVisits.Add(
    1, 
    KeyValuePair.Create<string, object>("UserType", "Admin"));

O para un histograma:


dbQueryDuration.Record(
    sw.Elapsed.TotalMilliseconds, 
    KeyValuePair.Create<string, object>("QueryType", "GetProducts"));

Gracias a los tags, en Grafana puedes crear gráficas no solo para toda la app, sino para segmentos específicos.

5. Integración con Prometheus, Application Insights, Datadog, Grafana

Exportadores e integración

  • Prometheus — monitoring open-source muy popular, estándar de facto en cloud y Kubernetes.
  • Application Insights — integración cloud para Azure.
  • Datadog, Grafana Cloud — para infraestructuras profesionales.

Todos estos sistemas pueden recoger métricas de .NET a través de los exportadores de OpenTelemetry. Documentación sobre exportadores OTel

Prometheus (pasos):

  1. Añadir el paquete NuGet: OpenTelemetry.Exporter.Prometheus.
  2. Añadir .AddPrometheusExporter() en el registro de métricas.
  3. Configurar en Grafana un datasource apuntando a Prometheus y crear dashboards.

Enlaces útiles:

6. Particularidades, trampas y errores típicos

Uno de los errores comunes es la excesiva granularidad de los tags. Si das a los tags demasiados valores únicos (por ejemplo, ID de usuario/pedido), el número de series temporales se disparará — esto sobrecargará el almacenamiento de métricas y aumentará los costos (lo que se conoce como cardinality explosion). Mantén los tags "coarse-grained".

Los desarrolladores a veces ignoran System.Diagnostics.Metrics y las herramientas listas, implementando soluciones caseras con logs y timers. Al final el monitoring queda peor integrado y es más difícil de mantener. Usa las herramientas estándar y la instrumentación automática.

Otro fallo es que las métricas se recopilan pero no se exportan. La configuración del exportador es obligatoria: añade, por ejemplo, .AddPrometheusExporter() y asegúrate de que el endpoint /metrics esté disponible para el scraping.

Y, por último, confundir los tipos de métricas: calcular el tiempo medio de respuesta con un Counter cuando deberías usar un Histogram — si haces eso no verás picos ni la distribución. Counters — para recuentos; histograms — para tiempos/tamaños/distribuciones; gauges — para estados actuales.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION