def send(self, value): if not self._nr_transaction: # create and start the transaction app = application_instance() txn = WebTransaction(app, self._nr_environ) import aiohttp txn.add_framework_info(name='aiohttp', version=aiohttp.__version__) self._nr_transaction = txn if txn.enabled: txn.__enter__() txn.drop_transaction() txn = self._nr_transaction # transaction may not be active if not txn.enabled: return self.__wrapped__.send(value) import aiohttp.web as _web txn.save_transaction() try: r = self.__wrapped__.send(value) txn.drop_transaction() return r except (GeneratorExit, StopIteration) as e: try: response = e.value _nr_process_response(response, txn) except: pass self._nr_transaction.__exit__(None, None, None) self._nr_request = None raise except _web.HTTPException as e: exc_info = sys.exc_info() try: _nr_process_response(e, txn) except: pass if should_ignore(*exc_info): self._nr_transaction.__exit__(None, None, None) else: self._nr_transaction.__exit__(*exc_info) self._nr_request = None raise except: exc_info = sys.exc_info() try: nr_headers = txn.process_response('500', ()) self._nr_request._nr_headers = dict(nr_headers) except: pass self._nr_transaction.__exit__(*exc_info) self._nr_request = None raise
def initiate_request_monitoring(request): # Creates a new transaction and associates it with the request. # We 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(request) # We now start recording the actual web transaction. purge_current_transaction() transaction = WebTransaction(application, environ) if not transaction.enabled: return None transaction.__enter__() # Immediately purge the transaction from the cache, so we don't associate # Tornado internals inappropriately with this transaction. purge_current_transaction() # We also need to add a reference to the request object in to the # transaction object so we can later access it in a deferred. We # need to use a weakref to avoid an object cycle which may prevent # cleanup of the transaction. transaction._nr_current_request = weakref.ref(request) # Records state of transaction transaction._is_finalized = False transaction._ref_count = 0 # For requests that complete normally, a transaction can only be closed # after the `finish()` method is called on both the `_ServerRequestAdapter` # and the `RequestHandler`. transaction._request_handler_finalize = False transaction._server_adapter_finalize = False # Record framework information for generation of framework metrics. import tornado if hasattr(tornado, 'version_info'): version = '.'.join(map(str, tornado.version_info)) else: version = None transaction.add_framework_info('Tornado/ASYNC', version) return transaction
def initiate_request_monitoring(request): # Creates a new transaction and associates it with the request. # We 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) # We now start recording the actual web transaction. Bail out though # if it turns out that recording of transactions is not enabled. transaction = WebTransaction(application, environ) if not transaction.enabled: return if tornado_settings.debug.transaction_monitoring: global _last_transaction_activation _last_transaction_activation = ''.join(traceback.format_stack()[:-1]) transaction.__enter__() request._nr_transaction = transaction request._nr_wait_function_trace = None request._nr_request_finished = False # We also need to add a reference to the request object in to the # transaction object so we can later access it in a deferred. We # need to use a weakref to avoid an object cycle which may prevent # cleanup of the transaction. transaction._nr_current_request = weakref.ref(request) # Record framework information for generation of framework metrics. import tornado if hasattr(tornado, 'version_info'): version = '.'.join(map(str, tornado.version_info)) else: version = None transaction.add_framework_info('Tornado/ASYNC', version) return transaction
def _nr_request_handler_init(wrapped, instance, args, kwargs): if current_transaction() is not None: _logger.error( 'Attempting to make a request (new transaction) when a ' 'transaction is already running. Please report this issue to ' 'New Relic support.\n%s', ''.join(traceback.format_stack()[:-1])) return wrapped(*args, **kwargs) def _bind_params(application, request, *args, **kwargs): return request request = _bind_params(*args, **kwargs) environ = _get_environ(request) if request.method not in instance.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(instance) else: # Otherwise we name the transaction after the handler function that # should end up being executed for the request. method = getattr(instance, request.method.lower()) name = callable_name(method) environ = _get_environ(request) app = application_instance() txn = WebTransaction(app, environ) txn.__enter__() if txn.enabled: txn.drop_transaction() instance._nr_transaction = txn txn.set_transaction_name(name) # Record framework information for generation of framework metrics. txn.add_framework_info('Tornado/ASYNC', _VERSION) return wrapped(*args, **kwargs)
def _wrap_headers_received(wrapped, instance, args, kwargs): start_line, headers = _bind_headers_received(*args, **kwargs) port = None try: # We only want to record port for ipv4 and ipv6 socket families. # Unix socket will just return a string instead of a tuple, so # skip this. sockname = request_conn.stream.socket.getsockname() if isinstance(sockname, tuple): port = sockname[1] except: pass path, sep, query = start_line.path.partition('?') transaction = WebTransaction( application=application_instance(), name=callable_name(instance), port=port, request_method=start_line.method, request_path=path, query_string=query, headers=headers, ) transaction.__enter__() if not transaction.enabled: return wrapped(*args, **kwargs) transaction.add_framework_info('Tornado', _VERSION) # Store the transaction on the HTTPMessageDelegate object since the # transaction lives for the lifetime of that object. request_conn._nr_transaction = transaction # Remove the headers_received circular reference vars(instance).pop('headers_received') return wrapped(*args, **kwargs)
def send(self, value): if not self._nr_transaction: # create and start the transaction app = application_instance() txn = WebTransaction(app, self._nr_environ) import sanic txn.add_framework_info( name='Sanic', version=sanic.__version__) self._nr_transaction = txn if txn.enabled: txn.__enter__() txn.drop_transaction() txn = self._nr_transaction # transaction may not be active if not txn.enabled: return self.__wrapped__.send(value) txn.save_transaction() try: r = self.__wrapped__.send(value) txn.drop_transaction() return r except (GeneratorExit, StopIteration): self._nr_transaction.__exit__(None, None, None) self._nr_request = None raise except: self._nr_transaction.__exit__(*sys.exc_info()) self._nr_request = None raise
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_wrapper(wrapped, instance, args, kwargs): # We have to deal with a special case here because when using # tornado.wsgi.WSGIApplication() to host the async API within # a WSGI application, Tornado will call the wrapped method via # the class method rather than via an instance. This means the # instance will be None and the self argument will actually # be the first argument. The args are still left intact for # when we call the wrapped function. def _request_unbound(instance, request, *args, **kwargs): return instance, request def _request_bound(request, *args, **kwargs): return request if instance is None: instance, request = _request_unbound(*args, **kwargs) else: request = _request_bound(*args, **kwargs) # If no transaction associated with request already, need to # create a new one. The exception is when the the ASYNC API is # being executed within a WSGI application, in which case a # transaction will already be active. For that we execute # straight away. if instance._wsgi: transaction = current_transaction() with FunctionTrace(transaction, name='Request/Process', group='Python/Tornado'): return wrapped(*args, **kwargs) elif not hasattr(request, '_nr_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) else: # If there was a transaction associated with the request, # only continue if a transaction is active though. transaction = current_transaction() if not transaction: return wrapped(*args, **kwargs) try: # Call the original method in a trace object to give better # context in transaction traces. with FunctionTrace(transaction, name='Request/Process', group='Python/Tornado'): handler = wrapped(*args, **kwargs) # In the case of an immediate result or an exception # occuring, then finish() will have been called on the # request already. We can't just exit the transaction in the # finish call however as need to still pop back up through # the above function trace. So if it has been flagged that # it is finished, which Tornado does by setting the request # object in the connection to None, then we exit the # transaction here. Otherwise we setup a function trace to # track wait time for deferred and manually pop the # transaction as being the current one for this thread. if handler._finished: 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() else: request._nr_wait_function_trace = FunctionTrace( transaction, name='Callback/Wait', 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. _logger.exception('Unexpected exception raised by Tornado ' 'Application.__call__().') transaction.__exit__(*sys.exc_info()) request._nr_transaction = None raise return handler
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 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 start_wrapper(wrapped, instance, args, kwargs): assert instance is not None request = args[0] # 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) # 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 = {} environ['REQUEST_URI'] = request.uri # 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_is_deferred_callback = False request._nr_wait_function_trace = None # 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. with FunctionTrace(transaction, name='Request/Process', group='Python/Tornado'): result = wrapped(*args, **kwargs) # In the case of an immediate result or an exception # occuring, then finish() will have been called on the # request already. We can't just exit the transaction in the # finish call however as need to still pop back up through # the above function trace. So if it has been flagged that # it is finished, which Tornado does by setting the request # object in the connection to None, then we exit the # transaction here. Otherwise we setup a function trace to # track wait time for deferred and manually pop the # transaction as being the current one for this thread. if request.connection._request is None: transaction.__exit__(None, None, None) request._nr_transaction = None else: request._nr_wait_function_trace = FunctionTrace( transaction, name='Callback/Wait', group='Python/Tornado') request._nr_wait_function_trace.__enter__() transaction.drop_transaction() except: # 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. _logger.exception('Unexpected exception raised by Tornado ' 'Application.__call__().') transaction.__exit__(*sys.exc_info()) request._nr_transaction = None raise return result