Пример #1
0
    def generate_request_headers(transaction):
        """
        Return a list of NewRelic specific headers as tuples
        [(HEADER_NAME0, HEADER_VALUE0), (HEADER_NAME1, HEADER_VALUE1)]

        """

        if transaction is None:
            return []

        settings = transaction.settings

        nr_headers = []

        if settings.cross_application_tracer.enabled:

            transaction.is_part_of_cat = True
            encoded_cross_process_id = obfuscate(settings.cross_process_id,
                                                 settings.encoding_key)
            nr_headers.append(('X-NewRelic-ID', encoded_cross_process_id))

            transaction_data = [
                transaction.guid, transaction.record_tt, transaction.trip_id,
                transaction.path_hash
            ]
            encoded_transaction = obfuscate(json_encode(transaction_data),
                                            settings.encoding_key)
            nr_headers.append(('X-NewRelic-Transaction', encoded_transaction))

        if transaction.synthetics_header:
            nr_headers.append(
                ('X-NewRelic-Synthetics', transaction.synthetics_header))

        return nr_headers
    def browser_monitoring_intrinsics(self, obfuscation_key):
        txn_name = obfuscate(self.path, obfuscation_key)

        queue_start = self.queue_start or self.start_time
        start_time = self.start_time
        end_time = time.time()

        queue_duration = int((start_time - queue_start) * 1000)
        request_duration = int((end_time - start_time) * 1000)

        intrinsics = {
            "beacon": self._settings.beacon,
            "errorBeacon": self._settings.error_beacon,
            "licenseKey": self._settings.browser_key,
            "applicationID": self._settings.application_id,
            "transactionName": txn_name,
            "queueTime": queue_duration,
            "applicationTime": request_duration,
            "agent": self._settings.js_agent_file,
        }

        if self._settings.browser_monitoring.ssl_for_http is not None:
            ssl_for_http = self._settings.browser_monitoring.ssl_for_http
            intrinsics['sslForHttp'] = ssl_for_http

        return intrinsics
def create_incoming_headers(transaction):
    settings = transaction.settings
    encoding_key = settings.encoding_key

    headers = []

    cross_process_id = '1#2'
    path = 'test'
    queue_time = 1.0
    duration = 2.0
    read_length = 1024
    guid = '0123456789012345'
    record_tt = False

    payload = (cross_process_id, path, queue_time, duration, read_length,
            guid, record_tt)
    app_data = json_encode(payload)

    value = obfuscate(app_data, encoding_key)

    assert isinstance(value, type(''))

    headers.append(('X-NewRelic-App-Data', value))

    return headers
