Skip to main content

Django Salmon

A standardized way to observe Django's internals.

Observability is critical feature of software development, but tends to be neglected. It seems like the majority of Python APMs and observability tools have to monkey-patch Django's internals to properly observe the application. This library seeks to do that monkey-patching once, then provide a standardized set of signals/hooks to observe an application.

Usage

  1. Install it as a dependency:
pip install django-salmon
  1. Add it to your INSTALLED_APPS:
INSTALLED_APPS = [
    # ...
    "django_salmon",
    # ...
]
  1. Connect to the relevant signals:
from django.dispatch import receiver
from django_salmon.signals import observe_cache_operation


@receiver(observe_cache_operation)
def observe_cache_ops(sender, args, result, timing, stacktrace):
    print(f"{sender=}\t{timing=}=")
    # stacktrace is a callable that will return the formatted stacktrace.
    print("".join(stacktrace()))

Configuration

Django Salmon supports customizing the decorators that are applied to Django functionality. For example, by default the following decorators are used on all cache operations:

OBSERVING = {
    "cache": [
        "django_salmon.decorators.prevent_nested_observe",
        "django_salmon.decorators.with_args",
        "django_salmon.decorators.with_result",
        "django_salmon.decorators.with_stacktrace",
        "django_salmon.decorators.with_timing",
    ],
}

Each of these decorators will measure a different facet and include it in the context for the django_salmon.decorators.observe decorator. If you only need to measure the timing facet, use the following configuration:

OBSERVING = {
    "cache": [
        "django_salmon.decorators.prevent_nested_observe",
        "django_salmon.decorators.with_timing",
    ],
}

Observing your own functions

Django Salmon supports you applying your own decorators explicitly or by using a registry and utilizing the OBSERVING configuration.

from django.dispatch import Signal
from django_salmon.decorators import observe, with_args

my_signal = Signal()


@observe(my_signal)
@with_args
def explicit_usage_example(arg1, arg2, kwarg1=None):
    return "result"

You can register your own stacked decorators to the registry as well:

# settings.py
OBSERVING = {
    "only_timing": [
        "django_salmon.decorators.prevent_nested_observe",
        "django_salmon.decorators.with_timing",
    ],
}

# signals.py
from django.dispatch import Signal

my_signal = Signal()

# observe.py / Or anything else you want to use
from django_salmon import registry
from django_salmon.decorators import observe
from .signals import my_signal


def observe_only_timing(func):
    """
    Custom decorator factory that emits ``my_signal`` signals.
    """
    return observe(my_signal)(registry.apply_decorators("only_timing", func))


# your_logic.py
from .observe import observe_only_timing


@observe_only_timing
def registry_usage_example(arg1, arg2, kwarg1=None):
    return "result"

Creating your own observer decorator

You can define your own decorator to be used with the registry by adding the relevant data to the context.

An example is:

import functools
from django.dispatch import receiver, Signal
from django_salmon.decorators import observe_context, observe


def with_answer_to_everything(func):
    """
    Decorator that adds the answer to life to the context.
    Must be used below @observe decorator.
    """

    @functools.wraps(func)
    def wrapper(*func_args, **func_kwargs):
        func_result = func(*func_args, **func_kwargs)
        # The context will be None if OBSERVING["enabled"] is False
        if (context := observe_context.get()) is not None:
            # Observe some aspect of the project
            context["answer_to_everything"] = 42
        return func_result

    return wrapper


my_signal = Signal()


@receiver(my_signal)
def my_signal_receiver(sender, answer_to_everything, **kwargs):
    """
    When my_signal is raised, it will now include answer_to_everything
    as a keyword argument.
    """
    print(f"{answer_to_everything=}")


@observe(my_signal)
@with_answer_to_everything
def custom_decorator_example():
    return "result"

Project goals

This project contains several hacks to support observing a Django application. The Django project should change to avoid the necessity of these hacks.

Going further, ideally the Django framework would consider adopting an observability API rendering this project obsolete.

Contributing

See CONTRIBUTING.md for how to contribute!

Metadata

Release files for django-salmon 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-salmon 0.1.0
File Size Uploaded Provenance
django_salmon-0.1.0.tar.gz 50.4 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for django-salmon 0.1.0
File Interpreter ABI Platform
django_salmon-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 61.1 kB

Release files / django_salmon-0.1.0.tar.gz

Download URL django_salmon-0.1.0.tar.gz
Size 50.4 kB
Tags Source
SHA-256 checksum
How to use checksums
7f9e01f9ccd9f78d79b66c1af6dc9356915d48b1aefca1ddf0450f1888193af7
BLAKE2b-256 checksum
How to use checksums
b7512f96559230c75a2d4229867722c45da8ca7088df03300245a69bbc727ef4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 31, 2026.

Transparency log

Release files / django_salmon-0.1.0-py3-none-any.whl

Download URL django_salmon-0.1.0-py3-none-any.whl
Size 10.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d11553fcf3dd86b34b7885a3756a263b892083ff735cceaa55768da7e4531472
BLAKE2b-256 checksum
How to use checksums
c15f0119ee09a19ba2200e29eb95a2cc776d9a72b0eb18c30678fe07f59b1b4b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 31, 2026.

Transparency log

Security for django-salmon 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_salmon-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page