Skip to main content

Catch Django exceptions and send formatted error reports to Telegram with optional database logging

Project description

django-telegram-notifier

PyPI version Python versions Django versions License: MIT

Catch unhandled Django exceptions and send formatted error reports to Telegram — like a lightweight Sentry. Includes full traceback as a .py file attachment with syntax highlighting, smart exception classification, optional database logging with a rich admin dashboard, and async support.


Features

  • Automatic exception catching via middleware (sync & async)
  • Non-blocking — Telegram API calls run in a background thread, never slowing down your response
  • Smart exception classification — auto-assigns level & severity based on exception type
  • Formatted Telegram messages with emoji levels, request context, and traceback preview
  • Full traceback as .py file — Telegram renders Python syntax highlighting
  • Exception filtering — ignore specific exceptions, paths, or use custom filter functions
  • Optional database logging — store every exception with request details, severity, status
  • Rich admin dashboard — stats, charts, action toolbar, prev/next navigation, Monaco editors
  • Light & dark mode admin — auto-detects system/Django admin theme
  • Configurable logger — use stdlib logging, loguru, structlog, or any custom logger
  • Celery support — optionally offload reporting to a Celery task
  • Decorator for wrapping individual functions/views
  • Multi-chat support — send to multiple Telegram chats
  • Proxy support for restricted environments
  • Management command to clean up old exception logs

Quick Start

1. Install

pip install django-telegram-notifier

2. Get a Telegram Bot Token

  1. Open Telegram, search for @BotFather
  2. Send /newbot and follow the prompts
  3. Copy the bot token (e.g. 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)
  4. Send a message to your bot, then visit https://api.telegram.org/bot<TOKEN>/getUpdates to find your chat_id

3. Configure

Add to your Django settings.py:

INSTALLED_APPS = [
    # ...
    "telegram_notifier",
]

MIDDLEWARE = [
    # ... other middleware ...
    "telegram_notifier.middleware.GlobalExceptionReporterMiddleware",
]

TELEGRAM_NOTIFIER = {
    "BOT_TOKEN": "your-bot-token",
    "CHAT_IDS": ["your-chat-id"],
}

4. Migrate (only if using database logging)

python manage.py migrate

That's it. Any unhandled exception will now send a notification to your Telegram chat.


Settings

All settings go inside the TELEGRAM_NOTIFIER dictionary in your Django settings:

TELEGRAM_NOTIFIER = {
    # Required
    "BOT_TOKEN": "your-bot-token",
    "CHAT_IDS": ["chat-id-1", "chat-id-2"],

    # Optional (defaults shown)
    "ENVIRONMENT": None,            # e.g. "production", "staging" — shown in messages
    "PROXY": None,                  # e.g. "socks5://127.0.0.1:1080"
    "MESSAGE_MAX_LENGTH": 4000,     # max message length (Telegram limit)
    "STORE_EXCEPTIONS": False,      # save exceptions to database
    "CLEANUP_DAYS": 30,             # days to keep exception logs

    # Filtering
    "IGNORE_EXCEPTIONS": [],        # exception class names to skip
    "IGNORE_PATHS": [],             # URL path prefixes to skip
    "FILTER": None,                 # custom callable(exc, request) -> bool

    # Logging
    "LOGGER": None,                 # custom logger instance (loguru, structlog, etc.)

    # Async / Celery
    "CELERY_TASK": None,            # Celery task for offloading (see Celery section)
}
Setting Type Default Description
BOT_TOKEN str required Telegram Bot API token
CHAT_IDS list[str] required Telegram chat IDs to send notifications to
ENVIRONMENT str | None None Environment name shown in messages (e.g. "production")
PROXY str | None None Proxy URL for Telegram API requests
MESSAGE_MAX_LENGTH int 4000 Maximum message length before truncation
STORE_EXCEPTIONS bool False Save exceptions to ExceptionLog model
CLEANUP_DAYS int 30 Days to keep exception logs (used by cleanup command)
IGNORE_EXCEPTIONS list[str] [] Exception class names to skip (checks MRO)
IGNORE_PATHS list[str] [] URL path prefixes to skip
FILTER callable | None None Custom filter function (exc, request) -> bool
LOGGER object | None None Custom logger instance (any object with .info(), .error())
CELERY_TASK Task | None None Celery task to offload reporting (see below)

Exception Filtering

Control which exceptions get reported with three layers of filtering:

Ignore by exception class

TELEGRAM_NOTIFIER = {
    # ...
    "IGNORE_EXCEPTIONS": [
        "Http404",
        "PermissionDenied",
        "DisallowedHost",
        "Throttled",
    ],
}

