Previously I wrote about creating Health Checks for Microsoft Orleans, but the JSON response was too minimal. In this post we’ll see about prettifying that output!
In the previous post we learned a bit about health checks, how to create them, and view their “health” from the perspective of Microsoft Orleans. The end result was a single word response of “Healthy”, “Degraded”, or “Unhealthy”; not very exciting stuff.
In this post, I’d like to quickly go over how you’d go about not only reporting on the “overarching status”, but giving details on the individual health checks that make up that overarching status.
(Note: I did have an issue out there with a hacktoberfest label, that I did get a PR for, but I wanted to go a slightly different route in the end, though I did have it integrated into master for some time.)
The Health check documentation does go into some detail about how to accomplish this health check prettifying, but I’m not a huge fan of “manually” writing out JSON; instead I opted for an anonymous object.
A few new things I want to report on from the response to the health check GET endpoint:
- Health Check Name
- Health Check Description
- Individual Health Check Status
- Some additional information specific to the health check that describes what makes the health check return “Degraded” or “Unhealthy”
Luckily all of this information can be made available to us via the
HealthReport generated as a part of the health check.
We’re going to introduce a new method that writes a custom response for our health check endpoint. From startup, we’ll want to provide a custom
Where the referenced
HealthCheckResponseWriter is a new static class we’ll be introducing next.
ResponseWriter expects a method with the following signature:
You’ll notice above the method receives an
HttpContext as well as HealthReport. This
HealthReport will make available to us several pieces of data that we can report on, specific to each individual health check.
As for our actual response writer implementation, here is the original that was merged into master from L-Dogg‘s PR:
The above definitely works, but I’m not huge on writing the json “manually” (if that makes sense). I wanted to write another blog post on this anyway, as I already had a branch going (and didn’t actually expect a PR :O), so here’s my solution:
I find it a bit more concise working with the anonymous object.
We’re not currently generating “data” information from the health checks that the
HealthCheckResponseWriter would be able to make use of, so let’s take a look at what we could do there.
My intention for the “data” property of the anonymous object is to describe what would make the specific health check return a “Degraded” or “Unhealthy”, anything aside from those two statuses can be assumed to be “Healthy”.
If you recall, we already built thresholds into the health checks to represent the degraded and unhealthy statuses, now we’ll just need to provide those available to the health report.
Taking a look at the
you’ll see that method takes in an optional
IReadOnlyDictionary<string, object> data = null, which happens to be the “data” member we made sure to return from our
WriteResponse method in the previous section of the post.
We will make use of this
IReadonlyDictionary to provide our “threshold” information on a per grain basis. I will be putting this threshold information into both the CPU and Memory grains, but just as an example here’s what one of those will look like:
You should notice in the above that we introduce a
ReadOnlyDictionary with the thresholds for degraded and unhealthy, then passed that
ReadOnlyDictionary to the
data parameter of the static method within
The only thing left to do is test it out! You may have seen the cover image which contained spoilers, but just to wrap things up, here’s what it looks like when hitting the “/health” endpoint after our changes: