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 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 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 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 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