This checks the exception's MRO, so "DatabaseError" also catches IntegrityError, OperationalError, etc.

Ignore by path

TELEGRAM_NOTIFIER = {
    # ...
    "IGNORE_PATHS": [
        "/health",
        "/favicon.ico",
        "/.well-known",
    ],
}

Custom filter function

TELEGRAM_NOTIFIER = {
    # ...
    "FILTER": lambda exc, request: (
        # Only report in production
        not getattr(request, 'path', '').startswith('/admin/')
    ),
}

Return True to report, False to skip. Filters are evaluated in order: IGNORE_EXCEPTIONS -> IGNORE_PATHS -> FILTER.


Smart Exception Classification

Exceptions are automatically classified by level and severity based on their type:

Category Level Severity Examples
System failures critical critical MemoryError, RecursionError, SystemExit
Infrastructure error high DatabaseError, ConnectionError, TimeoutError
Client/validation warning low Http404, ValidationError, PermissionDenied, Throttled
Default (bugs) error moderate TypeError, KeyError, AttributeError

You can override auto-classification by passing explicit level and severity to report_exception().


Usage

Middleware (recommended)

The middleware catches all unhandled exceptions automatically. Place it after Django's built-in middleware:

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "telegram_notifier.middleware.GlobalExceptionReporterMiddleware",
]

The middleware is async-capable — works with both WSGI and ASGI servers.

Decorator

Wrap individual functions or views:

from telegram_notifier import telegram_exception_notifier

@telegram_exception_notifier
def my_task():
    # if this raises, it gets reported to Telegram
    do_something_risky()

# Also works with async functions
@telegram_exception_notifier
async def my_async_task():
    await do_something_risky()

Manual Reporting

Report exceptions programmatically:

from telegram_notifier import report_exception

try:
    do_something()
except Exception as exc:
    report_exception(exc, level="critical", severity="high")

Parameters:

Parameter Type Default Description
exc Exception required The exception to report
request HttpRequest | None None Django request (adds path, method, body, user)
body bytes | None None Request body
level str | None auto Overrides auto-classification
severity str | None auto Overrides auto-classification

Custom Logger

By default, the package uses Python's stdlib logging. You can plug in any logger:

# loguru
from loguru import logger
TELEGRAM_NOTIFIER = { ..., "LOGGER": logger }

# structlog
import structlog
TELEGRAM_NOTIFIER = { ..., "LOGGER": structlog.get_logger() }

# silent (disable all logging)
TELEGRAM_NOTIFIER = { ..., "LOGGER": None }

Any object with .info() and .error() methods works.


Non-Blocking & Celery

By default, all Telegram API calls and database writes run in a background daemon thread — your request response is never delayed by slow network or Telegram downtime.

For projects using Celery, you can offload reporting to a Celery task instead:

# tasks.py
from celery import shared_task
from telegram_notifier.report import _do_report

@shared_task
def send_telegram_report(
    exc_class_name, exc_message, message,
    traceback_content, level, severity, request_data,
):
    _do_report(
        exc_class_name=exc_class_name,
        exc_message=exc_message,
        message=message,
        traceback_content=traceback_content,
        effective_level=level,
        effective_severity=severity,
        request_data=request_data,
        body=None,
    )
# settings.py
from myapp.tasks import send_telegram_report

TELEGRAM_NOTIFIER = {
    # ...
    "CELERY_TASK": send_telegram_report,
}

When CELERY_TASK is set, reporting is dispatched via .delay() instead of a thread — giving you retries, monitoring, and rate limiting through your existing Celery infrastructure.


Telegram Message Format

Each notification is sent as a document (.py file with full traceback) with a caption containing:

🔴 ValueError in production

Message: invalid literal for int()
Timestamp: 2026-03-11 12:30:45

▸ Traceback (preview)
    value = int(user_input)
ValueError: invalid literal for int() with base 10: 'abc'

▸ Request
  Path: /api/users/
  Method: POST
  Body: {"name": "test"}
  User: admin@example.com

Level emojis: ⚪ debug · 🔵 info · 🟡 warning · 🔴 error · ⛔ critical

The attached .py file contains the complete traceback with Python syntax highlighting in Telegram.


Database Logging & Admin Dashboard

Enable with "STORE_EXCEPTIONS": True. This creates an ExceptionLog entry for every reported exception.