Пример #4
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]
Пример #5
0
    def generate_request_headers(cls, transaction):
        """
        Return a list of NewRelic specific headers as tuples
        [(HEADER_NAME0, HEADER_VALUE0), (HEADER_NAME1, HEADER_VALUE1)]

        """

        if transaction is None:
            return []

        settings = transaction.settings

        nr_headers = []

        if settings.distributed_tracing.enabled:
            payload = transaction.create_distributed_trace_payload()
            if not payload:
                return []

            encoded_header = payload.http_safe()
            nr_headers.append((cls.cat_distributed_trace_key, encoded_header))

        elif settings.cross_application_tracer.enabled:
            transaction.is_part_of_cat = True
            encoded_cross_process_id = obfuscate(settings.cross_process_id,
                                                 settings.encoding_key)
            nr_headers.append((cls.cat_id_key, encoded_cross_process_id))

            transaction_data = [
                transaction.guid, transaction.record_tt, transaction.trip_id,
                transaction.path_hash
            ]
            encoded_transaction = obfuscate(json_encode(transaction_data),
                                            settings.encoding_key)
            nr_headers.append((cls.cat_transaction_key, encoded_transaction))

        if transaction.synthetics_header:
            nr_headers.append(
                (cls.cat_synthetics_key, transaction.synthetics_header))

        return nr_headers
    def generate_request_headers(cls, transaction):
        """
        Return a list of NewRelic specific headers as tuples
        [(HEADER_NAME0, HEADER_VALUE0), (HEADER_NAME1, HEADER_VALUE1)]

        """

        if transaction is None or transaction.settings is None:
            return []

        settings = transaction.settings

        nr_headers = []

        if settings.distributed_tracing.enabled:
            transaction.insert_distributed_trace_headers(nr_headers)

        elif settings.cross_application_tracer.enabled:
            transaction.is_part_of_cat = True
            path_hash = transaction.path_hash
            if path_hash is None:
                # Disable cat if path_hash fails to generate.
                transaction.is_part_of_cat = False
            else:
                encoded_cross_process_id = obfuscate(settings.cross_process_id,
                        settings.encoding_key)
                nr_headers.append((cls.cat_id_key, encoded_cross_process_id))

                transaction_data = [transaction.guid, transaction.record_tt,
                        transaction.trip_id, path_hash]
                encoded_transaction = obfuscate(json_encode(transaction_data),
                        settings.encoding_key)
                nr_headers.append(
                        (cls.cat_transaction_key, encoded_transaction))

        if transaction.synthetics_header:
            nr_headers.append(
                    (cls.cat_synthetics_key, transaction.synthetics_header))

        return nr_headers
    def browser_timing_footer(self):
        """Returns the JavaScript footer to be included in any HTML
        response to perform real user monitoring. This function returns
        the footer as a native Python string. In Python 2 native strings
        are stored as bytes. In Python 3 native strings are stored as
        unicode.

        """

        if not self.enabled:
            return ''

        if self._state != self.STATE_RUNNING:
            return ''

        if self.ignore_transaction:
            return ''

        # Only generate a footer if the header had already been
        # generated and we haven't already generated the footer.

        if not self.rum_header_generated:
            return ''

        if self.rum_footer_generated:
            return ''

        # Make sure we freeze the path.

        self._freeze_path()

        # When obfuscating values for the footer, we only use the
        # first 13 characters of the account license key.

        obfuscation_key = self._settings.license_key[:13]

        attributes = {}

        user_attributes = {}
        for attr in self.user_attributes:
            if attr.destinations & DST_BROWSER_MONITORING:
                user_attributes[attr.name] = attr.value

        if user_attributes:
            attributes['u'] = user_attributes

        request_parameters = self.request_parameters
        request_parameter_attributes = self.filter_request_parameters(
            request_parameters)
        agent_attributes = {}
        for attr in request_parameter_attributes:
            if attr.destinations & DST_BROWSER_MONITORING:
                agent_attributes[attr.name] = attr.value

        if agent_attributes:
            attributes['a'] = agent_attributes

        # create the data structure that pull all our data in

        footer_data = self.browser_monitoring_intrinsics(obfuscation_key)

        if attributes:
            attributes = obfuscate(json_encode(attributes), obfuscation_key)
            footer_data['atts'] = attributes

        footer = _js_agent_footer_fragment % json_encode(footer_data)

        # To avoid any issues with browser encodings, we will make sure that
        # the javascript we inject for the browser agent is ASCII encodable.
        # Since we obfuscate all agent and user attributes, and the transaction
        # name with base 64 encoding, this will preserve those strings, if
        # they have values outside of the ASCII character set.
        # In the case of Python 2, we actually then use the encoded value
        # as we need a native string, which for Python 2 is a byte string.
        # If encoding as ASCII fails we will return an empty string.

        try:
            if six.PY2:
                footer = footer.encode('ascii')
            else:
                footer.encode('ascii')

        except UnicodeError:
            if not WebTransaction.unicode_error_reported:
                _logger.error('ASCII encoding of js-agent-footer failed.',
                              footer)
                WebTransaction.unicode_error_reported = True

            footer = ''

        # We remember if we have returned a non empty string value and
        # if called a second time we will not return it again.

        if footer:
            self.rum_footer_generated = True

        return footer
Пример #8
0
    def process_response(self, status, response_headers, *args):
        """Processes response status and headers, extracting any
        details required and returning a set of additional headers
        to merge into that being returned for the web transaction.

        """

        additional_headers = []

        # Extract the HTTP status response code.

        try:
            self.response_code = int(status.split(' ')[0])
        except Exception:
            pass

        # Extract response content length and type for inclusion in agent
        # attributes

        try:

            for header, value in response_headers:
                lower_header = header.lower()
                if 'content-length' == lower_header:
                    self._response_properties['CONTENT_LENGTH'] = int(value)
                elif 'content-type' == lower_header:
                    self._response_properties['CONTENT_TYPE'] = value

        except Exception:
            pass

        # Generate metrics and response headers for inbound cross
        # process web external calls.

        if self.client_cross_process_id is not None:

            # Need to work out queueing time and duration up to this
            # point for inclusion in metrics and response header. If the
            # recording of the transaction had been prematurely stopped
            # via an API call, only return time up until that call was
            # made so it will match what is reported as duration for the
            # transaction.

            if self.queue_start:
                queue_time = self.start_time - self.queue_start
            else:
                queue_time = 0

            if self.end_time:
                duration = self.end_time = self.start_time
            else:
                duration = time.time() - self.start_time

            # Generate the metric identifying the caller.

            metric_name = 'ClientApplication/%s/all' % (
                    self.client_cross_process_id)
            self.record_custom_metric(metric_name, duration)

            # Generate the additional response headers which provide
            # information back to the caller. We need to freeze the
            # transaction name before adding to the header.

            self._freeze_path()

            payload = (self._settings.cross_process_id, self.path, queue_time,
                    duration, self._read_length, self.guid, self.record_tt)
            app_data = json_encode(payload)

            additional_headers.append(('X-NewRelic-App-Data', obfuscate(
                    app_data, self._settings.encoding_key)))

        # The additional headers returned need to be merged into the
        # original response headers passed back by the application.

        return additional_headers