
Durantes estos días, comenzamos a mejorar algunos de nuestros sistema de heathcheck para las APIs DotNet. Es justo en este momento cuando me he decido a probar finalmente Xabaril HealthChecks.
Sinceramente, me ha resultado mucho mas sencillo de lo que esperaba y, para no disponer de Prometheus o sistema similar (por el momento), considero que es un muy buen sistema de monitorización/chequeo de la salud.
Algunos puntos, entre otros, que he considerado importantes durante mis ejemplos son estos:
- Desde su versión 2.2 Microsoft adoptó este sistema/mecanismo de Heathchecks como parte nativa de .NET.
- Dispone de una configuración muy sencilla e intuitiva. En apenas unas pocas líneas el sistema se pone en marcha.
- Webhooks. Va a permitirnos lanzar notificaciones a otros sistemas, como por ejemplo a MS Team.
- Interfaz de usuario intuitiva y con cierta customización. Ej.: Logo del cliente/proyeco.
Estableciendo HealthChecks
Como punto de partida añadiremos los HealthChecks así como sus correspondientes nugets como dependencias del proyecto.
builder.Services.AddHealthChecks()
.AddSqlServer(configuration["Data:ConnectionStrings:Sql"], name: "Sql Server",
healthQuery: "SELECT 1;", failureStatus: HealthStatus.Degraded,
tags: new string[] { "searchengine", "sql", "sqlserver" })
.AddRedis(configuration["Data:ConnectionStrings:Redis"], name: "Redis")
.AddMongoDb(configuration["Data:ConnectionStrings:Mongo"], name: "Mongo")
.AddNpgSql(configuration["Data:ConnectionStrings:Postgres"], name: "Postgres")
.AddElasticsearch(configuration["Data:ConnectionStrings:Elastic"], name: "Elastic",
failureStatus: HealthStatus.Unhealthy,
tags: new string[] { "searchengine", "nosql", "elasticsearch" })
.AddCheck<RandomHealthCheckSample>("random", tags: new string[] { "sample" });
...
var app = builder.Build();
app
// Standard AspNet Healthcheck
.UseHealthChecks("/health", new HealthCheckOptions
{
Predicate = _ => true
})
.UseHealthChecks("/healthz", new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
})
En concreto estos nugets:
AspNetCore.HealthChecks.Elasticsearch
AspNetCore.HealthChecks.MongoDb
AspNetCore.HealthChecks.NpgSql
AspNetCore.HealthChecks.Redis
AspNetCore.HealthChecks.SqlServer
He profundizado haciendo algunas queries concretas y he incluido el uso de algunos «tags«. Lo que nos facilitara distintas agrupaciones, mediante el uso de la propiedad «Predicate«.
Adicionalmente, el paquete «AspNetCore.HealthChecks.Uris«, permitirá comprobar para cualquier url su estado o salud. En el ejemplo, la uso para el chequeo de una api adicional (Api1) que se encuentra escuchando en el puerto 7014 y para la cual he generado un sistema básico de heathcheck similar a este mismo.
En este punto si navegamos a las urls relativas /health y /healthz, podremos comprobar que en ambos casos se muestra el estado de la aplicación. En concreto y para este segundo, veremos un «json» similar al siguiente:
{"status":"Healthy","totalDuration":"00:00:00.0130766","entries":{"Sql Server":{"data":{},"duration":"00:00:00.0016176","status":"Healthy","tags":["searchengine","sql","sqlserver"]},"Redis":{"data":{},"duration":"00:00:00.0031553","status":"Healthy","tags":[]},"Mongo":{"data":{},"duration":"00:00:00.0086539","status":"Healthy","tags":[]},"Postgres":{"data":{},"duration":"00:00:00.0126980","status":"Healthy","tags":[]},"Elastic":{"data":{},"duration":"00:00:00.0055705","status":"Healthy","tags":["searchengine","nosql","elasticsearch"]},"random":{"data":{},"duration":"00:00:00.0000020","status":"Healthy","tags":["sample"]}}}
HealthCheck UI
Aprovechando estos endpoints, entre otras carácterísticas, Healthcheck UI explota esta información, mostrándola a modo de web (SPA) de una manera muy intuitiva y visual. Bastará con añadir el siguiente código:
builder.Services
.AddHealthChecksUI(c =>
{
c.AddHealthCheckEndpoint("Data Bases", "/healthz");
c.AddHealthCheckEndpoint("HTTP Api 1", "https://localhost:7014/healthz");
})
.AddInMemoryStorage();
Cuyo resultado es el siguiente.

Si además, para uno de los items (como es el caso de Redis), se han producido caidas u otro tipo de errores, podremos consultar su histórico:

Toda la información de estado así como su histórido la estoy almacenando en memoria (.AddInMemoryStorage), aunque también contamos con estos otros proveedores:
- Application Insight
- CloudWatch
- Datadog
- Prometheus Gateway
- Seq
Filtrando endpoints con el «Predicate»
En el ejemplo hemos visto el uso la propiedad «Predicate» de una manera muy sencilla, si bien, podemos utilizarla para agrupar diferentes chequeos, por tags, por nombre, etc. Por ejemplo, podríamos tener un endpoint adicional «/nosql» para agrupar los chequeos de todas las BBDD nosql que usa la aplicación.
.UseHealthChecks("/nosql", new HealthCheckOptions
{
Predicate = p => p.Tags.Contains("nosql"),
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
})
Tras este agrupación y para poder verla en nuestro Dashboard tendríamos que añadir un nuevo HealthCheckEndpoint, como sigue:
builder.Services
.AddHealthChecksUI(c =>
{
c.AddHealthCheckEndpoint("Data Bases", "/healthz");
c.AddHealthCheckEndpoint("HTTP Api 1", "https://localhost:7014/healthz");
c.AddHealthCheckEndpoint("No SQL", "/nosql");
})
.AddInMemoryStorage();
Siguiendo estos dos pequeños pasos, podríamos tener tantas agrupaciones como consideráramos.
Conclusión
Podríamos disponer de este sistema para cada una de las APIs o, por el contrario crear un único sistema (a modo de Dashboard) con el objetivo de centralizar toda esta información en un punto. En mi caso, he optado por la primera opción, simplemente a modo de demo/prueba.
El ejemplo completo puedes encontrarlo aquí (en Github).
Y, hasta aquí este post. Mas detalle en el github de Xabaril HealthChecks, donde podremos ampliar con mas ejemplos y otros recursos de interés.
Espero que sea de ayuda y/o motive para comenzar a utilizarlo más a menudo.
Saludos & happy healthchecks
Referencias:
- [Github] Código de esta demo/ejemplo
- [Github] Xabaril HealthChecks
- Imagen de portada