def _nr_wrapper_RequestHandler__execute_(wrapped, instance, args, kwargs): handler = instance request = handler.request if request is None: _logger.error('Runtime instrumentation error. Calling _execute on ' 'a RequestHandler when no request is present. Please ' 'report this issue to New Relic support.\n%s', ''.join(traceback.format_stack()[:-1])) return wrapped(*args, **kwargs) transaction = retrieve_request_transaction(request) if transaction is None: return wrapped(*args, **kwargs) if request.method not in handler.SUPPORTED_METHODS: # If the method isn't one of the supported ones, then we expect the # wrapped method to raise an exception for HTTPError(405). In this case # we name the transaction after the wrapped method. name = callable_name(wrapped) else: # Otherwise we name the transaction after the handler function that # should end up being executed for the request. name = callable_name(getattr(handler, request.method.lower())) transaction.set_transaction_name(name) # We need to set the current transaction so that the user code executed by # running _execute is traced to the transaction we grabbed off the request with TransactionContext(transaction): return wrapped(*args, **kwargs)
def _wrapper(context, request): transaction = current_transaction() if not transaction: return wrapper(context, request) name = callable_name(view) with FunctionTrace(transaction, name=name) as tracer: try: return wrapper(context, request) finally: attr = instance.attr if attr: inst = getattr(request, '__view__') name = callable_name(getattr(inst, attr)) transaction.set_transaction_name(name, priority=1) tracer.name = name else: inst = getattr(request, '__view__') method = getattr(inst, '__call__') if method: name = callable_name(method) transaction.set_transaction_name(name, priority=1) tracer.name = name
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) # The priority to be used when naming the transaction is # bit tricky. If the transaction name is already that of # the class based view, but not the method, then we want # the name of the method to override. This can occur # where the class based view was registered directly in # urls.py as the view handler. In this case we use the # priority of 5, matching what would be used by the view # handler so that it can override the transaction name. # # If however the transaction name is unrelated, we # preferably don't want it overridden. This can happen # where the class based view was invoked explicitly # within an existing view handler. In this case we use # the priority of 4 so it will not override the view # handler name where used as the transaction name. priority = 4 if transaction.group == 'Function': if transaction.name == callable_name(view): priority = 5 transaction.set_transaction_name(name, priority=priority) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs)
def _nr_wrapper_APIView_dispatch_(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) request_method = request.method.lower() if request_method in view.http_method_names: handler = getattr(view, request_method, view.http_method_not_allowed) else: handler = view.http_method_not_allowed view_func_callable_name = getattr(view, '_nr_view_func_callable_name', None) if view_func_callable_name: if handler == view.http_method_not_allowed: name = '%s.%s' % (view_func_callable_name, 'http_method_not_allowed') else: name = '%s.%s' % (view_func_callable_name, request_method) else: name = callable_name(handler) transaction.set_transaction_name(name) with FunctionTrace(transaction, name): return wrapped(*args, **kwargs)
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.set_transaction_name(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 FunctionWrapper(middleware, wrapper)
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, priority=4) with FunctionTrace(transaction, name=name): 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.set_transaction_name(name, priority=2) return FunctionWrapper(wrapped, wrapper)
def _coroutine_name(func): # Because of how coroutines get scheduled they will look like plain # functions (and not methods) in python 2 and will not have a class # associated with them. In particular, func will not have the attribute # im_class. This means callable_name will return the function name without # the class prefix. See PYTHON-1798. return '%s %s' % (callable_name(func), '(coroutine)')
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 = FunctionWrapper(wrapped, wrapper) result._nr_django_view_handler = True return result
def callback_wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) # Needs to be at a higher priority so that error handler processing # below will not override the web transaction being named after the # actual request handler. transaction.set_transaction_name(name, priority=2) with FunctionTrace(transaction, name): try: return wrapped(*args, **kwargs) except: # Catch all # In most cases this seems like it will never be invoked as # bottle will internally capture the exception before we # get a chance and rather than propagate the exception will # return it instead. This doesn't always seem to be the case # though when plugins are used, although that may depend on # the specific bottle version being used. transaction.record_exception(ignore_errors=should_ignore) raise
def _callback_wrapper(wrapped, instance, args, kwargs): if retrieve_current_transaction(): return wrapped(*args, **kwargs) transaction = resume_request_monitoring(request) if transaction is None: return wrapped(*args, **kwargs) try: name = callable_name(wrapped) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs) except Exception: record_exception(transaction, sys.exc_info()) raise finally: if not request_finished(request): suspend_request_monitoring(request, name='Callback/Wait') elif not request.connection.stream.writing(): finalize_request_monitoring(request) else: suspend_request_monitoring(request, name='Request/Output')
def _nr_wrapper_RequestHandler__execute_(wrapped, instance, args, kwargs): # Prior to Tornado 3.1, the calling of the handler request method # was performed from within RequestHandler._execute(). Any prepare() # method was called immediately and could not be a coroutine. For # later versions of Tornado, if the prepare() method is a coroutine # and the future cannot be completed immediately, then the handler # request method will be called from _execute_method() instead when # prepare() completes. handler = instance request = handler.request # Check to see if we are being called within the context of any sort # of transaction. If we aren't, then we don't bother doing anything and # just call the wrapped function. transaction = retrieve_current_transaction() if transaction is None: return wrapped(*args, **kwargs) # If the method isn't one of the supported ones, then we expect the # wrapped method to raise an exception for HTTPError(405). Name the # transaction after the wrapped method first so it is used if that # occurs. name = callable_name(wrapped) transaction.set_transaction_name(name) if request.method not in handler.SUPPORTED_METHODS: return wrapped(*args, **kwargs) # Otherwise we name the transaction after the handler function that # should end up being executed for the request. We don't create a # function trace node at this point as that is handled by the fact # that we wrapped the exposed methods from the wrapper for the # constructor of the request handler. name = callable_name(getattr(handler, request.method.lower())) transaction.set_transaction_name(name) # Call the original RequestHandler._execute(). So long as the # prepare() method is not a coroutine which doesn't complete # straight away, then the actual handler function handler should # also be called at this point. return wrapped(*args, **kwargs)
def _nr_wrapper_IOLoop_add_callback_(wrapped, instance, args, kwargs): transaction = retrieve_current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) def _args(callback, *args, **kwargs): return callback callback = _args(*args, **kwargs) params = dict(callback=callable_name(callback)) with FunctionTrace(transaction, name, params=params, terminal=True): return wrapped(*args, **kwargs)
def __call__(self, *args, **kwargs): transaction = current_transaction() with FunctionTrace(transaction, callable_name(self.__wrapped__), terminal=True, rollup='Database/all'): return self.__connection_wrapper__( self.__wrapped__(*args, **kwargs), self._nr_dbapi2_module, (args, kwargs))
def _requesthandler_function_trace(wrapped, instance, args, kwargs): # Use this function tracer when a function you want to trace is called # synchronously from a function that is already in the transaction, such as # web.RequestHandler._execute. transaction = retrieve_current_transaction() name = callable_name(wrapped) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs)
def _nr_stack_context_function_wrapper_(wrapped, instance, args, kwargs): # We can come in here with either an active transaction # or a request with a transaction bound to it. If there # is an active transaction then call the wrapped function # within function trace and return immediately. transaction = retrieve_current_transaction() if transaction is not None: name = callable_name(wrapped) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs) # For the case of a request with a transaction bound to # it, we need to resume the transaction and then call it. # As we resumed the transaction, need to handle # suspending or finalizing it. transaction = resume_request_monitoring(request) if transaction is None: return wrapped(*args, **kwargs) try: name = callable_name(wrapped) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs) except: # Catch all. record_exception(transaction, sys.exc_info()) raise finally: if not request_finished(request): suspend_request_monitoring(request, name='Callback/Wait') elif not request.connection.stream.writing(): finalize_request_monitoring(request) else: suspend_request_monitoring(request, name='Request/Output')
def __exit__(self, exc, value, tb): transaction = current_transaction() name = callable_name(self.__wrapped__.__exit__) with FunctionTrace(transaction, name): if exc is None: with DatabaseTrace(transaction, "COMMIT", self._nr_dbapi2_module): return self.__wrapped__.__exit__(exc, value, tb) else: with DatabaseTrace(transaction, "ROLLBACK", self._nr_dbapi2_module): return self.__wrapped__.__exit__(exc, value, tb)
def _nr_wrapper_convert_exception_to_response_(wrapped, instance, args, kwargs): def _bind_params(original_middleware, *args, **kwargs): return original_middleware original_middleware = _bind_params(*args, **kwargs) converted_middleware = wrapped(*args, **kwargs) name = callable_name(original_middleware) return _nr_wrap_converted_middleware_(converted_middleware, name)
def _nr_wrapper_api_view_decorator_(wrapped, instance, args, kwargs): def _bind_params(func, *args, **kwargs): return func func = _bind_params(*args, **kwargs) view = wrapped(*args, **kwargs) view.cls._nr_view_func_callable_name = callable_name(func) return view
def __exit__(self, exc, value, tb): transaction = current_transaction() name = callable_name(self.__wrapped__.__exit__) with FunctionTrace(transaction, name): if exc is None and value is None and tb is None: with DatabaseTrace(transaction, 'COMMIT', self._nr_dbapi2_module, self._nr_connect_params): return self.__wrapped__.__exit__(exc, value, tb) else: with DatabaseTrace(transaction, 'ROLLBACK', self._nr_dbapi2_module, self._nr_connect_params): return self.__wrapped__.__exit__(exc, value, tb)
def _nr_wrapper_Flask_before_request_wrapped_(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) transaction.set_transaction_name(name) with FunctionTrace(transaction, name): return wrapped(*args, **kwargs)
def __exit__(self, exc, value, tb): transaction = current_transaction() name = callable_name(self.__wrapped__.__exit__) with FunctionTrace(transaction, name): if exc is None and value is None and tb is None: with DatabaseTrace(transaction, 'COMMIT', self._nr_dbapi2_module): return self.__wrapped__.__exit__(exc, value, tb) else: with DatabaseTrace(transaction, 'ROLLBACK', self._nr_dbapi2_module): return self.__wrapped__.__exit__(exc, value, tb)
def __enter__(self): transaction = current_transaction() name = callable_name(self.__wrapped__.__enter__) with FunctionTrace(transaction, name): cursor = self.__wrapped__.__enter__() # The __enter__() method of original connection object returns # a new cursor instance for use with 'as' assignment. We need # to wrap that in a cursor wrapper otherwise we will not track # any queries done via it. return self.__cursor_wrapper__(cursor, self._nr_dbapi2_module, self._nr_connect_params, None)
def close(self): try: with FunctionTrace(self.transaction, name='Finalize', group='Python/WSGI'): if hasattr(self.generator, 'close'): name = callable_name(self.generator.close) with FunctionTrace(self.transaction, name): self.generator.close() except: # Catch all self.transaction.record_exception() raise
def wrapper_Resource_method(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) transaction.set_transaction_name(name) with FunctionTrace(transaction, name): return wrapped(*args, **kwargs)
def _nr_wrapper_HTTPServerRequest__init__(wrapped, instance, args, kwargs): # This is the first point of entry into our instrumentation. It gets called # after header but before the request body is read in one of 3 possible # places: # web.py: The normal case when the application passed to the HTTPServer # is an Tornado 4 Application object. # httpserver.py: A strange case where the application passed to the # HTTPServer is not a Tornado 4 Application object (so the # HTTPServerAdapter has no delegate). # wsgi.py: Needs more exploration. # # After this is called the request body may be streamed or not depending on # the application configuration (see tornado.web.stream_request_body). assert instance is not None result = wrapped(*args, **kwargs) # instance is now an initiated HTTPServerRequest object. Since instance was # just created there can not be a previously associated transaction. request = instance if is_websocket(request): transaction = None else: transaction = initiate_request_monitoring(request) # Transaction can still be None at this point, if it wasn't enabled during # WebTransaction.__init__(). if transaction: # Name transaction initially after the wrapped function so that if # the connection is dropped before all the request content is read, # then we don't get metric grouping issues with it being named after # the URL. name = callable_name(wrapped) transaction.set_transaction_name(name) # Use HTTPServerRequest start time as transaction start time. transaction.start_time = request._start_time # Even if transaction is `None`, we still attach it to the request, so we # can distinguish between a missing _nr_transaction attribute (error) from # the case where _nr_transaction is None (ok). request._nr_transaction = transaction return result
def __enter__(self): transaction = current_transaction() name = callable_name(self.__wrapped__.__enter__) with FunctionTrace(transaction, name): self.__wrapped__.__enter__() # Must return a reference to self as otherwise will be # returning the inner connection object. If 'as' is used # with the 'with' statement this will mean no longer # using the wrapped connection object and nothing will be # tracked. return self
def _wrap_decorated(wrapped, instance, args, kwargs): # Wraps the output of a tornado decorator. # # For an example see our wrapper for coroutine, # _nr_wrapper_coroutine_wrapper_. transaction = retrieve_current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs)
def __call__(self, *args, **kwargs): transaction = current_transaction() settings = global_settings() rollup = [] rollup.append('Datastore/all') rollup.append('Datastore/%s/all' % self._nr_dbapi2_module._nr_database_product) with FunctionTrace(transaction, callable_name(self.__wrapped__), terminal=True, rollup=rollup): return self.__connection_wrapper__(self.__wrapped__( *args, **kwargs), self._nr_dbapi2_module, (args, kwargs))
def __call__(self, environ, start_response): transaction = retrieve_current_transaction() if transaction is None: return self.wsgi_application(environ, start_response) name = callable_name(self.wsgi_application) with FunctionTrace(transaction, name='Application', group='Python/WSGI'): with FunctionTrace(transaction, name=name): result = self.wsgi_application(environ, start_response) return _WSGIApplicationIterable(transaction, result)
def _nr_wrapper_Task_start_(wrapped, instance, args, kwargs): # This wrapper is used around the start() method of the Task class. # The Task class executes a callback and we track that as a function # trace, naming it after the function the Task holds. transaction = retrieve_current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(instance.func) with FunctionTrace(transaction, name): 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=5), callback_args, callback_kwargs) else: result.func = wrap_view_handler(result.func, priority=5) return result try: return _wrapped(*args, **kwargs) finally: del transaction._nr_django_url_resolver return FunctionWrapper(wrapped, wrapper)
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) is tuple: callback, callback_args, callback_kwargs = result result = (wrap_view_handler(callback, priority=5), callback_args, callback_kwargs) else: result.func = wrap_view_handler(result.func, priority=5) return result try: return _wrapped(*args, **kwargs) finally: del transaction._nr_django_url_resolver return FunctionWrapper(wrapped, 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 FunctionWrapper(wrapped, wrapper)
def _requesthandler_transaction_function_trace(wrapped, instance, args, kwargs): # Use this function tracer when the function you want to trace is called # synchronously from a function that is not run inside the transaction, # such as http1connection.HTTP1Connection._read_message. request = instance.request transaction = retrieve_request_transaction(request) if transaction is None: # If transaction is None we don't want to trace this function. return wrapped(*args, **kwargs) with TransactionContext(transaction): name = callable_name(wrapped) with FunctionTrace(transaction, name=name): return wrapped(*args, **kwargs)
def handler_wrapper(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) # Set priority=2 so this will take precedence over any error # handler which will be at priority=1. transaction.set_transaction_name(name, priority=2) with FunctionTrace(transaction, name): return wrapped(*args, **kwargs)