def _test_cat_headers():
        transaction = current_transaction()

        payload = ExternalTrace.generate_request_headers(transaction)
        assert not payload

        trace = ExternalTrace('testlib', 'http://example.com')
        response_headers = [('X-NewRelic-App-Data', 'Cookies')]
        with trace:
            trace.process_response_headers(response_headers)

        assert transaction.settings.cross_application_tracer.enabled is False
예제 #2
0
        def wrap_next(_wrapped, _instance, _args, _kwargs):

            _start = time.time()
            try:
                result = _wrapped(*_args, **_kwargs)
            except StopIteration:
                raise
            except Exception:
                with ExternalTrace(transaction, library, _url, method) as t:
                    t.start_time = _start
                    raise
            else:
                with ExternalTrace(transaction, library, _url, method) as t:
                    t.start_time = _start
                    return result
예제 #3
0
        def wrap_result(_wrapped, _instance, _args, _kwargs):
            if _result_called:
                return _wrapped(*_args, **_kwargs)

            _result_called.append(True)
            try:
                result = _wrapped(*_args, **_kwargs)
            except Exception:
                with ExternalTrace(transaction, library, _url, method) as t:
                    t.start_time = _nr_start_time
                    raise
            else:
                with ExternalTrace(transaction, library, _url, method) as t:
                    t.start_time = _nr_start_time
                    return result
예제 #4
0
def _nr_aiohttp_add_cat_headers_(wrapped, instance, args, kwargs):
    transaction = current_transaction()
    if transaction is None:
        return wrapped(*args, **kwargs)

    try:
        cat_headers = ExternalTrace.generate_request_headers(transaction)
    except:
        return wrapped(*args, **kwargs)

    tmp = instance.headers
    instance.headers = HeaderProxy(tmp, cat_headers)

    if is_coroutine_function(wrapped):

        @asyncio.coroutine
        def new_coro():
            try:
                result = yield from wrapped(*args, **kwargs)
                return result
            finally:
                instance.headers = tmp

        return new_coro()
    else:
        try:
            return wrapped(*args, **kwargs)
        finally:
            instance.headers = tmp
예제 #5
0
def _nr_aiohttp_request_wrapper_(wrapped, instance, args, kwargs):
    transaction = current_transaction()
    if transaction is None:
        return wrapped(*args, **kwargs)

    method, url = _bind_request(*args, **kwargs)
    trace = ExternalTrace('aiohttp', str(url), method)

    @asyncio.coroutine
    def _coro():
        try:
            response = yield from wrapped(*args, **kwargs)

            try:
                trace.process_response_headers(response.headers.items())
            except:
                pass

            return response
        except Exception as e:
            try:
                trace.process_response_headers(e.headers.items())
            except:
                pass

            raise

    return async_wrapper(wrapped)(_coro, trace)()
예제 #6
0
    def _nr_wrapper_httplib2_connect_wrapper_inner(wrapped, instance, args,
            kwargs):
        transaction = current_transaction()

        if transaction is None:
            return wrapped(*args, **kwargs)

        def _connect_unbound(instance, *args, **kwargs):
            return instance

        if instance is None:
            instance = _connect_unbound(*args, **kwargs)

        connection = instance

        url = '%s://%s:%s' % (scheme, connection.host, connection.port)

        with ExternalTrace(transaction, library='httplib2', url=url) as tracer:
            # Add the tracer to the connection object. The tracer will be
            # used in getresponse() to add back into the external trace,
            # after the trace has already completed, details from the
            # response headers.

            connection._nr_external_tracer = tracer

            return wrapped(*args, **kwargs)
def _nr_endpoint_make_request_(wrapped, instance, args, kwargs):
    transaction = current_transaction()

    if transaction is None:
        return wrapped(*args, **kwargs)

    operation_model, request_dict = _bind_make_request_params(*args, **kwargs)
    url = request_dict.get('url', '')
    method = request_dict.get('method', None)

    with ExternalTrace(transaction, library='botocore', url=url,
            method=method) as trace:

        try:
            trace._add_agent_attribute('aws.operation', operation_model.name)
        except:
            pass

        result = wrapped(*args, **kwargs)
        try:
            request_id = result[1]['ResponseMetadata']['RequestId']
            trace._add_agent_attribute('aws.requestId', request_id)
        except:
            pass
        return result
