Exemple #1
0
def record_exception(exc_info):
    # Record the details of any exception ignoring status codes which
    # have been configured to be ignored.

    import tornado.web

    exc = exc_info[0]
    value = exc_info[1]

    # Not an error so we just return.
    if exc is tornado.web.Finish:
        return

    if exc is tornado.web.HTTPError:
        if ignore_status_code(value.status_code):
            return

    transaction = retrieve_current_transaction()
    if transaction:
        transaction.record_exception(*exc_info)
    else:
        # If we are not in a transaction we record the exception to the default
        # application specified in the agent configuration.
        application = application_instance()
        if application and application.enabled:
            application.record_exception(*exc_info)
Exemple #2
0
def monitored(fn):  # pragma: no cover
    """Provides monitoring capabilities for task methods."""
    # TODO(jvrbanac): Figure out how we should test third-party monitoring

    # Support NewRelic Monitoring
    if newrelic_loaded:
        # Create a NewRelic app instance
        app = application.application_instance()

        def newrelic_wrapper(*args, **kwargs):
            # Resolve real name since decorators are wrapper the method
            if len(args) > 0 and hasattr(args[0], fn.__name__):
                cls = type(args[0])
                task_name = '{0}:{1}.{2}'.format(cls.__module__, cls.__name__,
                                                 fn.__name__)
            else:
                task_name = newrelic.agent.callable_name(fn)

            # Execute task under a monitored context
            with newrelic.agent.BackgroundTask(app, task_name):
                fn(*args, **kwargs)

        return newrelic_wrapper

    return fn
    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
Exemple #4
0
def get_service_linking_metadata(application=None, settings=None):
    metadata = {
        "entity.type": "SERVICE",
    }

    trace = current_trace()
    if settings is None and trace:
        txn = trace.transaction
        if txn:
            settings = txn.settings

    if not settings:
        if application is None:
            from newrelic.api.application import application_instance
            application = application_instance(activate=False)

        if application is not None:
            settings = application.settings

    if settings:
        metadata["entity.name"] = settings.app_name
        entity_guid = settings.entity_guid
        if entity_guid:
            metadata["entity.guid"] = entity_guid
        metadata["hostname"] = platform.uname()[1]

    return metadata
Exemple #5
0
def test_sentinel_exited_complete_root_exception():
    """
    This test forces a transaction to exit while it still has an active trace
    this causes an exception to be raised in TraceCache complete_root(). It
    verifies that the sentinel.exited property is set to true if an exception
    is raised in complete_root()
    """
    expected_error = "not the current trace"

    try:
        txn = None
        sentinel = None
        txn = BackgroundTask(application_instance(), "Parent")
        txn.__enter__()
        sentinel = txn.root_span
        trace = FunctionTrace("trace")
        trace.__enter__()
        txn.__exit__(None, None, None)
        assert False, "Did not raise exception"
    except RuntimeError as e:
        assert str(e) == expected_error
    finally:
        assert sentinel.exited
        # Make sure to exit properly so cleanup is performed
        trace.__exit__(None, None, None)
        txn.__exit__(None, None, None)
        def create_transaction(transaction):
            if transaction:
                # If there is any active transaction we will return without
                # applying a new WSGI application wrapper context. In the
                # case of a transaction which is being ignored or which has
                # been stopped, we do that without doing anything further.

                if transaction.ignore_transaction or transaction.stopped:
                    return None

                if not transaction.background_task:
                    transaction.background_task = True
                    transaction.set_transaction_name(
                        *MessageTransaction.get_transaction_name(
                            _library, _destination_type, _destination_name))

                return None

            if type(application) != Application:
                _application = application_instance(application)
            else:
                _application = application

            return MessageTransaction(library=_library,
                                      destination_type=_destination_type,
                                      destination_name=_destination_name,
                                      application=_application,
                                      routing_key=_routing_key,
                                      exchange_type=_exchange_type,
                                      headers=_headers,
                                      queue_name=_queue_name,
                                      reply_to=_reply_to,
                                      correlation_id=_correlation_id)
Exemple #7
0
        def _possibly_create_traces(yielded):
            # This generator can be called either outside of a transaction, or
            # within the context of an existing transaction.  There are 3
            # possibilities we need to handle: (Note that this is similar to
            # our Celery instrumentation)
            #
            #   1. In an inactive transaction
            #
            #      If the end_of_transaction() or ignore_transaction() API
            #      calls have been invoked, this generator may be called in the
            #      context of an inactive transaction. In this case, don't wrap
            #      the generator in any way. Just run the original generator.
            #
            #   2. In an active transaction
            #
            #      Do nothing.
            #
            #   3. Outside of a transaction
            #
            #      Since it's not running inside of an existing transaction, we
            #      want to create a new background transaction for it but only
            #      when we've subscribed.

            transaction = current_transaction(active_only=False)
            method, properties, _ = yielded

            if transaction:
                # 1. In an inactive transaction
                # 2. In an active transaction
                return

            else:
                # 3. Outside of a transaction
                exchange = method.exchange or 'Default'
                routing_key = getattr(method, 'routing_key', None)
                headers = None
                reply_to = None
                correlation_id = 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)

                # Create a messagebroker task for each iteration through the
                # generator. This is important because it is foreseeable that
                # the generator process lasts a long time and consumes many
                # many messages.

                bt = MessageTransaction(application=application_instance(),
                                        library='RabbitMQ',
                                        destination_type='Exchange',
                                        destination_name=exchange,
                                        routing_key=routing_key,
                                        headers=headers,
                                        reply_to=reply_to,
                                        correlation_id=correlation_id)
                bt.__enter__()

                return bt
Exemple #8
0
def monitored(fn):  # pragma: no cover
    """Provides monitoring capabilities for task methods."""
    # TODO(jvrbanac): Figure out how we should test third-party monitoring

    # Support NewRelic Monitoring
    if newrelic_loaded:
        # Create a NewRelic app instance
        app = application.application_instance()

        def newrelic_wrapper(*args, **kwargs):
            # Resolve real name since decorators are wrapper the method
            if len(args) > 0 and hasattr(args[0], fn.__name__):
                cls = type(args[0])
                task_name = '{0}:{1}.{2}'.format(
                    cls.__module__,
                    cls.__name__,
                    fn.__name__
                )
            else:
                task_name = newrelic.agent.callable_name(fn)

            # Execute task under a monitored context
            with newrelic.agent.BackgroundTask(app, task_name):
                fn(*args, **kwargs)

        return newrelic_wrapper

    return fn
Exemple #9
0
def _nr_log_forwarder(message_instance):
    transaction = current_transaction()
    record = message_instance.record
    message = record.get("_nr_original_message", record["message"])

    if transaction:
        settings = transaction.settings
    else:
        settings = global_settings()

    # Return early if application logging not enabled
    if settings and settings.application_logging and settings.application_logging.enabled:
        level = record["level"]
        level_name = "UNKNOWN" if not level else (level.name or "UNKNOWN")

        if settings.application_logging.metrics and settings.application_logging.metrics.enabled:
            if transaction:
                transaction.record_custom_metric("Logging/lines", {"count": 1})
                transaction.record_custom_metric(
                    "Logging/lines/%s" % level_name, {"count": 1})
            else:
                application = application_instance(activate=False)
                if application and application.enabled:
                    application.record_custom_metric("Logging/lines",
                                                     {"count": 1})
                    application.record_custom_metric(
                        "Logging/lines/%s" % level_name, {"count": 1})

        if settings.application_logging.forwarding and settings.application_logging.forwarding.enabled:
            try:
                record_log_event(message, level_name,
                                 int(record["time"].timestamp()))
            except Exception:
                pass
Exemple #10
0
def test_nested_context_managers():
    app = application_instance()
    outer = BackgroundTask(app, 'outer')
    inner = BackgroundTask(app, 'inner')
    with outer:
        with inner:
            assert not inner.enabled
Exemple #11
0
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
Exemple #12
0
def exercise(override_expected=None, override_ignore=None, status_code=None):
    try:
        raise RuntimeError(_error_message)
    except RuntimeError:
        if current_transaction() is not None:
            # Record exception inside transaction
            notice_error(
                expected=override_expected,
                ignore=override_ignore,
                status_code=status_code,
            )
        else:
            # Record exception outside context of transaction
            application_instance().notice_error(
                expected=override_expected,
                ignore=override_ignore,
                status_code=status_code,
            )
        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)
Exemple #14
0
    def _make_test_transaction():
        application = application_instance()

        if not web_transaction:
            return BackgroundTask(application, transaction_name)

        environ = {'REQUEST_URI': '/trace_ends_after_txn'}
        tn = WSGIWebTransaction(application, environ)
        tn.set_transaction_name(transaction_name)
        return tn
