-
-
Notifications
You must be signed in to change notification settings - Fork 444
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
properly name functions #428
Comments
@hiaselhans I'm running into a similar problem when trying to get the original function name in a django middleware. Could you please tell me how you solved this issue? |
how did you fix this? I have the same problem with new relic. |
We had the same problem with New Relic, and I was able to work around it by implementing some middleware like this: class NewRelicMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self._set_ninja_new_relic_transaction_names()
def __call__(self, request):
response = self.get_response(request)
return response
def _set_ninja_new_relic_transaction_names(self):
"""
Without this, all django-ninja requests/errors show up in NewRelic with a
transaction name like `ninja.operation:PathView._sync_view`, which sucks for debugging.
This is a gross hack to fix that, so they are actually grouped in NR correctly,
by the actual api endpoint function name
"""
def nr_wrapper(api_fn, operation_run_fn):
def inner(*args, **kwargs):
# Properly set the NR transaction name based on the api function
# and then call the original operation.run()
transaction_name = f"{api_fn.__module__}.{api_fn.__name__}"
newrelic.agent.set_transaction_name(transaction_name)
return operation_run_fn(*args, **kwargs)
inner._ttam_nr_wrapped = True
return inner
all_urls = NewRelicMiddleware._get_all_resolved_urls()
for url_pattern in all_urls:
view_func = url_pattern.callback
is_ninja_request = isinstance(getattr(view_func, "__self__", None), PathView)
if not is_ninja_request:
continue
path_view: PathView = view_func.__self__
ninja_operation: Operation
for ninja_operation in path_view.operations:
if getattr(ninja_operation.run, "_ttam_nr_wrapped", False): # dont double-wrap the run function
continue
# This is the actual endpoint fn that we care about
api_function = ninja_operation.view_func
# Wrap ninja's Operation.run() function so that set the NR transaction name before it runs
ninja_operation.run = nr_wrapper(api_function, ninja_operation.run)
@classmethod
def _get_all_resolved_urls(cls, url_patterns=None):
"""Recursive function that gets all URLs registered with Django"""
if url_patterns is None:
# Start with the top level url patterns
url_patterns = get_resolver().url_patterns
url_patterns_resolved = []
for entry in url_patterns:
if hasattr(entry, "url_patterns"):
url_patterns_resolved += cls._get_all_resolved_urls(entry.url_patterns)
else:
url_patterns_resolved.append(entry)
return url_patterns_resolved This is kind of a gross hack though :) @vitalik do you have an ideas on how we could fix this in the library? Edit: updated the example, because there was a bug in the original implementation |
My first attempt was to try using Newrelic's ...
import functools
import newrelic.agent
...
def instrument_endpoint(view):
@functools.wraps(view)
async def wrapped_view(*args, **kwargs):
transaction_name = f"{view.__module__}.{view.__name__}"
newrelic.agent.set_transaction_name(transaction_name)
return await view(*args, **kwargs)
return wrapped_view
...
@api.get('/{cal:cal}/{year:year}/{month:month}/{day:day}/', response=DaySchema)
@instrument_endpoint
async def get_calendar_day(request, cal: Calendar, year: year, month: month, day: day):
... |
any update or ETA for this ? |
Tbh, I tried fixing it without reproducing with django-prometheus first, by just writing a UT to check the method name. I'd rather not check New Relic honestly, but maybe it should be possible to do something similar and just use the Also, we could still provide named functions.
Still, I'm really not sure this is the way to go, maybe we should just expect all logging libraries to be able to use Also,
|
Is your feature request related to a problem? Please describe.
I am using django-prometheus for statistics.
The view calls counters are bundled for function names and thus, all my api calls are in the name of
GET /api-1.0.0:ninja.operation._sync_view
I would prefer to have the original function's name or the api-name
Describe the solution you'd like
django-ninja/ninja/operation.py
Lines 314 to 322 in 3d745e7
we could set
func.__module__
andfunc.__name__
hereThe text was updated successfully, but these errors were encountered: