Skip to main content

A Django third-party package for observing Django functionality via signals.

Project description

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!

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_salmon-0.1.0.tar.gz (50.4 kB view details)

Uploaded Source

Built Distribution

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

django_salmon-0.1.0-py3-none-any.whl (10.7 kB view details)

Uploaded Python 3

File details

Details for the file django_salmon-0.1.0.tar.gz.

File metadata

  • Download URL: django_salmon-0.1.0.tar.gz
  • Upload date:
  • Size: 50.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for django_salmon-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7f9e01f9ccd9f78d79b66c1af6dc9356915d48b1aefca1ddf0450f1888193af7
MD5 6b01161a3e94a39439e906d47b10934e
BLAKE2b-256 b7512f96559230c75a2d4229867722c45da8ca7088df03300245a69bbc727ef4

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_salmon-0.1.0.tar.gz:

Publisher: release.yml on tim-schilling/django-salmon

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_salmon-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: django_salmon-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for django_salmon-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d11553fcf3dd86b34b7885a3756a263b892083ff735cceaa55768da7e4531472
MD5 8f33200187b40ac8fc93673fe4cfd0ee
BLAKE2b-256 c15f0119ee09a19ba2200e29eb95a2cc776d9a72b0eb18c30678fe07f59b1b4b

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_salmon-0.1.0-py3-none-any.whl:

Publisher: release.yml on tim-schilling/django-salmon

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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