def error_matches_rules(
    rules_prefix,
    exc_info,
    status_code=None,
):
    # Delay imports to prevent lockups
    from newrelic.api.application import application_instance
    from newrelic.core.trace_cache import trace_cache

    trace = trace_cache().current_trace()
    settings = trace and trace.settings

    if not settings:
        # Retrieve application settings
        application = application_instance()
        settings = application and application.settings

    # Default to global settings
    settings = settings or global_settings()  

    if not settings:
        return False

    # Retrieve settings based on prefix
    classes_rules = getattr(settings.error_collector, "%s_classes" % rules_prefix, set())
    status_codes_rules = getattr(settings.error_collector, "%s_status_codes" % rules_prefix, set())

    module, name, fullnames, message = parse_exc_info(exc_info)
    fullname = fullnames[0]

    # Check class names
    for fullname in fullnames:
        if fullname in classes_rules:
            return True

    # Check status_code
    # For callables, call on exc_info to retrieve status_code.
    # It's possible to return None, in which case no code is evaluated.
    if callable(status_code):
        status_code = status_code(*exc_info)
    
    # Match status_code if it exists
    if status_code is not None:
        try:
            # Coerce into integer
            status_code = int(status_code)
        except:
            _logger.error("Failed to coerce status code into integer. "
                          "status_code: %s" % str(status_code))
        else:
            if status_code in status_codes_rules:
                return True

    return False
Exemple #16
0
    def _make_test_transaction():
        application = application_instance()
        request = TestAsgiRequest()

        if not web_transaction:
            return BackgroundTask(application, transaction_name)

        tn = ASGIWebTransaction(application, request.scope, request.send,
                                request.receive)
        tn.set_transaction_name(transaction_name)
        return tn
def serverless_application(request):
    settings = global_settings()
    orig = settings.serverless_mode.enabled
    settings.serverless_mode.enabled = True

    application_name = 'Python Agent Test (test_serverless_mode:%s)' % (
        request.node.name)
    application = application_instance(application_name)
    application.activate()

    yield application

    settings.serverless_mode.enabled = orig
Exemple #18
0
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 test_dead_transaction_ends(circular):
    if circular and six.PY2:
        pytest.skip("Circular references in py2 result in a memory leak. "
                    "There is no way to remove transactions from the weakref "
                    "cache in this case.")

    transaction = BackgroundTask(application_instance(),
                                 "test_dead_transaction_ends")
    if circular:
        transaction._self = transaction

    transaction.__enter__()
    del transaction
    gc.collect()
def exercise(expected=None, ignore=None, status_code=None, application=None):
    try:
        raise RuntimeError(_error_message)
    except RuntimeError:
        if current_transaction() is None:
            # Record exception inside transaction
            application = application or application_instance()

        notice_error(
            expected=expected,
            ignore=ignore,
            status_code=status_code,
            application=application,
        )
def test_base_web_transaction(use_bytes):
    application = application_instance()

    request_headers = {
        'Accept': 'text/plain',
        'Content-Length': '0',
        'Content-Type': 'text/plain',
        'Host': 'localhost',
        'Referer': 'http://example.com?q=1&boat=⛵',
        'User-Agent': 'potato',
        'X-Request-Start': str(time.time() - 0.2),
        'newRelic': 'invalid',
    }

    if use_bytes:
        byte_headers = {}

        for name, value in request_headers.items():
            name = name.encode('utf-8')
            try:
                value = value.encode('utf-8')
            except UnicodeDecodeError:
                assert six.PY2
            byte_headers[name] = value

        request_headers = byte_headers

    transaction = WebTransaction(
            application,
            'test_base_web_transaction',
            group='Test',
            scheme='http',
            host='localhost',
            port=8000,
            request_method='HEAD',
            request_path='/foobar',
            query_string='foo=bar&boo=baz',
            headers=request_headers.items(),
    )

    if use_bytes:
        response_headers = ((b'Content-Length', b'0'),
                            (b'Content-Type', b'text/plain'))
    else:
        response_headers = (('Content-Length', '0'),
                            ('Content-Type', 'text/plain'))

    with transaction:
        transaction.process_response(200, response_headers)