예제 #8
0
def httplib_endheaders_wrapper(wrapped, instance, args, kwargs):
    transaction = current_transaction()

    if transaction is None:
        return wrapped(*args, **kwargs)

    connection = instance

    # Check if the NR headers have already been added. This is just in
    # case a higher level library which uses httplib underneath so
    # happened to have been instrumented to also add the headers.

    try:
        skip_headers = getattr(connection, '_nr_skip_headers', False)

        if skip_headers:
            return wrapped(*args, **kwargs)

        outgoing_headers = ExternalTrace.generate_request_headers(transaction)
        for header_name, header_value in outgoing_headers:
            connection.putheader(header_name, header_value)

        return wrapped(*args, **kwargs)

    finally:
        try:
            del connection._nr_skip_headers
        except AttributeError:
            pass
예제 #9
0
def target_wsgi_application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'application/json')])
    txn = current_transaction()
    if txn._sampled is None:
        txn._sampled = True
        txn._priority = 1.2
    headers = ExternalTrace.generate_request_headers(txn)
    return [json.dumps(headers).encode('utf-8')]
예제 #10
0
    def _test():
        transaction = current_transaction()
        transaction._sampled = True

        with ExternalTrace(library='library',
                           url='http://example.com/foo?secret=123',
                           method='get'):
            pass
예제 #11
0
def _nr_wrapper_make_request_(wrapped, instance, args, kwargs):
    def _bind_params(conn, method, url, *args, **kwargs):
        return "%s://%s:%s" % (instance.scheme, conn.host, conn.port)

    url_for_apm_ui = _bind_params(*args, **kwargs)

    with ExternalTrace('urllib3', url_for_apm_ui):
        return wrapped(*args, **kwargs)
    def _call_wrapper(wrapped, instance, args, kwargs):
        transaction = current_transaction()
        if transaction is None:
            return wrapped(*args, **kwargs)

        uri, method = _get_uri_method(instance)
        with ExternalTrace('gRPC', uri, method, source=wrapped):
            args, kwargs = prepare(transaction, None, *args, **kwargs)
            return wrapped(*args, **kwargs)
def wrap_next(_wrapped, _instance, _args, _kwargs):
    _nr_args = getattr(_instance, '_nr_args', None)
    if not _nr_args:
        return _wrapped(*_args, **_kwargs)

    _start = time.time()
    try:
        result = _wrapped(*_args, **_kwargs)
    except StopIteration:
        raise
    except Exception:
        with ExternalTrace(*_nr_args) as t:
            t.start_time = _start
            raise
    else:
        with ExternalTrace(*_nr_args) as t:
            t.start_time = _start
            return result
