def _callable_name(): # This is pretty ugly and inefficient, but a stack # frame doesn't provide any information about the # original callable object. We thus need to try and # deduce what it is by searching through the stack # frame globals. This will still not work in many # cases, including lambdas, generator expressions, # and decoratored attributes such as properties of # classes. try: if func_name in frame.f_globals: if frame.f_globals[func_name].func_code is co: return callable_name(frame.f_globals[func_name]) except Exception: pass for name, obj in six.iteritems(frame.f_globals): try: if obj.__dict__[func_name].func_code is co: return callable_name(obj.__dict__[func_name]) except Exception: pass
def wrap_handle_uncaught_exception(middleware): # Wrapper to be applied to handler called when exceptions # propagate up to top level from middleware. Records the # time spent in the handler as separate function node. Names # the web transaction after the name of the handler if not # already named at higher priority and capture further # errors in the handler. name = callable_name(middleware) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) def _wrapped(request, resolver, exc_info): transaction.name_transaction(name, priority=1) transaction.record_exception(*exc_info) try: return wrapped(request, resolver, exc_info) except: # Catch all transaction.record_exception(*sys.exc_info()) raise with FunctionTrace(transaction, name=name): return _wrapped(*args, **kwargs) return ObjectWrapper(middleware, None, wrapper)
def wrap_view_handler(wrapped, priority=3): # Ensure we don't wrap the view handler more than once. This # looks like it may occur in cases where the resolver is # called recursively. We flag that view handler was wrapped # using the '_nr_django_view_handler' attribute. if hasattr(wrapped, '_nr_django_view_handler'): return wrapped name = callable_name(wrapped) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) transaction.set_transaction_name(name, priority=priority) with FunctionTrace(transaction, name=name): try: return wrapped(*args, **kwargs) except: # Catch all transaction.record_exception(ignore_errors=should_ignore) raise result = ObjectWrapper(wrapped, None, wrapper) result._nr_django_view_handler = True return result
def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) def _args(request, *args, **kwargs): return request view = instance request = _args(*args, **kwargs) # We can't intercept the delegated view handler when it # is looked up by the dispatch() method so we need to # duplicate the lookup mechanism. if request.method.lower() in view.http_method_names: handler = getattr(view, request.method.lower(), view.http_method_not_allowed) else: handler = view.http_method_not_allowed name = callable_name(handler) transaction.set_transaction_name(name) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs)
def dynamic_wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) if callable(name): if instance and inspect.ismethod(wrapped): _name = name(instance, *args, **kwargs) else: _name = name(*args, **kwargs) elif name is None: _name = callable_name(wrapped) else: _name = name if callable(group): if instance and inspect.ismethod(wrapped): _group = group(instance, *args, **kwargs) else: _group = group(*args, **kwargs) else: _group = group transaction.name_transaction(_name, _group, priority) return wrapped(*args, **kwargs)
def wrapper(wrapped): # The middleware if a class method would already be # bound at this point, so is safe to determine the name # when it is being wrapped rather than on each # invocation. name = callable_name(wrapped) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) before = (transaction.name, transaction.group) with FunctionTrace(transaction, name=name): try: return wrapped(*args, **kwargs) finally: # We want to name the transaction after this # middleware but only if the transaction wasn't # named from within the middleware itself explicity. after = (transaction.name, transaction.group) if before == after: transaction.name_transaction(name, priority=2) return ObjectWrapper(wrapped, None, wrapper)
def __init__(self, consumer, source, name, settings, **properties): self.consumer = consumer self.properties = source(settings) self.factory = self.properties['factory'] self.instance = None self.properties.update(properties) self.name = (name or self.properties.get('name') or callable_name(source)) self.group = self.properties.get('group') if self.group: self.group = self.group.rstrip('/') environ = {} environ['consumer.name'] = consumer environ['consumer.vendor'] = 'New Relic' environ['producer.name'] = self.name environ['producer.group'] = self.group self.environ = environ _logger.debug('Initialising data sampler for %r.', self.environ)
def on_connection_close_wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction: return wrapped(*args, **kwargs) handler = instance request = handler.request transaction = getattr(request, '_nr_transaction', None) if not transaction: return wrapped(*args, **kwargs) transaction.save_transaction() if request._nr_wait_function_trace: request._nr_wait_function_trace.__exit__(None, None, None) name = callable_name(wrapped) try: with FunctionTrace(transaction, name): return wrapped(*args, **kwargs) except Exception: transaction.record_exception(*sys.exc_info()) finally: transaction.__exit__(None, None, None)
def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if callable(name): # Start Hotfix v2.2.1. #if instance and inspect.ismethod(wrapped): # _name = name(instance, *args, **kwargs) #else: # _name = name(*args, **kwargs) if instance is not None: _name = name(instance, *args, **kwargs) else: _name = name(*args, **kwargs) # End Hotfix v2.2.1. elif name is None: _name = callable_name(wrapped) else: _name = name # Helper for obtaining the appropriate application object. If # has an activate() method assume it is a valid application # object. Don't check by type so se can easily mock it for # testing if need be. def _application(): if hasattr(application, 'activate'): return application return application_instance(application) # Check to see if we are being called within the context of an # existing transaction. If we are, then we will record the call # as a function trace node instead. This situation can occur # when a function wrapped with Celery task decorator is called # explicitly in the context of an existing transaction. if transaction: with FunctionTrace(transaction, callable_name(wrapped)): return wrapped(*args, **kwargs) # Otherwise treat it as top level background task. with BackgroundTask(_application(), _name, 'Celery'): return wrapped(*args, **kwargs)
def callback_wrapper(wrapped, instance, args, kwargs): if current_transaction(): return wrapped(*args, **kwargs) if not hasattr(transaction, '_nr_current_request'): return wrapped(*args, **kwargs) request = transaction._nr_current_request() if not request: return wrapped(*args, **kwargs) if not hasattr(request, '_nr_wait_function_trace'): return wrapped(*args, **kwargs) if not request._nr_wait_function_trace: return wrapped(*args, **kwargs) transaction.save_transaction() if request._nr_wait_function_trace: request._nr_wait_function_trace.__exit__(None, None, None) request._nr_wait_function_trace = None try: name = callable_name(wrapped) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs) except Exception: transaction.record_exception(*sys.exc_info()) raise finally: if not request._nr_request_finished: request._nr_wait_function_trace = FunctionTrace( transaction, name='Callback/Wait', group='Python/Tornado') request._nr_wait_function_trace.__enter__() transaction.drop_transaction() elif not request.connection.stream.writing(): transaction.__exit__(None, None, None) request._nr_transaction = None else: request._nr_wait_function_trace = FunctionTrace( transaction, name='Request/Output', group='Python/Tornado') request._nr_wait_function_trace.__enter__() transaction.drop_transaction()
def _name_transaction(*args, **kwargs): transaction = newrelic.api.transaction.current_transaction() if transaction: if isinstance(args[1], basestring): f = args[1] else: f = callable_name(args[1]) transaction.name_transaction(f) return (args, kwargs)
def render_wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs)
def _name_transaction(*args, **kwargs): transaction = newrelic.api.transaction.current_transaction() if transaction: if isinstance(args[1], six.string_types): f = args[1] else: f = callable_name(args[1]) transaction.name_transaction(f) return (args, kwargs)
def transaction_name_delegate(*args, **kwargs): transaction = newrelic.api.transaction.current_transaction() if transaction: if isinstance(args[1], six.string_types): f = args[1] else: f = callable_name(args[1]) transaction.set_transaction_name(f) return (args, kwargs)
def literal_wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) _name = name or callable_name(wrapped) with FunctionTrace(transaction, _name, group, label, params): return wrapped(*args, **kwargs)
def literal_wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) _name = name or callable_name(wrapped) transaction.name_transaction(_name, group, priority) return wrapped(*args, **kwargs)
def wrap_url_resolver(wrapped): # Wrap URL resolver. If resolver returns valid result then # wrap the view handler returned. The type of the result # changes across Django versions so need to check and adapt # as necessary. For a 404 then a user supplied 404 handler # or the default 404 handler should get later invoked and # transaction should be named after that. name = callable_name(wrapped) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) if hasattr(transaction, '_nr_django_url_resolver'): return wrapped(*args, **kwargs) # Tag the transaction so we know when we are in the top # level call to the URL resolver as don't want to show # the inner ones as would be one for each url pattern. transaction._nr_django_url_resolver = True def _wrapped(path): # XXX This can raise a Resolver404. If this is not dealt # with, is this the source of our unnamed 404 requests. with FunctionTrace(transaction, name=name, label=path): result = wrapped(path) if type(result) == type(()): callback, callback_args, callback_kwargs = result result = (wrap_view_handler(callback, priority=3), callback_args, callback_kwargs) else: result.func = wrap_view_handler(result.func, priority=3) return result try: return _wrapped(*args, **kwargs) finally: del transaction._nr_django_url_resolver return ObjectWrapper(wrapped, None, wrapper)
def wrap_template_block(wrapped): name = callable_name(wrapped) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) with FunctionTrace(transaction, name=instance.name, group='Template/Block'): return wrapped(*args, **kwargs) return ObjectWrapper(wrapped, None, wrapper)
def dynamic_wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) if callable(name): if instance and inspect.ismethod(wrapped): _name = name(instance, *args, **kwargs) else: _name = name(*args, **kwargs) elif name is None: _name = callable_name(wrapped) else: _name = name if callable(group): if instance and inspect.ismethod(wrapped): _group = group(instance, *args, **kwargs) else: _group = group(*args, **kwargs) else: _group = group if callable(label): if instance and inspect.ismethod(wrapped): _label = label(instance, *args, **kwargs) else: _label = label(*args, **kwargs) else: _label = label if callable(params): if instance and inspect.ismethod(wrapped): _params = params(instance, *args, **kwargs) else: _params = params(*args, **kwargs) else: _params = params with FunctionTrace(transaction, _name, _group, _label, _params): return wrapped(*args, **kwargs)
def wrap_url_resolver_nnn(wrapped, priority=1): # Wrapper to be applied to the URL resolver for errors. name = callable_name(wrapped) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) with FunctionTrace(transaction, name=name): callback, param_dict = wrapped(*args, **kwargs) return (wrap_view_handler(callback, priority=priority), param_dict) return ObjectWrapper(wrapped, None, wrapper)
def wrapper(wrapped): # The middleware if a class method would already be # bound at this point, so is safe to determine the name # when it is being wrapped rather than on each # invocation. name = callable_name(wrapped) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs) return ObjectWrapper(wrapped, None, wrapper)
def wrap_view_handler(wrapped, priority=3): # Ensure we don't wrap the view handler more than once. This # looks like it may occur in cases where the resolver is # called recursively. We flag that view handler was wrapped # using the '_nr_django_view_handler' attribute. if hasattr(wrapped, '_nr_django_view_handler'): return wrapped name = callable_name(wrapped) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) transaction.name_transaction(name, priority=priority) with FunctionTrace(transaction, name=name): try: return wrapped(*args, **kwargs) except: # Catch all # Python 2.5 doesn't allow *args before keywords. # See http://bugs.python.org/issue3473. exc_info = sys.exc_info() transaction.record_exception(exc_info[0], exc_info[1], exc_info[2], ignore_errors=[ 'django.http:Http404', 'django.http.response:Http404' ]) raise finally: exc_info = None result = ObjectWrapper(wrapped, None, wrapper) result._nr_django_view_handler = True return result
def outer_fn_wrapper(outer_fn, instance, args, kwargs): view_name = args[0] meta = getattr(instance, "_meta", None) if meta is None: group = 'Python/TastyPie/Api' name = instance.api_name callback = getattr(instance, 'top_level', None) elif meta.api_name is not None: group = 'Python/TastyPie/Api' name = '%s/%s/%s' % (meta.api_name, meta.resource_name, view_name) callback = getattr(instance, view_name, None) else: group = 'Python/TastyPie/Resource' name = '%s/%s' % (meta.resource_name, view_name) callback = getattr(instance, view_name, None) # Give preference to naming web transaction and trace node after # target callback, but fall back to abstract path if for some reason # we don't get a valid target callback. if callback is not None: name = callable_name(callback) group = None def inner_fn_wrapper(inner_fn, instance, args, kwargs): transaction = current_transaction() if transaction is None or name is None: return inner_fn(*args, **kwargs) transaction.name_transaction(name, group, priority=4) with FunctionTrace(transaction, name, group): try: return inner_fn(*args, **kwargs) except: # Catch all transaction.record_exception(*sys.exc_info()) raise result = outer_fn(*args, **kwargs) return ObjectWrapper(result, None, inner_fn_wrapper)
def outer_fn_wrapper(outer_fn, instance, args, kwargs): view_name = args[0] meta = getattr(instance, "_meta", None) if meta is None: group = 'Python/TastyPie/Api' name = instance.api_name callback = getattr(instance, 'top_level', None) elif meta.api_name is not None: group = 'Python/TastyPie/Api' name = '%s/%s/%s' % (meta.api_name, meta.resource_name, view_name) callback = getattr(instance, view_name, None) else: group = 'Python/TastyPie/Resource' name = '%s/%s' % (meta.resource_name, view_name) callback = getattr(instance, view_name, None) # Give preference to naming web transaction and trace node after # target callback, but fall back to abstract path if for some reason # we don't get a valid target callback. if callback is not None: name = callable_name(callback) group = None def inner_fn_wrapper(inner_fn, instance, args, kwargs): transaction = current_transaction() if transaction is None or name is None: return inner_fn(*args, **kwargs) transaction.set_transaction_name(name, group, priority=4) with FunctionTrace(transaction, name, group): try: return inner_fn(*args, **kwargs) except: # Catch all transaction.record_exception(*sys.exc_info()) raise result = outer_fn(*args, **kwargs) return ObjectWrapper(result, None, inner_fn_wrapper)
def wrap_view_handler(wrapped, priority=3): # Ensure we don't wrap the view handler more than once. This # looks like it may occur in cases where the resolver is # called recursively. We flag that view handler was wrapped # using the '_nr_django_view_handler' attribute. if hasattr(wrapped, '_nr_django_view_handler'): return wrapped name = callable_name(wrapped) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) transaction.name_transaction(name, priority=priority) with FunctionTrace(transaction, name=name): try: return wrapped(*args, **kwargs) except: # Catch all # Python 2.5 doesn't allow *args before keywords. # See http://bugs.python.org/issue3473. exc_info = sys.exc_info() transaction.record_exception(exc_info[0], exc_info[1], exc_info[2], ignore_errors=['django.http:Http404', 'django.http.response:Http404']) raise finally: exc_info = None result = ObjectWrapper(wrapped, None, wrapper) result._nr_django_view_handler = True return result
def wrapper(wrapped): # The middleware if a class method would already be # bound at this point, so is safe to determine the name # when it is being wrapped rather than on each # invocation. name = callable_name(wrapped) def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() def _wrapped(request, view_func, view_args, view_kwargs): # This strips the view handler wrapper before call. if hasattr(view_func, '_nr_last_object'): view_func = view_func._nr_last_object return wrapped(request, view_func, view_args, view_kwargs) if transaction is None: return _wrapped(*args, **kwargs) before = (transaction.name, transaction.group) with FunctionTrace(transaction, name=name): try: return _wrapped(*args, **kwargs) finally: # We want to name the transaction after this # middleware but only if the transaction wasn't # named from within the middleware itself explicity. after = (transaction.name, transaction.group) if before == after: transaction.set_transaction_name(name, priority=2) return ObjectWrapper(wrapped, None, wrapper)
def register_browser_timing_middleware(middleware): # Inserts our middleware for inserting the RUM header and # footer into the list of middleware. Must check for certain # types of middleware which modify content as must always # come before them. Otherwise is added last so that comes # after any caching middleware. If don't do that then the # inserted header and footer will end up being cached and # then when served up from cache we would add a second # header and footer, something we don't want. content_type_modifying_middleware = [ 'django.middleware.gzip:GZipMiddleware.process_response' ] for i in range(len(middleware)): function = middleware[i] name = callable_name(function) if name in content_type_modifying_middleware: middleware.insert(i, browser_timing_middleware) break else: middleware.append(browser_timing_middleware)
def execute_wrapper(wrapped, instance, args, kwargs): assert instance is not None handler = instance request = handler.request # Check to see if we are being called within the context of any # sort of transaction. If we are, then we don't bother doing # anything and just call the wrapped function. This should not # really ever occur but check anyway. transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) if request.method not in handler.SUPPORTED_METHODS: return wrapped(*args, **kwargs) name = callable_name(getattr(handler, request.method.lower())) transaction.set_transaction_name(name) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs)
def wsgi_container_call_wrapper(wrapped, instance, args, kwargs): def _args(request, *args, **kwargs): return request request = _args(*args, **kwargs) transaction = getattr(request, '_nr_transaction', None) name = callable_name(instance.wsgi_application) if not transaction: # Always use the default application specified in the agent # configuration. application = application_instance() # We need to fake up a WSGI like environ dictionary with the # key bits of information we need. environ = request_environment(application, request) # Now start recording the actual web transaction. Bail out # though if turns out that recording transactions is not # enabled. transaction = WebTransaction(application, environ) if not transaction.enabled: return wrapped(*args, **kwargs) transaction.__enter__() request._nr_transaction = transaction request._nr_wait_function_trace = None request._nr_request_finished = False # We need to add a reference to the request object in to the # transaction object as only able to stash the transaction # in a deferred. Need to use a weakref to avoid an object # cycle which may prevent cleanup of transaction. transaction._nr_current_request = weakref.ref(request) try: # Call the original method in a trace object to give better # context in transaction traces. # XXX This is a temporary fiddle to preserve old default # URL naming convention until will move away from that # as a default. if transaction._request_uri is not None: transaction.set_transaction_name( transaction._request_uri, 'Uri', priority=1) with FunctionTrace(transaction, name='WSGI/Application', group='Python/Tornado'): with FunctionTrace(transaction, name=name): wrapped(*args, **kwargs) if not request.connection.stream.writing(): transaction.__exit__(None, None, None) request._nr_transaction = None else: request._nr_wait_function_trace = FunctionTrace( transaction, name='Request/Output', group='Python/Tornado') request._nr_wait_function_trace.__enter__() transaction.drop_transaction() except: # Catch all # If an error occurs assume that transaction should be # exited. transaction.__exit__(*sys.exc_info()) request._nr_transaction = None raise else: try: # XXX This is a temporary fiddle to preserve old default # URL naming convention until will move away from that # as a default. if transaction._request_uri is not None: transaction.set_transaction_name( transaction._request_uri, 'Uri', priority=1) with FunctionTrace(transaction, name='WSGI/Application', group='Python/Tornado'): with FunctionTrace(transaction, name=name): wrapped(*args, **kwargs) if not request.connection.stream.writing(): transaction.__exit__(None, None, None) request._nr_transaction = None else: request._nr_wait_function_trace = FunctionTrace( transaction, name='Request/Output', group='Python/Tornado') request._nr_wait_function_trace.__enter__() transaction.drop_transaction() except: # Catch all # If an error occurs assume that transaction should be # exited. transaction.__exit__(*sys.exc_info()) request._nr_transaction = None raise
def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction(active_only=False) if callable(name): # Start Hotfix v2.2.1. # if instance and inspect.ismethod(wrapped): # _name = name(instance, *args, **kwargs) # else: # _name = name(*args, **kwargs) if instance is not None: _name = name(instance, *args, **kwargs) else: _name = name(*args, **kwargs) # End Hotfix v2.2.1. elif name is None: _name = callable_name(wrapped) else: _name = name # Helper for obtaining the appropriate application object. If # has an activate() method assume it is a valid application # object. Don't check by type so se can easily mock it for # testing if need be. def _application(): if hasattr(application, 'activate'): return application return application_instance(application) # A Celery Task can be called either outside of a transaction, or # within the context of an existing transaction. There are 3 # possibilities we need to handle: # # 1. In an inactive transaction # # If the end_of_transaction() or ignore_transaction() API calls # have been invoked, this task may be called in the context # of an inactive transaction. In this case, don't wrap the task # in any way. Just run the original function. # # 2. In an active transaction # # Run the original function inside a FunctionTrace. # # 3. Outside of a transaction # # This is the typical case for a celery Task. Since it's not # running inside of an existing transaction, we want to create # a new background transaction for it. if transaction and (transaction.ignore_transaction or transaction.stopped): return wrapped(*args, **kwargs) elif transaction: with FunctionTrace(callable_name(wrapped)): return wrapped(*args, **kwargs) else: with BackgroundTask(_application(), _name, 'Celery'): return wrapped(*args, **kwargs)
def finish_wrapper(wrapped, instance, args, kwargs): assert instance is not None handler = instance request = handler.request # Call finish() method straight away if request object it is # being called on is not even associated with a transaction. # If we were in a running transaction we still want to record # the call though. This will occur when calling finish on # another request, but the target request wasn't monitored. transaction = getattr(request, '_nr_transaction', None) running_transaction = current_transaction() if not transaction: if running_transaction: name = callable_name(wrapped) with FunctionTrace(transaction, name): return wrapped(*args, **kwargs) else: return wrapped(*args, **kwargs) # Do we have a running transaction. When we do we need to # consider two possiblities. The first is where the current # running transaction doesn't match that bound to the request. # For this case it would be where from within one transaction # there is an attempt to call finish() on a distinct web request # which was being monitored. The second is where finish() is # being called for the current request. if running_transaction: if transaction != running_transaction: # For this case we need to suspend the current running # transaction and call ourselves again. When it returns # we need to restore things back the way they were. # We still trace the call in the running transaction # though so the fact that it called finish on another # request is apparent. name = callable_name(wrapped) with FunctionTrace(running_transaction, name): try: running_transaction.drop_transaction() return finish_wrapper(wrapped, instance, args, kwargs) finally: running_transaction.save_transaction() else: # For this case we just trace the call. name = callable_name(wrapped) with FunctionTrace(transaction, name): return wrapped(*args, **kwargs) # No current running transaction. If we aren't in a wait state # we call finish() straight away. if not request._nr_wait_function_trace: return wrapped(*args, **kwargs) # Now handle the special case where finish() was called while in # the wait state. We need to restore the transaction for the # request and then call finish(). When it returns we need to # either end the transaction or go into a new wait state where # we wait on output to be sent. transaction.save_transaction() try: complete = True request._nr_wait_function_trace.__exit__(None, None, None) name = callable_name(wrapped) with FunctionTrace(transaction, name): result = wrapped(*args, **kwargs) if not request.connection.stream.writing(): transaction.__exit__(None, None, None) else: request._nr_wait_function_trace = FunctionTrace( transaction, name='Request/Output', group='Python/Tornado') request._nr_wait_function_trace.__enter__() transaction.drop_transaction() complete = False return result except: # Catch all transaction.__exit__(*sys.exc_info()) raise finally: if complete: request._nr_wait_function_trace = None request._nr_transaction = None
def on_headers_wrapper(wrapped, instance, args, kwargs): assert instance is not None connection = instance # Check to see if we are being called within the context of any # sort of transaction. If we are, then we don't bother doing # anything and just call the wrapped function. This should not # really ever occur but check anyway. transaction = current_transaction() if transaction: return wrapped(*args, **kwargs) # Execute the wrapped function as we are only going to do # something after it has been called. The function doesn't # return anything. wrapped(*args, **kwargs) # Check to see if the connection has already been closed or the # request finished. The connection can be closed where request # content length was too big. if connection.stream.closed(): return if connection._request_finished: return # Check to see if have already associated a transaction with # the request, because if we have, even if not finished, then # do not need to do anything. request = connection._request if request is None: return if hasattr(request, '_nr_transaction'): return # Always use the default application specified in the agent # configuration. application = application_instance() # We need to fake up a WSGI like environ dictionary with the # key bits of information we need. environ = request_environment(application, request) # Now start recording the actual web transaction. Bail out # though if turns out that recording transactions is not # enabled. transaction = WebTransaction(application, environ) if not transaction.enabled: return transaction.__enter__() request._nr_transaction = transaction request._nr_wait_function_trace = None request._nr_request_finished = False # Add a callback variable to the connection object so we can # be notified when the connection is closed before all content # has been read. def _close(): transaction.save_transaction() try: if request._nr_wait_function_trace: request._nr_wait_function_trace.__exit__(None, None, None) finally: request._nr_wait_function_trace = None transaction.__exit__(None, None, None) request._nr_transaction = None connection.stream._nr_close_callback = _close # Name transaction initially after the wrapped function so # that if connection dropped before request content read, # then don't get metric grouping issues with it being named # after the URL. name = callable_name(wrapped) transaction.set_transaction_name(name) # We need to add a reference to the request object in to the # transaction object as only able to stash the transaction # in a deferred. Need to use a weakref to avoid an object # cycle which may prevent cleanup of transaction. transaction._nr_current_request = weakref.ref(request) try: request._nr_wait_function_trace = FunctionTrace( transaction, name='Request/Input', group='Python/Tornado') request._nr_wait_function_trace.__enter__() transaction.drop_transaction() except: # Catch all # If an error occurs assume that transaction should be # exited. Technically don't believe this should ever occur # unless our code here has an error. connection.stream._nr_close_callback = None _logger.exception('Unexpected exception raised by Tornado ' 'HTTPConnection._on_headers().') transaction.__exit__(*sys.exc_info()) request._nr_transaction = None raise
def __call__(self, frame, event, arg): if event not in [ 'call', 'c_call', 'return', 'c_return', 'exception', 'c_exception' ]: return transaction = current_transaction() if not transaction: return # Not sure if setprofile() is reliable in the face of # coroutine systems based on greenlets so don't run # if we detect may be using greenlets. if (hasattr(sys, '_current_frames') and not transaction.thread_id in sys._current_frames()): return co = frame.f_code func_name = co.co_name func_line_no = frame.f_lineno func_filename = co.co_filename def _callable_name(): # This is pretty ugly and inefficient, but a stack # frame doesn't provide any information about the # original callable object. We thus need to try and # deduce what it is by searching through the stack # frame globals. This will still not work in many # cases, including lambdas, generator expressions, # and decoratored attributes such as properties of # classes. try: if func_name in frame.f_globals: if frame.f_globals[func_name].func_code is co: return callable_name(frame.f_globals[func_name]) except Exception: pass for name, obj in six.iteritems(frame.f_globals): try: if obj.__dict__[func_name].func_code is co: return callable_name(obj.__dict__[func_name]) except Exception: pass if event in ['call', 'c_call']: # Skip the outermost as we catch that with the root # function traces for the profile trace. if len(self.function_traces) == 0: self.function_traces.append(None) return if self.current_depth >= self.maximum_depth: self.function_traces.append(None) return if func_filename.startswith(AGENT_PACKAGE_DIRECTORY): self.function_traces.append(None) return if event == 'call': name = _callable_name() if not name: name = '%s:%s#%s' % (func_filename, func_name, func_line_no) else: name = callable_name(arg) if not name: name = '%s:@%s#%s' % (func_filename, func_name, func_line_no) function_trace = FunctionTrace(transaction, name=name) function_trace.__enter__() self.function_traces.append(function_trace) self.current_depth += 1 elif event in ['return', 'c_return', 'c_exception']: if not self.function_traces: return try: function_trace = self.function_traces.pop() except IndexError: pass else: if function_trace: function_trace.__exit__(None, None, None) self.current_depth -= 1
def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) if callable(name): if instance and inspect.ismethod(wrapped): _name = name(instance, *args, **kwargs) else: _name = name(*args, **kwargs) elif name is None: _name = callable_name(wrapped) else: _name = name if callable(group): if instance and inspect.ismethod(wrapped): _group = group(instance, *args, **kwargs) else: _group = group(*args, **kwargs) else: _group = group if callable(label): if instance and inspect.ismethod(wrapped): _label = label(instance, *args, **kwargs) else: _label = label(*args, **kwargs) else: _label = label if callable(params): if instance and inspect.ismethod(wrapped): _params = params(instance, *args, **kwargs) else: _params = params(*args, **kwargs) else: _params = params with FunctionTrace(transaction, _name, _group, _label, _params): if not hasattr(sys, 'getprofile'): return wrapped(*args, **kwargs) profiler = sys.getprofile() if profiler: return wrapped(*args, **kwargs) sys.setprofile(ProfileTrace(depth)) try: return wrapped(*args, **kwargs) finally: sys.setprofile(None)
def wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if callable(name): if instance and inspect.ismethod(wrapped): _name = name(instance, *args, **kwargs) else: _name = name(*args, **kwargs) elif name is None: _name = callable_name(wrapped) else: _name = name if callable(group): if instance and inspect.ismethod(wrapped): _group = group(instance, *args, **kwargs) else: _group = group(*args, **kwargs) else: _group = group # Check to see if we are being called within the context # of a web transaction. If we are, then we will just # flag the current web transaction as a background task # if not already marked as such and name the web # transaction as well. In any case, if nested in another # transaction be it a web transaction or background # task, then we don't do anything else and just called # the wrapped function. if transaction: if type(transaction) == WebTransaction: if not transaction.background_task: transaction.background_task = True transaction.name_transaction(_name, _group) return wrapped(*args, **kwargs) # Otherwise treat it as top level transaction. if type(application) != Application: _application = application_instance(application) else: _application = application try: success = True manager = BackgroundTask(_application, _name, _group) manager.__enter__() try: return wrapped(*args, **kwargs) except: # Catch all success = False if not manager.__exit__(*sys.exc_info()): raise finally: if success: manager.__exit__(None, None, None)
def __call__(self, frame, event, arg): if event not in ['call', 'c_call', 'return', 'c_return', 'exception', 'c_exception']: return transaction = current_transaction() if not transaction: return # Not sure if setprofile() is reliable in the face of # coroutine systems based on greenlets so don't run # if we detect may be using greenlets. if (hasattr(sys, '_current_frames') and not transaction.thread_id in sys._current_frames()): return co = frame.f_code func_name = co.co_name func_line_no = frame.f_lineno func_filename = co.co_filename def _callable_name(): # This is pretty ugly and inefficient, but a stack # frame doesn't provide any information about the # original callable object. We thus need to try and # deduce what it is by searching through the stack # frame globals. This will still not work in many # cases, including lambdas, generator expressions, # and decoratored attributes such as properties of # classes. try: if func_name in frame.f_globals: if frame.f_globals[func_name].func_code is co: return callable_name(frame.f_globals[func_name]) except Exception: pass for name, obj in six.iteritems(frame.f_globals): try: if obj.__dict__[func_name].func_code is co: return callable_name(obj.__dict__[func_name]) except Exception: pass if event in ['call', 'c_call']: # Skip the outermost as we catch that with the root # function traces for the profile trace. if len(self.function_traces) == 0: self.function_traces.append(None) return if self.current_depth >= self.maximum_depth: self.function_traces.append(None) return if func_filename.startswith(AGENT_PACKAGE_DIRECTORY): self.function_traces.append(None) return if event == 'call': name = _callable_name() if not name: name = '%s:%s#%s' % (func_filename, func_name, func_line_no) else: name = callable_name(arg) if not name: name = '%s:@%s#%s' % (func_filename, func_name, func_line_no) function_trace = FunctionTrace(transaction, name=name) function_trace.__enter__() self.function_traces.append(function_trace) self.current_depth += 1 elif event in ['return', 'c_return', 'c_exception']: if not self.function_traces: return try: function_trace = self.function_traces.pop() except IndexError: pass else: if function_trace: function_trace.__exit__(None, None, None) self.current_depth -= 1