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 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 '_bw_django_view_handler' attribute. if hasattr(wrapped, '_bw_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._bw_django_view_handler = True return result
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): # 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 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 __call__(self, *args): # Temporary work around due to customer calling class method # directly with 'self' as first argument. Need to work out best # practice for dealing with this. if len(args) == 2: # Assume called as unbound method with (self, request). instance, request = args else: # Assume called as bound method with (request). instance = self._bw_instance request = args[-1] assert instance != None transaction = current_transaction() if transaction is None: return self._bw_next_object(*args) # This is wrapping the render() function of the resource. We # name the function node and the web transaction after the name # of the handler function augmented with the method type for the # request. name = "%s.render_%s" % ( callable_name( instance), request.method) transaction.set_transaction_name(name, priority=1) with FunctionTrace(transaction, name): return self._bw_next_object(*args)
def _bw_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 _bw_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 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 __iter__(self): name = callable_name(self._bw_wrapped) iterable = iter(self._bw_generator) while 1: transaction = current_transaction() with FunctionTrace( transaction, name, group='Python/Twisted/Generator'): yield next(iterable)
def transaction_name_delegate(*args, **kwargs): 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 _bw_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 __call__(self, *args, **kwargs): transaction = current_transaction() settings = global_settings() rollup = 'Database/all' with FunctionTrace(transaction, callable_name(self.__wrapped__), terminal=True, rollup=rollup): return self.__connection_wrapper__(self.__wrapped__( *args, **kwargs), self._bw_dbapi2_module, (args, kwargs))
def _bw_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 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 __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._bw_dbapi2_module): return self.__wrapped__.__exit__(exc, value, tb) else: with DatabaseTrace(transaction, 'ROLLBACK', self._bw_dbapi2_module): return self.__wrapped__.__exit__(exc, value, tb)
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 __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._bw_dbapi2_module, self._bw_connect_params, None)
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 __call__(self, environ, start_response): transaction = 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 _bw_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, '_bw_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._bw_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._bw_django_url_resolver return FunctionWrapper(wrapped, wrapper)
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 _bw_wrapper_handler_(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)
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 _bw_wrapper_Flask_handle_http_exception_(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) # Because we use priority=1, this name will only be used in cases # where an error handler was called without an actual request # handler having already being called. transaction.set_transaction_name(name, priority=1) with FunctionTrace(transaction, name): return wrapped(*args, **kwargs)
def _bw_wrapper_Flask_handle_exception_(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) # The Flask.handle_exception() method is always called in the # context of the except clause of the try block. We can therefore # rely on grabbing current exception details so we have access to # the addition stack trace information. transaction.record_exception(ignore_errors=should_ignore) name = callable_name(wrapped) with FunctionTrace(transaction, name): return wrapped(*args, **kwargs)
def _bw_wrapper_RequestHandler_render_(wrapped, instance, args, kwargs): # Intended to track time spent rendering response content, but # adding in the wrapper causes Tornado's calculation of where # templates are stored to fail as it walks the stack and looks at # where the calling code was stored and assumes templates exist in # that directory if an absolute path is not provided. Thus not being # used for now. 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 get(self, status, default=None): transaction = current_transaction() if transaction is None: return self.__wrapped__.get(status, default) handler = self.__wrapped__.get(status) if handler: name = callable_name(handler) transaction.set_transaction_name(name, priority=1) handler = FunctionTraceWrapper(handler, name=name) else: transaction.set_transaction_name(str(status), group='StatusCode', priority=1) return handler or default
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 FunctionWrapper(wrapped, 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 FunctionWrapper(wrapped, wrapper)