Exemple #22
0
def wrap_callHandlers(wrapped, instance, args, kwargs):
    transaction = current_transaction()
    record = bind_callHandlers(*args, **kwargs)

    logger_name = getattr(instance, "name", None)
    if logger_name and logger_name.split(".")[0] == "newrelic":
        return wrapped(*args, **kwargs)

    if transaction:
        settings = transaction.settings
    else:
        settings = global_settings()

    # Return early if application logging not enabled
    if settings and settings.application_logging and settings.application_logging.enabled:
        level_name = str(getattr(record, "levelname", "UNKNOWN"))
        if settings.application_logging.metrics and settings.application_logging.metrics.enabled:
            if transaction:
                transaction.record_custom_metric("Logging/lines", {"count": 1})
                transaction.record_custom_metric(
                    "Logging/lines/%s" % level_name, {"count": 1})
            else:
                application = application_instance(activate=False)
                if application and application.enabled:
                    application.record_custom_metric("Logging/lines",
                                                     {"count": 1})
                    application.record_custom_metric(
                        "Logging/lines/%s" % level_name, {"count": 1})

        if settings.application_logging.forwarding and settings.application_logging.forwarding.enabled:
            try:
                message = record.getMessage()
                record_log_event(message, level_name,
                                 int(record.created * 1000))
            except Exception:
                pass

        if settings.application_logging.local_decorating and settings.application_logging.local_decorating.enabled:
            record._nr_original_message = record.getMessage
            record.getMessage = wrap_getMessage(record.getMessage)

    return wrapped(*args, **kwargs)
Exemple #23
0
def test_sentinel_exited_complete_root_exception():
    """
    This test forces a transaction to exit while it still has an active trace
    this causes an exception to be raised in TraceCache complete_root(). It
    verifies that the sentinel.exited property is set to true if an exception
    is raised in complete_root(), and that the exception is caught.
    """

    txn = None
    sentinel = None
    txn = BackgroundTask(application_instance(), "Parent")
    txn.__enter__()
    sentinel = txn.root_span
    trace = FunctionTrace("trace")
    trace.__enter__()
    txn.__exit__(None, None, None)
    assert sentinel.exited
    # Make sure to exit properly so cleanup is performed
    trace.__exit__(None, None, None)
    txn.__exit__(None, None, None)
def wait_for_transaction_completion(fn):
    CALLED = threading.Event()
    application = application_instance()
    record_transaction = application.record_transaction

    def record_transaction_wrapper(*args, **kwargs):
        record_transaction(*args, **kwargs)
        CALLED.set()

    @functools.wraps(fn)
    def _waiter(*args, **kwargs):
        application.record_transaction = record_transaction_wrapper
        try:
            result = fn(*args, **kwargs)
            CALLED.wait(timeout=1)
            return result
        finally:
            application.record_transaction = record_transaction

    return _waiter
Exemple #25
0
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)
Exemple #26
0
    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)
Exemple #27
0
def test_inbound_distributed_trace(mock_grpc_server, method_name,
                                   streaming_request, stub):
    request = create_request(streaming_request)

    transaction = Transaction(application_instance())
    dt_headers = ExternalTrace.generate_request_headers(transaction)

    @validate_transaction_metrics(
        'sample_application:SampleApplicationServicer.' + method_name,
        rollup_metrics=(('Supportability/TraceContext/Accept/Success', 1), ),
    )
    @wait_for_transaction_completion
    def _test():
        method = getattr(stub, method_name)
        response = method(request, metadata=dt_headers)

        try:
            list(response)
        except Exception:
            pass

    _test()
Exemple #28
0
    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 wrapper(wrapped, instance, args, kwargs):
        transaction = current_transaction()

        if callable(name):
            if instance and inspect.ismethod(wrapped):
                _name = name(instance, *args, **kwargs)
            else:
                _name = name(*args, **kwargs)

        elif name is None:
            _name = callable_name(wrapped)

        else:
            _name = name

        if callable(group):
            if instance and inspect.ismethod(wrapped):
                _group = group(instance, *args, **kwargs)
            else:
                _group = group(*args, **kwargs)

        else:
            _group = group

        # Check to see if we are being called within the context
        # of a web transaction. If we are, then we will just
        # flag the current web transaction as a background task
        # if not already marked as such and name the web
        # transaction as well. In any case, if nested in another
        # transaction be it a web transaction or background
        # task, then we don't do anything else and just called
        # the wrapped function.

        if transaction:
            if type(transaction) == WebTransaction:
                if not transaction.background_task:
                    transaction.background_task = True
                    transaction.name_transaction(_name, _group)

            return wrapped(*args, **kwargs)

        # Otherwise treat it as top level transaction.

        if type(application) != Application:
            _application = application_instance(application)
        else:
            _application = application

        try:
            success = True
            manager = BackgroundTask(_application, _name, _group)
            manager.__enter__()
            try:
                return wrapped(*args, **kwargs)
            except: #  Catch all
                success = False
                if not manager.__exit__(*sys.exc_info()):
                    raise
        finally:
            if success:
                manager.__exit__(None, None, None)
 def _application():
     if hasattr(application, 'activate'):
         return application
     return application_instance(application)
