Repository URL to install this package:
|
Version:
2.68.0.50 ▾
|
import functools
from .time_trace import TimeTrace
from .transaction import current_transaction
from ..core.external_node import ExternalNode
from ..common.object_wrapper import FunctionWrapper, wrap_object
from ..common.encoding_utils import (obfuscate, deobfuscate, json_encode,
json_decode)
class ExternalTrace(TimeTrace):
def __init__(self, transaction, library, url, method=None):
super(ExternalTrace, self).__init__(transaction)
self.library = library
self.url = url
self.method = method
self.params = {}
self.settings = transaction and self.transaction.settings or None
def __repr__(self):
return '<%s %s>' % (self.__class__.__name__, dict(
library=self.library, url=self.url, method=self.method))
def create_node(self):
return ExternalNode(library=self.library, url=self.url,
method=self.method, children=self.children,
start_time=self.start_time, end_time=self.end_time,
duration=self.duration, exclusive=self.exclusive,
params=self.params)
def terminal_node(self):
return True
def process_response_headers(self, response_headers):
"""
Decode the response headers and create appropriate metics based on the
header values. The response_headers are passed in as a list of tuples.
[(HEADER_NAME0, HEADER_VALUE0), (HEADER_NAME1, HEADER_VALUE1)]
"""
if not self.settings.cross_application_tracer.enabled:
return
appdata = None
try:
for k, v in response_headers:
if k.upper() == 'X-NEWRELIC-APP-DATA':
appdata = json_decode(deobfuscate(v,
self.settings.encoding_key))
break
if appdata:
self.params['cross_process_id'] = appdata[0]
self.params['external_txn_name'] = appdata[1]
self.params['transaction_guid'] = appdata[5]
except Exception:
pass
@staticmethod
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 ExternalTraceWrapper(wrapped, library, url, method=None):
def dynamic_wrapper(wrapped, instance, args, kwargs):
transaction = current_transaction()
if transaction is None:
return wrapped(*args, **kwargs)
if callable(url):
if instance is not None:
_url = url(instance, *args, **kwargs)
else:
_url = url(*args, **kwargs)
else:
_url = url
if callable(method):
if instance is not None:
_method = method(instance, *args, **kwargs)
else:
_method = method(*args, **kwargs)
else:
_method = method
with ExternalTrace(transaction, library, _url, _method):
return wrapped(*args, **kwargs)
def literal_wrapper(wrapped, instance, args, kwargs):
transaction = current_transaction()
if transaction is None:
return wrapped(*args, **kwargs)
with ExternalTrace(transaction, library, url, method):
return wrapped(*args, **kwargs)
if callable(url) or callable(method):
return FunctionWrapper(wrapped, dynamic_wrapper)
return FunctionWrapper(wrapped, literal_wrapper)
def external_trace(library, url, method=None):
return functools.partial(ExternalTraceWrapper, library=library,
url=url, method=method)
def wrap_external_trace(module, object_path, library, url, method=None):
wrap_object(module, object_path, ExternalTraceWrapper,
(library, url, method))