Last active
January 23, 2019 13:02
-
-
Save seocam/0751464c2a17f6038646da07e8508dad to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -r -U3 newrelic/api/web_transaction.py newrelic/api/web_transaction.py | |
--- newrelic/api/web_transaction.py 2017-05-26 15:13:50.000000000 -0300 | |
+++ newrelic/api/web_transaction.py 2017-08-11 15:28:16.000000000 -0300 | |
@@ -720,11 +720,15 @@ | |
class _WSGIApplicationIterable(object): | |
- def __init__(self, transaction, generator): | |
+ def __init__(self, transaction, generator, group=None): | |
self.transaction = transaction | |
self.generator = generator | |
self.response_trace = None | |
self.closed = False | |
+ if group is not None: | |
+ self.group = group | |
+ else: | |
+ self.group = 'Python/WSGI' | |
def __iter__(self): | |
self.start_trace() | |
@@ -755,7 +759,7 @@ | |
if not self.response_trace: | |
self.response_trace = FunctionTrace(self.transaction, | |
- name='Response', group='Python/WSGI') | |
+ name='Response', group=self.group) | |
self.response_trace.__enter__() | |
def close(self): | |
@@ -1201,6 +1205,143 @@ | |
for data in self.response_data: | |
yield data | |
+ | |
+def encode_response_wrapper(wrapped, transaction): | |
+ def new_encode_response(wrapped, instance, args, kwargs): | |
+ if not transaction._sent_start: | |
+ transaction._sent_start = time.time() | |
+ message = wrapped(*args, **kwargs) | |
+ transaction._calls_write += 1 | |
+ try: | |
+ transaction._bytes_sent += len(message) | |
+ except Exception: | |
+ pass | |
+ transaction._sent_end = time.time() | |
+ return message | |
+ return FunctionWrapper(wrapped, new_encode_response) | |
+ | |
+ | |
+def ASGIApplicationWrapper(wrapped, application=None, name=None, | |
+ group=None, framework=None): | |
+ | |
+ if framework is not None and not isinstance(framework, tuple): | |
+ framework = (framework, None) | |
+ | |
+ def _nr_asgi_application_wrapper_(wrapped, instance, args, kwargs): | |
+ def _args(message, *args, **kwargs): | |
+ return message | |
+ | |
+ message = _args(*args, **kwargs) | |
+ # Check to see if any transaction is present, even an inactive | |
+ # one which has been marked to be ignored or which has been | |
+ # stopped already. | |
+ | |
+ transaction = current_transaction(active_only=False) | |
+ | |
+ if transaction: | |
+ # If there is any active transaction we will return without | |
+ # applying a new WSGI application wrapper context. In the | |
+ # case of a transaction which is being ignored or which has | |
+ # been stopped, we do that without doing anything further. | |
+ | |
+ if transaction.ignore_transaction or transaction.stopped: | |
+ return wrapped(*args, **kwargs) | |
+ | |
+ # For any other transaction, we record the details of any | |
+ # framework against the transaction for later reporting as | |
+ # supportability metrics. | |
+ | |
+ if framework: | |
+ transaction.add_framework_info( | |
+ name=framework[0], version=framework[1]) | |
+ | |
+ # Also override the web transaction name to be the name of | |
+ # the wrapped callable if not explicitly named, and we want | |
+ # the default name to be that of the WSGI component for the | |
+ # framework. This will override the use of a raw URL which | |
+ # can result in metric grouping issues where a framework is | |
+ # not instrumented or is leaking URLs. | |
+ | |
+ settings = transaction._settings | |
+ | |
+ if name is None and settings: | |
+ if framework is not None: | |
+ naming_scheme = settings.transaction_name.naming_scheme | |
+ if naming_scheme in (None, 'framework'): | |
+ transaction.set_transaction_name( | |
+ callable_name(wrapped), priority=1) | |
+ | |
+ elif name: | |
+ transaction.set_transaction_name(name, group, priority=1) | |
+ | |
+ return wrapped(*args, **kwargs) | |
+ | |
+ target_application = application | |
+ if not hasattr(application, 'activate'): | |
+ target_application = application_instance(application) | |
+ | |
+ # Now start recording the actual web transaction. | |
+ | |
+ request = instance.request_class(message) | |
+ transaction = WebTransaction(target_application, request.META) | |
+ transaction.__enter__() | |
+ | |
+ instance.encode_response = encode_response_wrapper( | |
+ instance.__class__.encode_response, | |
+ transaction, | |
+ ) | |
+ | |
+ # Record details of framework against the transaction for later | |
+ # reporting as supportability metrics. | |
+ | |
+ if framework: | |
+ transaction.add_framework_info( | |
+ name=framework[0], version=framework[1]) | |
+ | |
+ # Override the initial web transaction name to be the supplied | |
+ # name, or the name of the wrapped callable if wanting to use | |
+ # the callable as the default. This will override the use of a | |
+ # raw URL which can result in metric grouping issues where a | |
+ # framework is not instrumented or is leaking URLs. | |
+ # | |
+ # Note that at present if default for naming scheme is still | |
+ # None and we aren't specifically wrapping a designated | |
+ # framework, then we still allow old URL based naming to | |
+ # override. When we switch to always forcing a name we need to | |
+ # check for naming scheme being None here. | |
+ | |
+ settings = transaction._settings | |
+ | |
+ if name is None and settings: | |
+ naming_scheme = settings.transaction_name.naming_scheme | |
+ | |
+ if framework is not None: | |
+ if naming_scheme in (None, 'framework'): | |
+ transaction.set_transaction_name( | |
+ callable_name(wrapped), priority=1) | |
+ | |
+ elif naming_scheme in ('component', 'framework'): | |
+ transaction.set_transaction_name( | |
+ callable_name(wrapped), priority=1) | |
+ | |
+ elif name: | |
+ transaction.set_transaction_name(name, group, priority=1) | |
+ | |
+ try: | |
+ with FunctionTrace(transaction, name='Application', | |
+ group='Python/ASGI'): | |
+ with FunctionTrace(transaction, name=callable_name(wrapped)): | |
+ result = wrapped(message) | |
+ | |
+ except: # Catch all | |
+ transaction.__exit__(*sys.exc_info()) | |
+ raise | |
+ | |
+ return _WSGIApplicationIterable(transaction, result, group='Python/ASGI') | |
+ | |
+ return FunctionWrapper(wrapped, _nr_asgi_application_wrapper_) | |
+ | |
+ | |
def WSGIApplicationWrapper(wrapped, application=None, name=None, | |
group=None, framework=None): | |
diff -r -U3 newrelic/config.py newrelic/config.py | |
--- newrelic/config.py 2017-05-26 15:13:50.000000000 -0300 | |
+++ newrelic/config.py 2017-08-11 14:02:29.000000000 -0300 | |
@@ -1901,6 +1901,9 @@ | |
_process_module_definition('django.core.handlers.wsgi', | |
'newrelic.hooks.framework_django', | |
'instrument_django_core_handlers_wsgi') | |
+ _process_module_definition('channels.handler', | |
+ 'newrelic.hooks.framework_django', | |
+ 'instrument_channels_handler_asgi') | |
_process_module_definition('django.core.urlresolvers', | |
'newrelic.hooks.framework_django', | |
'instrument_django_core_urlresolvers') | |
diff -r -U3 newrelic/hooks/framework_django.py newrelic/hooks/framework_django.py | |
--- newrelic/hooks/framework_django.py 2017-05-26 15:13:50.000000000 -0300 | |
+++ newrelic/hooks/framework_django.py 2017-08-11 15:04:07.000000000 -0300 | |
@@ -13,7 +13,8 @@ | |
from newrelic.api.html_insertion import insert_html_snippet | |
from newrelic.api.transaction import current_transaction | |
from newrelic.api.transaction_name import wrap_transaction_name | |
-from newrelic.api.web_transaction import WSGIApplicationWrapper | |
+from newrelic.api.web_transaction import (ASGIApplicationWrapper, | |
+ WSGIApplicationWrapper) | |
from newrelic.common.object_wrapper import (FunctionWrapper, wrap_in_function, | |
wrap_post_function, wrap_function_wrapper, function_wrapper) | |
@@ -475,6 +476,21 @@ | |
return FunctionWrapper(middleware, wrapper) | |
+def instrument_channels_handler_asgi(module): | |
+ | |
+ import django | |
+ | |
+ framework = ('Django', django.get_version()) | |
+ | |
+ module.AsgiHandler.__call__ = ASGIApplicationWrapper( | |
+ module.AsgiHandler.__call__, framework=framework) | |
+ | |
+ if hasattr(module.AsgiHandler, 'handle_uncaught_exception'): | |
+ module.AsgiHandler.handle_uncaught_exception = ( | |
+ wrap_handle_uncaught_exception( | |
+ module.AsgiHandler.handle_uncaught_exception)) | |
+ | |
+ | |
def instrument_django_core_handlers_wsgi(module): | |
# Wrap the WSGI application entry point. If this is also |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello Sergio, good? are you still using this patch?