Exemple #31
0
 def process_initializer(*args, **kwargs):
     application_instance().activate()
     return _process_initializer(*args, **kwargs)
Exemple #32
0
 def force_application_activation(*args, **kwargs):
     application_instance().activate()
Exemple #33
0
 def _application():
     if hasattr(application, 'activate'):
         return application
     return application_instance(application)
def test_inbound_distributed_trace(app):
    transaction = Transaction(application_instance())
    dt_headers = ExternalTrace.generate_request_headers(transaction)

    response = app.fetch('get', '/', headers=dict(dt_headers))
    assert response.status == 200
Exemple #35
0
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
Exemple #36
0
    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
Exemple #37
0
    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
Exemple #38
0
    def _nr_wsgi_application_wrapper_(wrapped, instance, args, kwargs):
        # Check to see if any transaction is present, even an inactive
        # one which has been marked to be ignored or which has been
        # stopped already.

        transaction = current_transaction(active_only=False)

        if transaction:
            # If there is any active transaction we will return without
            # applying a new WSGI application wrapper context. In the
            # case of a transaction which is being ignored or which has
            # been stopped, we do that without doing anything further.

            if transaction.ignore_transaction or transaction.stopped:
                return wrapped(*args, **kwargs)

            # For any other transaction, we record the details of any
            # framework against the transaction for later reporting as
            # supportability metrics.

            if framework:
                transaction.add_framework_info(
                        name=framework[0], version=framework[1])

            # Also 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 name is None and settings:
                if framework is not None:
                    naming_scheme = settings.transaction_name.naming_scheme
                    if naming_scheme in (None, 'framework'):
                        transaction.set_transaction_name(
                                callable_name(wrapped), priority=1)

            elif name:
                transaction.set_transaction_name(name, group, priority=1)

            return wrapped(*args, **kwargs)

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

        def _args(environ, start_response, *args, **kwargs):
            return environ, start_response

        environ, start_response = _args(*args, **kwargs)

        target_application = application

        if 'newrelic.app_name' in environ:
            app_name = environ['newrelic.app_name']

            if ';' in app_name:
                app_names = [n.strip() for n in app_name.split(';')]
                app_name = app_names[0]
                target_application = application_instance(app_name)
                for altname in app_names[1:]:
                    target_application.link_to_application(altname)
            else:
                target_application = application_instance(app_name)
        else:
            # 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'):
                target_application = application_instance(application)

        # Now start recording the actual web transaction.
        transaction = WSGIWebTransaction(target_application, environ)
        transaction.__enter__()

        # Record details of framework against the transaction for later
        # reporting as supportability metrics.

        if framework:
            transaction.add_framework_info(
                    name=framework[0], version=framework[1])

        # 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 name is None and settings:
            naming_scheme = settings.transaction_name.naming_scheme

            if framework is not None:
                if naming_scheme in (None, 'framework'):
                    transaction.set_transaction_name(
                            callable_name(wrapped), priority=1)

            elif naming_scheme in ('component', 'framework'):
                transaction.set_transaction_name(
                        callable_name(wrapped), priority=1)

        elif name:
            transaction.set_transaction_name(name, 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'])

            with FunctionTrace(
                    name='Application', group='Python/WSGI'):
                with FunctionTrace(name=callable_name(wrapped)):
                    if (settings and settings.browser_monitoring.enabled and
                            not transaction.autorum_disabled):
                        result = _WSGIApplicationMiddleware(wrapped,
                                environ, _start_response, transaction)
                    else:
                        result = wrapped(environ, _start_response)

        except:  # Catch all
            transaction.__exit__(*sys.exc_info())
            raise

        return _WSGIApplicationIterable(transaction, result)
    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