-
Notifications
You must be signed in to change notification settings - Fork 554
feat(django): add instrumentation for django signals #1526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Hey @BeryJu ! |
Hey @BeryJu ! I have now tried your signals instrumentation. See the screenshots above. But, would be it be very difficult to add a span for all the receiver functions? So we would get the timing of the actual functions that where running because of signals? This would add really a LOT of value for all the Django developers out there! |
Hey @antonpirker, the PR should add a span for each signal receiver function. I used to run this modified library for https://github.com/goauthentik/authentik but have since reverted to the upstream SDK so I haven't actually tested this in a bit. I'll have a look this evening |
def patch_signals(): | ||
"""Patch django signal receivers to create a span""" | ||
|
||
def send(self: Signal, sender, **kwargs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you basically replace the existing send()
function with your own version.
Best practice is, that we just wrap the existing function and run our code before or after the existing function.
See this as a template: https://github.com/getsentry/sentry-python/blob/master/sentry_sdk/integrations/starlette.py#L204-L218
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah I wanted to originally just wrap the existing function for improved compatibility, but with that there's no way to instrument individual signal handlers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it can work by patching _live_receivers()
and instead of returning an array of receivers (=functions) we wrap all the elements of the array in a function that creates a span and then calls the old receiver.
Something like this:
old_live_receivers = Signal._live_receivers
def _sentry_live_receivers(self, sender)
receivers = old_live_receivers(self, sender)
def _receiver_with_span(*args, **kwargs):
old_receiver = receivers[idx]
name = old_receiver.__name__
with hub.start_span(
op="django.signals",
description=name,
) as span:
span.set_data("signal", name)
return old_receiver(*args, **kwargs)
for idx, receiver in enumerate(receivers):
receivers[idx] = _receiver_with_span
return receivers
Signal._live_receivers = _sentry_live_receivers
Note: this is untested code, I just wrote this on top of my head without ever running it. But I did something similar in another integration a couple of days ago, so it might work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah thats a good idea actually
I just updated my sample project to actually doing some work in the signal receivers (added a So this adds really value to Django projects! Now we just need to find a way to instrument individual signal handlers with wrapping instead of overriding the send function and we are good. Having it like as is is not going to work, because it could change the behavior of users code when they update the django version and we never do that. |
I added a comment with a possible solution to my review @BeryJu . Please have a look. And a heads up: I will be on vacation next week and the following week. So this will probably be merged after my vacation. |
Thanks for the quick update @BeryJu ! Unfortunately I will not be able to review it befor my 2 week vacation, but maybe a colleague (@sl0thentr0py ) picks it up and reviews it. |
Hey @BeryJu ! |
Should work for both, I have not actually tested it myself though (will see if I get some time to do so this weekend). Funnily enough I'll also be on vacation for the next two weeks, so no worries about the review |
Hey @BeryJu Sorry for the delay! I will have a look at the PR tomorrow, promised! |
The new behavior breaks some our our tests. Most notably this one: https://github.com/getsentry/sentry-python/blob/master/tests/integrations/django/test_basic.py#L687-L731 Could you change this test (and maybe other failing ones) to reflect the new behavior @BeryJu ? HINT: Navigating the test errors is still a bit cumbersome. But If you click on the details of the "CI / Run Tests" check above and then search for "error:" you find the actual error message the fastest. Thanks a lot! |
Tests should be fixed now, also added type annotations btw, stickers arrived, thank you very much! |
That was fast! Amazing! Only the tests for old versions (Python 2.7 and 3.5) are failing. Can you please take a look @BeryJu ? |
Should be all good now, missed some special cases for older django versions |
I will do some manual testing again, and then it will be released with the next version. (so probably early next week) Congratulations and Thankyou @BeryJu |
Hey @BeryJu Really great work. You are not by any chance a Go Freelancer and want to help us give our Go SDK a little love? |
If yes, you can message me at anton dot pirker ät sentry dot io |
Add instrumentation for Django signals