예제 #14
0
def target_wsgi_application(environ, start_response):
    status = '200 OK'

    txn_name = environ.get('txn')
    if six.PY2:
        txn_name = txn_name.decode('UTF-8')
    txn_name = txn_name.split('/', 3)

    guid = environ.get('guid')
    old_cat = environ.get('old_cat') == 'True'
    txn = current_transaction()

    txn.guid = guid
    for req in OUTBOUD_REQUESTS:
        # Change the transaction name before making an outbound call.
        outgoing_name = req['outboundTxnName'].split('/', 3)
        if outgoing_name[0] != 'WebTransaction':
            set_background_task(True)

        set_transaction_name(outgoing_name[2], group=outgoing_name[1])

        expected_outbound_header = obfuscate(
            json_encode(req['expectedOutboundPayload']), ENCODING_KEY)
        generated_outbound_header = dict(
            ExternalTrace.generate_request_headers(txn))

        # A 500 error is returned because 'assert' statements in the wsgi app
        # are ignored.

        if old_cat:
            if (expected_outbound_header !=
                    generated_outbound_header['X-NewRelic-Transaction']):
                status = '500 Outbound Headers Check Failed.'
        else:
            if 'X-NewRelic-Transaction' in generated_outbound_header:
                status = '500 Outbound Headers Check Failed.'
        r = urlopen(environ['server_url'])
        r.read(10)

    # Set the final transaction name.

    if txn_name[0] != 'WebTransaction':
        set_background_task(True)
    set_transaction_name(txn_name[2], group=txn_name[1])

    text = '<html><head>%s</head><body><p>RESPONSE</p>%s</body></html>'

    output = (text % (get_browser_timing_header(),
                      get_browser_timing_footer())).encode('UTF-8')

    response_headers = [('Content-type', 'text/html; charset=utf-8'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    return [output]
예제 #15
0
def wrap_result(_wrapped, _instance, _args, _kwargs):
    _nr_args = getattr(_instance, '_nr_args', None)
    if not _nr_args:
        return _wrapped(*_args, **_kwargs)
    delattr(_instance, '_nr_args')
    _nr_start_time = getattr(_instance, '_nr_start_time', 0.0)
    _nr_guid = getattr(_instance, '_nr_guid', None)

    try:
        result = _wrapped(*_args, **_kwargs)
    except Exception:
        with ExternalTrace(*_nr_args) as t:
            t.start_time = _nr_start_time or t.start_time
            t.guid = _nr_guid or t.guid
            raise
    else:
        with ExternalTrace(*_nr_args) as t:
            t.start_time = _nr_start_time or t.start_time
            t.guid = _nr_guid or t.guid
            return result
예제 #16
0
def wrap_httpclient_fetch(wrapped, instance, args, kwargs):
    try:
        req, raise_error = _prepare_request(*args, **kwargs)
    except:
        return wrapped(*args, **kwargs)

    trace = ExternalTrace('tornado', req.url, req.method.upper())

    outgoing_headers = trace.generate_request_headers(current_transaction())
    for header_name, header_value in outgoing_headers:
        # User headers should override our CAT headers
        if header_name in req.headers:
            continue
        req.headers[header_name] = header_value

    try:
        fetch = create_client_wrapper(wrapped, trace)
    except:
        return wrapped(*args, **kwargs)

    return convert_yielded(fetch(req, raise_error))
async def async_send_wrapper(wrapped, instance, args, kwargs):
    request = bind_request(*args, **kwargs)

    with ExternalTrace("httpx", str(request.url), request.method) as tracer:
        if hasattr(tracer, "generate_request_headers"):
            outgoing_headers = tracer.generate_request_headers(
                tracer.transaction)
            for header_name, header_value in outgoing_headers:
                # User headers should override our CAT headers
                if header_name not in request.headers:
                    request.headers[header_name] = header_value

        return await wrapped(*args, **kwargs)
def wrap_result(_wrapped, _instance, _args, _kwargs):
    _result_called = getattr(_instance, '_nr_result_called', True)
    if _result_called:
        return _wrapped(*_args, **_kwargs)
    _instance._nr_result_called = True

    _nr_args = getattr(_instance, '_nr_args', None)
    if not _nr_args:
        return _wrapped(*_args, **_kwargs)

    _nr_start_time = getattr(_instance, '_nr_start_time', 0.0)

    try:
        result = _wrapped(*_args, **_kwargs)
    except Exception:
        with ExternalTrace(*_nr_args) as t:
            t.start_time = _nr_start_time
            raise
    else:
        with ExternalTrace(*_nr_args) as t:
            t.start_time = _nr_start_time
            return result
예제 #19
0
def _nr_wrapper_make_request_(wrapped, instance, args, kwargs, scheme):
    def _bind_params(conn, method, url, *args, **kwargs):
        return "%s://%s:%s" % (scheme, conn.host, conn.port)

    transaction = current_transaction()

    if transaction is None:
        return wrapped(*args, **kwargs)

    url_for_apm_ui = _bind_params(*args, **kwargs)

    with ExternalTrace(transaction, 'urllib3', url_for_apm_ui):
        return wrapped(*args, **kwargs)
예제 #20
0
    def _nr_wrapper(wrapped, instance, args, kwargs):
        transaction = current_transaction()

        if transaction is None:
            return wrapped(*args, **kwargs)

        url = bind_params_fn(*args, **kwargs)

        details = urlparse.urlparse(url)

        if details.hostname is None:
            return wrapped(*args, **kwargs)

        with ExternalTrace(transaction, library, url):
            return wrapped(*args, **kwargs)
예제 #21
0
def _nr_aiohttp_add_cat_headers_simple_(wrapped, instance, args, kwargs):
    transaction = current_transaction()
    if transaction is None:
        return wrapped(*args, **kwargs)

    try:
        cat_headers = ExternalTrace.generate_request_headers(transaction)
    except:
        return wrapped(*args, **kwargs)

    for k, _ in cat_headers:
        if k in instance.headers:
            return wrapped(*args, **kwargs)

    instance.headers.update(cat_headers)
    return wrapped(*args, **kwargs)
예제 #22
0
def _nr_wrap_PayloadWriter_write_headers(wrapped, instance, args, kwargs):
    transaction = current_transaction()
    if transaction is None:
        return wrapped(*args, **kwargs)

    status_line, headers, _args, _kwargs = _bind_write_headers(
            *args, **kwargs)

    try:
        cat_headers = ExternalTrace.generate_request_headers(transaction)
        updated_headers = dict(cat_headers + [(k, v) for k, v in
                headers.items()])
    except:
        return wrapped(*args, **kwargs)

    return wrapped(status_line, updated_headers, *_args, **_kwargs)
예제 #23
0
def httplib_endheaders_wrapper(wrapped, instance, args, kwargs, scheme,
                               library):
    transaction = current_transaction()

    if transaction is None:
        return wrapped(*args, **kwargs)

    def _connect_unbound(instance, *args, **kwargs):
        return instance

    if instance is None:
        instance = _connect_unbound(*args, **kwargs)

    connection = instance

    if hasattr(connection, '_nr_library_info'):
        library, scheme = connection._nr_library_info

    url = '%s://%s:%s' % (scheme, connection.host, connection.port)

    # Check if the NR headers have already been added. This is just in
    # case a higher level library which uses httplib underneath so
    # happened to have been instrumented to also add the headers.

    try:
        skip_headers = getattr(connection, '_nr_skip_headers', False)

        with ExternalTrace(library=library, url=url) as tracer:
            # Add the tracer to the connection object. The tracer will be
            # used in getresponse() to add back into the external trace,
            # after the trace has already completed, details from the
            # response headers.
            if not skip_headers and hasattr(tracer,
                                            'generate_request_headers'):
                outgoing_headers = tracer.generate_request_headers(transaction)
                for header_name, header_value in outgoing_headers:
                    connection.putheader(header_name, header_value)

            connection._nr_external_tracer = tracer

            return wrapped(*args, **kwargs)

    finally:
        try:
            del connection._nr_skip_headers
        except AttributeError:
            pass
예제 #24
0
def test_cat_fips_compliance(monkeypatch, fips_enabled):
    # Set md5 to raise a ValueError to simulate FIPS compliance issues.
    def md5_crash(*args, **kwargs):
        raise ValueError()

    if fips_enabled:
        # monkeypatch.setattr("hashlib.md5", md5_crash)
        import hashlib
        monkeypatch.setattr(hashlib, "md5", md5_crash)

    # Generate and send request using actual transaction api instead of fixture.
    # Otherwise the proper code paths are not exercised.
    with ExternalTrace("cat_test", "http://localhost/200") as tracer:
        headers = tracer.generate_request_headers(tracer.transaction)
    
    expected = not fips_enabled  # Invert to make more human readable
    assert ('X-NewRelic-Transaction' in dict(headers)) == expected
def wrapper_GearmanConnectionManager_poll_connections_until_stopped(
        wrapped, instance, args, kwargs):

    def _bind_params(submitted_connections, *args, **kwargs):
        return submitted_connections

    transaction = current_transaction()

    if transaction is None:
        return wrapped(*args, **kwargs)

    # Because gearman uses a custom message based protocol over a raw
    # socket, we can't readily wrap a single function which is
    # performing a request and then returning a response. The best we
    # can do is wrap as an external the poll_connections_until_stopped()
    # function. This is what manages looking for whether data is
    # available from the server, or whether data can be written, and
    # then handles those events.
    #
    # This is complicated somewhat though due to a gearman client being
    # able to be supplied multiple servers to communicate with. We can
    # not actually determine which server communication will occur with
    # until the specific handle function for read, write or error is
    # called but that is too late in cases where a failure of some sort
    # occurs such as a timeout. What we therefore do is presume
    # initially that the server will be whatever is the first in the
    # list of server connections and we will override this latter based
    # on which server we ended up communicating with. It is possible this
    # still will not always be correct if data is handled for multiple
    # servers in the one call, but it is likely as close as we can get.
    # As likely that most clients will only be talking to a single
    # server, it likely will not matter too much.

    submitted_connections = _bind_params(*args, **kwargs)

    if not submitted_connections:
        return wrapped(*args, **kwargs)

    first_connection = list(submitted_connections)[0]

    url = 'gearman://%s:%s' % (first_connection.gearman_host,
            first_connection.gearman_port)

    with ExternalTrace(transaction, 'gearman', url):
        return wrapped(*args, **kwargs)
예제 #26
0
def _nr_wrapper_httpclient_AsyncHTTPClient_fetch_(wrapped, instance, args,
                                                  kwargs):

    transaction = current_transaction()

    if transaction is None:
        return wrapped(*args, **kwargs)

    try:
        req, _cb, _raise_error = _prepare_request(*args, **kwargs)
    except:
        return wrapped(*args, **kwargs)

    # Prepare outgoing CAT headers
    outgoing_headers = ExternalTrace.generate_request_headers(transaction)
    for header_name, header_value in outgoing_headers:
        # User headers should override our CAT headers
        if header_name in req.headers:
            continue
        req.headers[header_name] = header_value

    trace = ExternalTrace(transaction, 'tornado.httpclient', req.url,
                          req.method.upper())

    def external_trace_done(future):
        exc_info = future.exc_info()
        if exc_info:
            trace.__exit__(*exc_info)
        else:
            response = future.result()
            # Process CAT response headers
            trace.process_response_headers(response.headers.get_all())
            trace.__exit__(None, None, None)

    trace.__enter__()
    if trace.transaction and trace.transaction.current_node is trace:
        # externals should not have children
        trace.transaction._pop_current(trace)

    try:
        future = wrapped(req, _cb, _raise_error)
        future.add_done_callback(external_trace_done)
    except Exception:
        trace.__exit__(*sys.exc_info())
        raise
    return future
예제 #27
0
    def _validate_synthetics_external_trace_header(wrapped, instance,
            args, kwargs):
        def _bind_params(transaction, *args, **kwargs):
            return transaction

        transaction = _bind_params(*args, **kwargs)

        try:
            result = wrapped(*args, **kwargs)
        except:
            raise
        else:
            if should_exist:
                # XXX This validation routine is technically
                # broken as the argument to record_transaction()
                # is not actually an instance of the Transaction
                # object. Instead it is a TransactionNode object.
                # The static method generate_request_headers() is
                # expecting a Transaction object and not
                # TransactionNode. The latter provides attributes
                # which are not updatable by the static method
                # generate_request_headers(), which it wants to
                # update, so would fail. For now what we do is use
                # a little proxy wrapper so that updates do not
                # fail. The use of this wrapper needs to be
                # reviewed and a better way of achieving what is
                # required found.

                class _Transaction(object):
                    def __init__(self, wrapped):
                        self.__wrapped__ = wrapped

                    def __getattr__(self, name):
                        return getattr(self.__wrapped__, name)

                external_headers = ExternalTrace.generate_request_headers(
                        _Transaction(transaction))
                assert required_header in external_headers, (
                        'required_header=%r, ''external_headers=%r' % (
                        required_header, external_headers))

        return result
예제 #28
0
def _nr_wrapper_httpclient_AsyncHTTPClient_fetch_(wrapped, instance, args,
                                                  kwargs):

    transaction = retrieve_current_transaction()

    if transaction is None:
        return wrapped(*args, **kwargs)

    req, _cb, _raise_error = _prepare_request(*args, **kwargs)

    # Prepare outgoing CAT headers
    outgoing_headers = ExternalTrace.generate_request_headers(transaction)
    for header_name, header_value in outgoing_headers:
        req.headers[header_name] = header_value

    trace = ExternalTrace(transaction, 'tornado.httpclient', req.url)

    def external_trace_done(future):
        exc_info = future.exc_info()
        if exc_info:
            trace.__exit__(*exc_info)
        else:
            response = future.result()
            # Process CAT response headers
            trace.process_response_headers(response.headers.get_all())
            trace.__exit__(None, None, None)
        transaction._ref_count -= 1

    transaction._ref_count += 1
    trace.__enter__()

    # Because traces are terminal but can be generated concurrently in
    # tornado, pop the trace immediately after entering.
    if trace.transaction and trace.transaction.current_node is trace:
        trace.transaction._pop_current(trace)

    try:
        future = wrapped(req, _cb, _raise_error)
        future.add_done_callback(external_trace_done)
    except Exception:
        transaction._ref_count -= 1
        trace.__exit__(*sys.exc_info())
        raise
    return future
def _nr_wrapper_opener_director_open_(wrapped, instance, args, kwargs):
    transaction = current_transaction()

    if transaction is None:
        return wrapped(*args, **kwargs)

    def _bind_params(fullurl, *args, **kwargs):
        if isinstance(fullurl, six.string_types):
            return fullurl
        else:
            return fullurl.get_full_url()

    url = _bind_params(*args, **kwargs)

    details = urlparse.urlparse(url)

    if details.hostname is None:
        return wrapped(*args, **kwargs)

    with ExternalTrace('urllib2', url):
        return wrapped(*args, **kwargs)
예제 #30
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()