def __call__(self, environ, start_response): 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. if transaction: # Record details of framework against the transaction # for later reporting as supportability metrics. if self._nr_framework: transaction._frameworks.add(self._nr_framework) # Override the web transaction name to be the name of the # wrapped callable if not explicitly named, and we want the # default name to be that of the WSGI component for the # framework. This will override the use of a raw URL which # can result in metric grouping issues where a framework is # not instrumented or is leaking URLs. settings = transaction._settings if self._nr_name is None and settings: if self._nr_framework is not None: naming_scheme = settings.transaction_name.naming_scheme if naming_scheme in (None, 'framework'): name = newrelic.api.object_wrapper.callable_name( self._nr_next_object) transaction.name_transaction(name, priority=1) elif self._nr_name: transaction.name_transaction(self._nr_name, self._nr_group, priority=1) return self._nr_next_object(environ, start_response) # Otherwise treat it as top level transaction. # We have to though look first to see whether the # application name has been overridden through # the WSGI environ dictionary. app_name = environ.get('newrelic.app_name') if app_name: if app_name.find(';') != -1: app_names = [string.strip(n) for n in app_name.split(';')] app_name = app_names[0] application = newrelic.api.application.application_instance( app_name) for altname in app_names[1:]: application.link_to_application(altname) else: application = newrelic.api.application.application_instance( app_name) else: application = self._nr_application # If application has an activate() method we assume it is an # actual application. Do this rather than check type so that # can easily mock it for testing. # FIXME Should this allow for multiple apps if a string. if not hasattr(application, 'activate'): application = newrelic.api.application.application_instance( application) # Now start recording the actual web transaction. transaction = WebTransaction(application, environ) transaction.__enter__() # Record details of framework against the transaction # for later reporting as supportability metrics. if self._nr_framework: transaction._frameworks.add(self._nr_framework) # Override the initial web transaction name to be the supplied # name, or the name of the wrapped callable if wanting to use # the callable as the default. This will override the use of a # raw URL which can result in metric grouping issues where a # framework is not instrumented or is leaking URLs. # # Note that at present if default for naming scheme is still # None and we aren't specifically wrapping a designated # framework, then we still allow old URL based naming to # override. When we switch to always forcing a name we need to # check for naming scheme being None here. settings = transaction._settings if self._nr_name is None and settings: naming_scheme = settings.transaction_name.naming_scheme if self._nr_framework is not None: if naming_scheme in (None, 'framework'): name = newrelic.api.object_wrapper.callable_name( self._nr_next_object) transaction.name_transaction(name, priority=1) elif naming_scheme in ('component', 'framework'): name = newrelic.api.object_wrapper.callable_name( self._nr_next_object) transaction.name_transaction(name, priority=1) elif self._nr_name: transaction.name_transaction(self._nr_name, self._nr_group, priority=1) def _start_response(status, response_headers, *args): additional_headers = transaction.process_response( status, response_headers, *args) _write = start_response(status, response_headers+additional_headers, *args) def write(data): if not transaction._sent_start: transaction._sent_start = time.time() result = _write(data) transaction._calls_write += 1 try: transaction._bytes_sent += len(data) except Exception: pass transaction._sent_end = time.time() return result return write try: # Should always exist, but check as test harnesses may not # have it. if 'wsgi.input' in environ: environ['wsgi.input'] = WSGIInputWrapper(transaction, environ['wsgi.input']) application = newrelic.api.function_trace.FunctionTraceWrapper( self._nr_next_object) with newrelic.api.function_trace.FunctionTrace( transaction, name='Application', group='Python/WSGI'): result = application(environ, _start_response) except: # Catch all transaction.__exit__(*sys.exc_info()) raise return _WSGIApplicationIterable(transaction, result)
def __call__(self, environ, start_response): 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. if transaction: return self._nr_next_object(environ, start_response) # Otherwise treat it as top level transaction. # We have to though look first to see whether the # application name has been overridden through # the WSGI environ dictionary. app_name = environ.get('newrelic.app_name') if app_name: if app_name.find(';') != -1: app_names = [string.strip(n) for n in app_name.split(';')] app_name = app_names[0] application = newrelic.api.application.application_instance( app_name) for altname in app_names[1:]: application.link_to_application(altname) else: application = newrelic.api.application.application_instance( app_name) else: application = self._nr_application # FIXME Should this allow for multiple apps if a string. if type(application) != newrelic.api.application.Application: application = newrelic.api.application.application_instance( application) # Now start recording the actual web transaction. transaction = WebTransaction(application, environ) transaction.__enter__() def _start_response(status, response_headers, *args): try: transaction.response_code = int(status.split(' ')[0]) except: pass try: header = filter(lambda x: x[0].lower() == 'content-length', response_headers)[-1:] if header: transaction._response_properties['CONTENT_LENGTH'] = \ header[0][1] except: pass _write = start_response(status, response_headers, *args) def write(data): if not transaction._sent_start: transaction._sent_start = time.time() result = _write(data) transaction._calls_write += 1 try: transaction._bytes_sent += len(data) except: pass transaction._sent_end = time.time() return result return write try: # Should always exist, but check as test harnesses may not # have it. if 'wsgi.input' in environ: environ['wsgi.input'] = WSGIInputWrapper(transaction, environ['wsgi.input']) application = newrelic.api.function_trace.FunctionTraceWrapper( self._nr_next_object) with newrelic.api.function_trace.FunctionTrace( transaction, name='Application', group='Python/WSGI'): result = application(environ, _start_response) except: transaction.__exit__(*sys.exc_info()) raise return _WSGIApplicationIterable(transaction, 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(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, environ, start_response): 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. if transaction: # Record details of framework against the transaction # for later reporting as supportability metrics. if self._nr_framework: transaction._frameworks.add(self._nr_framework) # Override the web transaction name to be the name of the # wrapped callable if not explicitly named, and we want the # default name to be that of the WSGI component for the # framework. This will override the use of a raw URL which # can result in metric grouping issues where a framework is # not instrumented or is leaking URLs. settings = transaction._settings if self._nr_name is None and settings: if self._nr_framework is not None: naming_scheme = settings.transaction_name.naming_scheme if naming_scheme in (None, 'framework'): name = newrelic.api.object_wrapper.callable_name( self._nr_next_object) transaction.set_transaction_name(name, priority=1) elif self._nr_name: transaction.set_transaction_name(self._nr_name, self._nr_group, priority=1) return self._nr_next_object(environ, start_response) # Otherwise treat it as top level transaction. # We have to though look first to see whether the # application name has been overridden through # the WSGI environ dictionary. app_name = environ.get('newrelic.app_name') if app_name: if app_name.find(';') != -1: app_names = [string.strip(n) for n in app_name.split(';')] app_name = app_names[0] application = newrelic.api.application.application_instance( app_name) for altname in app_names[1:]: application.link_to_application(altname) else: application = newrelic.api.application.application_instance( app_name) else: application = self._nr_application # If application has an activate() method we assume it is an # actual application. Do this rather than check type so that # can easily mock it for testing. # FIXME Should this allow for multiple apps if a string. if not hasattr(application, 'activate'): application = newrelic.api.application.application_instance( application) # Now start recording the actual web transaction. transaction = WebTransaction(application, environ) transaction.__enter__() # Record details of framework against the transaction # for later reporting as supportability metrics. if self._nr_framework: transaction._frameworks.add(self._nr_framework) # Override the initial web transaction name to be the supplied # name, or the name of the wrapped callable if wanting to use # the callable as the default. This will override the use of a # raw URL which can result in metric grouping issues where a # framework is not instrumented or is leaking URLs. # # Note that at present if default for naming scheme is still # None and we aren't specifically wrapping a designated # framework, then we still allow old URL based naming to # override. When we switch to always forcing a name we need to # check for naming scheme being None here. settings = transaction._settings if self._nr_name is None and settings: naming_scheme = settings.transaction_name.naming_scheme if self._nr_framework is not None: if naming_scheme in (None, 'framework'): name = newrelic.api.object_wrapper.callable_name( self._nr_next_object) transaction.set_transaction_name(name, priority=1) elif naming_scheme in ('component', 'framework'): name = newrelic.api.object_wrapper.callable_name( self._nr_next_object) transaction.set_transaction_name(name, priority=1) elif self._nr_name: transaction.set_transaction_name(self._nr_name, self._nr_group, priority=1) def _start_response(status, response_headers, *args): additional_headers = transaction.process_response( status, response_headers, *args) _write = start_response(status, response_headers+additional_headers, *args) def write(data): if not transaction._sent_start: transaction._sent_start = time.time() result = _write(data) transaction._calls_write += 1 try: transaction._bytes_sent += len(data) except Exception: pass transaction._sent_end = time.time() return result return write try: # Should always exist, but check as test harnesses may not # have it. if 'wsgi.input' in environ: environ['wsgi.input'] = WSGIInputWrapper(transaction, environ['wsgi.input']) application = newrelic.api.function_trace.FunctionTraceWrapper( self._nr_next_object) with newrelic.api.function_trace.FunctionTrace( transaction, name='Application', group='Python/WSGI'): result = application(environ, _start_response) except: # Catch all transaction.__exit__(*sys.exc_info()) raise return _WSGIApplicationIterable(transaction, 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 # Call finish() method straight away if request is not even # associated with a transaction. if not hasattr(self._nr_instance, '_nr_transaction'): return self._nr_next_object() # Technically we should only be able to be called here without # an active transaction if we are in the wait state. If we # are called in context of original request process() function # or a deferred the transaction should already be registered. transaction = self._nr_instance._nr_transaction if self._nr_instance._nr_wait_function_trace: if newrelic.api.transaction.current_transaction(): _logger.debug('The Twisted.Web request finish() method is ' 'being called while in wait state but there is ' 'already a current transaction.') else: transaction.save_transaction() elif not newrelic.api.transaction.current_transaction(): _logger.debug('The Twisted.Web request finish() method is ' 'being called from request process() method or a ' 'deferred but there is not a current transaction.') # Except for case of being called when in wait state, we can't # actually exit the transaction at this point as may be called # in context of an outer function trace node. We thus flag that # are finished and pop back out allowing outer scope to actually # exit the transaction. self._nr_instance._nr_is_request_finished = True # Now call the original finish() function. if self._nr_instance._nr_is_deferred_callback: # If we are in a deferred callback log any error against the # transaction here so we know we will capture it. We # possibly don't need to do it here as outer scope may catch # it anyway. Duplicate will be ignored so not too important. # Most likely the finish() call would never fail anyway. try: with newrelic.api.function_trace.FunctionTrace(transaction, name='Request/Finish', group='Python/Twisted'): result = self._nr_next_object() except: # Catch all transaction.record_exception(*sys.exc_info()) raise elif self._nr_instance._nr_wait_function_trace: # Now handle the special case where finish() was called # while in the wait state. We might get here through # Twisted.Web itself somehow calling finish() when still # waiting for a deferred. If this were to occur though then # the transaction will not be popped if we simply marked # request as finished as no outer scope to see that and # clean up. We will thus need to end the function trace and # exit the transaction. We end function trace here and then # the transaction down below. try: self._nr_instance._nr_wait_function_trace.__exit__( None, None, None) with newrelic.api.function_trace.FunctionTrace(transaction, name='Request/Finish', group='Python/Twisted'): result = self._nr_next_object() transaction.__exit__(None, None, None) except: # Catch all transaction.__exit__(*sys.exc_info()) raise finally: self._nr_instance._nr_wait_function_trace = None self._nr_instance._nr_transaction = None self._nr_instance = None else: # This should be the case where finish() is being called in # the original render() function. with newrelic.api.function_trace.FunctionTrace(transaction, name='Request/Finish', group='Python/Twisted'): result = self._nr_next_object() 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.WSGIWebTransaction( application, environ, source=self._nr_next_object) 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. result = newrelic.api.function_trace.FunctionTraceWrapper(self._nr_next_object, name='Request/Process', group='Python/Twisted') # 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( name='Deferred/Wait', group='Python/Twisted', source=self._nr_next_object) 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(): return newrelic.api.function_trace.FunctionTraceWrapper(self._nr_next_object, name='Deferred/Call', group='Python/Twisted') 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', source=self._nr_next_object) request._nr_wait_function_trace.__enter__() transaction.drop_transaction() request._nr_is_deferred_callback = False
def __call__(self): assert self._nr_instance != None # Call finish() method straight away if request is not even # associated with a transaction. if not hasattr(self._nr_instance, '_nr_transaction'): return self._nr_next_object() # Technically we should only be able to be called here without # an active transaction if we are in the wait state. If we # are called in context of original request process() function # or a deferred the transaction should already be registered. transaction = self._nr_instance._nr_transaction if self._nr_instance._nr_wait_function_trace: if newrelic.api.transaction.current_transaction(): _logger.debug('The Twisted.Web request finish() method is ' 'being called while in wait state but there is ' 'already a current transaction.') else: transaction.save_transaction() elif not newrelic.api.transaction.current_transaction(): _logger.debug('The Twisted.Web request finish() method is ' 'being called from request process() method or a ' 'deferred but there is not a current transaction.') # Except for case of being called when in wait state, we can't # actually exit the transaction at this point as may be called # in context of an outer function trace node. We thus flag that # are finished and pop back out allowing outer scope to actually # exit the transaction. self._nr_instance._nr_is_request_finished = True # Now call the original finish() function. if self._nr_instance._nr_is_deferred_callback: # If we are in a deferred callback log any error against the # transaction here so we know we will capture it. We # possibly don't need to do it here as outer scope may catch # it anyway. Duplicate will be ignored so not too important. # Most likely the finish() call would never fail anyway. try: result = newrelic.api.function_trace.FunctionTraceWrapper(self._nr_next_object, name='Request/Finish', group='Python/Twisted') except: # Catch all notice_error(sys.exc_info()) raise elif self._nr_instance._nr_wait_function_trace: # Now handle the special case where finish() was called # while in the wait state. We might get here through # Twisted.Web itself somehow calling finish() when still # waiting for a deferred. If this were to occur though then # the transaction will not be popped if we simply marked # request as finished as no outer scope to see that and # clean up. We will thus need to end the function trace and # exit the transaction. We end function trace here and then # the transaction down below. try: self._nr_instance._nr_wait_function_trace.__exit__( None, None, None) result = newrelic.api.function_trace.FunctionTraceWrapper(self._nr_next_object, name='Request/Finish', group='Python/Twisted') transaction.__exit__(None, None, None) except: # Catch all transaction.__exit__(*sys.exc_info()) raise finally: self._nr_instance._nr_wait_function_trace = None self._nr_instance._nr_transaction = None self._nr_instance = None else: # This should be the case where finish() is being called in # the original render() function. result = newrelic.api.function_trace.FunctionTraceWrapper(self._nr_next_object, name='Request/Finish', group='Python/Twisted') return result