Skip to content

Usage

Setting up monitoring

You can use tools like Pingdom, StatusCake or other uptime robots to monitor service status. The /health/ endpoint will respond with an HTTP 200 if all checks passed and with an HTTP 500 if any of the tests failed. Getting machine-readable JSON reports

If you want machine-readable status reports you can request the /health/ endpoint with the Accept HTTP header set to application/json or pass format=json as a query parameter.

The backend will return a JSON response:

$ curl -v -X GET -H "Accept: application/json" http://www.example.com/health/

> GET /health/ HTTP/1.1
> Host: www.example.com
> Accept: application/json
>
< HTTP/1.1 200 OK
< Content-Type: application/json

{
    "CacheBackend": "working",
    "DatabaseBackend": "working",
    "S3BotoStorageHealthCheck": "working"
}

$ curl -v -X GET http://www.example.com/health/?format=json

> GET /health/?format=json HTTP/1.1
> Host: www.example.com
>
< HTTP/1.1 200 OK
< Content-Type: application/json

{
    "CacheBackend": "working",
    "DatabaseBackend": "working",
    "S3BotoStorageHealthCheck": "working"
}

Writing a custom health check

You can write your own health checks by inheriting from HealthCheck and implementing the check_status method. For example:

import dataclasses
from health_check.backends import HealthCheck


@dataclasses.dataclass
class MyHealthCheckBackend(HealthCheck):
    #: The status endpoints will respond with a 200 status code
    #: even if the check errors.
    critical_service = False

    def check_status(self):
        # The test code goes here.
        # You can use `self.add_error` or
        # raise a `HealthCheckException`,
        # similar to Django's form validation.
        pass

health_check.HealthCheck dataclass

Base class for all health check backends.

To create your own health check backend, subclass this class and implement the check_status method.

Source code in health_check/backends.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
@dataclasses.dataclass()
class HealthCheck:
    """
    Base class for all health check backends.

    To create your own health check backend, subclass this class
    and implement the ``check_status`` method.
    """

    critical_service: bool = dataclasses.field(init=False, default=True, repr=False)
    errors: list[HealthCheckException] = dataclasses.field(init=False, default_factory=list, repr=False)

    def check_status(self):
        """
        Execute the health check logic.

        This method should be overridden by subclasses to implement
        specific health check logic. If the check fails, it should
        call `self.add_error` with an appropriate error message or
        raise a `HealthCheckException`.

        Raises:
            HealthCheckException: If the health check fails.
            ServiceWarning: If the health check encounters a warning condition.

        """
        raise NotImplementedError

    def run_check(self):
        start = timer()
        self.errors = []
        try:
            self.check_status()
        except HealthCheckException as e:
            self.add_error(e, e)
        except BaseException:
            logger.exception("Unexpected Error!")
            raise
        finally:
            self.time_taken = timer() - start

    def add_error(self, error, cause=None):
        if isinstance(error, HealthCheckException):
            pass
        elif isinstance(error, str):
            msg = error
            error = HealthCheckException(msg)
        else:
            msg = "unknown error"
            error = HealthCheckException(msg)
        if isinstance(cause, BaseException):
            logger.exception(str(error))
        else:
            logger.error(str(error))
        self.errors.append(error)

    def pretty_status(self):
        if self.errors:
            return "\n".join(str(e) for e in self.errors)
        return "OK"

    @property
    def status(self):
        return int(not self.errors)

    def __repr__(self):
        if hasattr(self, "identifier"):
            warnings.warn(
                "`identifier()` method is deprecated: implement `__repr__()` instead to return a stable identifier. Action: update your backend class to implement `__repr__` and remove `identifier()`. See migration guide: https://codingjoe.dev/django-health-check/migrate-to-v4/ (docs/migrate-to-v4.md).",
                DeprecationWarning,
            )
            return self.identifier()

        return self.__class__.__name__

check_status()

Execute the health check logic.

This method should be overridden by subclasses to implement specific health check logic. If the check fails, it should call self.add_error with an appropriate error message or raise a HealthCheckException.

Raises:

Type Description
HealthCheckException

If the health check fails.

ServiceWarning

If the health check encounters a warning condition.

Source code in health_check/backends.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def check_status(self):
    """
    Execute the health check logic.

    This method should be overridden by subclasses to implement
    specific health check logic. If the check fails, it should
    call `self.add_error` with an appropriate error message or
    raise a `HealthCheckException`.

    Raises:
        HealthCheckException: If the health check fails.
        ServiceWarning: If the health check encounters a warning condition.

    """
    raise NotImplementedError

Customizing output

You can customize HTML or JSON rendering by inheriting from HealthCheckView and customizing the template_name, get, render_to_response and render_to_response_json properties:

# views.py
from django.http import HttpResponse, JsonResponse

from health_check.views import HealthCheckView


class HealthCheckCustomView(HealthCheckView):
    template_name = "myapp/health_check_dashboard.html"  # customize the used templates

    def get(self, request, *args, **kwargs):
        plugins = []
        status = 200  # needs to be filled status you need
        # …
        if "application/json" in request.META.get("HTTP_ACCEPT", ""):
            return self.render_to_response_json(plugins, status)
        return self.render_to_response(plugins, status)

    def render_to_response(self, plugins, status):  # customize HTML output
        return HttpResponse("COOL" if status == 200 else "SWEATY", status=status)

    def render_to_response_json(self, plugins, status):  # customize JSON output
        return JsonResponse({repr(p): "COOL" if status == 200 else "SWEATY" for p in plugins}, status=status)


# urls.py
from django.urls import path

from . import views

urlpatterns = [
    # …
    path(
        "ht/",
        views.HealthCheckCustomView.as_view(checks=["myapp.health_checks.MyHealthCheckBackend"]),
        name="health_check_custom",
    ),
]

health_check.views.HealthCheckView

Bases: _MainView

Perform health checks and return results in various formats.

Source code in health_check/views.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
class HealthCheckView(_MainView):
    """Perform health checks and return results in various formats."""

    checks: list[str | tuple[str, dict]] | None = None

    def get_plugins(self):
        for check in self.checks or [
            "health_check.Cache",
            "health_check.Database",
            "health_check.Disk",
            "health_check.Mail",
            "health_check.Memory",
            "health_check.Storage",
        ]:
            try:
                check, options = check
            except ValueError:
                options = {}
            if isinstance(check, str):
                check = import_string(check)
            plugin_instance = check(**options)
            yield repr(plugin_instance), plugin_instance

    @cached_property
    def plugins(self):
        return dict(self.get_plugins())

Django command

You can run the Django command health_check to perform your health checks via the command line, or periodically with a cron, as follows:

django-admin health_check --help

This should yield the following output:

Database                 ... OK
CustomHealthCheck        ... unavailable: Something went wrong!

Similar to the http version, a critical error will cause the command to quit with the exit code 1.