Admin List View

  • Summary stats — exceptions in last 24h/7d, by level, unresolved count
  • Charts — exceptions timeline (24h bar chart) and level breakdown (doughnut)
  • Colored badges — level, severity, method, environment, status
  • Inline status editing — change status directly from the list
  • Bulk actions — Mark as Resolved, Mark as Ignored, Mark as Seen, Resend to Telegram
  • Date hierarchy — quick date navigation
  • Filters — by level, severity, status, sent, environment, method, date

Admin Detail View

  • Action toolbar — Resolve, Seen, Ignore, Resend to Telegram (AJAX, no reload)
  • Occurrence stats — how many times this exception occurred in 24h/7d/total
  • Prev/Next navigation — browse exceptions chronologically
  • Monaco editors — syntax-highlighted traceback (Python), headers/body/params (JSON)
  • Copy/Format/Minify buttons — on all JSON sections with tooltip feedback
  • Collapsible headers section
  • Light & dark mode — auto-detects Django admin theme and system preference

ExceptionLog Fields

Field Type Description
exception_class CharField e.g. "ValueError"
message TextField Exception message
traceback TextField Full traceback
level CharField debug, info, warning, error, critical
severity CharField low, moderate, high, critical
status CharField new, seen, resolved, ignored
path CharField Request path
method CharField HTTP method
query_params JSONField Query string parameters
body TextField Request body
user_info CharField Authenticated user string
ip_address GenericIPAddressField Client IP (with X-Forwarded-For support)
headers JSONField Request headers (sensitive headers filtered)
view_name CharField Django view name
hostname CharField Server hostname
environment CharField Environment from settings
is_sent BooleanField Whether Telegram notification was sent
created_at DateTimeField When the exception occurred

Querying Exceptions

from telegram_notifier import ExceptionLog, Status, Level

# Unresolved errors
ExceptionLog.objects.filter(status=Status.NEW, level=Level.ERROR)

# Errors in the last 24 hours
from django.utils.timezone import now
from datetime import timedelta
ExceptionLog.objects.filter(created_at__gte=now() - timedelta(hours=24))

# Mark as resolved
ExceptionLog.objects.filter(pk=1).update(status=Status.RESOLVED)

Cleanup Command

Delete old exception logs:

# Use CLEANUP_DAYS setting (default: 30)
python manage.py cleanup_exceptions

# Override with custom days
python manage.py cleanup_exceptions --days=7

Schedule with cron for automatic cleanup:

0 3 * * * python /path/to/manage.py cleanup_exceptions

Public API

from telegram_notifier import (
    # Core
    report_exception,              # Report an exception manually
    notify_error_via_telegram,     # Send raw message to Telegram
    classify_exception,            # Get (level, severity) for an exception

    # Message building
    build_exception_message,       # Build formatted HTML message
    build_traceback_content,       # Get full traceback string

    # Middleware & decorator
    GlobalExceptionReporterMiddleware,
    telegram_exception_notifier,

    # Models & choices
    ExceptionLog,                  # Database model (lazy-loaded)
    Level,                         # debug, info, warning, error, critical
    Severity,                      # low, moderate, high, critical
    Status,                        # new, seen, resolved, ignored
)

Requirements

  • Python >= 3.11
  • Django >= 5.2
  • httpx >= 0.28.1

Development

git clone https://github.com/ganiyevuz/django-telegram-notifier.git
cd django-telegram-notifier

# Install dependencies
uv sync --group dev

# Copy env file and add your bot token
cp .env.example .env

# Run tests
pytest

# Run linter
ruff check .

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_telegram_notifier-0.2.0.tar.gz (26.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_telegram_notifier-0.2.0-py3-none-any.whl (32.7 kB view details)

Uploaded Python 3

File details

Details for the file django_telegram_notifier-0.2.0.tar.gz.

File metadata

File hashes

Hashes for django_telegram_notifier-0.2.0.tar.gz
Algorithm Hash digest
SHA256 3b4203f41c46084de8efe8cd8f593aeb7108507fd6517726c9151beff83cdd04
MD5 0b132124bc1e71d427a71f17a06a9d69
BLAKE2b-256 ae66bd276bffb1a5c457ceadbc31ec71ea2ee6356cbb20699bc225b7bda396fb

See more details on using hashes here.

File details

Details for the file django_telegram_notifier-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_telegram_notifier-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ad00ee0beebb0e0fe5facee543b795f657bf3c7b911e134e2a4a9b18f60207b2
MD5 fc17ae6d3556d5bde0488d7fe438dd97
BLAKE2b-256 6759d953b1175da008a8cb51d4a00c302496738810353c62e825235ec1d68c4b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page