Históricamente, las métricas en .NET (vía System.Diagnostics.Metrics) se gestionaban de forma estática. Esto era una pesadilla para las Pruebas Unitarias y la Inyección de Dependencias (DI). En 2025-2026, la norma es usar IMeterFactory para tener un control granular y aislable de nuestras mediciones.
El Infierno de las Métricas Estáticas
Antes, creábamos un Meter global. El problema es que, en un test unitario, si diez tests escriben en el mismo Meter estático, los resultados se ensucian. No podías «limpiar» las métricas entre pruebas.
Escenario de Falla:
Si mides el tiempo de procesamiento de una orden con un static Meter, y lanzas 100 tests en paralelo, tu reporte de Grafana o Prometheus mostrará basura porque no puedes distinguir qué métrica pertenece a qué instancia del servicio.
Inyección de IMeterFactory
Con IMeterFactory, el ciclo de vida del Meter está atado al contenedor de dependencias. Esto permite crear contenedores aislados para cada ejecución o prueba.
Implementación Técnica (Paso a Paso):
builder.Services.AddMetrics(); // Registra IMeterFactory automáticamente builder.Services.AddSingleton<OrderService>();
Ahora, inyectamos la factoría en nuestro servicio de negocio:
public class OrderService
{
private readonly Counter<int> _orderCounter;
public OrderService(IMeterFactory meterFactory)
{
// Creamos el Meter a través de la factoría
var meter = meterFactory.Create("Shop.Orders", "1.0.0");
// Definimos el instrumento (Counter, Histogram, etc.)
_orderCounter = meter.CreateCounter<int>("orders.processed", "Orders");
}
public void ProcessOrder(int orderId)
{
// Lógica de negocio...
// Registramos la métrica con Tags para mayor contexto (Cardinalidad)
_orderCounter.Add(1, new TagList { { "order.type", "digital" } });
}
}
Testing y Aislamiento
Esta es la razón real para usar IMeterFactory. Podemos crear un mock o una instancia local en nuestros tests para verificar que las métricas se están disparando correctamente sin afectar el estado global del sistema.
[Fact]
public void ProcessOrder_Should_Increment_Counter()
{
// 1. Setup: Usamos una factoría local
var serviceCollection = new ServiceCollection();
serviceCollection.AddMetrics();
var provider = serviceCollection.BuildServiceProvider();
var factory = provider.GetRequiredService<IMeterFactory>();
var service = new OrderService(factory);
// 2. Ejecución
service.ProcessOrder(123);
// 3. Verificación (Usando un MeterListener para "escuchar" la métrica)
// Aquí validaríamos que el contador subió a 1.
}
¿Por qué esto es vital en 2025?
En arquitecturas modernas, las métricas son el «faro» del escalado automático (Auto-scaling).
- Punteros/Span (Lo que vimos antes): Optimizan el uso de CPU.
- IMeterFactory: Te dice cuándo esa optimización es necesaria midiendo la latencia real en producción.
| Característica | Meter Estático (Old School) | IMeterFactory (Modern) |
| Inyección de Dependencias | No compatible | Nativo |
| Testabilidad | Muy difícil / Frágil | Excelente / Aislada |
| Ciclo de Vida | Durante toda la App | Controlado por el contenedor |
| Riesgo de Memory Leak | Bajo | Requiere Dispose correcto del Factory |
NOTAS
- Abandona el static Meter: Si estás en .NET 8 o superior, refactoriza hacia IMeterFactory. Es el estándar para que tus servicios sean testeables.
- Usa Instrumentos Correctos: * Counter: Para cosas que solo suben (ej. órdenes totales).
- Histogram: Para latencias (ej. cuánto tardó el Span<T> en procesar el buffer).
- UpDownCounter: Para cosas que fluctúan (ej. usuarios activos).
- Cuidado con la Cardinalidad: Al agregar Tags en _orderCounter.Add(), evita usar IDs únicos (como OrderId). Esto genera miles de series de tiempo en tu base de datos de métricas (Prometheus) y puede tumbar el sistema de monitoreo. Usa categorías (ej. Status, Region).
- Dispose: Asegúrate de que los Meters creados por la factoría se liberen si el servicio tiene un tiempo de vida corto (Scoped), aunque en Singletons el Factory se encarga al cerrar la App.
Conclusion
Si trabajas en .NET 8 o superior, adopta IMeterFactory y deja atrás el static Meter: ganarás testabilidad y alineación con el estándar moderno de observabilidad. Elige el instrumento correcto según el comportamiento del dato: Counter para valores acumulativos, Histogram para latencias y UpDownCounter para métricas que fluctúan. Sé extremadamente cuidadoso con la cardinalidad de los tags: evita identificadores únicos que saturen sistemas como Prometheus y prioriza categorías controladas. Finalmente, gestiona correctamente el ciclo de vida y libera los Meters cuando corresponda. Buena observabilidad no es solo medir, es medir con criterio arquitectónico.
