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(name=name): return _wrapped(*args, **kwargs) return FunctionWrapper(middleware, 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 = FunctionWrapper(wrapped, 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() if transaction is None: return wrapped(*args, **kwargs) before = (transaction.name, transaction.group) with FunctionTrace(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 wrap_middleware(wrapped, instance, args, kwargs): result = wrapped(*args, **kwargs) dispatch_func = getattr(result, "dispatch_func", None) name = dispatch_func and callable_name(dispatch_func) return FunctionTraceWrapper(result, name=name)
def grpc_web_transaction(wrapped, instance, args, kwargs): rpc_event, behavior = _bind_transaction_args(*args, **kwargs) behavior_name = callable_name(behavior) call_details = (getattr(rpc_event, 'call_details', None) or getattr(rpc_event, 'request_call_details', None)) metadata = (getattr(rpc_event, 'invocation_metadata', None) or getattr(rpc_event, 'request_metadata', None)) host = port = None if call_details: try: host, port = call_details.host.split(b':', 1) except Exception: pass request_path = call_details.method return WebTransactionWrapper(wrapped, name=behavior_name, request_path=request_path, host=host, port=port, headers=metadata)(*args, **kwargs)
def route_naming_wrapper(wrapped, instance, args, kwargs): with ContextOf(request=bind_request(*args, **kwargs)): transaction = current_transaction() if transaction: transaction.set_transaction_name(callable_name(wrapped), priority=2) return wrapped(*args, **kwargs)
def test_span_event_error_attributes_observed(trace_type, args): error = ValueError("whoops") exact_agents = { 'error.class': callable_name(error), 'error.message': 'whoops', } # Verify errors are not recorded since record_exception is not called rollups = [('Errors/all', None)] + _span_event_metrics @dt_enabled @validate_transaction_metrics( 'test_span_event_error_attributes_observed', background_task=True, rollup_metrics=rollups) @validate_span_events( count=1, exact_agents=exact_agents,) @background_task(name='test_span_event_error_attributes_observed') def _test(): try: with trace_type(*args): raise error except: pass _test()
def test_span_event_error_attributes_record_exception(trace_type, args): _settings = { 'distributed_tracing.enabled': True, 'span_events.enabled': True, } error = ValueError("whoops") exact_agents = { 'error.class': callable_name(error), 'error.message': 'whoops', } @override_application_settings(_settings) @validate_transaction_metrics( 'test_span_event_error_attributes_record_exception', background_task=True, rollup_metrics=_span_event_metrics) @validate_span_events( count=1, exact_agents=exact_agents,) @background_task(name='test_span_event_error_attributes_record_exception') def _test(): transaction = current_transaction() transaction._sampled = True with trace_type(*args): try: raise ValueError("whoops") except: record_exception() _test()
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 close(self): if self.closed: return if self.response_trace: self.response_trace.__exit__(None, None, None) self.response_trace = None try: with FunctionTrace(self.transaction, name='Finalize', group='Python/WSGI'): if isinstance(self.generator, _WSGIApplicationMiddleware): self.generator.close() elif hasattr(self.generator, 'close'): name = callable_name(self.generator.close) with FunctionTrace(self.transaction, name): self.generator.close() except: # Catch all self.transaction.__exit__(*sys.exc_info()) raise else: self.transaction.__exit__(None, None, None) self.transaction._sent_end = time.time() finally: self.closed = True
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_handler_(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) view_class = getattr(wrapped, 'view_class', None) if view_class: try: method = args[0].method.lower() name = callable_name(view_class) + '.' + method except: pass transaction.set_transaction_name(name, priority=3) return function_trace(name=name)(wrapped)(*args, **kwargs)
def close(self): # Call close() on the iterable as required by the # WSGI specification. if hasattr(self.iterable, 'close'): name = callable_name(self.iterable.close) with FunctionTrace(name): self.iterable.close()
def wrap_parse(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) transaction.set_transaction_name(callable_name(wrapped), "GraphQL", priority=10) with ErrorTrace(ignore=ignore_graphql_duplicate_exception): 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 test_uvicorn_200(port, app): @validate_transaction_metrics(callable_name(app)) @raise_background_exceptions() @wait_for_background_threads() def response(): return urlopen("http://localhost:%d" % port) assert response().status == 200
def _nr_wrapper_web_requesthandler_init(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(instance) transaction.set_transaction_name(name, priority=1) return wrapped(*args, **kwargs)
def transaction_aware(wrapped, instance, args, kwargs): # Variables from the outer scope are not assignable in a closure, # so we use a mutable object to hold the transaction, so we can # change it if we need to. inner_transaction = transaction[0] if inner_transaction is not None: # Callback run outside the main thread must not affect the cache if inner_transaction.thread_id != current_thread_id(): return fxn(*args, **kwargs) if inner_transaction is not None and inner_transaction._is_finalized: inner_transaction = None transaction[0] = None with TransactionContext(inner_transaction): if inner_transaction is None: # A transaction will be None for fxns scheduled on the ioloop # not associated with a transaction. ret = fxn(*args, **kwargs) elif should_trace is False: try: ret = fxn(*args, **kwargs) except: record_exception(sys.exc_info()) wrapped._nr_recorded_exception = True raise else: name = callable_name(fxn_for_name) with FunctionTrace(inner_transaction, name=name) as ft: try: ret = fxn(*args, **kwargs) except: record_exception(sys.exc_info()) wrapped._nr_recorded_exception = True raise # Coroutines are wrapped in lambdas when they are # scheduled. See tornado.gen.Runner.run(). In this # case, we don't know the name until the function # is run. We only know it then because we pass # out the name as an attribute on the result. # We update the name now. if hasattr(fxn, '_nr_coroutine_name'): ft.name = fxn._nr_coroutine_name # If decrementing the ref count in Runner.run() takes it to 0, then # we need to end the transaction here. if inner_transaction: possibly_finalize_transaction(inner_transaction) return ret
def callback_wrapper(wrapped, instance, args, kwargs): name = callable_name(wrapped) transaction = current_transaction(active_only=False) if transaction and (transaction.ignore_transaction or transaction.stopped): return wrapped(*args, **kwargs) elif transaction: with FunctionTrace(name=name): return wrapped(*args, **kwargs) else: if hasattr(channel, '_nr_disable_txn_tracing'): return wrapped(*args, **kwargs) # Keyword arguments are unknown since this is a user # defined callback exchange = 'Unknown' routing_key = None headers = None reply_to = None correlation_id = None unknown_kwargs = False if not kwargs: method, properties = args[1:3] exchange = method.exchange or 'Default' routing_key = getattr(method, 'routing_key', None) if properties is not None: headers = getattr(properties, 'headers', None) reply_to = getattr(properties, 'reply_to', None) correlation_id = getattr( properties, 'correlation_id', None) else: unknown_kwargs = True with MessageTransaction( application=application_instance(), library='RabbitMQ', destination_type='Exchange', destination_name=exchange, routing_key=routing_key, headers=headers, queue_name=queue, reply_to=reply_to, correlation_id=correlation_id) as mt: # Improve transaction naming _new_txn_name = 'RabbitMQ/Exchange/%s/%s' % (exchange, name) mt.set_transaction_name(_new_txn_name, group='Message') # Record that something went horribly wrong if unknown_kwargs: m = mt._transaction_metrics.get(KWARGS_ERROR, 0) mt._transaction_metrics[KWARGS_ERROR] = m + 1 return wrapped(*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 _nr_aiohttp_initial_class_transaction_name_(wrapped, instance, args, kwargs): transaction = current_transaction() if not transaction: return wrapped(*args, **kwargs) name = callable_name(instance) transaction.set_transaction_name(name, priority=1) return wrapped(*args, **kwargs)
def _nr_aiohttp_view_wrapper_(wrapped, instance, args, kwargs): transaction = current_transaction() if not transaction: return wrapped(*args, **kwargs) name = callable_name(wrapped) transaction.set_transaction_name(name, priority=1) return function_trace(name=name)(wrapped)(*args, **kwargs)
def _nr_wrapper_handler_(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) transaction.set_transaction_name(name, priority=3) return function_trace(name=name)(wrapped)(*args, **kwargs)
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 _sanic_app_init(wrapped, instance, args, kwargs): result = wrapped(*args, **kwargs) error_handler = getattr(instance, 'error_handler') if hasattr(error_handler, 'response'): instance.error_handler.response = error_response( error_handler.response) if hasattr(error_handler, 'add'): error_handler.add = _nr_sanic_error_handlers(error_handler.add) router = getattr(instance, 'router') if hasattr(router, 'add'): router.add = _nr_sanic_router_add(router.add) if hasattr(router, 'get'): # Cache the callable_name on the router.get callable_name(router.get) router.get = _nr_sanic_router_get(router.get) return result
def __call__(self, *args, **kwargs): rollup = [] rollup.append('Datastore/all') rollup.append('Datastore/%s/all' % self._nr_dbapi2_module._nr_database_product) with FunctionTrace(callable_name(self.__wrapped__), terminal=True, rollup=rollup, source=self.__wrapped__): return self.__connection_wrapper__(self.__wrapped__( *args, **kwargs), self._nr_dbapi2_module, (args, kwargs))
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 wrap_middleware(wrapped, instance, args, kwargs): transaction = current_transaction() if transaction is None: return wrapped(*args, **kwargs) name = callable_name(wrapped) transaction.set_transaction_name(name, "GraphQL", priority=12) with FunctionTrace(name, source=wrapped): with ErrorTrace(ignore=ignore_graphql_duplicate_exception): return wrapped(*args, **kwargs)
def _nr_sanic_router_get(wrapped, instance, args, kwargs): # Rename all transactions that generate an exception in the router get try: return wrapped(*args, **kwargs) except Exception: transaction = current_transaction() if transaction: name = callable_name(wrapped) transaction.set_transaction_name(name, priority=2) raise