Health checks are useful to not only test the internal health of your application but also it’s external dependencies such as confirming that a third party api is available or confirming the connectivity to a database for example. App Metrics provides such health checks and exposes a health endpoint whereby results can be viewed and monitored. Health checks in App Metrics are small tests which return either a healthy, degraded or unhealthy result. Health checks are executed when the health endpoint is requested via ASP.NET Core Middleware.

Here we’ll look at configuring App Metrics to provide health checks in an ASP.NET Core MVC application.

Create a new ASP.NET Web Application

1.png

Add App.Metrics packages

Add the packages marked below to start using App Metrics for it’s health checking capablity in a web context.

3.png

This demo is assuming a dependency on ASP.NET Core MVC although not required i.e. App.Metrics.Extensions.Middleware exposes the health endpoint through ASP.NET Core Middleware.

The App.Metrics.Extensions.Mvc package provides requested MVC route templates to App Metrics to measure things like reponse times and error rates per endpoint for example, this package has a dependency on the middleware package.

Configure Services

To configure the required application services we need to wire-up App Metrics on the IServiceCollection. At the moment JSON serialization is the only supported format.

 public void ConfigureServices(IServiceCollection services)
 {
     services.
         AddMetrics(Configuration.GetSection("AppMetrics"), options => options.GlobalTags.Add("app", "sample app")).
             AddJsonSerialization().                     
             AddHealthChecks().
             AddMetricsMiddleware(Configuration.GetSection("AspNetMetrics"));
     
     services.AddMvc(options => options.AddMetricsResourceFilter());
 }

Configure Middleware

Next we need to register the required ASP.NET Core middleware via the IApplicationBuilder.

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
 {
     app.UseMetrics();
 
     app.UseMvc();
 }

Configuration Options

App Metrics provides configuration options via code, config or a mix of both. For more details on what is available see the docs on AppMetrics Configuration and AppMetrics Middleware Configuration. For now add the following to appsettings.json.

 {
     "AppMetrics": {
         "DefaultContextLabel": "SampleApi",
         "MetricsEnabled": true,
         "ReportingEnabled": false,
         "GlobalTags": { "env": "stage" },
         "ApdexTSeconds": 0.1
     }
 }

Viewing the results

Now that we have everything wired-up, run the web application and request /health, the response will look as follows

 {
   "degraded": {},
   "healthy": {
     "apdex Score": "Satisfied. Score 1"
   },
   "status": "Healthy",
   "timestamp": "2017-04-17T00:00:00.0000Z",
   "unhealthy": {}
 }

You will notice an Apdex Score check already registered. This is a health check registered by default which can be disabled through configuration.

Implementing Health Checks

Health checks can be written either by inheriting HealthCheck or using the IHealthCheckFactory provided via the IMetricHostBuilder allowing checks to be fluently registered.

App Metrics will automatically register all classes inheritenting HealthCheck on startup by scanning the host project as well as any of it’s references which have a dependency on App Metrics, so we basically just need to provide an implementation.

Health Check class implementation

To demostrate how to have a health check return a degraded result, add a new HealthCheck class.

4.png

Then modify the class with the following snippet which simply returns a degraded result.

 public class SampleDegradedHealthCheck : HealthCheck
 {
     public SampleDegradedHealthCheck() : base("Sample Degraded")
     {
     }
 
     protected override Task CheckAsync(CancellationToken token = default(CancellationToken))
     {
         return Task.FromResult(HealthCheckResult.Degraded("Degraded"));
     }
 }

To demonstrate returning an unhealthy result, add another HealthCheck implementation

Add sample unhealthy

 public class SampleHealthCheckUnhealthy : HealthCheck
 {
     public SampleHealthCheckUnhealthy() : base("Sample Unhealthy") { }
 
     protected override Task CheckAsync(CancellationToken token = default(CancellationToken))
     {
         return Task.FromResult(HealthCheckResult.Unhealthy("OOPS"));
     }
 }

Viewing the results

Now by running the web application and requesting /health, the response will look as follows

 {
   "degraded": {
     "sample Degraded": "Degraded"
   },
   "healthy": {
     "apdex Score": "Satisfied. Score 1"
   },
   "status": "Unhealthy",
   "timestamp": "2017-04-17T00:00:00.0000Z",
   "unhealthy": {
     "sample UnHealthy": "OOPS"
   }
 }

We can see our sample degraded and unhealthy checks along with their failure reasons.

Health Check fluent implementation

Alternatively, App Metrics allows Health Checks is to be registered fluently and also comes with some pre-defined checks such as performing a ping on a domain, confirming a GET request on a specified URI returns a 200 status and checking the physical, private and virtual memory sizes against a configured threshold for example.

Update the ConfigureServices method with the following to demonstrate.

 public void ConfigureServices(IServiceCollection services)
 {
     services.AddMetrics(Configuration.GetSection("AppMetrics"), options => options.GlobalTags.Add("app", "sample app")).
              AddJsonSerialization().                     
              AddHealthChecks(
                  factory =>
                  {
                      var physicalMemoryThresholdBytes = 100 * 1024 * 1024;
                      factory.RegisterProcessPhysicalMemoryHealthCheck("physical memory", physicalMemoryThresholdBytes);                      
                      factory.RegisterPingHealthCheck("google ping", "google.com", TimeSpan.FromSeconds(10));
                      factory.RegisterHttpGetHealthCheck("github", new Uri("https://github.com/"), TimeSpan.FromSeconds(10));
                  }).
              AddMetricsMiddleware(Configuration.GetSection("AspNetMetrics"));
     services.AddMvc(options => options.AddMetricsResourceFilter());
 }

Additional health checks can be implemented this way through an extension method on the IHealthCheckFactory, see here for example. When using App Metrics for performance monitoring, health checks can be implemented comparing values measured by your application against a specified threshold, see the ApdexHealthCheck as an example.

Viewing the results

Once again by running the web application and requesting /health, the response will look as follows displaying the newly registered checks via the health check factory.

 {
   "degraded": {
     "sample Degraded": "Degraded"
   },
   "healthy": {
     "apdex Score": "Satisfied. Score 1",
     "github": "OK. https://github.com/",
     "google ping": "OK. google.com",
     "physical memory": "OK. 104857600 bytes"
   },
   "status": "Unhealthy",
   "timestamp": "2017-04-17T17:00:00.0000Z",
   "unhealthy": {    
     "sample UnHealthy": "OOPS"
   }
 }

Response Headers

Regardless of the health check result, the health endpoint will respond with the following response headers

Cache-Control:no-cache, no-store, must-revalidate
Content-Type:application/json
Expires:0
Pragma:no-cache

In addition:

When all checks pass, a 200 status code will be returned.

When one or more checks fail or throw an uncaught exception, a 500 status code will be returned.

When no checks fail but one or more checks were considered to be degrading the application, a 200 status code as well as a warning response header of Warning:100 'Degraded' will be returned to indicate the application is in a degrading state.

What’s next

Having our application’s health exposed over an HTTP endpoint isn’t really that useful yet. This becomes more useful when we have automated monitoring and alerting on this endpoint e.g. Pingdom, or by persisting the results to build for example a health status page. App Metrics will automatically record health check results as gauges, which can be configured to report metrics to InfluxDB or Elasticsearch for example.

For other features provided by App Metrics see the documentation.

Advertisements

Posted by Allan Hardy

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s