def __call__(self): assert self._nr_instance != None transaction = newrelic.api.transaction.current_transaction() # If there is an active transaction then deferred is being # called within a context of another deferred so simply call the # callback and return. if transaction: return self._nr_next_object() # If there is no transaction recorded against the deferred then # don't need to do anything and can simply call the callback and # return. if not hasattr(self._nr_instance, '_nr_transaction'): return self._nr_next_object() transaction = self._nr_instance._nr_transaction # If we can't find a Twisted.Web request object associated with # the transaction or it is no longer valid then simply call the # callback and return. if not hasattr(transaction, '_nr_current_request'): return self._nr_next_object() request = transaction._nr_current_request() if not request: return self._nr_next_object() try: # Save the transaction recorded against the deferred as the # active transaction. transaction.save_transaction() # Record that are calling a deferred. This changes what we # do if the request finish() method is being called. request._nr_is_deferred_callback = True # We should always be calling into a deferred when we are # in the wait state for the request. We need to exit that # wait state. if request._nr_wait_function_trace: request._nr_wait_function_trace.__exit__(None, None, None) request._nr_wait_function_trace = None else: _logger.debug('Called a Twisted.Web deferred when we were ' 'not in a wait state.') # Call the deferred and capture any errors that may come # back from it. with newrelic.api.error_trace.ErrorTrace(transaction): with newrelic.api.function_trace.FunctionTrace( transaction, name='Deferred/Call', group='Python/Twisted'): return self._nr_next_object() finally: # If the request finish() method was called from the # deferred then we need to exit the transaction. Other wise # we need to create a new function trace node for a new wait # state and pop the transaction. if request._nr_is_request_finished: transaction.__exit__(None, None, None) self._nr_instance._nr_transaction = None else: # XXX Should we be removing the transaction from the # deferred object as well. Can the same deferred be # called multiple times for same request. It probably # can be reregistered. request._nr_wait_function_trace = \ newrelic.api.function_trace.FunctionTrace( transaction, name='Deferred/Wait', group='Python/Twisted') request._nr_wait_function_trace.__enter__() transaction.drop_transaction() request._nr_is_deferred_callback = False
def __call__(self): assert self._nr_instance != None transaction = newrelic.api.transaction.current_transaction() # 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 with Twisted.Web wrapper but check anyway. if transaction: return self._nr_next_object() # Always use the default application specified in the agent # configuration. application = newrelic.api.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'] = self._nr_instance.path # Now start recording the actual web transaction. transaction = newrelic.api.web_transaction.WebTransaction( application, environ) if not transaction.enabled: return self._nr_next_object() transaction.__enter__() self._nr_instance._nr_transaction = transaction self._nr_instance._nr_is_deferred_callback = False self._nr_instance._nr_is_request_finished = False self._nr_instance._nr_wait_function_trace = None # We need to add a reference to the Twisted.Web request object # in the transaction 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(self._nr_instance) try: # Call the original method in a trace object to give better # context in transaction traces. Three things can happen # within this call. The render() function which is in turn # called can return a result immediately which means user # code should have called finish() on the request, it can # raise an exception which is caught in process() function # where error handling calls finish(), or it can return that # it is not done yet and register deferred callbacks to # complete the request. with newrelic.api.function_trace.FunctionTrace( transaction, name='Request/Process', group='Python/Twisted'): result = self._nr_next_object() # In the case of a result having being returned or an # exception occuring, then finish() will have been called. # 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 flagged that have finished, 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 self._nr_instance._nr_is_request_finished: transaction.__exit__(None, None, None) self._nr_instance._nr_transaction = None self._nr_instance = None else: self._nr_instance._nr_wait_function_trace = \ newrelic.api.function_trace.FunctionTrace( transaction, name='Deferred/Wait', group='Python/Twisted') self._nr_instance._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 or Twisted.Web is # broken. _logger.exception('Unexpected exception raised by Twisted.Web ' 'Request.process() exception.') transaction.__exit__(*sys.exc_info()) self._nr_instance._nr_transaction = None self._nr_instance = None raise return result
def __call__(self): assert self._nr_instance != None transaction = newrelic.api.transaction.current_transaction() # 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 with Twisted.Web wrapper but check anyway. if transaction: return self._nr_next_object() # Always use the default application specified in the agent # configuration. application = newrelic.api.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'] = self._nr_instance.path # Now start recording the actual web transaction. transaction = newrelic.api.web_transaction.WebTransaction( application, environ) if not transaction.enabled: return self._nr_next_object() transaction.__enter__() self._nr_instance._nr_transaction = transaction self._nr_instance._nr_is_deferred_callback = False self._nr_instance._nr_is_request_finished = False self._nr_instance._nr_wait_function_trace = None # We need to add a reference to the Twisted.Web request object # in the transaction 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(self._nr_instance) try: # Call the original method in a trace object to give better # context in transaction traces. Three things can happen # within this call. The render() function which is in turn # called can return a result immediately which means user # code should have called finish() on the request, it can # raise an exception which is caught in process() function # where error handling calls finish(), or it can return that # it is not done yet and register deferred callbacks to # complete the request. with newrelic.api.function_trace.FunctionTrace(transaction, name='Request/Process', group='Python/Twisted'): result = self._nr_next_object() # In the case of a result having being returned or an # exception occuring, then finish() will have been called. # 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 flagged that have finished, 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 self._nr_instance._nr_is_request_finished: transaction.__exit__(None, None, None) self._nr_instance._nr_transaction = None self._nr_instance = None else: self._nr_instance._nr_wait_function_trace = \ newrelic.api.function_trace.FunctionTrace( transaction, name='Deferred/Wait', group='Python/Twisted') self._nr_instance._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 or Twisted.Web is # broken. _logger.exception('Unexpected exception raised by Twisted.Web ' 'Request.process() exception.') transaction.__exit__(*sys.exc_info()) self._nr_instance._nr_transaction = None self._nr_instance = None raise return result
def __call__(self): assert self._nr_instance != None transaction = newrelic.api.transaction.current_transaction() # If there is an active transaction then deferred is being # called within a context of another deferred so simply call the # callback and return. if transaction: return self._nr_next_object() # If there is no transaction recorded against the deferred then # don't need to do anything and can simply call the callback and # return. if not hasattr(self._nr_instance, '_nr_transaction'): return self._nr_next_object() transaction = self._nr_instance._nr_transaction # If we can't find a Twisted.Web request object associated with # the transaction or it is no longer valid then simply call the # callback and return. if not hasattr(transaction, '_nr_current_request'): return self._nr_next_object() request = transaction._nr_current_request() if not request: return self._nr_next_object() try: # Save the transaction recorded against the deferred as the # active transaction. transaction.save_transaction() # Record that are calling a deferred. This changes what we # do if the request finish() method is being called. request._nr_is_deferred_callback = True # We should always be calling into a deferred when we are # in the wait state for the request. We need to exit that # wait state. if request._nr_wait_function_trace: request._nr_wait_function_trace.__exit__(None, None, None) request._nr_wait_function_trace = None else: _logger.debug('Called a Twisted.Web deferred when we were ' 'not in a wait state.') # Call the deferred and capture any errors that may come # back from it. with newrelic.api.error_trace.ErrorTrace(): with newrelic.api.function_trace.FunctionTrace( name='Deferred/Call', group='Python/Twisted'): return self._nr_next_object() finally: # If the request finish() method was called from the # deferred then we need to exit the transaction. Other wise # we need to create a new function trace node for a new wait # state and pop the transaction. if request._nr_is_request_finished: transaction.__exit__(None, None, None) self._nr_instance._nr_transaction = None else: # XXX Should we be removing the transaction from the # deferred object as well. Can the same deferred be # called multiple times for same request. It probably # can be reregistered. request._nr_wait_function_trace = \ newrelic.api.function_trace.FunctionTrace( name='Deferred/Wait', group='Python/Twisted') request._nr_wait_function_trace.__enter__() transaction.drop_transaction() request._nr_is_deferred_callback = False