{"id":13815249,"url":"https://github.com/mwarkentin/django-watchman","last_synced_at":"2025-05-14T09:06:23.514Z","repository":{"id":13955156,"uuid":"16655352","full_name":"mwarkentin/django-watchman","owner":"mwarkentin","description":"django-watchman exposes a status endpoint for your backing services like databases, caches, etc.","archived":false,"fork":false,"pushed_at":"2025-03-31T19:51:33.000Z","size":374,"stargazers_count":544,"open_issues_count":22,"forks_count":62,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-15T02:11:19.053Z","etag":null,"topics":["cache","database","django","django-watchman","healthcheck","monitoring","panopta","pingdom","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"cartalyst/demo-cart","license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mwarkentin.png","metadata":{"files":{"readme":"README.rst","changelog":"HISTORY.rst","contributing":"CONTRIBUTING.rst","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.rst","dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2014-02-08T23:10:54.000Z","updated_at":"2025-04-10T08:42:19.000Z","dependencies_parsed_at":"2023-02-16T15:15:29.120Z","dependency_job_id":"9ddce6a8-19ad-4bdc-945f-23be5365d8ae","html_url":"https://github.com/mwarkentin/django-watchman","commit_stats":{"total_commits":317,"total_committers":32,"mean_commits":9.90625,"dds":"0.34069400630914826","last_synced_commit":"74a61a35884c36b0dcd3e2382390968be74776b2"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwarkentin%2Fdjango-watchman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwarkentin%2Fdjango-watchman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwarkentin%2Fdjango-watchman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mwarkentin%2Fdjango-watchman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mwarkentin","download_url":"https://codeload.github.com/mwarkentin/django-watchman/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254110374,"owners_count":22016391,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","database","django","django-watchman","healthcheck","monitoring","panopta","pingdom","python"],"created_at":"2024-08-04T04:03:12.736Z","updated_at":"2025-05-14T09:06:23.492Z","avatar_url":"https://github.com/mwarkentin.png","language":"Python","funding_links":[],"categories":["Python","Monitoring and Logging"],"sub_categories":[],"readme":"=============================\ndjango-watchman\n=============================\n\n.. image:: http://img.shields.io/pypi/v/django-watchman.svg\n    :target: http://badge.fury.io/py/django-watchman\n\n.. image:: http://img.shields.io/coveralls/mwarkentin/django-watchman.svg\n    :target: https://coveralls.io/r/mwarkentin/django-watchman?branch=main\n\ndjango-watchman exposes a status endpoint for your backing services like\ndatabases, caches, etc.\n\n.. image:: https://mwarkentin-snaps.s3.amazonaws.com/Watchmen_The_One_Thing_Nobody_Says_about_Adrian_Veidt_aka_Ozymandias_2022-03-23_08-36-18.png\n\nDocumentation\n-------------\n\nThe full documentation is at http://django-watchman.rtfd.org.\n\nTestimonials\n------------\n\n    We're in love with django-watchman. External monitoring is a vital part of our service offering. Using django-watchman we can introspect the infrastructure of an application via a secure URL. It's very well written and easy to extend. We've recommended it to many of our clients already.\n\n— Hany Fahim, CEO, `VM Farms \u003chttps://vmfarms.com/\u003e`_.\n\nQuickstart\n----------\n\n1. Install ``django-watchman``::\n\n    pip install django-watchman\n\n2. Add ``watchman`` to your ``INSTALLED_APPS`` setting like this::\n\n    INSTALLED_APPS = (\n        ...\n        'watchman',\n    )\n\n3. Include the watchman URLconf in your project ``urls.py`` like this::\n\n    re_path(r'^watchman/', include('watchman.urls')),\n\n4. Start the development server and visit ``http://127.0.0.1:8000/watchman/`` to\n   get a JSON response of your backing service statuses::\n\n    {\n        \"databases\": [\n            {\n                \"default\": {\n                    \"ok\": true\n                }\n            }\n        ],\n        \"caches\": [\n            {\n                \"default\": {\n                    \"ok\": true\n                }\n            }\n        ],\n        \"storage\": {\"ok\": true}\n    }\n\nPycon Canada Presentation (10 minutes)\n--------------------------------------\n\n.. image:: https://mwarkentin-snaps.s3.amazonaws.com/Full-stack_Django_application_monitoring_with_django-watchman_Michael_Warkentin_-_YouTube_2022-03-23_08-34-24.png\n   :target: https://www.youtube.com/watch?v=iEgOCY7_zGI\n\nFeatures\n--------\n\nHuman-friendly dashboard\n************************\n\nVisit ``http://127.0.0.1:8000/watchman/dashboard/`` to get a human-friendly HTML\nrepresentation of all of your watchman checks.\n\nToken based authentication\n**************************\n\nIf you want to protect the status endpoint, you can use the ``WATCHMAN_TOKENS`` setting.\nThis is a comma-separated list of tokens.\nWhen this setting is added, you must pass one of the tokens in as the ``watchman-token`` **GET** parameter::\n\n    GET http://127.0.0.1:8000/watchman/?watchman-token=:token\n\nOr by setting the ``Authorization: WATCHMAN-TOKEN`` header on the request::\n\n    curl -X GET -H \"Authorization: WATCHMAN-TOKEN Token=\\\":token\\\"\" http://127.0.0.1:8000/watchman/\n\nIf you want to change the token name, you can set the ``WATCHMAN_TOKEN_NAME``.\nThe value of this setting will be the **GET** parameter that you must pass in::\n\n    WATCHMAN_TOKEN_NAME = 'custom-token-name'\n\n    GET http://127.0.0.1:8000/watchman/?custom-token-name=:token\n\n**DEPRECATION WARNING**: ``WATCHMAN_TOKEN`` was replaced by the ``WATCHMAN_TOKENS`` setting to support multiple authentication tokens in django-watchman ``0.11``.\nIt will continue to work until it's removed in django-watchman ``1.0``.\n\nCustom authentication/authorization\n***********************************\n\nIf you want to protect the status endpoint with a customized\nauthentication/authorization decorator, you can add ``WATCHMAN_AUTH_DECORATOR``\nto your settings. This needs to be a dotted-path to a decorator, and defaults\nto ``watchman.decorators.token_required``::\n\n    WATCHMAN_AUTH_DECORATOR = 'django.contrib.admin.views.decorators.staff_member_required'\n\nNote that the ``token_required`` decorator does not protect a view unless\n``WATCHMAN_TOKENS`` is set in settings.\n\nCustom checks\n*************\n\ndjango-watchman allows you to customize the checks which are run by modifying\nthe ``WATCHMAN_CHECKS`` setting. In ``settings.py``::\n\n    WATCHMAN_CHECKS = (\n        'module.path.to.callable',\n        'another.module.path.to.callable',\n    )\n\nYou can also import the watchman.constants to include the DEFAULT_CHECKS and PAID_CHECKS in your ``settings.py``::\n\n   from watchman import constants as watchman_constants\n\n   WATCHMAN_CHECKS = watchman_constants.DEFAULT_CHECKS + ('module.path.to.callable', )\n\nChecks take no arguments, and must return a ``dict`` whose keys are applied to the JSON response.\n\nUse the ``watchman.decorators.check`` decorator to capture exceptions::\n\n    from watchman.decorators import check\n\n    def custom_check():\n        return {\"custom_check\": _custom_check()}\n\n    @check\n    def _custom_check():\n        return {\"ok\": True, \"extra_info\": \"if helpful\"}\n\nIn the absence of any checks, a 404 is thrown, which is then handled by the\n``json_view`` decorator.\n\nRun a subset of available checks\n********************************\n\nA subset of checks may be run, by passing ``?check=module.path.to.callable\u0026check=...``\nin the request URL. Only the callables given in the querystring which are also\nin ``WATCHMAN_CHECKS`` should be run, eg::\n\n    curl -XGET http://127.0.0.1:8080/watchman/?check=watchman.checks.caches\n\nSkip specific checks\n********************\n\nYou can skip any number of checks, by passing ``?skip=module.path.to.callable\u0026skip=...``\nin the request URL. Only the checks in ``WATCHMAN_CHECKS`` which are not in the\nquerystring should be run, eg::\n\n    curl -XGET http://127.0.0.1:8080/watchman/?skip=watchman.checks.email\n\nCheck a subset of databases or caches\n*************************************\n\nIf your application has a large number of databases or caches configured,\nwatchman may open too many connections as it checks each database or cache.\n\nYou can set the ``WATCHMAN_DATABASES`` or ``WATCHMAN_CACHES`` settings in order\nto override the default set of databases and caches to be monitored.\n\nPing\n****\n\nIf you want to simply check that your application is running and able to handle\nrequests, you can call ping:\n\n    GET http://127.0.0.1:8000/watchman/ping/\n\nIt will return the text ``pong`` with a 200 status code. Calling this doesn't\nrun any of the checks.\n\nBare status view\n****************\n\nIf you would like a \"bare\" status view (one that doesn't report any details,\njust ``HTTP 200`` if checks pass, and ``HTTP 500`` if any checks fail), you\ncan use the ``bare_status`` view by putting the following into ``urls.py``::\n\n    import watchman.views\n    # ...\n    re_path(r'^status/?$', watchman.views.bare_status),\n\nDjango management command\n*************************\n\nYou can also run your checks without starting the webserver and making requests.\nThis can be useful for testing your configuration before enabling a server,\nchecking configuration on worker servers, etc. Run the management command like so::\n\n    python manage.py watchman\n\nBy default, successful checks will not print any output. If all checks pass\nsuccessfully, the exit code will be ``0``. If a check fails, the exit code will\nbe ``1``, and the error message including stack trace will be printed to ``stderr``.\n\nIf you'd like to see output for successful checks as well, set verbosity to\n``2`` or higher::\n\n    python manage.py watchman -v 2\n    {\"storage\": {\"ok\": true}}\n    {\"caches\": [{\"default\": {\"ok\": true}}]}\n    {\"databases\": [{\"default\": {\"ok\": true}}]}\n\nIf you'd like to run a subset of checks, use ``-c`` and a comma-separated list\nof python module paths::\n\n    python manage.py watchman -c watchman.checks.caches,watchman.checks.databases -v 2\n    {\"caches\": [{\"default\": {\"ok\": true}}]}\n    {\"databases\": [{\"default\": {\"ok\": true}}]}\n\nIf you'd like to skip certain checks, use ``-s`` and a comma-separated list of\npython module paths::\n\n    python manage.py watchman -s watchman.checks.caches,watchman.checks.databases -v 2\n    {\"storage\": {\"ok\": true}}\n\nUse ``-h`` to see a full list of options::\n\n    python manage.py watchman -h\n\nX-Watchman-Version response header\n**********************************\n\nWatchman can return the version of watchman which is running to help you keep\ntrack of whether or not your sites are using an up-to-date version. This is\ndisabled by default to prevent any unintended information leakage for websites\nwithout authentication. To enable, update the ``EXPOSE_WATCHMAN_VERSION``\nsetting::\n\n    EXPOSE_WATCHMAN_VERSION = True\n\nCustom response code\n********************\n\nBy default, watchman will return a ``500`` HTTP response code, even if there's a\nfailing check. You can specify a different response code for failing checks\nusing the ``WATCHMAN_ERROR_CODE`` setting::\n\n    WATCHMAN_ERROR_CODE = 200\n\nLogging\n*******\n\nwatchman includes log messages using a logger called ``watchman``.\nYou can configure this by configuring the ``LOGGING`` section of your Django\nsettings file.\n\nHere is a simple example that would log to the console::\n\n    LOGGING = {\n        'version': 1,\n        'disable_existing_loggers': False,\n        'handlers': {\n            'console': {\n                'class': 'logging.StreamHandler',\n            },\n        },\n        'loggers': {\n            'watchman': {\n                'handlers': ['console'],\n                'level': 'DEBUG',\n            },\n        },\n    }\n\nMore information is available in the `Django documentation\n\u003chttps://docs.djangoproject.com/en/2.0/topics/logging/#configuring-logging]\u003e`_.\n\nAPM (Datadog, New Relic)\n************************\n\nIf you're using APM and watchman is being often hit for health checks (such as an ELB on\nAWS), you will find some stats based on averages will be affected (average transaction\ntime, apdex, etc):\n\nYou can disable APM instrumentation for watchman by using the ``WATCHMAN_DISABLE_APM``\nsetting::\n\n    WATCHMAN_DISABLE_APM = True\n\nThis currently supports the following agents:\n\n* Datadog\n* New Relic\n\nPlease open an issue if there's another APM you use which is being affected.\n\n\nAvailable checks\n----------------\n\ncaches\n******\n\nFor each cache in ``django.conf.settings.CACHES``:\n\n* Set a test cache item\n* Get test item\n* Delete test item\n\ndatabases\n*********\n\nFor each database in ``django.conf.settings.DATABASES``:\n\n* Verify connection by calling ``connections[database].introspection.table_names()``\n\nemail\n*****\n\nSend a test email to ``to@example.com`` using ``django.core.mail.send_mail``.\n\nIf you're using a 3rd party mail provider, this check could end up costing you\nmoney, depending how aggressive you are with your monitoring. For this reason,\nthis check is **not enabled** by default.\n\nFor reference, if you were using Mandrill, and hitting your watchman endpoint\nonce per minute, this would cost you ~$5.60/month.\n\n**Custom Settings**\n\n* ``WATCHMAN_EMAIL_SENDER`` (default: ``watchman@example.com``): Specify an email to be the sender of the test email\n* ``WATCHMAN_EMAIL_RECIPIENTS`` (default: ``[to@example.com]``): Specify a list of email addresses to send the test email\n* ``WATCHMAN_EMAIL_HEADERS`` (default: ``{}``): Specify a dict of custom headers to be added to the test email\n\nstorage\n*******\n\nUsing ``django.core.files.storage.default_storage``:\n\n* Write a test file\n* Check the test file's size\n* Read the test file's contents\n* Delete the test file\n\nBy default the test file gets written on the root of the django ``MEDIA_ROOT``.\n\nThere are two reasons why you may need to override this.  You can use\nthe setting ``WATCHMAN_STORAGE_PATH`` to accomplish this.\n\n1) Django triggers a `django.core.exceptions.SuspiciousFileOperation\n\u003chttps://docs.djangoproject.com/en/5.0/ref/exceptions/#suspiciousoperation\u003e`\non the storage check.\n\n2) If for whatever reason, the base of ``MEDIA_ROOT`` is not writable by\nthe user that runs Django.\n\nIn either case, choose a path within and relative to ``MEDIA_ROOT``.\n\n  WATCHMAN_STORAGE_PATH = \"django-watchman/\"\n\nIf the ``MEDIA_ROOT`` is already defined::\n\n  from os.path import join as joinpath\n  WATCHMAN_STORAGE_PATH = joinpath(MEDIA_ROOT, \"django-watchman/\")\n\nDefault checks\n**************\n\nBy default, django-watchman will run checks against your databases\n(``watchman.checks.databases``), caches (``watchman.checks.caches``), and\nstorage (``watchman.checks.storage``).\n\nPaid checks\n***********\n\nPaid checks are checks which may cost you money if they are run regularly.\n\nCurrently there is only one \"paid\" check - ``watchman.checks.email``. Many\ntimes email is sent using managed services like SendGrid or Mailgun. You can\nenable it by setting the ``WATCHMAN_ENABLE_PAID_CHECKS`` to ``True``, or by\noverriding the ``WATCHMAN_CHECKS`` setting.\n\nTrying it out with Docker\n--------------------------\n\nA sample project is available along with a Dockerfile to make it easy to try\nout django-watchman. It includes examples of how to write simple custom checks.\n\nOne of the custom checks will always fail, so if you want to see what responses\nlook like with 100% succeeding checks, add `?skip=sample_project.checks.fail_custom_check`\n\nRequirements\n************\n\n* `Docker \u003chttps://www.docker.com/get-docker\u003e`\n\nInstructions\n************\n\n1. Build and run the Docker image with the current local code: ``make run``\n2. Visit watchman json endpoint in your browser: http://127.0.0.1:8000/watchman/\n3. Visit watchman json endpoint in your browser: http://127.0.0.1:8000/watchman/?skip=sample_project.checks.fail_custom_check\n4. Visit watchman dashboard in your browser: http://127.0.0.1:8000/watchman/dashboard/\n5. Visit watchman dashboard in your browser: http://127.0.0.1:8000/watchman/dashboard/?skip=sample_project.checks.fail_custom_check\n6. Visit watchman ping in your browser: http://127.0.0.1:8000/watchman/ping/\n7. Visit watchman bare status in your browser: http://127.0.0.1:8000/watchman/bare/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmwarkentin%2Fdjango-watchman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmwarkentin%2Fdjango-watchman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmwarkentin%2Fdjango-watchman/lists"}