From 464282322ad8dd7dfad49978ba9b3b1bd3120415 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Fri, 14 Feb 2020 15:19:17 +0100 Subject: [PATCH 01/29] Refactor, reorganize and cleanup for AWS prep --- instana/agent.py | 110 ++++++++++++++++++++++++++++------------- instana/agent_const.py | 7 --- instana/fsm.py | 38 +++----------- instana/meter.py | 96 ++--------------------------------- instana/options.py | 52 +++++++++++++------ instana/recorder.py | 8 +-- instana/sensor.py | 11 +---- instana/singletons.py | 4 +- instana/tracer.py | 3 +- instana/util.py | 68 +++++++++++++++++++++++++ 10 files changed, 200 insertions(+), 197 deletions(-) delete mode 100644 instana/agent_const.py diff --git a/instana/agent.py b/instana/agent.py index 5d3174ed..0a7d9ff2 100644 --- a/instana/agent.py +++ b/instana/agent.py @@ -8,24 +8,39 @@ import instana.singletons -from .agent_const import (AGENT_DATA_PATH, AGENT_DEFAULT_HOST, - AGENT_DEFAULT_PORT, AGENT_DISCOVERY_PATH, - AGENT_HEADER, AGENT_RESPONSE_PATH, AGENT_TRACES_PATH) from .fsm import TheMachine from .log import logger from .sensor import Sensor -from .util import to_json +from .util import to_json, get_py_source, package_version +from .options import StandardOptions, AWSLambdaOptions -class From(object): - pid = "" +class AnnounceData(object): + pid = 0 agentUuid = "" def __init__(self, **kwds): self.__dict__.update(kwds) -class Agent(object): +class AWSLambdaFrom(object): + hl = True + cp = "aws" + e = "qualifiedARN" + + def __init__(self, **kwds): + self.__dict__.update(kwds) + + +class BaseAgent(object): + client = requests.Session() + sensor = None + + def __init__(self): + pass + + +class StandardAgent(BaseAgent): """ The Agent class is the central controlling entity for the Instana Python language sensor. The key parts it handles are the announce state and the collection and reporting of metrics and spans to the @@ -36,21 +51,24 @@ class Agent(object): 2. Sensor -> Meter - metric collection and reporting 3. Tracer -> Recorder - span queueing and reporting """ - sensor = None - host = AGENT_DEFAULT_HOST - port = AGENT_DEFAULT_PORT + AGENT_DISCOVERY_PATH = "com.instana.plugin.python.discovery" + AGENT_DATA_PATH = "com.instana.plugin.python.%d" + AGENT_HEADER = "Instana Agent" + + announce_data = None + options = StandardOptions() + machine = None - from_ = From() last_seen = None last_fork_check = None _boot_pid = os.getpid() extra_headers = None secrets_matcher = 'contains-ignore-case' secrets_list = ['key', 'password', 'secret'] - client = requests.Session() should_threads_shutdown = threading.Event() def __init__(self): + super(StandardAgent, self).__init__() logger.debug("initializing agent") self.sensor = Sensor(self) self.machine = TheMachine(self) @@ -82,7 +100,7 @@ def reset(self): self.should_threads_shutdown.set() self.last_seen = None - self.from_ = From() + self.announce_data = None # Will schedule a restart of the announce cycle in the future self.machine.reset() @@ -124,19 +142,19 @@ def set_from(self, json_string): self.extra_headers = res_data['extraHeaders'] logger.info("Will also capture these custom headers: %s", self.extra_headers) - self.from_ = From(pid=res_data['pid'], agentUuid=res_data['agentUuid']) + self.announce_data = AnnounceData(pid=res_data['pid'], agentUuid=res_data['agentUuid']) def is_agent_listening(self, host, port): """ Check if the Instana Agent is listening on and . """ + rv = False try: - rv = False url = "http://%s:%s/" % (host, port) response = self.client.get(url, timeout=0.8) server_header = response.headers["Server"] - if server_header == AGENT_HEADER: + if server_header == self.AGENT_HEADER: logger.debug("Instana host agent found on %s:%d", host, port) rv = True else: @@ -152,10 +170,10 @@ def announce(self, discovery): """ With the passed in Discovery class, attempt to announce to the host agent. """ + response = None try: url = self.__discovery_url() # logger.debug("making announce request to %s", url) - response = None response = self.client.put(url, data=to_json(discovery), headers={"Content-Type": "application/json"}, @@ -185,8 +203,8 @@ def report_data(self, entity_data): """ Used to report entity data (metrics & snapshot) to the host agent. """ + response = None try: - response = None response = self.client.post(self.__data_url(), data=to_json(entity_data), headers={"Content-Type": "application/json"}, @@ -205,13 +223,13 @@ def report_traces(self, spans): """ Used to report entity data (metrics & snapshot) to the host agent. """ + response = None try: # Concurrency double check: Don't report if we don't have # any spans if len(spans) == 0: return 0 - response = None response = self.client.post(self.__traces_url(), data=to_json(spans), headers={"Content-Type": "application/json"}, @@ -226,13 +244,31 @@ def report_traces(self, spans): finally: return response - def task_response(self, message_id, data): + def handle_agent_tasks(self, task): + """ + When request(s) are received by the host agent, it is sent here + for handling & processing. + """ + logger.debug("Received agent request with messageId: %s", task["messageId"]) + if "action" in task: + if task["action"] == "python.source": + payload = get_py_source(task["args"]["file"]) + else: + message = "Unrecognized action: %s. An newer Instana package may be required " \ + "for this. Current version: %s" % (task["action"], package_version()) + payload = {"error": message} + else: + payload = {"error": "Instana Python: No action specified in request."} + + self.__task_response(task["messageId"], payload) + + def __task_response(self, message_id, data): """ When the host agent passes us a task and we do it, this function is used to respond with the results of the task. """ + response = None try: - response = None payload = json.dumps(data) logger.debug("Task response is %s: %s", self.__response_url(message_id), payload) @@ -252,31 +288,39 @@ def __discovery_url(self): """ URL for announcing to the host agent """ - port = self.sensor.options.agent_port - if port == 0: - port = AGENT_DEFAULT_PORT - - return "http://%s:%s/%s" % (self.host, port, AGENT_DISCOVERY_PATH) + return "http://%s:%s/%s" % (self.options.agent_host, self.options.agent_port, self.AGENT_DISCOVERY_PATH) def __data_url(self): """ URL for posting metrics to the host agent. Only valid when announced. """ - path = AGENT_DATA_PATH % self.from_.pid - return "http://%s:%s/%s" % (self.host, self.port, path) + path = self.AGENT_DATA_PATH % self.announce_data.pid + return "http://%s:%s/%s" % (self.options.agent_host, self.options.agent_port, path) def __traces_url(self): """ URL for posting traces to the host agent. Only valid when announced. """ - path = AGENT_TRACES_PATH % self.from_.pid - return "http://%s:%s/%s" % (self.host, self.port, path) + path = "com.instana.plugin.python/traces.%d" % self.announce_data.pid + return "http://%s:%s/%s" % (self.options.agent_host, self.options.agent_port, path) def __response_url(self, message_id): """ URL for responding to agent requests. """ - if self.from_.pid != 0: - path = AGENT_RESPONSE_PATH % (self.from_.pid, message_id) + path = "com.instana.plugin.python/response.%d?messageId=%s" % (int(self.announce_data.pid), message_id) + return "http://%s:%s/%s" % (self.options.agent_host, self.options.agent_port, path) + + +class AWSLambdaAgent(BaseAgent): + from_ = AWSLambdaFrom() + options = AWSLambdaOptions() + + def __init__(self): + super(AWSLambdaAgent, self).__init__() + + if self.options.endpoint_url is None or self.options.agent_key is None: + logger.warn("Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. " + "We will not be able monitor this function.") + - return "http://%s:%s/%s" % (self.host, self.port, path) diff --git a/instana/agent_const.py b/instana/agent_const.py deleted file mode 100644 index da025b5c..00000000 --- a/instana/agent_const.py +++ /dev/null @@ -1,7 +0,0 @@ -AGENT_DISCOVERY_PATH = "com.instana.plugin.python.discovery" -AGENT_TRACES_PATH = "com.instana.plugin.python/traces.%d" -AGENT_DATA_PATH = "com.instana.plugin.python.%d" -AGENT_RESPONSE_PATH = "com.instana.plugin.python/response.%d?messageId=%s" -AGENT_DEFAULT_HOST = "localhost" -AGENT_DEFAULT_PORT = 42699 -AGENT_HEADER = "Instana Agent" diff --git a/instana/fsm.py b/instana/fsm.py index cf368fcd..bedd2fcb 100644 --- a/instana/fsm.py +++ b/instana/fsm.py @@ -10,7 +10,6 @@ from fysom import Fysom import pkg_resources -from .agent_const import AGENT_DEFAULT_HOST, AGENT_DEFAULT_PORT from .log import logger from .util import get_default_gateway @@ -96,7 +95,8 @@ def reset(self): def lookup_agent_host(self, e): self.agent.should_threads_shutdown.clear() - host, port = self.__get_agent_host_port() + host = self.agent.options.agent_host + port = self.agent.options.agent_port if self.agent.is_agent_listening(host, port): self.agent.host = host @@ -159,7 +159,8 @@ def announce_sensor(self, e): if response and (response.status_code == 200) and (len(response.content) > 2): self.agent.set_from(response.content) self.fsm.pending() - logger.debug("Announced pid: %s (true pid: %s). Waiting for Agent Ready...", str(pid), str(self.agent.from_.pid)) + logger.debug("Announced pid: %s (true pid: %s). Waiting for Agent Ready...", + str(pid), str(self.agent.announce_data.pid)) return True else: logger.debug("Cannot announce sensor. Scheduling retry.") @@ -174,7 +175,7 @@ def schedule_retry(self, fun, e, name): def on_ready(self, _): logger.info("Instana host agent available. We're in business. Announced pid: %s (true pid: %s)", - str(os.getpid()), str(self.agent.from_.pid)) + str(os.getpid()), str(self.agent.announce_data.pid)) def __get_real_pid(self): """ @@ -200,31 +201,4 @@ def __get_real_pid(self): if pid is None: pid = os.getpid() - return pid - - def __get_agent_host_port(self): - """ - Iterates the the various ways the host and port of the Instana host - agent may be configured: default, env vars, sensor options... - """ - host = AGENT_DEFAULT_HOST - port = AGENT_DEFAULT_PORT - - if "INSTANA_AGENT_HOST" in os.environ: - host = os.environ["INSTANA_AGENT_HOST"] - if "INSTANA_AGENT_PORT" in os.environ: - port = int(os.environ["INSTANA_AGENT_PORT"]) - - elif "INSTANA_AGENT_IP" in os.environ: - # Deprecated: INSTANA_AGENT_IP environment variable - # To be removed in a future version - host = os.environ["INSTANA_AGENT_IP"] - if "INSTANA_AGENT_PORT" in os.environ: - port = int(os.environ["INSTANA_AGENT_PORT"]) - - elif self.agent.sensor.options.agent_host != "": - host = self.agent.sensor.options.agent_host - if self.agent.sensor.options.agent_port != 0: - port = self.agent.sensor.options.agent_port - - return host, port + return pid \ No newline at end of file diff --git a/instana/meter.py b/instana/meter.py index 1665632d..74c0e8e1 100644 --- a/instana/meter.py +++ b/instana/meter.py @@ -1,7 +1,6 @@ import copy import gc as gc_ import json -import os import platform import resource import sys @@ -12,7 +11,7 @@ from pkg_resources import DistributionNotFound, get_distribution from .log import logger -from .util import get_py_source, package_version, every, get_proc_cmdline +from .util import every, determine_service_name class Snapshot(object): @@ -212,111 +211,26 @@ def process(self): else: md = copy.deepcopy(cm).delta_data(self.last_metrics) - ed = EntityData(pid=self.agent.from_.pid, snapshot=ss, metrics=md) + ed = EntityData(pid=self.agent.announce_data.pid, snapshot=ss, metrics=md) response = self.agent.report_data(ed) if response: if response.status_code == 200 and len(response.content) > 2: # The host agent returned something indicating that is has a request for us that we # need to process. - self.handle_agent_tasks(json.loads(response.content)[0]) + self.agent.handle_agent_tasks(json.loads(response.content)[0]) self.last_metrics = cm.__dict__ - def handle_agent_tasks(self, task): - """ - When request(s) are received by the host agent, it is sent here - for handling & processing. - """ - logger.debug("Received agent request with messageId: %s", task["messageId"]) - if "action" in task: - if task["action"] == "python.source": - payload = get_py_source(task["args"]["file"]) - else: - message = "Unrecognized action: %s. An newer Instana package may be required " \ - "for this. Current version: %s" % (task["action"], package_version()) - payload = {"error": message} - else: - payload = {"error": "Instana Python: No action specified in request."} - - self.agent.task_response(task["messageId"], payload) - - def get_application_name(self): - """ This function makes a best effort to name this application process. """ - - # One environment variable to rule them all - if "INSTANA_SERVICE_NAME" in os.environ: - return os.environ["INSTANA_SERVICE_NAME"] - - try: - # Now best effort in naming this process. No nice package.json like in Node.js - # so we do best effort detection here. - app_name = "python" # the default name - - if not hasattr(sys, 'argv'): - proc_cmdline = get_proc_cmdline(as_string=False) - return os.path.basename(proc_cmdline[0]) - - basename = os.path.basename(sys.argv[0]) - if basename == "gunicorn": - if 'setproctitle' in sys.modules: - # With the setproctitle package, gunicorn renames their processes - # to pretty things - we use those by default - # gunicorn: master [djface.wsgi] - # gunicorn: worker [djface.wsgi] - app_name = get_proc_cmdline(as_string=True) - else: - app_name = basename - elif "FLASK_APP" in os.environ: - app_name = os.environ["FLASK_APP"] - elif "DJANGO_SETTINGS_MODULE" in os.environ: - app_name = os.environ["DJANGO_SETTINGS_MODULE"].split('.')[0] - elif basename == '': - if sys.stdout.isatty(): - app_name = "Interactive Console" - else: - # No arguments. Take executable as app_name - app_name = os.path.basename(sys.executable) - else: - # Last chance. app_name for "python main.py" would be "main.py" here. - app_name = basename - - # We should have a good app_name by this point. - # Last conditional, if uwsgi, then wrap the name - # with the uwsgi process type - if basename == "uwsgi": - # We have an app name by this point. Now if running under - # uwsgi, augment the app name - try: - import uwsgi - - if app_name == "uwsgi": - app_name = "" - else: - app_name = " [%s]" % app_name - - if os.getpid() == uwsgi.masterpid(): - uwsgi_type = "uWSGI master%s" - else: - uwsgi_type = "uWSGI worker%s" - - app_name = uwsgi_type % app_name - except ImportError: - pass - return app_name - except Exception as e: - logger.debug("get_application_name: ", exc_info=True) - return app_name - def collect_snapshot(self): """ Collects snapshot related information to this process and environment """ try: if self.cached_snapshot is not None: return self.cached_snapshot - app_name = self.get_application_name() + service_name = determine_service_name() - s = Snapshot(name=app_name, version=platform.version(), + s = Snapshot(name=service_name, version=platform.version(), f=platform.python_implementation(), a=platform.architecture()[0], djmw=self.djmw) diff --git a/instana/options.py b/instana/options.py index f0fdc535..40860b4c 100644 --- a/instana/options.py +++ b/instana/options.py @@ -1,33 +1,53 @@ import logging import os +AGENT_DEFAULT_HOST = "localhost" +AGENT_DEFAULT_PORT = 42699 -class Options(object): + +class StandardOptions(object): service = None service_name = None - agent_host = '' - agent_port = 0 + agent_host = None + agent_port = None log_level = logging.WARN + debug = None def __init__(self, **kwds): - """ Initialize Options - Respect any environment variables that may be set. - """ if "INSTANA_DEBUG" in os.environ: self.log_level = logging.DEBUG + self.debug = True + + self.service_name = os.environ.get("INSTANA_SERVICE_NAME", None) + self.agent_host = os.environ.get("INSTANA_AGENT_HOST", AGENT_DEFAULT_HOST) + self.agent_port = os.environ.get("INSTANA_AGENT_PORT", AGENT_DEFAULT_PORT) + + if type(self.agent_port) is str: + self.agent_port = int(self.agent_port) + + self.debug = os.environ.get("INSTANA_DEBUG", False) + + self.__dict__.update(kwds) - if "INSTANA_SERVICE_NAME" in os.environ: - self.service_name = os.environ["INSTANA_SERVICE_NAME"] - if "INSTANA_AGENT_IP" in os.environ: - # Deprecated: INSTANA_AGENT_IP environment variable - # To be removed in a future version - self.agent_host = os.environ["INSTANA_AGENT_IP"] +class AWSLambdaOptions: + endpoint_url = None + agent_key = None + extra_http_headers = None + timeout = None + log_level = logging.WARN + debug = None + + def __init__(self, **kwds): + if "INSTANA_DEBUG" in os.environ: + self.log_level = logging.DEBUG + self.debug = True - if "INSTANA_AGENT_HOST" in os.environ: - self.agent_host = os.environ["INSTANA_AGENT_HOST"] + self.endpoint_url = os.environ.get("INSTANA_ENDPOINT_URL", None); + self.agent_key = os.environ.get("INSTANA_AGENT_KEY", None); - if "INSTANA_AGENT_PORT" in os.environ: - self.agent_port = os.environ["INSTANA_AGENT_PORT"] + self.extra_http_headers = os.environ.get("INSTANA_EXTRA_HTTP_HEADERS", None) + self.timeout = os.environ.get("INSTANA_TIMEOUT", 30) + self.log_level = os.environ.get("INSTANA_LOG_LEVEL", None) self.__dict__.update(kwds) diff --git a/instana/recorder.py b/instana/recorder.py index eb8c8d70..7f7efcfb 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -258,8 +258,8 @@ def build_registered_span(self, span): if "parameters" in l.key_values: data.log["parameters"] = l.key_values.pop("parameters", None) - entity_from = {'e': instana.singletons.agent.from_.pid, - 'h': instana.singletons.agent.from_.agentUuid} + entity_from = {'e': instana.singletons.agent.announce_data.pid, + 'h': instana.singletons.agent.announce_data.agentUuid} json_span = JsonSpan(n=span.operation_name, k=kind, @@ -305,8 +305,8 @@ def build_sdk_span(self, span): sdk_data.Return = span.tags["return"] data = Data(service=instana.singletons.agent.sensor.options.service_name, sdk=sdk_data) - entity_from = {'e': instana.singletons.agent.from_.pid, - 'h': instana.singletons.agent.from_.agentUuid} + entity_from = {'e': instana.singletons.agent.announce_data.pid, + 'h': instana.singletons.agent.announce_data.agentUuid} json_span = JsonSpan(t=span.context.trace_id, p=span.parent_id, diff --git a/instana/sensor.py b/instana/sensor.py index 25db6b18..7453e0df 100644 --- a/instana/sensor.py +++ b/instana/sensor.py @@ -1,25 +1,16 @@ from __future__ import absolute_import from .meter import Meter -from .options import Options class Sensor(object): - options = None agent = None meter = None - def __init__(self, agent, options=None): - self.set_options(options) + def __init__(self, agent): self.agent = agent self.meter = Meter(agent) - def set_options(self, options): - if options is None: - self.options = Options() - else: - self.options = options - def start(self): # Nothing to do for the Sensor; Pass onto Meter self.meter.start() diff --git a/instana/singletons.py b/instana/singletons.py index f933bff2..38f819d8 100644 --- a/instana/singletons.py +++ b/instana/singletons.py @@ -1,12 +1,12 @@ import sys import opentracing -from .agent import Agent +from .agent import StandardAgent, AWSLambdaAgent from .tracer import InstanaTracer, InstanaRecorder # The Instana Agent which carries along with it a Sensor that collects metrics. -agent = Agent() +agent = StandardAgent() span_recorder = InstanaRecorder() diff --git a/instana/tracer.py b/instana/tracer.py index fc334667..1254d899 100644 --- a/instana/tracer.py +++ b/instana/tracer.py @@ -12,14 +12,13 @@ from .http_propagator import HTTPPropagator from .text_propagator import TextPropagator from .span_context import InstanaSpanContext -from .options import Options from .recorder import InstanaRecorder, InstanaSampler from .span import InstanaSpan from .util import generate_id class InstanaTracer(BasicTracer): - def __init__(self, options=Options(), scope_manager=None, recorder=None): + def __init__(self, scope_manager=None, recorder=None): if recorder is None: recorder = InstanaRecorder() diff --git a/instana/util.py b/instana/util.py index 2d73f924..7a18c626 100644 --- a/instana/util.py +++ b/instana/util.py @@ -305,5 +305,73 @@ def every(delay, task, name): next_time += (time.time() - next_time) // delay * delay + delay +def determine_service_name(): + """ This function makes a best effort to name this application process. """ + + # One environment variable to rule them all + if "INSTANA_SERVICE_NAME" in os.environ: + return os.environ["INSTANA_SERVICE_NAME"] + + try: + # Now best effort in naming this process. No nice package.json like in Node.js + # so we do best effort detection here. + app_name = "python" # the default name + + if not hasattr(sys, 'argv'): + proc_cmdline = get_proc_cmdline(as_string=False) + return os.path.basename(proc_cmdline[0]) + + basename = os.path.basename(sys.argv[0]) + if basename == "gunicorn": + if 'setproctitle' in sys.modules: + # With the setproctitle package, gunicorn renames their processes + # to pretty things - we use those by default + # gunicorn: master [djface.wsgi] + # gunicorn: worker [djface.wsgi] + app_name = get_proc_cmdline(as_string=True) + else: + app_name = basename + elif "FLASK_APP" in os.environ: + app_name = os.environ["FLASK_APP"] + elif "DJANGO_SETTINGS_MODULE" in os.environ: + app_name = os.environ["DJANGO_SETTINGS_MODULE"].split('.')[0] + elif basename == '': + if sys.stdout.isatty(): + app_name = "Interactive Console" + else: + # No arguments. Take executable as app_name + app_name = os.path.basename(sys.executable) + else: + # Last chance. app_name for "python main.py" would be "main.py" here. + app_name = basename + + # We should have a good app_name by this point. + # Last conditional, if uwsgi, then wrap the name + # with the uwsgi process type + if basename == "uwsgi": + # We have an app name by this point. Now if running under + # uwsgi, augment the app name + try: + import uwsgi + + if app_name == "uwsgi": + app_name = "" + else: + app_name = " [%s]" % app_name + + if os.getpid() == uwsgi.masterpid(): + uwsgi_type = "uWSGI master%s" + else: + uwsgi_type = "uWSGI worker%s" + + app_name = uwsgi_type % app_name + except ImportError: + pass + return app_name + except Exception as e: + logger.debug("get_application_name: ", exc_info=True) + return app_name + + From d09004962974165f048e9a35771523aca921a316 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 25 Feb 2020 23:15:42 +0100 Subject: [PATCH 02/29] AWS Lambda Agent, Layer, Span & handler method --- bin/build_lambda_layer.py | 62 ++++++ instana/__init__.py | 17 ++ instana/agent.py | 70 +++++- instana/collector.py | 88 ++++++++ instana/configurator.py | 20 +- instana/hooks/hook_uwsgi.py | 4 +- instana/instrumentation/aws_lambda.py | 39 ++++ instana/json_span.py | 293 ++++++++++++++++---------- instana/meter.py | 2 +- instana/options.py | 17 +- instana/recorder.py | 232 ++++++-------------- instana/singletons.py | 15 +- instana/span.py | 23 ++ instana/util.py | 12 ++ 14 files changed, 580 insertions(+), 314 deletions(-) create mode 100755 bin/build_lambda_layer.py create mode 100644 instana/collector.py create mode 100644 instana/instrumentation/aws_lambda.py diff --git a/bin/build_lambda_layer.py b/bin/build_lambda_layer.py new file mode 100755 index 00000000..174341d2 --- /dev/null +++ b/bin/build_lambda_layer.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +import os +import glob +import shutil +import time +import distutils.spawn +from subprocess import call + +# Check requirements first +for cmd in ["pip", "zip"]: + if distutils.spawn.find_executable(cmd) is None: + print("Can't find required tool: %s" % cmd) + exit(1) + +# Determine where this script is running from +this_file_path = os.path.dirname(os.path.realpath(__file__)) + +# Change directory to the base of the Python sensor repository +os.chdir(this_file_path + "/../") + +cwd = os.getcwd() +print("===> Working directory is: %s" % cwd) + +# For development, respect or set PYTHONPATH to this repository +local_env = os.environ.copy() +if "PYTHONPATH" not in os.environ: + local_env["PYTHONPATH"] = os.getcwd() + +build_directory = os.getcwd() + '/build/lambda/python' + +if os.path.isdir(build_directory): + print("===> Cleaning build pre-existing directory: %s" % build_directory) + shutil.rmtree(build_directory) + +print("===> Creating new build directory: %s" % build_directory) +os.makedirs(build_directory, exist_ok=True) + +print("===> Installing Instana and dependencies into build directory") +call(["pip", "install", "-q", "-U", "-t", os.getcwd() + '/build/lambda/python', "instana"], env=local_env) + +print("===> Manually copying in local dev code") +shutil.rmtree(build_directory + "/instana") +shutil.copytree(os.getcwd() + '/instana', build_directory + "/instana") + +print("===> Creating Lambda ZIP file") +timestamp = time.strftime("%Y-%m-%d_%H:%M:%S") +zip_filename = "instana-py-layer-%s.zip" % timestamp + +os.chdir(os.getcwd() + "/build/lambda/") +call(["zip", "-q", "-r", zip_filename, "./python", "-x", "*.pyc", "./python/pip*", "./python/setuptools*", "./python/wheel*"]) + +fq_zip_filename = os.getcwd() + '/%s' % zip_filename +aws_zip_filename = "fileb://%s" % fq_zip_filename + +print("===> Uploading zipfile to AWS as a new lambda layer version") +call(["aws", "lambda", "publish-layer-version", "--layer-name", "instana-py-test", "--zip-file", aws_zip_filename, + "--compatible-runtimes", "python2.7", "python3.6", "python3.7", "python3.8"]) + +print("Zipfile should be at: ", fq_zip_filename) + + diff --git a/instana/__init__.py b/instana/__init__.py index 2cb79f56..18230cff 100644 --- a/instana/__init__.py +++ b/instana/__init__.py @@ -45,6 +45,21 @@ def load(_): if "INSTANA_DEBUG" in os.environ: print("Instana: activated via AUTOWRAPT_BOOTSTRAP") + if "INSTANA_ENDPOINT_URL" in os.environ: + print("load: detected lambda environment") + + +def lambda_handler(event, context): + print("Instana Python lives!") + print("Attempting import of default handler") + try: + from lambda_function import lambda_handler as original_lambda_handler + except ImportError: + print("couldn't import default lambda handler") + else: + print("found default lambda handler!") + original_lambda_handler(event, context) + def boot_agent(): """Initialize the Instana agent and conditionally load auto-instrumentation.""" @@ -56,6 +71,8 @@ def boot_agent(): # Instrumentation if "INSTANA_DISABLE_AUTO_INSTR" not in os.environ: # Import & initialize instrumentation + from .instrumentation import aws_lambda + if sys.version_info >= (3, 5, 3): from .instrumentation import asyncio from .instrumentation.aiohttp import client diff --git a/instana/agent.py b/instana/agent.py index 0a7d9ff2..d29b2e9f 100644 --- a/instana/agent.py +++ b/instana/agent.py @@ -2,6 +2,7 @@ import json import os +import time from datetime import datetime import threading import requests @@ -13,6 +14,7 @@ from .sensor import Sensor from .util import to_json, get_py_source, package_version from .options import StandardOptions, AWSLambdaOptions +from instana.collector import Collector class AnnounceData(object): @@ -144,6 +146,9 @@ def set_from(self, json_string): self.announce_data = AnnounceData(pid=res_data['pid'], agentUuid=res_data['agentUuid']) + def get_from_structure(self): + return {'e': self.announce_data.pid, 'h': self.announce_data.agentUuid} + def is_agent_listening(self, host, port): """ Check if the Instana Agent is listening on and . @@ -199,7 +204,7 @@ def is_agent_ready(self): except (requests.ConnectTimeout, requests.ConnectionError): logger.debug("is_agent_ready: Instana host agent connection error") - def report_data(self, entity_data): + def report_data_payload(self, entity_data): """ Used to report entity data (metrics & snapshot) to the host agent. """ @@ -313,14 +318,71 @@ def __response_url(self, message_id): class AWSLambdaAgent(BaseAgent): - from_ = AWSLambdaFrom() - options = AWSLambdaOptions() + from_ = None + options = None + meter = None + collector = None + report_headers = dict() + + _can_send = False + + AGENT_DATA_PATH = "com.instana.plugin.python.%d" + AGENT_HEADER = "Instana Agent" def __init__(self): super(AWSLambdaAgent, self).__init__() - if self.options.endpoint_url is None or self.options.agent_key is None: + self.from_ = AWSLambdaFrom() + self.options = AWSLambdaOptions() + + if self._validate_options(): + self._can_send = True + + # Prepare request headers + self.report_headers["Content-Type"] = "application/json" + self.report_headers["X-Instana-Host"] = "ARN" + self.report_headers["X-Instana-Key"] = self.options.agent_key + self.report_headers["X-Instana-Time"] = int(round(time.time() * 1000)) + + self.collector = Collector(self) + self.collector.start() + else: logger.warn("Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. " "We will not be able monitor this function.") + def can_send(self): + return self._can_send + + def get_from_structure(self): + return {'e': self.announce_data.pid, 'h': self.announce_data.agentUuid} + def report_data_payload(self, payload): + """ + Used to report metrics and span data to the endpoint URL in self.options.endpoint_url + """ + response = None + try: + response = self.client.post(self.__data_bundle_url(), + data=to_json(payload), + headers=self.report_headers, + timeout=self.options.timeout) + + logger.debug("report_data_payload: response.status_code is %s" % response.status_code) + except (requests.ConnectTimeout, requests.ConnectionError): + logger.debug("report_traces: Instana host agent connection error") + # FIXME: Larger exception capture space + finally: + return response + + def _validate_options(self): + """ + Validate that the options used by this Agent are valid. e.g. can we report data? + """ + # TODO: Endpoint and Agent key validation + return True + + def __data_bundle_url(self): + """ + URL for posting metrics to the host agent. Only valid when announced. + """ + return "%s/bundle" % self.options.endpoint_url \ No newline at end of file diff --git a/instana/collector.py b/instana/collector.py new file mode 100644 index 00000000..053906a7 --- /dev/null +++ b/instana/collector.py @@ -0,0 +1,88 @@ +import sys +import threading + +from .log import logger +from .util import every, to_json, stan_dictionary + + +if sys.version_info.major == 2: + import Queue as queue +else: + import queue + + +class Collector(object): + def __init__(self, agent): + logger.debug("Loading collector") + self.agent = agent + self.span_queue = queue.Queue() + self.shutdown = threading.Event() + self.shutdown.clear() + self.context = None + self.snapshot_data = None + self.snapshot_data_sent = False + + def start(self): + if self.agent.can_send(): + t = threading.Thread(target=self.prepare_and_report_data, args=()) + t.setDaemon(True) + t.start() + else: + logger.warn("Collector started but the agent tells us we can't send anything out.") + + def set_context(self, context): + self.context = context + + def prepare_and_report_data(self): + logger.debug("prepare_and_report_data") + + def work(): + logger.debug("prepare_and_report_data loop") + if self.shutdown.is_set(): + logger.debug("Thread shutdown signal from agent is active: Shutting down span reporting thread") + return False + + payload = stan_dictionary() + + if self.snapshot_data and self.snapshot_data_sent is False: + payload["metrics"] = self.collect_snapshot() + + if not self.span_queue.empty(): + payload["spans"] = self.__queued_spans() + + if len(payload) > 0: + logger.debug(to_json(payload)) + self.agent.report_data_payload(payload) + + every(5, work, "Instana Collector: prepare_and_report_data") + + def collect_snapshot(self): + ss = stan_dictionary() + ss["arn"] = self.context.invoked_function_arn + ss["version"] = self.context.function_version + # ss["revision"] + # ss["code_sha_256"] + # ss["description"] + ss["runtime"] = "python" + # ss["handler"] + # ss["timeout"] + ss["memory_size"] = self.context.memory_limit_in_mb + # ss["last_modified"] + # ss["aws_grouping_zone"] + # ss["tags"] + # ss["event_source_mappings"] + # ss["legacy_endpoint_used"] + return ss + + def __queued_spans(self): + """ Get all of the spans in the queue """ + span = None + spans = [] + while True: + try: + span = self.span_queue.get(False) + except queue.Empty: + break + else: + spans.append(span) + return spans diff --git a/instana/configurator.py b/instana/configurator.py index ba477ba6..71daf321 100644 --- a/instana/configurator.py +++ b/instana/configurator.py @@ -1,19 +1,9 @@ +""" +This file contains a config object that will hold configuration options for the package. +Defaults are set and can be overridden after package load. +""" from __future__ import absolute_import -from collections import defaultdict - -# This file contains a config object that will hold configuration options for the package. -# Defaults are set and can be overridden after package load. - - -# Simple implementation of a nested dictionary. -# -# Same as: -# stan_dictionary = lambda: defaultdict(stan_dictionary) -# but we use the function form because of PEP 8 -# -def stan_dictionary(): - return defaultdict(stan_dictionary) - +from .util import stan_dictionary # La Protagonista config = stan_dictionary() diff --git a/instana/hooks/hook_uwsgi.py b/instana/hooks/hook_uwsgi.py index 5af1a27a..e5d82358 100644 --- a/instana/hooks/hook_uwsgi.py +++ b/instana/hooks/hook_uwsgi.py @@ -33,6 +33,6 @@ def uwsgi_handle_fork(): logger.debug("Applied uWSGI hooks") else: logger.debug("uWSGI --master=%s --lazy-apps=%s: postfork hooks not applied", opt_master, opt_lazy_apps) -except ImportError as e: - logger.debug('uwsgi hooks: decorators not available: %s', e) +except ImportError: + logger.debug('uwsgi hooks: decorators not available: likely not running under uWSGI') pass diff --git a/instana/instrumentation/aws_lambda.py b/instana/instrumentation/aws_lambda.py new file mode 100644 index 00000000..b805450c --- /dev/null +++ b/instana/instrumentation/aws_lambda.py @@ -0,0 +1,39 @@ +import os +import sys +import wrapt + +from ..log import logger +from ..singletons import tracer + + +if os.environ.get("INSTANA_ENDPOINT_URL", False): + handler = os.environ.get("_HANDLER", False) + if handler: + parts = handler.split(".") + handler_function = parts.pop() + handler_module = ".".join(parts) + + logger.debug("AWS Lambda: Instrumenting handler %s.%s" % (handler_module, handler_function)) + + sys.path.insert(0, '/var/runtime') + sys.path.insert(0, '/var/task') + + try: + import importlib + module = importlib.import_module(handler_module, package=None) + except ImportError: + logger.warn("Couldn't do the manual import") + + @wrapt.patch_function_wrapper(handler_module, handler_function) + def lambda_handler_with_instana(wrapped, instance, args, kwargs): + logger.debug("we got the handler!") + + with tracer.start_active_span("aws.lambda.entry") as scope: + try: + result = wrapped(*args, **kwargs) + except Exception as e: + if scope.span: + scope.span.log_exception(e) + raise + else: + return result diff --git a/instana/json_span.py b/instana/json_span.py index 4a569663..cfd8509b 100644 --- a/instana/json_span.py +++ b/instana/json_span.py @@ -1,3 +1,6 @@ +import os +import opentracing.ext.tags as ot_tags + class BaseSpan(object): def __str__(self): @@ -6,41 +9,57 @@ def __str__(self): def __repr__(self): return self.__dict__.__str__() - def __init__(self, **kwds): - self.__dict__.update(kwds) + def __init__(self, **kwargs): + self.__dict__.update(kwargs) class JsonSpan(BaseSpan): - k = None - t = 0 - p = None - s = 0 - ts = 0 - ta = "py" - d = 0 - n = None - f = None - ec = None - error = None - data = None - stack = None - - -class CassandraData(BaseSpan): - cluster = None - query = None - keyspace = None - fetchSize = None - achievedConsistency = None - triedHosts = None - fullyFetched = None - error = None + def __init__(self, span, kind, data, agent, **kwargs): + self.k = kind + self.t = span.context.trace_id + self.p = span.parent_id + self.s = span.context.span_id + self.ts = int(round(span.start_time * 1000)) + self.ta = "py" + self.d = int(round(span.duration * 1000)) + self.f = agent.get_from_structure() + self.ec = span.tags.pop("ec", None) + self.error = span.tags.pop("error", False) + + if data.sdk: + self.n = "sdk" + else: + self.n = span.operation_name + + if span.stack: + self.stack = span.stack + + if len(span.context.baggage) > 0: + data.baggage = span.context.baggage + + # Send along any left over custom tags + if len(span.tags) > 0: + if data.custom is None: + data.custom = CustomData() + data.custom.tags = span.tags + + logs = span.collect_logs() + if len(logs) > 0: + if data.custom is None: + data.custom = CustomData() + data.custom.logs = logs + + self.data = data + super(JsonSpan, self).__init__(**kwargs) class CustomData(BaseSpan): tags = None logs = None + def __init__(self, **kwargs): + super(CustomData, self).__init__(**kwargs) + class Data(BaseSpan): baggage = None @@ -48,6 +67,7 @@ class Data(BaseSpan): couchbase = None custom = None http = None + _lambda = None log = None pg = None rabbitmq = None @@ -58,119 +78,176 @@ class Data(BaseSpan): service = None sqlalchemy = None soap = None - log = None -class CouchbaseData(BaseSpan): - hostname = None - bucket = None - type = None - error = None - error_code = None - sql = None +""" General Spans """ class HttpData(BaseSpan): - host = None - url = None - params = None - status = 0 - method = None - path = None - path_tpl = None - error = None + def __init__(self, span, **kwargs): + self.host = span.tags.pop("http.host", None) + self.url = span.tags.pop(ot_tags.HTTP_URL, None) + self.path = span.tags.pop("http.path", None) + self.params = span.tags.pop('http.params', None) + self.method = span.tags.pop(ot_tags.HTTP_METHOD, None) + self.status = span.tags.pop(ot_tags.HTTP_STATUS_CODE, None) + self.path_tpl = span.tags.pop("http.path_tpl", None) + self.error = span.tags.pop('http.error', None) + super(HttpData, self).__init__(**kwargs) -class LogData(object): +class SDKData(BaseSpan): + name = None + + # Since 'type' and 'return' are a Python builtin and a reserved keyword respectively, these keys (all keys) are + # lower-case'd in json encoding. See Agent.to_json + Type = None + Return = None + + arguments = None + custom = None + + +""" Entry Spans """ + + +class AWSLambdaData(BaseSpan): + def __init__(self, span, **kwargs): + self.arn = "" + self.alias = None + self.runtime = "py" + self.functionName = os.environ.get("AWS_LAMBDA_FUNCTION_NAME", "Unknown") + self.functionVersion = os.environ.get("AWS_LAMBDA_FUNCTION_VERSION", "0") + self.error = "" + super(AWSLambdaData, self).__init__(**kwargs) + + +""" Local Spans """ + + +class RenderData(BaseSpan): + type = None + name = None message = None parameters = None - def __init__(self, **kwds): - self.__dict__.update(kwds) + def __init__(self, span, **kwargs): + self.name = span.tags.pop('name', None) + self.type = span.tags.pop('type', None) + super(RenderData, self).__init__(**kwargs) -class MySQLData(BaseSpan): - db = None - host = None - user = None - stmt = None - error = None +""" Exit Spans """ -class MongoDBData(BaseSpan): - service = None - namespace = None - command = None - filter = None - json = None - error = None +class CassandraData(BaseSpan): + def __init__(self, span, **kwargs): + self.cluster = span.tags.pop('cassandra.cluster', None) + self.query = span.tags.pop('cassandra.query', None) + self.keyspace = span.tags.pop('cassandra.keyspace', None) + self.fetchSize = span.tags.pop('cassandra.fetchSize', None) + self.achievedConsistency = span.tags.pop('cassandra.achievedConsistency', None) + self.triedHosts = span.tags.pop('cassandra.triedHosts', None) + self.fullyFetched = span.tags.pop('cassandra.fullyFetched', None) + self.error = span.tags.pop('cassandra.error', None) + super(CassandraData, self).__init__(**kwargs) -class PostgresData(BaseSpan): - db = None - host = None - port = None - user = None - stmt = None - error = None +class CouchbaseData(BaseSpan): + def __init__(self, span, **kwargs): + self.hostname = span.tags.pop('couchbase.hostname', None) + self.bucket = span.tags.pop('couchbase.bucket', None) + self.type = span.tags.pop('couchbase.type', None) + self.error = span.tags.pop('couchbase.error', None) + self.error_type = span.tags.pop('couchbase.error_type', None) + self.sql = span.tags.pop('couchbase.sql', None) + super(CouchbaseData, self).__init__(**kwargs) -class RabbitmqData(BaseSpan): - exchange = None - queue = None - sort = None - address = None - key = None +class LogData(object): + def __init__(self, span, **kwargs): + self.message = span.tags.pop('message', None), + self.parameters = span.tags.pop('parameters', None) + super(LogData, self).__init__(**kwargs) -class RedisData(BaseSpan): - connection = None - driver = None - command = None - error = None - subCommands = None +class MongoDBData(BaseSpan): + def __init__(self, span, **kwargs): + service = "%s:%s" % (span.tags.pop('host', None), span.tags.pop('port', None)) + namespace = "%s.%s" % (span.tags.pop('db', "?"), span.tags.pop('collection', "?")) + self.service = service + self.namespace = namespace + self.command = span.tags.pop('command', None) + self.filter = span.tags.pop('filter', None) + self.json = span.tags.pop('json', None) + self.error = span.tags.pop('command', None) + super(MongoDBData, self).__init__(**kwargs) -class RPCData(BaseSpan): - flavor = None - host = None - port = None - call = None - call_type = None - params = None - baggage = None - error = None +class MySQLData(BaseSpan): + def __init__(self, span, **kwargs): + self.host = span.tags.pop('host', None) + self.db = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) + self.user = span.tags.pop(ot_tags.DATABASE_USER, None) + self.stmt = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) + super(MySQLData, self).__init__(**kwargs) -class RenderData(object): - type = None - name = None - message = None - parameters = None - def __init__(self, **kwds): - self.__dict__.update(kwds) +class PostgresData(BaseSpan): + def __init__(self, span, **kwargs): + self.host = span.tags.pop('host', None) + self.db = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) + self.user = span.tags.pop(ot_tags.DATABASE_USER, None) + self.stmt = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) + self.error = span.tags.pop('pg.error', None) + super(PostgresData, self).__init__(**kwargs) -class SQLAlchemyData(BaseSpan): - sql = None - url = None - eng = None - error = None +class RabbitmqData(BaseSpan): + def __init__(self, span, **kwargs): + self.exchange = span.tags.pop('exchange', None), + self.queue = span.tags.pop('queue', None), + self.sort = span.tags.pop('sort', None), + self.address = span.tags.pop('address', None), + self.key = span.tags.pop('key', None) + super(RabbitmqData, self).__init__(**kwargs) -class SoapData(BaseSpan): - action = None +class RedisData(BaseSpan): + def __init__(self, span, **kwargs): + self.connection = span.tags.pop('connection', None) + self.driver = span.tags.pop('driver', None) + self.command = span.tags.pop('command', None) + self.error = span.tags.pop('redis.error', None) + self.subCommands = span.tags.pop('subCommands', None) + super(RedisData, self).__init__(**kwargs) -class SDKData(BaseSpan): - name = None +class RPCData(BaseSpan): + def __init__(self, span, **kwargs): + self.flavor = span.tags.pop('rpc.flavor', None) + self.host = span.tags.pop('rpc.host', None) + self.port = span.tags.pop('rpc.port', None) + self.call = span.tags.pop('rpc.call', None) + self.call_type = span.tags.pop('rpc.call_type', None) + self.params = span.tags.pop('rpc.params', None) + self.baggage = span.tags.pop('rpc.baggage', None) + self.error = span.tags.pop('rpc.error', None) + super(RPCData, self).__init__(**kwargs) - # Since 'type' and 'return' are a Python builtin and a reserved keyword respectively, these keys (all keys) are - # lower-case'd in json encoding. See Agent.to_json - Type = None - Return = None - arguments = None - custom = None +class SQLAlchemyData(BaseSpan): + def __init__(self, span, **kwargs): + self.sql = span.tags.pop('sqlalchemy.sql', None) + self.eng = span.tags.pop('sqlalchemy.eng', None) + self.url = span.tags.pop('sqlalchemy.url', None) + self.err = span.tags.pop('sqlalchemy.err', None) + super(SQLAlchemyData, self).__init__(**kwargs) + + +class SoapData(BaseSpan): + def __init__(self, span, **kwargs): + self.action = span.tags.pop('soap.action', None) + super(SoapData, self).__init__(**kwargs) diff --git a/instana/meter.py b/instana/meter.py index 74c0e8e1..ab4da7e3 100644 --- a/instana/meter.py +++ b/instana/meter.py @@ -212,7 +212,7 @@ def process(self): md = copy.deepcopy(cm).delta_data(self.last_metrics) ed = EntityData(pid=self.agent.announce_data.pid, snapshot=ss, metrics=md) - response = self.agent.report_data(ed) + response = self.agent.report_data_payload(ed) if response: if response.status_code == 200 and len(response.content) > 2: diff --git a/instana/options.py b/instana/options.py index 40860b4c..98863d74 100644 --- a/instana/options.py +++ b/instana/options.py @@ -1,9 +1,6 @@ import logging import os -AGENT_DEFAULT_HOST = "localhost" -AGENT_DEFAULT_PORT = 42699 - class StandardOptions(object): service = None @@ -13,20 +10,22 @@ class StandardOptions(object): log_level = logging.WARN debug = None + AGENT_DEFAULT_HOST = "localhost" + AGENT_DEFAULT_PORT = 42699 + def __init__(self, **kwds): if "INSTANA_DEBUG" in os.environ: self.log_level = logging.DEBUG self.debug = True self.service_name = os.environ.get("INSTANA_SERVICE_NAME", None) - self.agent_host = os.environ.get("INSTANA_AGENT_HOST", AGENT_DEFAULT_HOST) - self.agent_port = os.environ.get("INSTANA_AGENT_PORT", AGENT_DEFAULT_PORT) + self.agent_host = os.environ.get("INSTANA_AGENT_HOST", self.AGENT_DEFAULT_HOST) + self.agent_port = os.environ.get("INSTANA_AGENT_PORT", self.AGENT_DEFAULT_PORT) if type(self.agent_port) is str: self.agent_port = int(self.agent_port) self.debug = os.environ.get("INSTANA_DEBUG", False) - self.__dict__.update(kwds) @@ -43,11 +42,11 @@ def __init__(self, **kwds): self.log_level = logging.DEBUG self.debug = True - self.endpoint_url = os.environ.get("INSTANA_ENDPOINT_URL", None); - self.agent_key = os.environ.get("INSTANA_AGENT_KEY", None); + self.endpoint_url = os.environ.get("INSTANA_ENDPOINT_URL", None) + self.agent_key = os.environ.get("INSTANA_AGENT_KEY", None) self.extra_http_headers = os.environ.get("INSTANA_EXTRA_HTTP_HEADERS", None) - self.timeout = os.environ.get("INSTANA_TIMEOUT", 30) + self.timeout = os.environ.get("INSTANA_TIMEOUT", 0.5) self.log_level = os.environ.get("INSTANA_LOG_LEVEL", None) self.__dict__.update(kwds) diff --git a/instana/recorder.py b/instana/recorder.py index 7f7efcfb..051be3de 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -4,18 +4,16 @@ import sys import threading -import opentracing.ext.tags as ext -from basictracer import Sampler, SpanRecorder - +from .log import logger +from .util import every import instana.singletons -from .json_span import (CassandraData, CouchbaseData, CustomData, Data, HttpData, JsonSpan, LogData, +from basictracer import Sampler, SpanRecorder + +from .json_span import (AWSLambdaData, CassandraData, CouchbaseData, CustomData, Data, HttpData, JsonSpan, LogData, MongoDBData, MySQLData, PostgresData, RabbitmqData, RedisData, RenderData, RPCData, SDKData, SoapData, SQLAlchemyData) -from .log import logger -from .util import every - if sys.version_info.major == 2: import Queue as queue else: @@ -24,9 +22,9 @@ class InstanaRecorder(SpanRecorder): THREAD_NAME = "Instana Span Reporting" - registered_spans = ("aiohttp-client", "aiohttp-server", "cassandra", "couchbase", "django", "log", - "memcache", "mongo", "mysql", "postgres", "rabbitmq", "redis", "render", "rpc-client", - "rpc-server", "sqlalchemy", "soap", "tornado-client", "tornado-server", + registered_spans = ("aiohttp-client", "aiohttp-server", "aws.lambda.entry", "cassandra", "couchbase", + "django", "log","memcache", "mongo", "mysql", "postgres", "rabbitmq", "redis", "render", + "rpc-client", "rpc-server", "sqlalchemy", "soap", "tornado-client", "tornado-server", "urllib3", "wsgi") http_spans = ("aiohttp-client", "aiohttp-server", "django", "http", "soap", "tornado-client", @@ -36,9 +34,9 @@ class InstanaRecorder(SpanRecorder): "rabbitmq", "redis", "rpc-client", "sqlalchemy", "soap", "tornado-client", "urllib3", "pymongo") - entry_spans = ("aiohttp-server", "django", "wsgi", "rabbitmq", "rpc-server", "tornado-server") + entry_spans = ("aiohttp-server", "aws.lambda.entry", "django", "wsgi", "rabbitmq", "rpc-server", "tornado-server") - local_spans = ("log", "render") + local_spans = ("render") entry_kind = ["entry", "server", "consumer"] exit_kind = ["exit", "client", "producer"] @@ -128,125 +126,84 @@ def record_span(self, span): else: json_span = self.build_sdk_span(span) + logger.debug("Recorded span: %s", json_span) + self.queue.put(json_span) def build_registered_span(self, span): """ Takes a BasicSpan and converts it into a registered JsonSpan """ data = Data() - if len(span.context.baggage) > 0: - data.baggage = span.context.baggage - kind = 1 # entry - if span.operation_name in self.exit_spans: + kind = 1 + if span.operation_name in self.entry_spans: + # entry + self._populate_entry_span_data(span, data) + elif span.operation_name in self.exit_spans: kind = 2 # exit - if span.operation_name in self.local_spans: + self._populate_exit_span_data(span, data) + elif span.operation_name in self.local_spans: kind = 3 # intermediate span + self._populate_local_span_data(span, data) - logs = self.collect_logs(span) - if len(logs) > 0: - if data.custom is None: - data.custom = CustomData() - data.custom.logs = logs + if data.rabbitmq and data.rabbitmq.sort == 'consume': + kind = 1 # entry if span.operation_name in self.http_spans: - data.http = HttpData(host=span.tags.pop("http.host", None), - url=span.tags.pop(ext.HTTP_URL, None), - path=span.tags.pop("http.path", None), - params=span.tags.pop('http.params', None), - method=span.tags.pop(ext.HTTP_METHOD, None), - status=span.tags.pop(ext.HTTP_STATUS_CODE, None), - path_tpl=span.tags.pop("http.path_tpl", None), - error=span.tags.pop('http.error', None)) - + data.http = HttpData(span) + + return JsonSpan(span, kind, data, instana.singletons.agent) + + def _populate_entry_span_data(self, span, data): + if span.operation_name == "rpc-server": + data.rpc = RPCData(span) + elif span.operation_name == "aws.lambda.entry": + data.aws_lambda = AWSLambdaData(span) + else: + logger.debug("SpanRecorder: Unknown entry span: %s" % span.operation_name) + + def _populate_local_span_data(self, span, data): + if span.operation_name == "render": + data.render = RenderData(span) + data.log = LogData(span) + else: + logger.debug("SpanRecorder: Unknown local span: %s" % span.operation_name) + + def _populate_exit_span_data(self, span, data): if span.operation_name == "rabbitmq": - data.rabbitmq = RabbitmqData(exchange=span.tags.pop('exchange', None), - queue=span.tags.pop('queue', None), - sort=span.tags.pop('sort', None), - address=span.tags.pop('address', None), - key=span.tags.pop('key', None)) - if data.rabbitmq.sort == 'consume': - kind = 1 # entry + data.rabbitmq = RabbitmqData(span) elif span.operation_name == "cassandra": - data.cassandra = CassandraData(cluster=span.tags.pop('cassandra.cluster', None), - query=span.tags.pop('cassandra.query', None), - keyspace=span.tags.pop('cassandra.keyspace', None), - fetchSize=span.tags.pop('cassandra.fetchSize', None), - achievedConsistency=span.tags.pop('cassandra.achievedConsistency', None), - triedHosts=span.tags.pop('cassandra.triedHosts', None), - fullyFetched=span.tags.pop('cassandra.fullyFetched', None), - error=span.tags.pop('cassandra.error', None)) + data.cassandra = CassandraData(span) elif span.operation_name == "couchbase": - data.couchbase = CouchbaseData(hostname=span.tags.pop('couchbase.hostname', None), - bucket=span.tags.pop('couchbase.bucket', None), - type=span.tags.pop('couchbase.type', None), - error=span.tags.pop('couchbase.error', None), - error_type=span.tags.pop('couchbase.error_type', None), - sql=span.tags.pop('couchbase.sql', None)) + data.couchbase = CouchbaseData(span) elif span.operation_name == "redis": - data.redis = RedisData(connection=span.tags.pop('connection', None), - driver=span.tags.pop('driver', None), - command=span.tags.pop('command', None), - error=span.tags.pop('redis.error', None), - subCommands=span.tags.pop('subCommands', None)) - - elif span.operation_name == "rpc-client" or span.operation_name == "rpc-server": - data.rpc = RPCData(flavor=span.tags.pop('rpc.flavor', None), - host=span.tags.pop('rpc.host', None), - port=span.tags.pop('rpc.port', None), - call=span.tags.pop('rpc.call', None), - call_type=span.tags.pop('rpc.call_type', None), - params=span.tags.pop('rpc.params', None), - baggage=span.tags.pop('rpc.baggage', None), - error=span.tags.pop('rpc.error', None)) - - elif span.operation_name == "render": - data.render = RenderData(name=span.tags.pop('name', None), - type=span.tags.pop('type', None)) - data.log = LogData(message=span.tags.pop('message', None), - parameters=span.tags.pop('parameters', None)) + data.redis = RedisData(span) + + elif span.operation_name == "rpc-client": + data.rpc = RPCData(span) elif span.operation_name == "sqlalchemy": - data.sqlalchemy = SQLAlchemyData(sql=span.tags.pop('sqlalchemy.sql', None), - eng=span.tags.pop('sqlalchemy.eng', None), - url=span.tags.pop('sqlalchemy.url', None), - err=span.tags.pop('sqlalchemy.err', None)) + data.sqlalchemy = SQLAlchemyData(span) elif span.operation_name == "soap": - data.soap = SoapData(action=span.tags.pop('soap.action', None)) + data.soap = SoapData(span) elif span.operation_name == "mysql": - data.mysql = MySQLData(host=span.tags.pop('host', None), - port=span.tags.pop('port', None), - db=span.tags.pop(ext.DATABASE_INSTANCE, None), - user=span.tags.pop(ext.DATABASE_USER, None), - stmt=span.tags.pop(ext.DATABASE_STATEMENT, None)) + data.mysql = MySQLData(span) if (data.custom is not None) and (data.custom.logs is not None) and len(data.custom.logs): tskey = list(data.custom.logs.keys())[0] data.mysql.error = data.custom.logs[tskey]['message'] elif span.operation_name == "postgres": - data.pg = PostgresData(host=span.tags.pop('host', None), - port=span.tags.pop('port', None), - db=span.tags.pop(ext.DATABASE_INSTANCE, None), - user=span.tags.pop(ext.DATABASE_USER, None), - stmt=span.tags.pop(ext.DATABASE_STATEMENT, None), - error=span.tags.pop('pg.error', None)) + data.pg = PostgresData(span) if (data.custom is not None) and (data.custom.logs is not None) and len(data.custom.logs): tskey = list(data.custom.logs.keys())[0] data.pg.error = data.custom.logs[tskey]['message'] elif span.operation_name == "mongo": - service = "%s:%s" % (span.tags.pop('host', None), span.tags.pop('port', None)) - namespace = "%s.%s" % (span.tags.pop('db', "?"), span.tags.pop('collection', "?")) - data.mongo = MongoDBData(service=service, - namespace=namespace, - command=span.tags.pop('command', None), - filter=span.tags.pop('filter', None), - json=span.tags.pop('json', None), - error=span.tags.pop('command', None)) + data.mongo = MongoDBData(span) elif span.operation_name == "log": data.log = {} @@ -257,42 +214,14 @@ def build_registered_span(self, span): data.log["message"] = l.key_values.pop("message", None) if "parameters" in l.key_values: data.log["parameters"] = l.key_values.pop("parameters", None) - - entity_from = {'e': instana.singletons.agent.announce_data.pid, - 'h': instana.singletons.agent.announce_data.agentUuid} - - json_span = JsonSpan(n=span.operation_name, - k=kind, - t=span.context.trace_id, - p=span.parent_id, - s=span.context.span_id, - ts=int(round(span.start_time * 1000)), - d=int(round(span.duration * 1000)), - f=entity_from, - data=data) - - if span.stack: - json_span.stack = span.stack - - error = span.tags.pop("error", False) - ec = span.tags.pop("ec", None) - - if error and ec: - json_span.error = error - json_span.ec = ec - - if len(span.tags) > 0: - if data.custom is None: - data.custom = CustomData() - data.custom.tags = span.tags - - return json_span + else: + logger.debug("SpanRecorder: Unknown exit span: %s" % span.operation_name) def build_sdk_span(self, span): """ Takes a BasicSpan and converts into an SDK type JsonSpan """ custom_data = CustomData(tags=span.tags, - logs=self.collect_logs(span)) + logs=span.collect_logs()) sdk_data = SDKData(name=span.operation_name, custom=custom_data, @@ -304,28 +233,8 @@ def build_sdk_span(self, span): if "return" in span.tags: sdk_data.Return = span.tags["return"] - data = Data(service=instana.singletons.agent.sensor.options.service_name, sdk=sdk_data) - entity_from = {'e': instana.singletons.agent.announce_data.pid, - 'h': instana.singletons.agent.announce_data.agentUuid} - - json_span = JsonSpan(t=span.context.trace_id, - p=span.parent_id, - s=span.context.span_id, - ts=int(round(span.start_time * 1000)), - d=int(round(span.duration * 1000)), - k=self.get_span_kind_as_int(span), - n="sdk", - f=entity_from, - data=data) - - error = span.tags.pop("error", False) - ec = span.tags.pop("ec", None) - - if error and ec: - json_span.error = error - json_span.ec = ec - - return json_span + data = Data(service=instana.singletons.agent.options.service_name, sdk=sdk_data) + return JsonSpan(span, self.get_span_kind_as_int(span), data, instana.singletons.agent) def get_span_kind_as_string(self, span): """ @@ -363,30 +272,7 @@ def get_span_kind_as_int(self, span): kind = 3 return kind - def collect_logs(self, span): - """ - Collect up log data and feed it to the Instana brain. - - :param span: The span to search for logs in - :return: Logs ready for consumption by the Instana brain. - """ - logs = {} - for log in span.logs: - ts = int(round(log.timestamp * 1000)) - if ts not in logs: - logs[ts] = {} - - if 'message' in log.key_values: - logs[ts]['message'] = log.key_values['message'] - if 'event' in log.key_values: - logs[ts]['event'] = log.key_values['event'] - if 'parameters' in log.key_values: - logs[ts]['parameters'] = log.key_values['parameters'] - - return logs - class InstanaSampler(Sampler): - def sampled(self, _): return False diff --git a/instana/singletons.py b/instana/singletons.py index 38f819d8..7f2ce675 100644 --- a/instana/singletons.py +++ b/instana/singletons.py @@ -1,3 +1,4 @@ +import os import sys import opentracing @@ -5,9 +6,19 @@ from .tracer import InstanaTracer, InstanaRecorder -# The Instana Agent which carries along with it a Sensor that collects metrics. -agent = StandardAgent() +def get_appropriate_agent(): + if os.environ.get("INSTANA_ENDPOINT_URL", False): + print("Lambda environment") + return AWSLambdaAgent() + else: + print("Standard host environment") + return StandardAgent() +def get_agent_instance(): + global agent + return agent + +agent = get_appropriate_agent() span_recorder = InstanaRecorder() diff --git a/instana/span.py b/instana/span.py index 402084e0..b53e44bd 100644 --- a/instana/span.py +++ b/instana/span.py @@ -30,3 +30,26 @@ def log_exception(self, e): logger.debug("span.log_exception", exc_info=True) raise + def collect_logs(self): + """ + Collect up log data and feed it to the Instana brain. + + :param span: The span to search for logs in + :return: Logs ready for consumption by the Instana brain. + """ + logs = {} + for log in self.logs: + ts = int(round(log.timestamp * 1000)) + if ts not in logs: + logs[ts] = {} + + if 'message' in log.key_values: + logs[ts]['message'] = log.key_values['message'] + if 'event' in log.key_values: + logs[ts]['event'] = log.key_values['event'] + if 'parameters' in log.key_values: + logs[ts]['parameters'] = log.key_values['parameters'] + + return logs + + diff --git a/instana/util.py b/instana/util.py index 7a18c626..9167cee6 100644 --- a/instana/util.py +++ b/instana/util.py @@ -6,6 +6,8 @@ import time import pkg_resources +from collections import defaultdict + try: from urllib import parse @@ -27,6 +29,16 @@ BAD_ID = "BADCAFFE" # Bad Caffe +# Simple implementation of a nested dictionary. +# +# Same as: +# stan_dictionary = lambda: defaultdict(stan_dictionary) +# but we use the function form because of PEP 8 +# +def stan_dictionary(): + return defaultdict(stan_dictionary) + + def generate_id(): """ Generate a 64bit base 16 ID for use as a Span or Trace ID """ global _current_pid From 4e5e1edc370b6cf26b2e84a715fab727e189e5b3 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Thu, 27 Feb 2020 15:46:17 +0100 Subject: [PATCH 03/29] Functional Lambda Tracing and Infra linking --- bin/build_lambda_layer.py | 1 - instana/agent.py | 43 ++++++++------- instana/collector.py | 77 +++++++++++++++------------ instana/instrumentation/aws_lambda.py | 24 +++++---- instana/json_span.py | 10 ++-- instana/recorder.py | 40 ++++++++++---- instana/singletons.py | 26 +++++---- 7 files changed, 130 insertions(+), 91 deletions(-) diff --git a/bin/build_lambda_layer.py b/bin/build_lambda_layer.py index 174341d2..7ca8dbdd 100755 --- a/bin/build_lambda_layer.py +++ b/bin/build_lambda_layer.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import os -import glob import shutil import time import distutils.spawn diff --git a/instana/agent.py b/instana/agent.py index d29b2e9f..758cc030 100644 --- a/instana/agent.py +++ b/instana/agent.py @@ -147,7 +147,11 @@ def set_from(self, json_string): self.announce_data = AnnounceData(pid=res_data['pid'], agentUuid=res_data['agentUuid']) def get_from_structure(self): - return {'e': self.announce_data.pid, 'h': self.announce_data.agentUuid} + if os.environ.get("INSTANA_TEST", False): + fs = {'e': os.getpid(), 'h': 'fake'} + else: + fs = {'e': self.announce_data.pid, 'h': self.announce_data.agentUuid} + return fs def is_agent_listening(self, host, port): """ @@ -318,32 +322,19 @@ def __response_url(self, message_id): class AWSLambdaAgent(BaseAgent): - from_ = None - options = None - meter = None - collector = None - report_headers = dict() - - _can_send = False - - AGENT_DATA_PATH = "com.instana.plugin.python.%d" - AGENT_HEADER = "Instana Agent" + # AGENT_DATA_PATH = "com.instana.plugin.python.%d" + # AGENT_HEADER = "Instana Agent" def __init__(self): super(AWSLambdaAgent, self).__init__() self.from_ = AWSLambdaFrom() self.options = AWSLambdaOptions() + self.report_headers = None + self._can_send = False if self._validate_options(): self._can_send = True - - # Prepare request headers - self.report_headers["Content-Type"] = "application/json" - self.report_headers["X-Instana-Host"] = "ARN" - self.report_headers["X-Instana-Key"] = self.options.agent_key - self.report_headers["X-Instana-Time"] = int(round(time.time() * 1000)) - self.collector = Collector(self) self.collector.start() else: @@ -354,7 +345,7 @@ def can_send(self): return self._can_send def get_from_structure(self): - return {'e': self.announce_data.pid, 'h': self.announce_data.agentUuid} + return {'hl': True, 'cp': 'aws', 'e': self.collector.context.invoked_function_arn} def report_data_payload(self, payload): """ @@ -362,6 +353,18 @@ def report_data_payload(self, payload): """ response = None try: + logger.debug("report_data_payload entry: %s" % self.__data_bundle_url()) + + if self.report_headers is None: + # Prepare request headers + self.report_headers = dict() + self.report_headers["Content-Type"] = "application/json" + self.report_headers["X-Instana-Host"] = self.collector.context.invoked_function_arn + self.report_headers["X-Instana-Key"] = self.options.agent_key + self.report_headers["X-Instana-Time"] = str(round(time.time() * 1000)) + + logger.debug("using these headers: %s" % self.report_headers) + response = self.client.post(self.__data_bundle_url(), data=to_json(payload), headers=self.report_headers, @@ -371,6 +374,8 @@ def report_data_payload(self, payload): except (requests.ConnectTimeout, requests.ConnectionError): logger.debug("report_traces: Instana host agent connection error") # FIXME: Larger exception capture space + except: + logger.debug("report_data_payload: ", exc_info=True) finally: return response diff --git a/instana/collector.py b/instana/collector.py index 053906a7..3ab6191b 100644 --- a/instana/collector.py +++ b/instana/collector.py @@ -16,63 +16,72 @@ def __init__(self, agent): logger.debug("Loading collector") self.agent = agent self.span_queue = queue.Queue() - self.shutdown = threading.Event() - self.shutdown.clear() + self.thread_shutdown = threading.Event() + self.thread_shutdown.clear() self.context = None + self.event = None self.snapshot_data = None self.snapshot_data_sent = False + self.lock = threading.Lock() def start(self): if self.agent.can_send(): - t = threading.Thread(target=self.prepare_and_report_data, args=()) + t = threading.Thread(target=self.thread_loop, args=()) t.setDaemon(True) t.start() else: logger.warn("Collector started but the agent tells us we can't send anything out.") - def set_context(self, context): - self.context = context + def shutdown(self): + logger.debug("Collector.shutdown: Reporting final data.") + self.thread_shutdown.set() + self.prepare_and_report_data() - def prepare_and_report_data(self): - logger.debug("prepare_and_report_data") + def thread_loop(self): + every(5, self.background_report, "Instana Collector: prepare_and_report_data") - def work(): - logger.debug("prepare_and_report_data loop") - if self.shutdown.is_set(): - logger.debug("Thread shutdown signal from agent is active: Shutting down span reporting thread") - return False + def background_report(self): + if self.thread_shutdown.is_set(): + logger.debug("Thread shutdown signal is active: Shutting down reporting thread") + return False + return self.prepare_and_report_data() + def prepare_and_report_data(self): + lock_acquired = self.lock.acquire(False) + if lock_acquired: payload = stan_dictionary() - if self.snapshot_data and self.snapshot_data_sent is False: - payload["metrics"] = self.collect_snapshot() - if not self.span_queue.empty(): payload["spans"] = self.__queued_spans() + if self.snapshot_data and self.snapshot_data_sent is False: + payload["metrics"] = self.snapshot_data + self.snapshot_data_sent = True + if len(payload) > 0: logger.debug(to_json(payload)) self.agent.report_data_payload(payload) + else: + logger.debug("prepare_and_report_data: No data to report") + self.lock.release() + else: + logger.debug("prepare_and_report_data: Couldn't acquire lock") + return True + + def collect_snapshot(self, event, context): + self.snapshot_data = stan_dictionary() + metrics = stan_dictionary() + + self.context = context + self.event = event + + try: + metrics["name"] = "com.instana.plugin.aws.lambda" + metrics["entityId"] = self.context.invoked_function_arn + self.snapshot_data["plugins"] = [metrics] + except: + logger.debug("collect_snapshot error", exc_info=True) - every(5, work, "Instana Collector: prepare_and_report_data") - - def collect_snapshot(self): - ss = stan_dictionary() - ss["arn"] = self.context.invoked_function_arn - ss["version"] = self.context.function_version - # ss["revision"] - # ss["code_sha_256"] - # ss["description"] - ss["runtime"] = "python" - # ss["handler"] - # ss["timeout"] - ss["memory_size"] = self.context.memory_limit_in_mb - # ss["last_modified"] - # ss["aws_grouping_zone"] - # ss["tags"] - # ss["event_source_mappings"] - # ss["legacy_endpoint_used"] - return ss def __queued_spans(self): """ Get all of the spans in the queue """ diff --git a/instana/instrumentation/aws_lambda.py b/instana/instrumentation/aws_lambda.py index b805450c..b77b45d7 100644 --- a/instana/instrumentation/aws_lambda.py +++ b/instana/instrumentation/aws_lambda.py @@ -3,7 +3,7 @@ import wrapt from ..log import logger -from ..singletons import tracer +from ..singletons import agent, tracer if os.environ.get("INSTANA_ENDPOINT_URL", False): @@ -18,22 +18,28 @@ sys.path.insert(0, '/var/runtime') sys.path.insert(0, '/var/task') - try: - import importlib - module = importlib.import_module(handler_module, package=None) - except ImportError: - logger.warn("Couldn't do the manual import") + # try: + # import importlib + # module = importlib.import_module(handler_module, package=None) + # except ImportError: + # logger.warn("Couldn't do the manual import") @wrapt.patch_function_wrapper(handler_module, handler_function) def lambda_handler_with_instana(wrapped, instance, args, kwargs): - logger.debug("we got the handler!") + agent.collector.collect_snapshot(*args) + result = None with tracer.start_active_span("aws.lambda.entry") as scope: try: + scope.span.set_tag('lambda.arn', agent.collector.context.invoked_function_arn) + scope.span.set_tag('lambda.name', agent.collector.context.function_name) + scope.span.set_tag('lambda.version', agent.collector.context.function_version) + result = wrapped(*args, **kwargs) except Exception as e: if scope.span: scope.span.log_exception(e) raise - else: - return result + + agent.collector.shutdown() + return result diff --git a/instana/json_span.py b/instana/json_span.py index cfd8509b..c79fe5a3 100644 --- a/instana/json_span.py +++ b/instana/json_span.py @@ -4,7 +4,7 @@ class BaseSpan(object): def __str__(self): - return self.__class__.__str__() + ": " + self.__dict__.__str__() + return "BaseSpan(%s)" % self.__dict__.__str__() def __repr__(self): return self.__dict__.__str__() @@ -113,11 +113,11 @@ class SDKData(BaseSpan): class AWSLambdaData(BaseSpan): def __init__(self, span, **kwargs): - self.arn = "" + self.arn = span.tags.pop('lambda.arn', "Unknown") self.alias = None - self.runtime = "py" - self.functionName = os.environ.get("AWS_LAMBDA_FUNCTION_NAME", "Unknown") - self.functionVersion = os.environ.get("AWS_LAMBDA_FUNCTION_VERSION", "0") + self.runtime = "python" + self.functionName = span.tags.pop('lambda.name', "Unknown") + self.functionVersion = span.tags.pop('lambda.version', "Unknown") self.error = "" super(AWSLambdaData, self).__init__(**kwargs) diff --git a/instana/recorder.py b/instana/recorder.py index 051be3de..87d66292 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -8,7 +8,7 @@ from .util import every import instana.singletons -from basictracer import Sampler, SpanRecorder +from basictracer import Sampler from .json_span import (AWSLambdaData, CassandraData, CouchbaseData, CustomData, Data, HttpData, JsonSpan, LogData, MongoDBData, MySQLData, PostgresData, RabbitmqData, RedisData, RenderData, @@ -20,7 +20,7 @@ import queue -class InstanaRecorder(SpanRecorder): +class InstanaRecorder(object): THREAD_NAME = "Instana Span Reporting" registered_spans = ("aiohttp-client", "aiohttp-server", "aws.lambda.entry", "cassandra", "couchbase", "django", "log","memcache", "mongo", "mysql", "postgres", "rabbitmq", "redis", "render", @@ -45,7 +45,6 @@ class InstanaRecorder(SpanRecorder): thread = None def __init__(self): - super(InstanaRecorder, self).__init__() self.queue = queue.Queue() def start(self): @@ -126,7 +125,7 @@ def record_span(self, span): else: json_span = self.build_sdk_span(span) - logger.debug("Recorded span: %s", json_span) + # logger.debug("Recorded span: %s", json_span) self.queue.put(json_span) @@ -148,13 +147,12 @@ def build_registered_span(self, span): if data.rabbitmq and data.rabbitmq.sort == 'consume': kind = 1 # entry - if span.operation_name in self.http_spans: - data.http = HttpData(span) - return JsonSpan(span, kind, data, instana.singletons.agent) def _populate_entry_span_data(self, span, data): - if span.operation_name == "rpc-server": + if span.operation_name in self.http_spans: + data.http = HttpData(span) + elif span.operation_name == "rpc-server": data.rpc = RPCData(span) elif span.operation_name == "aws.lambda.entry": data.aws_lambda = AWSLambdaData(span) @@ -169,7 +167,10 @@ def _populate_local_span_data(self, span, data): logger.debug("SpanRecorder: Unknown local span: %s" % span.operation_name) def _populate_exit_span_data(self, span, data): - if span.operation_name == "rabbitmq": + if span.operation_name in self.http_spans: + data.http = HttpData(span) + + elif span.operation_name == "rabbitmq": data.rabbitmq = RabbitmqData(span) elif span.operation_name == "cassandra": @@ -273,6 +274,27 @@ def get_span_kind_as_int(self, span): return kind +class AWSLambdaRecorder(InstanaRecorder): + def __init__(self, agent): + self.agent = agent + super(AWSLambdaRecorder, self).__init__() + + def record_span(self, span): + """ + Convert the passed BasicSpan into an JsonSpan and + add it to the span queue + """ + json_span = None + + if span.operation_name in self.registered_spans: + json_span = self.build_registered_span(span) + else: + json_span = self.build_sdk_span(span) + + logger.debug("Recorded span: %s", json_span) + self.agent.collector.span_queue.put(json_span) + + class InstanaSampler(Sampler): def sampled(self, _): return False diff --git a/instana/singletons.py b/instana/singletons.py index 7f2ce675..bf49072d 100644 --- a/instana/singletons.py +++ b/instana/singletons.py @@ -3,24 +3,22 @@ import opentracing from .agent import StandardAgent, AWSLambdaAgent -from .tracer import InstanaTracer, InstanaRecorder +from .tracer import InstanaTracer +from .recorder import InstanaRecorder, AWSLambdaRecorder -def get_appropriate_agent(): - if os.environ.get("INSTANA_ENDPOINT_URL", False): - print("Lambda environment") - return AWSLambdaAgent() - else: - print("Standard host environment") - return StandardAgent() +agent = None +span_recorder = None -def get_agent_instance(): - global agent - return agent +if os.environ.get("INSTANA_ENDPOINT_URL", False): + print("Lambda environment") + agent = AWSLambdaAgent() + span_recorder = AWSLambdaRecorder(agent) +else: + print("Standard host environment") + agent = StandardAgent() + span_recorder = InstanaRecorder() -agent = get_appropriate_agent() - -span_recorder = InstanaRecorder() # The global OpenTracing compatible tracer used internally by # this package. From a53e74b27aa2b64dcf807e331569bbfefbce792d Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Thu, 27 Feb 2020 21:13:12 +0100 Subject: [PATCH 04/29] Bug fixes for test suite issues --- instana/json_span.py | 4 ++-- instana/recorder.py | 8 ++++++-- tests/test_ot_propagators.py | 37 ++++++++++++------------------------ 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/instana/json_span.py b/instana/json_span.py index c79fe5a3..d6170236 100644 --- a/instana/json_span.py +++ b/instana/json_span.py @@ -20,11 +20,10 @@ def __init__(self, span, kind, data, agent, **kwargs): self.p = span.parent_id self.s = span.context.span_id self.ts = int(round(span.start_time * 1000)) - self.ta = "py" self.d = int(round(span.duration * 1000)) self.f = agent.get_from_structure() self.ec = span.tags.pop("ec", None) - self.error = span.tags.pop("error", False) + self.error = span.tags.pop("error", None) if data.sdk: self.n = "sdk" @@ -191,6 +190,7 @@ def __init__(self, span, **kwargs): self.db = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) self.user = span.tags.pop(ot_tags.DATABASE_USER, None) self.stmt = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) + self.error = span.tags.pop('error', None) super(MySQLData, self).__init__(**kwargs) diff --git a/instana/recorder.py b/instana/recorder.py index 87d66292..c4ef77dc 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -152,10 +152,14 @@ def build_registered_span(self, span): def _populate_entry_span_data(self, span, data): if span.operation_name in self.http_spans: data.http = HttpData(span) - elif span.operation_name == "rpc-server": - data.rpc = RPCData(span) elif span.operation_name == "aws.lambda.entry": data.aws_lambda = AWSLambdaData(span) + elif span.operation_name == "rabbitmq": + data.rabbitmq = RabbitmqData(span) + elif span.operation_name == "rpc-server": + data.rpc = RPCData(span) + elif span.operation_name == "soap": + data.soap = SoapData(span) else: logger.debug("SpanRecorder: Unknown entry span: %s" % span.operation_name) diff --git a/tests/test_ot_propagators.py b/tests/test_ot_propagators.py index e6c4742f..3b741fbc 100644 --- a/tests/test_ot_propagators.py +++ b/tests/test_ot_propagators.py @@ -1,6 +1,5 @@ import inspect -import basictracer import opentracing as ot from nose.tools import assert_equals @@ -23,8 +22,7 @@ def test_http_basics(): def test_http_inject_with_dict(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {} span = ot.tracer.start_span("nosetests") @@ -39,8 +37,7 @@ def test_http_inject_with_dict(): def test_http_inject_with_list(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = [] span = ot.tracer.start_span("nosetests") @@ -52,8 +49,7 @@ def test_http_inject_with_list(): def test_http_basic_extract(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {'X-Instana-T': '1', 'X-Instana-S': '1', 'X-Instana-L': '1'} ctx = ot.tracer.extract(ot.Format.HTTP_HEADERS, carrier) @@ -64,8 +60,7 @@ def test_http_basic_extract(): def test_http_mixed_case_extract(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {'x-insTana-T': '1', 'X-inSTANa-S': '1', 'X-INstana-l': '1'} ctx = ot.tracer.extract(ot.Format.HTTP_HEADERS, carrier) @@ -76,8 +71,7 @@ def test_http_mixed_case_extract(): def test_http_no_context_extract(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {} ctx = ot.tracer.extract(ot.Format.HTTP_HEADERS, carrier) @@ -86,8 +80,7 @@ def test_http_no_context_extract(): def test_http_128bit_headers(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {'X-Instana-T': '0000000000000000b0789916ff8f319f', 'X-Instana-S': '0000000000000000b0789916ff8f319f', 'X-Instana-L': '1'} @@ -111,8 +104,7 @@ def test_text_basics(): def test_text_inject_with_dict(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {} span = ot.tracer.start_span("nosetests") @@ -127,8 +119,7 @@ def test_text_inject_with_dict(): def test_text_inject_with_list(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = [] span = ot.tracer.start_span("nosetests") @@ -140,8 +131,7 @@ def test_text_inject_with_list(): def test_text_basic_extract(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {'X-INSTANA-T': '1', 'X-INSTANA-S': '1', 'X-INSTANA-L': '1'} ctx = ot.tracer.extract(ot.Format.TEXT_MAP, carrier) @@ -152,8 +142,7 @@ def test_text_basic_extract(): def test_text_mixed_case_extract(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {'x-insTana-T': '1', 'X-inSTANa-S': '1', 'X-INstana-l': '1'} ctx = ot.tracer.extract(ot.Format.TEXT_MAP, carrier) @@ -162,8 +151,7 @@ def test_text_mixed_case_extract(): def test_text_no_context_extract(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {} ctx = ot.tracer.extract(ot.Format.TEXT_MAP, carrier) @@ -172,8 +160,7 @@ def test_text_no_context_extract(): def test_text_128bit_headers(): - opts = options.Options() - ot.tracer = InstanaTracer(opts) + ot.tracer = InstanaTracer() carrier = {'X-INSTANA-T': '0000000000000000b0789916ff8f319f', 'X-INSTANA-S': ' 0000000000000000b0789916ff8f319f', 'X-INSTANA-L': '1'} From f0d336e821cda45b067042aaebd46eec5fadbdc8 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Thu, 27 Feb 2020 21:51:59 +0100 Subject: [PATCH 05/29] Bug fixes for test suite issues: second batch --- instana/json_span.py | 2 ++ instana/recorder.py | 9 ++++----- tests/test_logging.py | 5 ++--- tests/test_ot_span.py | 1 - 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/instana/json_span.py b/instana/json_span.py index d6170236..83243bd5 100644 --- a/instana/json_span.py +++ b/instana/json_span.py @@ -187,6 +187,7 @@ def __init__(self, span, **kwargs): class MySQLData(BaseSpan): def __init__(self, span, **kwargs): self.host = span.tags.pop('host', None) + self.port = span.tags.pop('port', None) self.db = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) self.user = span.tags.pop(ot_tags.DATABASE_USER, None) self.stmt = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) @@ -197,6 +198,7 @@ def __init__(self, span, **kwargs): class PostgresData(BaseSpan): def __init__(self, span, **kwargs): self.host = span.tags.pop('host', None) + self.port = span.tags.pop('port', None) self.db = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) self.user = span.tags.pop(ot_tags.DATABASE_USER, None) self.stmt = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) diff --git a/instana/recorder.py b/instana/recorder.py index c4ef77dc..bee5b73b 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -152,14 +152,14 @@ def build_registered_span(self, span): def _populate_entry_span_data(self, span, data): if span.operation_name in self.http_spans: data.http = HttpData(span) + if span.operation_name == "soap": + data.soap = SoapData(span) elif span.operation_name == "aws.lambda.entry": data.aws_lambda = AWSLambdaData(span) elif span.operation_name == "rabbitmq": data.rabbitmq = RabbitmqData(span) elif span.operation_name == "rpc-server": data.rpc = RPCData(span) - elif span.operation_name == "soap": - data.soap = SoapData(span) else: logger.debug("SpanRecorder: Unknown entry span: %s" % span.operation_name) @@ -173,6 +173,8 @@ def _populate_local_span_data(self, span, data): def _populate_exit_span_data(self, span, data): if span.operation_name in self.http_spans: data.http = HttpData(span) + if span.operation_name == "soap": + data.soap = SoapData(span) elif span.operation_name == "rabbitmq": data.rabbitmq = RabbitmqData(span) @@ -192,9 +194,6 @@ def _populate_exit_span_data(self, span, data): elif span.operation_name == "sqlalchemy": data.sqlalchemy = SQLAlchemyData(span) - elif span.operation_name == "soap": - data.soap = SoapData(span) - elif span.operation_name == "mysql": data.mysql = MySQLData(span) if (data.custom is not None) and (data.custom.logs is not None) and len(data.custom.logs): diff --git a/tests/test_logging.py b/tests/test_logging.py index e576eb53..0171e2b6 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -20,7 +20,6 @@ def test_no_span(self): with tracer.start_active_span('test'): self.logger.info('info message') - spans = self.recorder.queued_spans() self.assertEqual(1, len(spans)) @@ -30,7 +29,7 @@ def test_extra_span(self): spans = self.recorder.queued_spans() self.assertEqual(2, len(spans)) - self.assertEqual(3, spans[0].k) # intermediate kind + self.assertEqual(2, spans[0].k) self.assertEqual('foo bar', spans[0].data.log.get('message')) @@ -40,7 +39,7 @@ def test_log_with_tuple(self): spans = self.recorder.queued_spans() self.assertEqual(2, len(spans)) - self.assertEqual(3, spans[0].k) # intermediate kind + self.assertEqual(2, spans[0].k) self.assertEqual("foo ('bar',)", spans[0].data.log.get('message')) diff --git a/tests/test_ot_span.py b/tests/test_ot_span.py index da1e9e63..f4993cf3 100644 --- a/tests/test_ot_span.py +++ b/tests/test_ot_span.py @@ -79,7 +79,6 @@ def test_sdk_spans(self): assert sdk_span.ts > 0 assert sdk_span.d assert sdk_span.d > 0 - assert_equals("py", sdk_span.ta) assert sdk_span.data assert sdk_span.data.sdk From df6f73fe262037c8432350633714330987c11211 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 3 Mar 2020 13:41:13 +0100 Subject: [PATCH 06/29] Restructured tag collection --- docker-compose.yml | 28 +- instana/collector.py | 13 +- instana/configurator.py | 4 +- instana/json_span.py | 467 ++++++++++--------- instana/recorder.py | 196 +------- instana/span.py | 10 +- instana/tracer.py | 5 +- instana/util.py | 17 +- tests/config/database/mysql/conf.d/mysql.cnf | 4 +- tests/helpers.py | 1 + tests/test_aiohttp.py | 153 +++--- tests/test_asynqp.py | 82 ++-- tests/test_cassandra-driver.py | 10 +- tests/test_couchbase.py | 314 ++++++------- tests/test_django.py | 42 +- tests/test_flask.py | 230 ++++----- tests/test_grpcio.py | 220 ++++----- tests/test_logging.py | 6 +- tests/test_mysql-python.py | 62 +-- tests/test_mysqlclient.py | 62 +-- tests/test_ot_span.py | 20 +- tests/test_psycopg2.py | 66 ++- tests/test_pymongo.py | 80 ++-- tests/test_pymysql.py | 77 ++- tests/test_redis.py | 124 ++--- tests/test_sqlalchemy.py | 56 +-- tests/test_sudsjurko.py | 52 +-- tests/test_tornado_client.py | 108 ++--- tests/test_tornado_server.py | 138 +++--- tests/test_urllib3.py | 262 +++++------ tests/test_wsgi.py | 50 +- 31 files changed, 1406 insertions(+), 1553 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 40fc12d3..69abaf9b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,20 +40,31 @@ services: - ./bin:/nodejs-collector-bin # command: ["/nodejs-collector-bin/wait-for-it.sh", "-s", "-t", "120", "zookeeper:2181", "--", "start-kafka.sh"] - mysql: - image: mysql:8.0.1 + couchbase: + image: couchbase + ports: + - 8091-8094:8091-8094 + - 11210:11210 + + mariadb: + image: mariadb ports: - 3306:3306 environment: - MYSQL_ALLOW_EMPTY_PASSWORD: 'true' + MYSQL_DATABASE: 'circle_test' + MYSQL_USER: 'root' + MYSQL_PASSWORD: '' + MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' MYSQL_ROOT_PASSWORD: '' - MYSQL_DATABASE: circle_test - MYSQL_USER: root - MYSQL_PASSWORD: - MYSQL_ROOT_HOST: '0.0.0.0' + MYSQL_ROOT_HOST: '%' volumes: - ./tests/config/database/mysql/conf.d:/etc/mysql/conf.d + mongodb: + image: 'mongo:3.4.1' + ports: + - '27017:27017' + postgres: image: postgres:10.5 ports: @@ -68,3 +79,6 @@ services: ports: - 5671:5671 - 5672:5672 + +#volumes: +# mysql-data: diff --git a/instana/collector.py b/instana/collector.py index 3ab6191b..821e872e 100644 --- a/instana/collector.py +++ b/instana/collector.py @@ -2,7 +2,7 @@ import threading from .log import logger -from .util import every, to_json, stan_dictionary +from .util import every, to_json, DictionaryOfStan if sys.version_info.major == 2: @@ -49,7 +49,7 @@ def background_report(self): def prepare_and_report_data(self): lock_acquired = self.lock.acquire(False) if lock_acquired: - payload = stan_dictionary() + payload = DictionaryOfStan() if not self.span_queue.empty(): payload["spans"] = self.__queued_spans() @@ -69,16 +69,15 @@ def prepare_and_report_data(self): return True def collect_snapshot(self, event, context): - self.snapshot_data = stan_dictionary() - metrics = stan_dictionary() + self.snapshot_data = DictionaryOfStan() + metrics = DictionaryOfStan() self.context = context self.event = event try: - metrics["name"] = "com.instana.plugin.aws.lambda" - metrics["entityId"] = self.context.invoked_function_arn - self.snapshot_data["plugins"] = [metrics] + self.snapshot_data["plugins"]["name"] = "com.instana.plugin.aws.lambda" + self.snapshot_data["plugins"]["entityId"] = self.context.invoked_function_arn except: logger.debug("collect_snapshot error", exc_info=True) diff --git a/instana/configurator.py b/instana/configurator.py index 71daf321..a6a57fbe 100644 --- a/instana/configurator.py +++ b/instana/configurator.py @@ -3,10 +3,10 @@ Defaults are set and can be overridden after package load. """ from __future__ import absolute_import -from .util import stan_dictionary +from .util import DictionaryOfStan # La Protagonista -config = stan_dictionary() +config = DictionaryOfStan() # This option determines if tasks created via asyncio (with ensure_future or create_task) will diff --git a/instana/json_span.py b/instana/json_span.py index 83243bd5..01ab888c 100644 --- a/instana/json_span.py +++ b/instana/json_span.py @@ -1,4 +1,5 @@ -import os +from .log import logger +from .util import DictionaryOfStan import opentracing.ext.tags as ot_tags @@ -9,247 +10,261 @@ def __str__(self): def __repr__(self): return self.__dict__.__str__() - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - - -class JsonSpan(BaseSpan): - def __init__(self, span, kind, data, agent, **kwargs): - self.k = kind + def __init__(self, span, source, **kwargs): self.t = span.context.trace_id self.p = span.parent_id self.s = span.context.span_id self.ts = int(round(span.start_time * 1000)) self.d = int(round(span.duration * 1000)) - self.f = agent.get_from_structure() + self.f = source self.ec = span.tags.pop("ec", None) self.error = span.tags.pop("error", None) - if data.sdk: - self.n = "sdk" - else: - self.n = span.operation_name - if span.stack: self.stack = span.stack - if len(span.context.baggage) > 0: - data.baggage = span.context.baggage - - # Send along any left over custom tags - if len(span.tags) > 0: - if data.custom is None: - data.custom = CustomData() - data.custom.tags = span.tags - - logs = span.collect_logs() - if len(logs) > 0: - if data.custom is None: - data.custom = CustomData() - data.custom.logs = logs - - self.data = data - super(JsonSpan, self).__init__(**kwargs) - - -class CustomData(BaseSpan): - tags = None - logs = None + self.__dict__.update(kwargs) - def __init__(self, **kwargs): - super(CustomData, self).__init__(**kwargs) +class SDKSpan(BaseSpan): + ENTRY_KIND = ["entry", "server", "consumer"] + EXIT_KIND = ["exit", "client", "producer"] -class Data(BaseSpan): - baggage = None - cassandra = None - couchbase = None - custom = None - http = None - _lambda = None - log = None - pg = None - rabbitmq = None - redis = None - rpc = None - render = None - sdk = None - service = None - sqlalchemy = None - soap = None + def __init__(self, span, source, service_name, **kwargs): + super(SDKSpan, self).__init__(span, source, **kwargs) + self.n = "sdk" + self.k = self.get_span_kind_as_int(span) + self.data = DictionaryOfStan() + self.data["sdk"]["name"] = span.operation_name + self.data["sdk"]["type"] = self.get_span_kind_as_string(span) + self.data["sdk"]["custom"]["tags"] = span.tags + self.data["sdk"]["custom"]["logs"] = span.logs + self.data["service"] = service_name -""" General Spans """ - - -class HttpData(BaseSpan): - def __init__(self, span, **kwargs): - self.host = span.tags.pop("http.host", None) - self.url = span.tags.pop(ot_tags.HTTP_URL, None) - self.path = span.tags.pop("http.path", None) - self.params = span.tags.pop('http.params', None) - self.method = span.tags.pop(ot_tags.HTTP_METHOD, None) - self.status = span.tags.pop(ot_tags.HTTP_STATUS_CODE, None) - self.path_tpl = span.tags.pop("http.path_tpl", None) - self.error = span.tags.pop('http.error', None) - super(HttpData, self).__init__(**kwargs) + # self.data = Data() + # self.data.sdk = SDKData(name=span.operation_name, Type=self.get_span_kind_as_string(span)) + # self.data.sdk.custom = CustomData(tags=span.tags, logs=span.collect_logs()) + # self.data.service = service_name + if "arguments" in span.tags: + self.data.sdk.arguments = span.tags["arguments"] -class SDKData(BaseSpan): - name = None - - # Since 'type' and 'return' are a Python builtin and a reserved keyword respectively, these keys (all keys) are - # lower-case'd in json encoding. See Agent.to_json - Type = None - Return = None - - arguments = None - custom = None - - -""" Entry Spans """ - - -class AWSLambdaData(BaseSpan): - def __init__(self, span, **kwargs): - self.arn = span.tags.pop('lambda.arn', "Unknown") - self.alias = None - self.runtime = "python" - self.functionName = span.tags.pop('lambda.name', "Unknown") - self.functionVersion = span.tags.pop('lambda.version', "Unknown") - self.error = "" - super(AWSLambdaData, self).__init__(**kwargs) - - -""" Local Spans """ - - -class RenderData(BaseSpan): - type = None - name = None - message = None - parameters = None - - def __init__(self, span, **kwargs): - self.name = span.tags.pop('name', None) - self.type = span.tags.pop('type', None) - super(RenderData, self).__init__(**kwargs) - - -""" Exit Spans """ - - -class CassandraData(BaseSpan): - def __init__(self, span, **kwargs): - self.cluster = span.tags.pop('cassandra.cluster', None) - self.query = span.tags.pop('cassandra.query', None) - self.keyspace = span.tags.pop('cassandra.keyspace', None) - self.fetchSize = span.tags.pop('cassandra.fetchSize', None) - self.achievedConsistency = span.tags.pop('cassandra.achievedConsistency', None) - self.triedHosts = span.tags.pop('cassandra.triedHosts', None) - self.fullyFetched = span.tags.pop('cassandra.fullyFetched', None) - self.error = span.tags.pop('cassandra.error', None) - super(CassandraData, self).__init__(**kwargs) - - -class CouchbaseData(BaseSpan): - def __init__(self, span, **kwargs): - self.hostname = span.tags.pop('couchbase.hostname', None) - self.bucket = span.tags.pop('couchbase.bucket', None) - self.type = span.tags.pop('couchbase.type', None) - self.error = span.tags.pop('couchbase.error', None) - self.error_type = span.tags.pop('couchbase.error_type', None) - self.sql = span.tags.pop('couchbase.sql', None) - super(CouchbaseData, self).__init__(**kwargs) - - -class LogData(object): - def __init__(self, span, **kwargs): - self.message = span.tags.pop('message', None), - self.parameters = span.tags.pop('parameters', None) - super(LogData, self).__init__(**kwargs) - - -class MongoDBData(BaseSpan): - def __init__(self, span, **kwargs): - service = "%s:%s" % (span.tags.pop('host', None), span.tags.pop('port', None)) - namespace = "%s.%s" % (span.tags.pop('db', "?"), span.tags.pop('collection', "?")) - - self.service = service - self.namespace = namespace - self.command = span.tags.pop('command', None) - self.filter = span.tags.pop('filter', None) - self.json = span.tags.pop('json', None) - self.error = span.tags.pop('command', None) - super(MongoDBData, self).__init__(**kwargs) - - -class MySQLData(BaseSpan): - def __init__(self, span, **kwargs): - self.host = span.tags.pop('host', None) - self.port = span.tags.pop('port', None) - self.db = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) - self.user = span.tags.pop(ot_tags.DATABASE_USER, None) - self.stmt = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) - self.error = span.tags.pop('error', None) - super(MySQLData, self).__init__(**kwargs) - - -class PostgresData(BaseSpan): - def __init__(self, span, **kwargs): - self.host = span.tags.pop('host', None) - self.port = span.tags.pop('port', None) - self.db = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) - self.user = span.tags.pop(ot_tags.DATABASE_USER, None) - self.stmt = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) - self.error = span.tags.pop('pg.error', None) - super(PostgresData, self).__init__(**kwargs) - - -class RabbitmqData(BaseSpan): - def __init__(self, span, **kwargs): - self.exchange = span.tags.pop('exchange', None), - self.queue = span.tags.pop('queue', None), - self.sort = span.tags.pop('sort', None), - self.address = span.tags.pop('address', None), - self.key = span.tags.pop('key', None) - super(RabbitmqData, self).__init__(**kwargs) - - -class RedisData(BaseSpan): - def __init__(self, span, **kwargs): - self.connection = span.tags.pop('connection', None) - self.driver = span.tags.pop('driver', None) - self.command = span.tags.pop('command', None) - self.error = span.tags.pop('redis.error', None) - self.subCommands = span.tags.pop('subCommands', None) - super(RedisData, self).__init__(**kwargs) - - -class RPCData(BaseSpan): - def __init__(self, span, **kwargs): - self.flavor = span.tags.pop('rpc.flavor', None) - self.host = span.tags.pop('rpc.host', None) - self.port = span.tags.pop('rpc.port', None) - self.call = span.tags.pop('rpc.call', None) - self.call_type = span.tags.pop('rpc.call_type', None) - self.params = span.tags.pop('rpc.params', None) - self.baggage = span.tags.pop('rpc.baggage', None) - self.error = span.tags.pop('rpc.error', None) - super(RPCData, self).__init__(**kwargs) - - -class SQLAlchemyData(BaseSpan): - def __init__(self, span, **kwargs): - self.sql = span.tags.pop('sqlalchemy.sql', None) - self.eng = span.tags.pop('sqlalchemy.eng', None) - self.url = span.tags.pop('sqlalchemy.url', None) - self.err = span.tags.pop('sqlalchemy.err', None) - super(SQLAlchemyData, self).__init__(**kwargs) - - -class SoapData(BaseSpan): - def __init__(self, span, **kwargs): - self.action = span.tags.pop('soap.action', None) - super(SoapData, self).__init__(**kwargs) + if "return" in span.tags: + self.data.sdk.Return = span.tags["return"] + if len(span.context.baggage) > 0: + self.data["baggage"] = span.context.baggage + + def get_span_kind_as_string(self, span): + """ + Will retrieve the `span.kind` tag and return the appropriate string value for the Instana backend or + None if the tag is set to something we don't recognize. + + :param span: The span to search for the `span.kind` tag + :return: String + """ + kind = None + if "span.kind" in span.tags: + if span.tags["span.kind"] in self.ENTRY_KIND: + kind = "entry" + elif span.tags["span.kind"] in self.EXIT_KIND: + kind = "exit" + else: + kind = "intermediate" + return kind + + def get_span_kind_as_int(self, span): + """ + Will retrieve the `span.kind` tag and return the appropriate integer value for the Instana backend or + None if the tag is set to something we don't recognize. + + :param span: The span to search for the `span.kind` tag + :return: Integer + """ + kind = None + if "span.kind" in span.tags: + if span.tags["span.kind"] in self.ENTRY_KIND: + kind = 1 + elif span.tags["span.kind"] in self.EXIT_KIND: + kind = 2 + else: + kind = 3 + return kind + + +class RegisteredSpan(BaseSpan): + HTTP_SPANS = ("aiohttp-client", "aiohttp-server", "django", "http", "soap", "tornado-client", + "tornado-server", "urllib3", "wsgi") + + EXIT_SPANS = ("aiohttp-client", "cassandra", "couchbase", "log", "memcache", "mongo", "mysql", "postgres", + "rabbitmq", "redis", "rpc-client", "sqlalchemy", "soap", "tornado-client", "urllib3", + "pymongo") + + ENTRY_SPANS = ("aiohttp-server", "aws.lambda.entry", "django", "wsgi", "rabbitmq", "rpc-server", "tornado-server") + + LOCAL_SPANS = ("render") + + def __init__(self, span, source, **kwargs): + super(RegisteredSpan, self).__init__(span, source, **kwargs) + self.n = span.operation_name + self.data = DictionaryOfStan() + + self.k = 1 + if span.operation_name in self.ENTRY_SPANS: + # entry + self._populate_entry_span_data(span) + elif span.operation_name in self.EXIT_SPANS: + self.k = 2 # exit + self._populate_exit_span_data(span) + elif span.operation_name in self.LOCAL_SPANS: + self.k = 3 # intermediate span + self._populate_local_span_data(span) + + if "rabbitmq" in self.data and self.data["rabbitmq"]["sort"] == "consume": + self.k = 1 # entry + + # Store any leftover tags in the custom section + if len(span.tags): + self.data["custom"]["tags"] = span.tags + + + def _populate_entry_span_data(self, span): + if span.operation_name in self.HTTP_SPANS: + self._collect_http_tags(span) + elif span.operation_name == "aws.lambda.entry": + self.data["lambda"]["arn"] = span.tags.pop('lambda.arn', "Unknown") + self.data["lambda"]["alias"] = None + self.data["lambda"]["runtime"] = "python" + self.data["lambda"]["functionName"] = span.tags.pop('lambda.name', "Unknown") + self.data["lambda"]["functionVersion"] = span.tags.pop('lambda.version', "Unknown") + self.data["lambda"]["error"] = None + + elif span.operation_name == "rabbitmq": + self.data["rabbitmq"]["exchange"] = span.tags.pop('exchange', None) + self.data["rabbitmq"]["queue"] = span.tags.pop('queue', None) + self.data["rabbitmq"]["sort"] = span.tags.pop('sort', None) + self.data["rabbitmq"]["address"] = span.tags.pop('address', None) + self.data["rabbitmq"]["key"] = span.tags.pop('key', None) + + elif span.operation_name == "rpc-server": + self.data["rpc"]["flavor"] = span.tags.pop('rpc.flavor', None) + self.data["rpc"]["host"] = span.tags.pop('rpc.host', None) + self.data["rpc"]["port"] = span.tags.pop('rpc.port', None) + self.data["rpc"]["call"] = span.tags.pop('rpc.call', None) + self.data["rpc"]["call_type"] = span.tags.pop('rpc.call_type', None) + self.data["rpc"]["params"] = span.tags.pop('rpc.params', None) + self.data["rpc"]["baggage"] = span.tags.pop('rpc.baggage', None) + self.data["rpc"]["error"] = span.tags.pop('rpc.error', None) + else: + logger.debug("SpanRecorder: Unknown entry span: %s" % span.operation_name) + + def _populate_local_span_data(self, span): + if span.operation_name == "render": + self.data["render"]["name"] = span.tags.pop('name', None) + self.data["render"]["type"] = span.tags.pop('type', None) + self.data["log"]["message"] = span.tags.pop('message', None) + self.data["log"]["parameters"] = span.tags.pop('parameters', None) + else: + logger.debug("SpanRecorder: Unknown local span: %s" % span.operation_name) + + def _populate_exit_span_data(self, span): + if span.operation_name in self.HTTP_SPANS: + self._collect_http_tags(span) + elif span.operation_name == "rabbitmq": + self.data["rabbitmq"]["exchange"] = span.tags.pop('exchange', None) + self.data["rabbitmq"]["queue"] = span.tags.pop('queue', None) + self.data["rabbitmq"]["sort"] = span.tags.pop('sort', None) + self.data["rabbitmq"]["address"] = span.tags.pop('address', None) + self.data["rabbitmq"]["key"] = span.tags.pop('key', None) + + elif span.operation_name == "cassandra": + self.data["cassandra"]["cluster"] = span.tags.pop('cassandra.cluster', None) + self.data["cassandra"]["query"] = span.tags.pop('cassandra.query', None) + self.data["cassandra"]["keyspace"] = span.tags.pop('cassandra.keyspace', None) + self.data["cassandra"]["fetchSize"] = span.tags.pop('cassandra.fetchSize', None) + self.data["cassandra"]["achievedConsistency"] = span.tags.pop('cassandra.achievedConsistency', None) + self.data["cassandra"]["triedHosts"] = span.tags.pop('cassandra.triedHosts', None) + self.data["cassandra"]["fullyFetched"] = span.tags.pop('cassandra.fullyFetched', None) + self.data["cassandra"]["error"] = span.tags.pop('cassandra.error', None) + + elif span.operation_name == "couchbase": + self.data["couchbase"]["hostname"] = span.tags.pop('couchbase.hostname', None) + self.data["couchbase"]["bucket"] = span.tags.pop('couchbase.bucket', None) + self.data["couchbase"]["type"] = span.tags.pop('couchbase.type', None) + self.data["couchbase"]["error"] = span.tags.pop('couchbase.error', None) + self.data["couchbase"]["error_type"] = span.tags.pop('couchbase.error_type', None) + self.data["couchbase"]["sql"] = span.tags.pop('couchbase.sql', None) + + elif span.operation_name == "redis": + self.data["redis"]["connection"] = span.tags.pop('connection', None) + self.data["redis"]["driver"] = span.tags.pop('driver', None) + self.data["redis"]["command"] = span.tags.pop('command', None) + self.data["redis"]["error"] = span.tags.pop('redis.error', None) + self.data["redis"]["subCommands"] = span.tags.pop('subCommands', None) + + elif span.operation_name == "rpc-client": + self.data["rpc"]["flavor"] = span.tags.pop('rpc.flavor', None) + self.data["rpc"]["host"] = span.tags.pop('rpc.host', None) + self.data["rpc"]["port"] = span.tags.pop('rpc.port', None) + self.data["rpc"]["call"] = span.tags.pop('rpc.call', None) + self.data["rpc"]["call_type"] = span.tags.pop('rpc.call_type', None) + self.data["rpc"]["params"] = span.tags.pop('rpc.params', None) + self.data["rpc"]["baggage"] = span.tags.pop('rpc.baggage', None) + self.data["rpc"]["error"] = span.tags.pop('rpc.error', None) + + elif span.operation_name == "sqlalchemy": + self.data["sqlalchemy"]["sql"] = span.tags.pop('sqlalchemy.sql', None) + self.data["sqlalchemy"]["eng"] = span.tags.pop('sqlalchemy.eng', None) + self.data["sqlalchemy"]["url"] = span.tags.pop('sqlalchemy.url', None) + self.data["sqlalchemy"]["err"] = span.tags.pop('sqlalchemy.err', None) + + elif span.operation_name == "mysql": + self.data["mysql"]["host"] = span.tags.pop('host', None) + self.data["mysql"]["port"] = span.tags.pop('port', None) + self.data["mysql"]["db"] = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) + self.data["mysql"]["user"] = span.tags.pop(ot_tags.DATABASE_USER, None) + self.data["mysql"]["stmt"] = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) + self.data["mysql"]["error"] = span.tags.pop('mysql.error', None) + + elif span.operation_name == "postgres": + self.data["pg"]["host"] = span.tags.pop('host', None) + self.data["pg"]["port"] = span.tags.pop('port', None) + self.data["pg"]["db"] = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) + self.data["pg"]["user"] = span.tags.pop(ot_tags.DATABASE_USER, None) + self.data["pg"]["stmt"] = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) + self.data["pg"]["error"] = span.tags.pop('pg.error', None) + + elif span.operation_name == "mongo": + service = "%s:%s" % (span.tags.pop('host', None), span.tags.pop('port', None)) + namespace = "%s.%s" % (span.tags.pop('db', "?"), span.tags.pop('collection', "?")) + + self.data["mongo"]["service"] = service + self.data["mongo"]["namespace"] = namespace + self.data["mongo"]["command"] = span.tags.pop('command', None) + self.data["mongo"]["filter"] = span.tags.pop('filter', None) + self.data["mongo"]["json"] = span.tags.pop('json', None) + self.data["mongo"]["error"] = span.tags.pop('error', None) + + elif span.operation_name == "log": + # use last special key values + for l in span.logs: + if "message" in l.key_values: + self.data["log"]["message"] = l.key_values.pop("message", None) + if "parameters" in l.key_values: + self.data["log"]["parameters"] = l.key_values.pop("parameters", None) + else: + logger.debug("SpanRecorder: Unknown exit span: %s" % span.operation_name) + + def _collect_http_tags(self, span): + self.data["http"]["host"] = span.tags.pop("http.host", None) + self.data["http"]["url"] = span.tags.pop(ot_tags.HTTP_URL, None) + self.data["http"]["path"] = span.tags.pop("http.path", None) + self.data["http"]["params"] = span.tags.pop('http.params', None) + self.data["http"]["method"] = span.tags.pop(ot_tags.HTTP_METHOD, None) + self.data["http"]["status"] = span.tags.pop(ot_tags.HTTP_STATUS_CODE, None) + self.data["http"]["path_tpl"] = span.tags.pop("http.path_tpl", None) + self.data["http"]["error"] = span.tags.pop('http.error', None) + + if span.operation_name == "soap": + self.data["soap"]["action"] = span.tags.pop('soap.action', None) diff --git a/instana/recorder.py b/instana/recorder.py index bee5b73b..eb82a0f6 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -10,9 +10,7 @@ from basictracer import Sampler -from .json_span import (AWSLambdaData, CassandraData, CouchbaseData, CustomData, Data, HttpData, JsonSpan, LogData, - MongoDBData, MySQLData, PostgresData, RabbitmqData, RedisData, RenderData, - RPCData, SDKData, SoapData, SQLAlchemyData) +from .json_span import (RegisteredSpan, SDKSpan) if sys.version_info.major == 2: import Queue as queue @@ -22,25 +20,12 @@ class InstanaRecorder(object): THREAD_NAME = "Instana Span Reporting" - registered_spans = ("aiohttp-client", "aiohttp-server", "aws.lambda.entry", "cassandra", "couchbase", - "django", "log","memcache", "mongo", "mysql", "postgres", "rabbitmq", "redis", "render", + + REGISTERED_SPANS = ("aiohttp-client", "aiohttp-server", "aws.lambda.entry", "cassandra", "couchbase", + "django", "log","memcache", "mongo", "mysql", "postgres", "pymongo", "rabbitmq", "redis", "render", "rpc-client", "rpc-server", "sqlalchemy", "soap", "tornado-client", "tornado-server", "urllib3", "wsgi") - http_spans = ("aiohttp-client", "aiohttp-server", "django", "http", "soap", "tornado-client", - "tornado-server", "urllib3", "wsgi") - - exit_spans = ("aiohttp-client", "cassandra", "couchbase", "log", "memcache", "mongo", "mysql", "postgres", - "rabbitmq", "redis", "rpc-client", "sqlalchemy", "soap", "tornado-client", "urllib3", - "pymongo") - - entry_spans = ("aiohttp-server", "aws.lambda.entry", "django", "wsgi", "rabbitmq", "rpc-server", "tornado-server") - - local_spans = ("render") - - entry_kind = ["entry", "server", "consumer"] - exit_kind = ["exit", "client", "producer"] - # Recorder thread for collection/reporting of spans thread = None @@ -114,168 +99,19 @@ def clear_spans(self): def record_span(self, span): """ - Convert the passed BasicSpan into an JsonSpan and - add it to the span queue + Convert the passed BasicSpan into and add it to the span queue """ if instana.singletons.agent.can_send() or "INSTANA_TEST" in os.environ: - json_span = None + source = instana.singletons.agent.get_from_structure() - if span.operation_name in self.registered_spans: - json_span = self.build_registered_span(span) + if span.operation_name in self.REGISTERED_SPANS: + json_span = RegisteredSpan(span, source) else: - json_span = self.build_sdk_span(span) - - # logger.debug("Recorded span: %s", json_span) + service_name = instana.singletons.agent.options.service_name + json_span = SDKSpan(span, source, service_name) self.queue.put(json_span) - def build_registered_span(self, span): - """ Takes a BasicSpan and converts it into a registered JsonSpan """ - data = Data() - - kind = 1 - if span.operation_name in self.entry_spans: - # entry - self._populate_entry_span_data(span, data) - elif span.operation_name in self.exit_spans: - kind = 2 # exit - self._populate_exit_span_data(span, data) - elif span.operation_name in self.local_spans: - kind = 3 # intermediate span - self._populate_local_span_data(span, data) - - if data.rabbitmq and data.rabbitmq.sort == 'consume': - kind = 1 # entry - - return JsonSpan(span, kind, data, instana.singletons.agent) - - def _populate_entry_span_data(self, span, data): - if span.operation_name in self.http_spans: - data.http = HttpData(span) - if span.operation_name == "soap": - data.soap = SoapData(span) - elif span.operation_name == "aws.lambda.entry": - data.aws_lambda = AWSLambdaData(span) - elif span.operation_name == "rabbitmq": - data.rabbitmq = RabbitmqData(span) - elif span.operation_name == "rpc-server": - data.rpc = RPCData(span) - else: - logger.debug("SpanRecorder: Unknown entry span: %s" % span.operation_name) - - def _populate_local_span_data(self, span, data): - if span.operation_name == "render": - data.render = RenderData(span) - data.log = LogData(span) - else: - logger.debug("SpanRecorder: Unknown local span: %s" % span.operation_name) - - def _populate_exit_span_data(self, span, data): - if span.operation_name in self.http_spans: - data.http = HttpData(span) - if span.operation_name == "soap": - data.soap = SoapData(span) - - elif span.operation_name == "rabbitmq": - data.rabbitmq = RabbitmqData(span) - - elif span.operation_name == "cassandra": - data.cassandra = CassandraData(span) - - elif span.operation_name == "couchbase": - data.couchbase = CouchbaseData(span) - - elif span.operation_name == "redis": - data.redis = RedisData(span) - - elif span.operation_name == "rpc-client": - data.rpc = RPCData(span) - - elif span.operation_name == "sqlalchemy": - data.sqlalchemy = SQLAlchemyData(span) - - elif span.operation_name == "mysql": - data.mysql = MySQLData(span) - if (data.custom is not None) and (data.custom.logs is not None) and len(data.custom.logs): - tskey = list(data.custom.logs.keys())[0] - data.mysql.error = data.custom.logs[tskey]['message'] - - elif span.operation_name == "postgres": - data.pg = PostgresData(span) - if (data.custom is not None) and (data.custom.logs is not None) and len(data.custom.logs): - tskey = list(data.custom.logs.keys())[0] - data.pg.error = data.custom.logs[tskey]['message'] - - elif span.operation_name == "mongo": - data.mongo = MongoDBData(span) - - elif span.operation_name == "log": - data.log = {} - # use last special key values - # TODO - logic might need a tweak here - for l in span.logs: - if "message" in l.key_values: - data.log["message"] = l.key_values.pop("message", None) - if "parameters" in l.key_values: - data.log["parameters"] = l.key_values.pop("parameters", None) - else: - logger.debug("SpanRecorder: Unknown exit span: %s" % span.operation_name) - - def build_sdk_span(self, span): - """ Takes a BasicSpan and converts into an SDK type JsonSpan """ - - custom_data = CustomData(tags=span.tags, - logs=span.collect_logs()) - - sdk_data = SDKData(name=span.operation_name, - custom=custom_data, - Type=self.get_span_kind_as_string(span)) - - if "arguments" in span.tags: - sdk_data.arguments = span.tags["arguments"] - - if "return" in span.tags: - sdk_data.Return = span.tags["return"] - - data = Data(service=instana.singletons.agent.options.service_name, sdk=sdk_data) - return JsonSpan(span, self.get_span_kind_as_int(span), data, instana.singletons.agent) - - def get_span_kind_as_string(self, span): - """ - Will retrieve the `span.kind` tag and return the appropriate string value for the Instana backend or - None if the tag is set to something we don't recognize. - - :param span: The span to search for the `span.kind` tag - :return: String - """ - kind = None - if "span.kind" in span.tags: - if span.tags["span.kind"] in self.entry_kind: - kind = "entry" - elif span.tags["span.kind"] in self.exit_kind: - kind = "exit" - else: - kind = "intermediate" - return kind - - def get_span_kind_as_int(self, span): - """ - Will retrieve the `span.kind` tag and return the appropriate integer value for the Instana backend or - None if the tag is set to something we don't recognize. - - :param span: The span to search for the `span.kind` tag - :return: Integer - """ - kind = None - if "span.kind" in span.tags: - if span.tags["span.kind"] in self.entry_kind: - kind = 1 - elif span.tags["span.kind"] in self.exit_kind: - kind = 2 - else: - kind = 3 - return kind - class AWSLambdaRecorder(InstanaRecorder): def __init__(self, agent): @@ -284,15 +120,15 @@ def __init__(self, agent): def record_span(self, span): """ - Convert the passed BasicSpan into an JsonSpan and - add it to the span queue + Convert the passed BasicSpan and add it to the span queue """ - json_span = None + source = instana.singletons.agent.get_from_structure() - if span.operation_name in self.registered_spans: - json_span = self.build_registered_span(span) + if span.operation_name in self.REGISTERED_SPANS: + json_span = RegisteredSpan(span, source) else: - json_span = self.build_sdk_span(span) + service_name = instana.singletons.agent.options.service_name + json_span = SDKSpan(span, source, service_name) logger.debug("Recorded span: %s", json_span) self.agent.collector.span_queue.put(json_span) diff --git a/instana/span.py b/instana/span.py index b53e44bd..3f4c4de3 100644 --- a/instana/span.py +++ b/instana/span.py @@ -10,6 +10,7 @@ def finish(self, finish_time=None): def log_exception(self, e): try: + logger.debug("Logging error for span %s" % self.operation_name) message = "" self.set_tag("error", True) @@ -23,9 +24,12 @@ def log_exception(self, e): if self.operation_name in ['rpc-server', 'rpc-client']: self.set_tag('rpc.error', message) - - self.log_kv({'message': message}) - + elif self.operation_name == "postgres": + self.set_tag('pg.error', message) + elif self.operation_name == "mysql": + self.set_tag('mysql.error', message) + else: + self.log_kv({'message': message}) except Exception: logger.debug("span.log_exception", exc_info=True) raise diff --git a/instana/tracer.py b/instana/tracer.py index 1254d899..3cb1a35b 100644 --- a/instana/tracer.py +++ b/instana/tracer.py @@ -15,6 +15,7 @@ from .recorder import InstanaRecorder, InstanaSampler from .span import InstanaSpan from .util import generate_id +from .json_span import RegisteredSpan class InstanaTracer(BasicTracer): @@ -102,10 +103,10 @@ def start_span(self, tags=tags, start_time=start_time) - if operation_name in self.recorder.exit_spans: + if operation_name in RegisteredSpan.EXIT_SPANS: self.__add_stack(span) - elif operation_name in self.recorder.entry_spans: + elif operation_name in RegisteredSpan.ENTRY_SPANS: # For entry spans, add only a backtrace fingerprint self.__add_stack(span, limit=2) diff --git a/instana/util.py b/instana/util.py index 9167cee6..d166e44f 100644 --- a/instana/util.py +++ b/instana/util.py @@ -8,7 +8,6 @@ import pkg_resources from collections import defaultdict - try: from urllib import parse except ImportError: @@ -17,7 +16,6 @@ from .log import logger - if sys.version_info.major == 2: string_types = basestring else: @@ -28,15 +26,8 @@ BAD_ID = "BADCAFFE" # Bad Caffe - # Simple implementation of a nested dictionary. -# -# Same as: -# stan_dictionary = lambda: defaultdict(stan_dictionary) -# but we use the function form because of PEP 8 -# -def stan_dictionary(): - return defaultdict(stan_dictionary) +DictionaryOfStan = lambda: defaultdict(DictionaryOfStan) def generate_id(): @@ -327,7 +318,7 @@ def determine_service_name(): try: # Now best effort in naming this process. No nice package.json like in Node.js # so we do best effort detection here. - app_name = "python" # the default name + app_name = "python" # the default name if not hasattr(sys, 'argv'): proc_cmdline = get_proc_cmdline(as_string=False) @@ -383,7 +374,3 @@ def determine_service_name(): except Exception as e: logger.debug("get_application_name: ", exc_info=True) return app_name - - - - diff --git a/tests/config/database/mysql/conf.d/mysql.cnf b/tests/config/database/mysql/conf.d/mysql.cnf index 4b6c05fa..7a2212ed 100644 --- a/tests/config/database/mysql/conf.d/mysql.cnf +++ b/tests/config/database/mysql/conf.d/mysql.cnf @@ -1,6 +1,8 @@ [mysqld] -bind-address = 0.0.0.0 +#bind-address = 0.0.0.0 +#skip-networking skip-host-cache skip-name-resolve character-set-server = utf8 collation-server = utf8_general_ci + diff --git a/tests/helpers.py b/tests/helpers.py index c6e7c418..57bda117 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -56,6 +56,7 @@ testenv['mongodb_user'] = os.environ.get('MONGO_USER', None) testenv['mongodb_pw'] = os.environ.get('MONGO_PW', None) + def get_first_span_by_name(spans, name): for span in spans: if span.n == name: diff --git a/tests/test_aiohttp.py b/tests/test_aiohttp.py index 16f29fee..ed8d62b0 100644 --- a/tests/test_aiohttp.py +++ b/tests/test_aiohttp.py @@ -65,9 +65,9 @@ async def test(): self.assertIsNone(wsgi_span.ec) self.assertEqual("aiohttp-client", aiohttp_span.n) - self.assertEqual(200, aiohttp_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) + self.assertEqual(200, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -121,9 +121,9 @@ async def test(): self.assertIsNone(wsgi_span2.ec) self.assertEqual("aiohttp-client", aiohttp_span.n) - self.assertEqual(200, aiohttp_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/301", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) + self.assertEqual(200, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/301", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -172,9 +172,9 @@ async def test(): self.assertIsNone(wsgi_span.ec) self.assertEqual("aiohttp-client", aiohttp_span.n) - self.assertEqual(405, aiohttp_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/405", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) + self.assertEqual(405, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/405", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -223,10 +223,10 @@ async def test(): self.assertEqual(wsgi_span.ec, 1) self.assertEqual("aiohttp-client", aiohttp_span.n) - self.assertEqual(500, aiohttp_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/500", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) - self.assertEqual('INTERNAL SERVER ERROR', aiohttp_span.data.http.error) + self.assertEqual(500, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/500", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) + self.assertEqual('INTERNAL SERVER ERROR', aiohttp_span.data["http"]["error"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -275,10 +275,10 @@ async def test(): self.assertEqual(wsgi_span.ec, 1) self.assertEqual("aiohttp-client", aiohttp_span.n) - self.assertEqual(504, aiohttp_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/504", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) - self.assertEqual('GATEWAY TIMEOUT', aiohttp_span.data.http.error) + self.assertEqual(504, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/504", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) + self.assertEqual('GATEWAY TIMEOUT', aiohttp_span.data["http"]["error"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -327,10 +327,10 @@ async def test(): self.assertIsNone(wsgi_span.ec) self.assertEqual("aiohttp-client", aiohttp_span.n) - self.assertEqual(200, aiohttp_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) - self.assertEqual("secret=", aiohttp_span.data.http.params) + self.assertEqual(200, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) + self.assertEqual("secret=", aiohttp_span.data["http"]["params"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -382,13 +382,13 @@ async def test(): self.assertIsNone(wsgi_span.ec) self.assertEqual("aiohttp-client", aiohttp_span.n) - self.assertEqual(200, aiohttp_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/response_headers", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) + self.assertEqual(200, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/response_headers", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) - self.assertTrue('http.X-Capture-This' in aiohttp_span.data.custom.tags) + self.assertTrue('http.X-Capture-This' in aiohttp_span.data["custom"]["tags"]) assert("X-Instana-T" in response.headers) self.assertEqual(response.headers["X-Instana-T"], traceId) @@ -401,7 +401,6 @@ async def test(): agent.extra_headers = original_extra_headers - def test_client_error(self): async def test(): with async_tracer.start_active_span('test'): @@ -436,11 +435,11 @@ async def test(): self.assertEqual(aiohttp_span.ec, 1) self.assertEqual("aiohttp-client", aiohttp_span.n) - self.assertIsNone(aiohttp_span.data.http.status) - self.assertEqual("http://doesnotexist:10/", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) - self.assertIsNotNone(aiohttp_span.data.http.error) - assert(len(aiohttp_span.data.http.error)) + self.assertIsNone(aiohttp_span.data["http"]["status"]) + self.assertEqual("http://doesnotexist:10/", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) + self.assertIsNotNone(aiohttp_span.data["http"]["error"]) + assert(len(aiohttp_span.data["http"]["error"])) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -482,17 +481,17 @@ async def test(): self.assertIsNone(aioserver_span.ec) self.assertEqual("aiohttp-server", aioserver_span.n) - self.assertEqual(200, aioserver_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/", aioserver_span.data.http.url) - self.assertEqual("GET", aioserver_span.data.http.method) + self.assertEqual(200, aioserver_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/", aioserver_span.data["http"]["url"]) + self.assertEqual("GET", aioserver_span.data["http"]["method"]) self.assertIsNotNone(aioserver_span.stack) self.assertTrue(type(aioserver_span.stack) is list) self.assertTrue(len(aioserver_span.stack) > 1) self.assertEqual("aiohttp-client", aioclient_span.n) - self.assertEqual(200, aioclient_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/", aioclient_span.data.http.url) - self.assertEqual("GET", aioclient_span.data.http.method) + self.assertEqual(200, aioclient_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/", aioclient_span.data["http"]["url"]) + self.assertEqual("GET", aioclient_span.data["http"]["method"]) self.assertIsNotNone(aioclient_span.stack) self.assertTrue(type(aioclient_span.stack) is list) self.assertTrue(len(aioclient_span.stack) > 1) @@ -541,19 +540,19 @@ async def test(): self.assertIsNone(aioserver_span.ec) self.assertEqual("aiohttp-server", aioserver_span.n) - self.assertEqual(200, aioserver_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/", aioserver_span.data.http.url) - self.assertEqual("GET", aioserver_span.data.http.method) - self.assertEqual("secret=", aioserver_span.data.http.params) + self.assertEqual(200, aioserver_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/", aioserver_span.data["http"]["url"]) + self.assertEqual("GET", aioserver_span.data["http"]["method"]) + self.assertEqual("secret=", aioserver_span.data["http"]["params"]) self.assertIsNotNone(aioserver_span.stack) self.assertTrue(type(aioserver_span.stack) is list) self.assertTrue(len(aioserver_span.stack) > 1) self.assertEqual("aiohttp-client", aioclient_span.n) - self.assertEqual(200, aioclient_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/", aioclient_span.data.http.url) - self.assertEqual("GET", aioclient_span.data.http.method) - self.assertEqual("secret=", aioclient_span.data.http.params) + self.assertEqual(200, aioclient_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/", aioclient_span.data["http"]["url"]) + self.assertEqual("GET", aioclient_span.data["http"]["method"]) + self.assertEqual("secret=", aioclient_span.data["http"]["params"]) self.assertIsNotNone(aioclient_span.stack) self.assertTrue(type(aioclient_span.stack) is list) self.assertTrue(len(aioclient_span.stack) > 1) @@ -609,19 +608,19 @@ async def test(): self.assertIsNone(aioserver_span.ec) self.assertEqual("aiohttp-server", aioserver_span.n) - self.assertEqual(200, aioserver_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/", aioserver_span.data.http.url) - self.assertEqual("GET", aioserver_span.data.http.method) - self.assertEqual("secret=", aioserver_span.data.http.params) + self.assertEqual(200, aioserver_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/", aioserver_span.data["http"]["url"]) + self.assertEqual("GET", aioserver_span.data["http"]["method"]) + self.assertEqual("secret=", aioserver_span.data["http"]["params"]) self.assertIsNotNone(aioserver_span.stack) self.assertTrue(type(aioserver_span.stack) is list) self.assertTrue(len(aioserver_span.stack) > 1) self.assertEqual("aiohttp-client", aioclient_span.n) - self.assertEqual(200, aioclient_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/", aioclient_span.data.http.url) - self.assertEqual("GET", aioclient_span.data.http.method) - self.assertEqual("secret=", aioclient_span.data.http.params) + self.assertEqual(200, aioclient_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/", aioclient_span.data["http"]["url"]) + self.assertEqual("GET", aioclient_span.data["http"]["method"]) + self.assertEqual("secret=", aioclient_span.data["http"]["params"]) self.assertIsNotNone(aioclient_span.stack) self.assertTrue(type(aioclient_span.stack) is list) self.assertTrue(len(aioclient_span.stack) > 1) @@ -635,10 +634,10 @@ async def test(): assert("Server-Timing" in response.headers) self.assertEqual(response.headers["Server-Timing"], "intid;desc=%s" % traceId) - assert("http.X-Capture-This" in aioserver_span.data.custom.tags) - self.assertEqual('this', aioserver_span.data.custom.tags['http.X-Capture-This']) - assert("http.X-Capture-That" in aioserver_span.data.custom.tags) - self.assertEqual('that', aioserver_span.data.custom.tags['http.X-Capture-That']) + assert("http.X-Capture-This" in aioserver_span.data["custom"]["tags"]) + self.assertEqual('this', aioserver_span.data["custom"]["tags"]['http.X-Capture-This']) + assert("http.X-Capture-That" in aioserver_span.data["custom"]["tags"]) + self.assertEqual('that', aioserver_span.data["custom"]["tags"]['http.X-Capture-That']) def test_server_get_401(self): async def test(): @@ -675,17 +674,17 @@ async def test(): self.assertIsNone(aioserver_span.ec) self.assertEqual("aiohttp-server", aioserver_span.n) - self.assertEqual(401, aioserver_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/401", aioserver_span.data.http.url) - self.assertEqual("GET", aioserver_span.data.http.method) + self.assertEqual(401, aioserver_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/401", aioserver_span.data["http"]["url"]) + self.assertEqual("GET", aioserver_span.data["http"]["method"]) self.assertIsNotNone(aioserver_span.stack) self.assertTrue(type(aioserver_span.stack) is list) self.assertTrue(len(aioserver_span.stack) > 1) self.assertEqual("aiohttp-client", aioclient_span.n) - self.assertEqual(401, aioclient_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/401", aioclient_span.data.http.url) - self.assertEqual("GET", aioclient_span.data.http.method) + self.assertEqual(401, aioclient_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/401", aioclient_span.data["http"]["url"]) + self.assertEqual("GET", aioclient_span.data["http"]["method"]) self.assertIsNotNone(aioclient_span.stack) self.assertTrue(type(aioclient_span.stack) is list) self.assertTrue(len(aioclient_span.stack) > 1) @@ -734,18 +733,18 @@ async def test(): self.assertEqual(aioserver_span.ec, 1) self.assertEqual("aiohttp-server", aioserver_span.n) - self.assertEqual(500, aioserver_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/500", aioserver_span.data.http.url) - self.assertEqual("GET", aioserver_span.data.http.method) + self.assertEqual(500, aioserver_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/500", aioserver_span.data["http"]["url"]) + self.assertEqual("GET", aioserver_span.data["http"]["method"]) self.assertIsNotNone(aioserver_span.stack) self.assertTrue(type(aioserver_span.stack) is list) self.assertTrue(len(aioserver_span.stack) > 1) self.assertEqual("aiohttp-client", aioclient_span.n) - self.assertEqual(500, aioclient_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/500", aioclient_span.data.http.url) - self.assertEqual("GET", aioclient_span.data.http.method) - self.assertEqual('I must simulate errors.', aioclient_span.data.http.error) + self.assertEqual(500, aioclient_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/500", aioclient_span.data["http"]["url"]) + self.assertEqual("GET", aioclient_span.data["http"]["method"]) + self.assertEqual('I must simulate errors.', aioclient_span.data["http"]["error"]) self.assertIsNotNone(aioclient_span.stack) self.assertTrue(type(aioclient_span.stack) is list) self.assertTrue(len(aioclient_span.stack) > 1) @@ -795,18 +794,18 @@ async def test(): self.assertEqual(aioserver_span.ec, 1) self.assertEqual("aiohttp-server", aioserver_span.n) - self.assertEqual(500, aioserver_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/exception", aioserver_span.data.http.url) - self.assertEqual("GET", aioserver_span.data.http.method) + self.assertEqual(500, aioserver_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/exception", aioserver_span.data["http"]["url"]) + self.assertEqual("GET", aioserver_span.data["http"]["method"]) self.assertIsNotNone(aioserver_span.stack) self.assertTrue(type(aioserver_span.stack) is list) self.assertTrue(len(aioserver_span.stack) > 1) self.assertEqual("aiohttp-client", aioclient_span.n) - self.assertEqual(500, aioclient_span.data.http.status) - self.assertEqual(testenv["aiohttp_server"] + "/exception", aioclient_span.data.http.url) - self.assertEqual("GET", aioclient_span.data.http.method) - self.assertEqual('Internal Server Error', aioclient_span.data.http.error) + self.assertEqual(500, aioclient_span.data["http"]["status"]) + self.assertEqual(testenv["aiohttp_server"] + "/exception", aioclient_span.data["http"]["url"]) + self.assertEqual("GET", aioclient_span.data["http"]["method"]) + self.assertEqual('Internal Server Error', aioclient_span.data["http"]["error"]) self.assertIsNotNone(aioclient_span.stack) self.assertTrue(type(aioclient_span.stack) is list) self.assertTrue(len(aioclient_span.stack) > 1) diff --git a/tests/test_asynqp.py b/tests/test_asynqp.py index 7f0fa4f2..c02bcaf2 100644 --- a/tests/test_asynqp.py +++ b/tests/test_asynqp.py @@ -91,10 +91,10 @@ def test(): self.assertIsNone(rabbitmq_span.ec) # Rabbitmq - self.assertEqual('test.exchange', rabbitmq_span.data.rabbitmq.exchange) - self.assertEqual('publish', rabbitmq_span.data.rabbitmq.sort) - self.assertIsNotNone(rabbitmq_span.data.rabbitmq.address) - self.assertEqual('routing.key', rabbitmq_span.data.rabbitmq.key) + self.assertEqual('test.exchange', rabbitmq_span.data["rabbitmq"]["exchange"]) + self.assertEqual('publish', rabbitmq_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(rabbitmq_span.data["rabbitmq"]["address"]) + self.assertEqual('routing.key', rabbitmq_span.data["rabbitmq"]["key"]) self.assertIsNotNone(rabbitmq_span.stack) self.assertTrue(type(rabbitmq_span.stack) is list) self.assertGreater(len(rabbitmq_span.stack), 0) @@ -129,10 +129,10 @@ def test(): self.assertIsNone(rabbitmq_span.ec) # Rabbitmq - self.assertEqual('test.exchange', rabbitmq_span.data.rabbitmq.exchange) - self.assertEqual('publish', rabbitmq_span.data.rabbitmq.sort) - self.assertIsNotNone(rabbitmq_span.data.rabbitmq.address) - self.assertEqual('routing.key', rabbitmq_span.data.rabbitmq.key) + self.assertEqual('test.exchange', rabbitmq_span.data["rabbitmq"]["exchange"]) + self.assertEqual('publish', rabbitmq_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(rabbitmq_span.data["rabbitmq"]["address"]) + self.assertEqual('routing.key', rabbitmq_span.data["rabbitmq"]["key"]) self.assertIsNotNone(rabbitmq_span.stack) self.assertTrue(type(rabbitmq_span.stack) is list) self.assertGreater(len(rabbitmq_span.stack), 0) @@ -201,16 +201,16 @@ def publish(): self.assertIsNone(get_span.ec) # Publish - self.assertEqual('publish', publish_span.data.rabbitmq.sort) - self.assertIsNotNone(publish_span.data.rabbitmq.address) + self.assertEqual('publish', publish_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(publish_span.data["rabbitmq"]["address"]) self.assertIsNotNone(publish_span.stack) self.assertTrue(type(publish_span.stack) is list) self.assertGreater(len(publish_span.stack), 0) # get - self.assertEqual('test.queue', get_span.data.rabbitmq.queue) - self.assertEqual('consume', get_span.data.rabbitmq.sort) - self.assertIsNotNone(get_span.data.rabbitmq.address) + self.assertEqual('test.queue', get_span.data["rabbitmq"]["queue"]) + self.assertEqual('consume', get_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(get_span.data["rabbitmq"]["address"]) self.assertIsNotNone(get_span.stack) self.assertTrue(type(get_span.stack) is list) self.assertGreater(len(get_span.stack), 0) @@ -250,19 +250,19 @@ def test(): self.assertEqual(consume_span.p, publish_span.s) # publish - self.assertEqual('test.exchange', publish_span.data.rabbitmq.exchange) - self.assertEqual('publish', publish_span.data.rabbitmq.sort) - self.assertIsNotNone(publish_span.data.rabbitmq.address) - self.assertEqual('routing.key', publish_span.data.rabbitmq.key) + self.assertEqual('test.exchange', publish_span.data["rabbitmq"]["exchange"]) + self.assertEqual('publish', publish_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(publish_span.data["rabbitmq"]["address"]) + self.assertEqual('routing.key', publish_span.data["rabbitmq"]["key"]) self.assertIsNotNone(publish_span.stack) self.assertTrue(type(publish_span.stack) is list) self.assertGreater(len(publish_span.stack), 0) # consume - self.assertEqual('test.exchange', consume_span.data.rabbitmq.exchange) - self.assertEqual('consume', consume_span.data.rabbitmq.sort) - self.assertIsNotNone(consume_span.data.rabbitmq.address) - self.assertEqual('routing.key', consume_span.data.rabbitmq.key) + self.assertEqual('test.exchange', consume_span.data["rabbitmq"]["exchange"]) + self.assertEqual('consume', consume_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(consume_span.data["rabbitmq"]["address"]) + self.assertEqual('routing.key', consume_span.data["rabbitmq"]["key"]) self.assertIsNotNone(consume_span.stack) self.assertTrue(type(consume_span.stack) is list) self.assertGreater(len(consume_span.stack), 0) @@ -314,27 +314,27 @@ def test(): self.assertEqual(publish2_span.p, consume1_span.s) # publish - self.assertEqual('test.exchange', publish1_span.data.rabbitmq.exchange) - self.assertEqual('publish', publish1_span.data.rabbitmq.sort) - self.assertIsNotNone(publish1_span.data.rabbitmq.address) - self.assertEqual('routing.key', publish1_span.data.rabbitmq.key) + self.assertEqual('test.exchange', publish1_span.data["rabbitmq"]["exchange"]) + self.assertEqual('publish', publish1_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(publish1_span.data["rabbitmq"]["address"]) + self.assertEqual('routing.key', publish1_span.data["rabbitmq"]["key"]) self.assertIsNotNone(publish1_span.stack) self.assertTrue(type(publish1_span.stack) is list) self.assertGreater(len(publish1_span.stack), 0) - self.assertEqual('test.exchange', publish2_span.data.rabbitmq.exchange) - self.assertEqual('publish', publish2_span.data.rabbitmq.sort) - self.assertIsNotNone(publish2_span.data.rabbitmq.address) - self.assertEqual('another.key', publish2_span.data.rabbitmq.key) + self.assertEqual('test.exchange', publish2_span.data["rabbitmq"]["exchange"]) + self.assertEqual('publish', publish2_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(publish2_span.data["rabbitmq"]["address"]) + self.assertEqual('another.key', publish2_span.data["rabbitmq"]["key"]) self.assertIsNotNone(publish2_span.stack) self.assertTrue(type(publish2_span.stack) is list) self.assertGreater(len(publish2_span.stack), 0) # consume - self.assertEqual('test.exchange', consume1_span.data.rabbitmq.exchange) - self.assertEqual('consume', consume1_span.data.rabbitmq.sort) - self.assertIsNotNone(consume1_span.data.rabbitmq.address) - self.assertEqual('routing.key', consume1_span.data.rabbitmq.key) + self.assertEqual('test.exchange', consume1_span.data["rabbitmq"]["exchange"]) + self.assertEqual('consume', consume1_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(consume1_span.data["rabbitmq"]["address"]) + self.assertEqual('routing.key', consume1_span.data["rabbitmq"]["key"]) self.assertIsNotNone(consume1_span.stack) self.assertTrue(type(consume1_span.stack) is list) self.assertGreater(len(consume1_span.stack), 0) @@ -409,19 +409,19 @@ def test(): self.assertEqual(wsgi_span.p, aioclient_span.s) # publish - self.assertEqual('test.exchange', publish_span.data.rabbitmq.exchange) - self.assertEqual('publish', publish_span.data.rabbitmq.sort) - self.assertIsNotNone(publish_span.data.rabbitmq.address) - self.assertEqual('routing.key', publish_span.data.rabbitmq.key) + self.assertEqual('test.exchange', publish_span.data["rabbitmq"]["exchange"]) + self.assertEqual('publish', publish_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(publish_span.data["rabbitmq"]["address"]) + self.assertEqual('routing.key', publish_span.data["rabbitmq"]["key"]) self.assertIsNotNone(publish_span.stack) self.assertTrue(type(publish_span.stack) is list) self.assertGreater(len(publish_span.stack), 0) # consume - self.assertEqual('test.exchange', consume_span.data.rabbitmq.exchange) - self.assertEqual('consume', consume_span.data.rabbitmq.sort) - self.assertIsNotNone(consume_span.data.rabbitmq.address) - self.assertEqual('routing.key', consume_span.data.rabbitmq.key) + self.assertEqual('test.exchange', consume_span.data["rabbitmq"]["exchange"]) + self.assertEqual('consume', consume_span.data["rabbitmq"]["sort"]) + self.assertIsNotNone(consume_span.data["rabbitmq"]["address"]) + self.assertEqual('routing.key', consume_span.data["rabbitmq"]["key"]) self.assertIsNotNone(consume_span.stack) self.assertTrue(type(consume_span.stack) is list) self.assertGreater(len(consume_span.stack), 0) diff --git a/tests/test_cassandra-driver.py b/tests/test_cassandra-driver.py index 5fd6da99..8ec8122c 100644 --- a/tests/test_cassandra-driver.py +++ b/tests/test_cassandra-driver.py @@ -73,7 +73,7 @@ def test_execute(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cspan = get_first_span_by_name(spans, 'cassandra') self.assertIsNotNone(cspan) @@ -107,7 +107,7 @@ def test_execute_async(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cspan = get_first_span_by_name(spans, 'cassandra') self.assertIsNotNone(cspan) @@ -145,7 +145,7 @@ def test_simple_statement(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cspan = get_first_span_by_name(spans, 'cassandra') self.assertIsNotNone(cspan) @@ -183,7 +183,7 @@ def test_execute_error(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cspan = get_first_span_by_name(spans, 'cassandra') self.assertIsNotNone(cspan) @@ -222,7 +222,7 @@ def test_prepared_statement(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cspan = get_first_span_by_name(spans, 'cassandra') self.assertIsNotNone(cspan) diff --git a/tests/test_couchbase.py b/tests/test_couchbase.py index ba3a6793..4440fd06 100644 --- a/tests/test_couchbase.py +++ b/tests/test_couchbase.py @@ -58,7 +58,7 @@ def test_upsert(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -71,9 +71,9 @@ def test_upsert(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'upsert') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'upsert') def test_upsert_multi(self): res = None @@ -94,7 +94,7 @@ def test_upsert_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -107,9 +107,9 @@ def test_upsert_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'upsert_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'upsert_multi') def test_insert_new(self): res = None @@ -129,7 +129,7 @@ def test_insert_new(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -142,9 +142,9 @@ def test_insert_new(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'insert') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'insert') def test_insert_existing(self): res = None @@ -166,7 +166,7 @@ def test_insert_existing(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -179,12 +179,12 @@ def test_insert_existing(self): self.assertTrue(cb_span.error) self.assertEqual(cb_span.ec, 1) # Just search for the substring of the exception class - found = cb_span.data.couchbase.error.find("_KeyExistsError") + found = cb_span.data["couchbase"]["error"].find("_KeyExistsError") self.assertFalse(found == -1, "Error substring not found.") - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'insert') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'insert') def test_insert_multi(self): res = None @@ -211,7 +211,7 @@ def test_insert_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -224,9 +224,9 @@ def test_insert_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'insert_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'insert_multi') def test_replace(self): res = None @@ -246,7 +246,7 @@ def test_replace(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -259,9 +259,9 @@ def test_replace(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'replace') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'replace') def test_replace_non_existent(self): res = None @@ -284,7 +284,7 @@ def test_replace_non_existent(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -297,12 +297,12 @@ def test_replace_non_existent(self): self.assertTrue(cb_span.error) self.assertEqual(cb_span.ec, 1) # Just search for the substring of the exception class - found = cb_span.data.couchbase.error.find("NotFoundError") + found = cb_span.data["couchbase"]["error"].find("NotFoundError") self.assertFalse(found == -1, "Error substring not found.") - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'replace') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'replace') def test_replace_multi(self): res = None @@ -326,7 +326,7 @@ def test_replace_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -339,9 +339,9 @@ def test_replace_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'replace_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'replace_multi') def test_append(self): self.bucket.upsert("test_append", "one") @@ -358,7 +358,7 @@ def test_append(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -371,9 +371,9 @@ def test_append(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'append') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'append') def test_append_multi(self): res = None @@ -397,7 +397,7 @@ def test_append_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -410,9 +410,9 @@ def test_append_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'append_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'append_multi') def test_prepend(self): self.bucket.upsert("test_prepend", "one") @@ -429,7 +429,7 @@ def test_prepend(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -442,9 +442,9 @@ def test_prepend(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'prepend') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'prepend') def test_prepend_multi(self): res = None @@ -468,7 +468,7 @@ def test_prepend_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -481,9 +481,9 @@ def test_prepend_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'prepend_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'prepend_multi') def test_get(self): res = None @@ -499,7 +499,7 @@ def test_get(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -512,9 +512,9 @@ def test_get(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'get') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'get') def test_rget(self): res = None @@ -532,7 +532,7 @@ def test_rget(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -545,12 +545,12 @@ def test_rget(self): self.assertTrue(cb_span.error) self.assertEqual(cb_span.ec, 1) # Just search for the substring of the exception class - found = cb_span.data.couchbase.error.find("CouchbaseTransientError") + found = cb_span.data["couchbase"]["error"].find("CouchbaseTransientError") self.assertFalse(found == -1, "Error substring not found.") - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'rget') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'rget') def test_get_not_found(self): res = None @@ -572,7 +572,7 @@ def test_get_not_found(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -585,12 +585,12 @@ def test_get_not_found(self): self.assertTrue(cb_span.error) self.assertEqual(cb_span.ec, 1) # Just search for the substring of the exception class - found = cb_span.data.couchbase.error.find("NotFoundError") + found = cb_span.data["couchbase"]["error"].find("NotFoundError") self.assertFalse(found == -1, "Error substring not found.") - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'get') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'get') def test_get_multi(self): res = None @@ -610,7 +610,7 @@ def test_get_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -623,9 +623,9 @@ def test_get_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'get_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'get_multi') def test_touch(self): res = None @@ -642,7 +642,7 @@ def test_touch(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -655,9 +655,9 @@ def test_touch(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'touch') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'touch') def test_touch_multi(self): res = None @@ -677,7 +677,7 @@ def test_touch_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -690,9 +690,9 @@ def test_touch_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'touch_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'touch_multi') def test_lock(self): res = None @@ -713,13 +713,13 @@ def test_lock(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') - filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "lock" + filter = lambda span: span.n == "couchbase" and span.data["couchbase"]["type"] == "lock" cb_lock_span = get_span_by_filter(spans, filter) self.assertIsNotNone(cb_lock_span) - filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "upsert" + filter = lambda span: span.n == "couchbase" and span.data["couchbase"]["type"] == "upsert" cb_upsert_span = get_span_by_filter(spans, filter) self.assertIsNotNone(cb_upsert_span) @@ -737,12 +737,12 @@ def test_lock(self): self.assertFalse(cb_upsert_span.error) self.assertIsNone(cb_upsert_span.ec) - self.assertEqual(cb_lock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_lock_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_lock_span.data.couchbase.type, 'lock') - self.assertEqual(cb_upsert_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_upsert_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_upsert_span.data.couchbase.type, 'upsert') + self.assertEqual(cb_lock_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_lock_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_lock_span.data["couchbase"]["type"], 'lock') + self.assertEqual(cb_upsert_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_upsert_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_upsert_span.data["couchbase"]["type"], 'upsert') def test_lock_unlock(self): res = None @@ -763,13 +763,13 @@ def test_lock_unlock(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') - filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "lock" + filter = lambda span: span.n == "couchbase" and span.data["couchbase"]["type"] == "lock" cb_lock_span = get_span_by_filter(spans, filter) self.assertIsNotNone(cb_lock_span) - filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "unlock" + filter = lambda span: span.n == "couchbase" and span.data["couchbase"]["type"] == "unlock" cb_unlock_span = get_span_by_filter(spans, filter) self.assertIsNotNone(cb_unlock_span) @@ -787,12 +787,12 @@ def test_lock_unlock(self): self.assertFalse(cb_unlock_span.error) self.assertIsNone(cb_unlock_span.ec) - self.assertEqual(cb_lock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_lock_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_lock_span.data.couchbase.type, 'lock') - self.assertEqual(cb_unlock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_unlock_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_unlock_span.data.couchbase.type, 'unlock') + self.assertEqual(cb_lock_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_lock_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_lock_span.data["couchbase"]["type"], 'lock') + self.assertEqual(cb_unlock_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_unlock_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_unlock_span.data["couchbase"]["type"], 'unlock') def test_lock_unlock_muilti(self): res = None @@ -815,13 +815,13 @@ def test_lock_unlock_muilti(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') - filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "lock_multi" + filter = lambda span: span.n == "couchbase" and span.data["couchbase"]["type"] == "lock_multi" cb_lock_span = get_span_by_filter(spans, filter) self.assertIsNotNone(cb_lock_span) - filter = lambda span: span.n == "couchbase" and span.data.couchbase.type == "unlock_multi" + filter = lambda span: span.n == "couchbase" and span.data["couchbase"]["type"] == "unlock_multi" cb_unlock_span = get_span_by_filter(spans, filter) self.assertIsNotNone(cb_unlock_span) @@ -839,12 +839,12 @@ def test_lock_unlock_muilti(self): self.assertFalse(cb_unlock_span.error) self.assertIsNone(cb_unlock_span.ec) - self.assertEqual(cb_lock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_lock_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_lock_span.data.couchbase.type, 'lock_multi') - self.assertEqual(cb_unlock_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_unlock_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_unlock_span.data.couchbase.type, 'unlock_multi') + self.assertEqual(cb_lock_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_lock_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_lock_span.data["couchbase"]["type"], 'lock_multi') + self.assertEqual(cb_unlock_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_unlock_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_unlock_span.data["couchbase"]["type"], 'unlock_multi') def test_remove(self): res = None @@ -861,7 +861,7 @@ def test_remove(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -874,9 +874,9 @@ def test_remove(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'remove') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'remove') def test_remove_multi(self): res = None @@ -897,7 +897,7 @@ def test_remove_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -910,9 +910,9 @@ def test_remove_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'remove_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'remove_multi') def test_counter(self): res = None @@ -929,7 +929,7 @@ def test_counter(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -942,9 +942,9 @@ def test_counter(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'counter') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'counter') def test_counter_multi(self): res = None @@ -963,7 +963,7 @@ def test_counter_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -976,9 +976,9 @@ def test_counter_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'counter_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'counter_multi') def test_mutate_in(self): res = None @@ -998,7 +998,7 @@ def test_mutate_in(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -1011,9 +1011,9 @@ def test_mutate_in(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'mutate_in') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'mutate_in') def test_lookup_in(self): res = None @@ -1033,7 +1033,7 @@ def test_lookup_in(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -1046,9 +1046,9 @@ def test_lookup_in(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'lookup_in') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'lookup_in') def test_stats(self): res = None @@ -1063,7 +1063,7 @@ def test_stats(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -1076,9 +1076,9 @@ def test_stats(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'stats') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'stats') def test_ping(self): res = None @@ -1093,7 +1093,7 @@ def test_ping(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -1106,9 +1106,9 @@ def test_ping(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'ping') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'ping') def test_diagnostics(self): res = None @@ -1123,7 +1123,7 @@ def test_diagnostics(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -1136,9 +1136,9 @@ def test_diagnostics(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'diagnostics') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'diagnostics') def test_observe(self): res = None @@ -1155,7 +1155,7 @@ def test_observe(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -1168,9 +1168,9 @@ def test_observe(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'observe') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'observe') def test_observe_multi(self): res = None @@ -1191,7 +1191,7 @@ def test_observe_multi(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -1204,9 +1204,9 @@ def test_observe_multi(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'observe_multi') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'observe_multi') def test_raw_n1ql_query(self): res = None @@ -1221,7 +1221,7 @@ def test_raw_n1ql_query(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -1234,10 +1234,10 @@ def test_raw_n1ql_query(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'n1ql_query') - self.assertEqual(cb_span.data.couchbase.sql, 'SELECT 1') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'n1ql_query') + self.assertEqual(cb_span.data["couchbase"]["sql"], 'SELECT 1') def test_n1ql_query(self): res = None @@ -1252,7 +1252,7 @@ def test_n1ql_query(self): test_span = get_first_span_by_name(spans, 'sdk') self.assertIsNotNone(test_span) - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') cb_span = get_first_span_by_name(spans, 'couchbase') self.assertIsNotNone(cb_span) @@ -1265,7 +1265,7 @@ def test_n1ql_query(self): self.assertFalse(cb_span.error) self.assertIsNone(cb_span.ec) - self.assertEqual(cb_span.data.couchbase.hostname, "%s:8091" % testenv['couchdb_host']) - self.assertEqual(cb_span.data.couchbase.bucket, 'travel-sample') - self.assertEqual(cb_span.data.couchbase.type, 'n1ql_query') - self.assertEqual(cb_span.data.couchbase.sql, 'SELECT name FROM `travel-sample` WHERE brewery_id ="mishawaka_brewing"') + self.assertEqual(cb_span.data["couchbase"]["hostname"], "%s:8091" % testenv['couchdb_host']) + self.assertEqual(cb_span.data["couchbase"]["bucket"], 'travel-sample') + self.assertEqual(cb_span.data["couchbase"]["type"], 'n1ql_query') + self.assertEqual(cb_span.data["couchbase"]["sql"], 'SELECT name FROM `travel-sample` WHERE brewery_id ="mishawaka_brewing"') diff --git a/tests/test_django.py b/tests/test_django.py index 6b264ed7..96f87d8b 100644 --- a/tests/test_django.py +++ b/tests/test_django.py @@ -52,7 +52,7 @@ def test_basic_request(self): assert ('Server-Timing' in response.headers) self.assertEqual(server_timing_value, response.headers['Server-Timing']) - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals("urllib3", urllib3_span.n) assert_equals("django", django_span.n) @@ -65,9 +65,9 @@ def test_basic_request(self): assert_equals(None, django_span.error) assert_equals(None, django_span.ec) - assert_equals('/', django_span.data.http.url) - assert_equals('GET', django_span.data.http.method) - assert_equals(200, django_span.data.http.status) + assert_equals('/', django_span.data["http"]["url"]) + assert_equals('GET', django_span.data["http"]["method"]) + assert_equals(200, django_span.data["http"]["status"]) assert django_span.stack assert_equals(2, len(django_span.stack)) @@ -101,7 +101,7 @@ def test_request_with_error(self): assert ('Server-Timing' in response.headers) self.assertEqual(server_timing_value, response.headers['Server-Timing']) - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals("urllib3", urllib3_span.n) assert_equals("django", django_span.n) assert_equals("log", log_span.n) @@ -117,10 +117,10 @@ def test_request_with_error(self): assert_equals(True, django_span.error) assert_equals(1, django_span.ec) - assert_equals('/cause_error', django_span.data.http.url) - assert_equals('GET', django_span.data.http.method) - assert_equals(500, django_span.data.http.status) - assert_equals('This is a fake error: /cause-error', django_span.data.http.error) + assert_equals('/cause_error', django_span.data["http"]["url"]) + assert_equals('GET', django_span.data["http"]["method"]) + assert_equals(500, django_span.data["http"]["status"]) + assert_equals('This is a fake error: /cause-error', django_span.data["http"]["error"]) assert(django_span.stack) assert_equals(2, len(django_span.stack)) @@ -154,7 +154,7 @@ def test_complex_request(self): assert ('Server-Timing' in response.headers) self.assertEqual(server_timing_value, response.headers['Server-Timing']) - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals("urllib3", urllib3_span.n) assert_equals("django", django_span.n) assert_equals("sdk", ot_span1.n) @@ -175,9 +175,9 @@ def test_complex_request(self): assert(django_span.stack) assert_equals(2, len(django_span.stack)) - assert_equals('/complex', django_span.data.http.url) - assert_equals('GET', django_span.data.http.method) - assert_equals(200, django_span.data.http.status) + assert_equals('/complex', django_span.data["http"]["url"]) + assert_equals('GET', django_span.data["http"]["method"]) + assert_equals(200, django_span.data["http"]["status"]) def test_custom_header_capture(self): # Hack together a manual custom headers list @@ -201,7 +201,7 @@ def test_custom_header_capture(self): urllib3_span = spans[1] django_span = spans[0] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals("urllib3", urllib3_span.n) assert_equals("django", django_span.n) @@ -216,14 +216,14 @@ def test_custom_header_capture(self): assert(django_span.stack) assert_equals(2, len(django_span.stack)) - assert_equals('/', django_span.data.http.url) - assert_equals('GET', django_span.data.http.method) - assert_equals(200, django_span.data.http.status) + assert_equals('/', django_span.data["http"]["url"]) + assert_equals('GET', django_span.data["http"]["method"]) + assert_equals(200, django_span.data["http"]["status"]) - assert_equals(True, "http.X-Capture-This" in django_span.data.custom.__dict__['tags']) - assert_equals("this", django_span.data.custom.__dict__['tags']["http.X-Capture-This"]) - assert_equals(True, "http.X-Capture-That" in django_span.data.custom.__dict__['tags']) - assert_equals("that", django_span.data.custom.__dict__['tags']["http.X-Capture-That"]) + assert_equals(True, "http.X-Capture-This" in django_span.data["custom"]['tags']) + assert_equals("this", django_span.data["custom"]['tags']["http.X-Capture-This"]) + assert_equals(True, "http.X-Capture-That" in django_span.data["custom"]['tags']) + assert_equals("that", django_span.data["custom"]['tags']["http.X-Capture-That"]) def test_with_incoming_context(self): request_headers = dict() diff --git a/tests/test_flask.py b/tests/test_flask.py index 66bdd932..1b7163a5 100644 --- a/tests/test_flask.py +++ b/tests/test_flask.py @@ -76,26 +76,26 @@ def test_get_request(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should NOT have a path template for this route - self.assertIsNone(wsgi_span.data.http.path_tpl) + self.assertIsNone(wsgi_span.data["http"]["path_tpl"]) def test_render_template(self): with tracer.start_active_span('test'): @@ -152,33 +152,33 @@ def test_render_template(self): # render self.assertEqual("render", render_span.n) self.assertEqual(3, render_span.k) - self.assertEqual('flask_render_template.html', render_span.data.render.name) - self.assertEqual('template', render_span.data.render.type) - self.assertIsNone(render_span.data.log.message) - self.assertIsNone(render_span.data.log.parameters) + self.assertEqual('flask_render_template.html', render_span.data["render"]["name"]) + self.assertEqual('template', render_span.data["render"]["type"]) + self.assertIsNone(render_span.data["log"]["message"]) + self.assertIsNone(render_span.data["log"]["parameters"]) # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/render', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/render', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/render', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/render', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should NOT have a path template for this route - self.assertIsNone(wsgi_span.data.http.path_tpl) + self.assertIsNone(wsgi_span.data["http"]["path_tpl"]) def test_render_template_string(self): with tracer.start_active_span('test'): @@ -235,33 +235,33 @@ def test_render_template_string(self): # render self.assertEqual("render", render_span.n) self.assertEqual(3, render_span.k) - self.assertEqual('(from string)', render_span.data.render.name) - self.assertEqual('template', render_span.data.render.type) - self.assertIsNone(render_span.data.log.message) - self.assertIsNone(render_span.data.log.parameters) + self.assertEqual('(from string)', render_span.data["render"]["name"]) + self.assertEqual('template', render_span.data["render"]["type"]) + self.assertIsNone(render_span.data["log"]["message"]) + self.assertIsNone(render_span.data["log"]["parameters"]) # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/render_string', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/render_string', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/render_string', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/render_string', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should NOT have a path template for this route - self.assertIsNone(wsgi_span.data.http.path_tpl) + self.assertIsNone(wsgi_span.data["http"]["path_tpl"]) def test_301(self): with tracer.start_active_span('test'): @@ -313,26 +313,26 @@ def test_301(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/301', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(301, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/301', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(301, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(301, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/301', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(301, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/301', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should NOT have a path template for this route - self.assertIsNone(wsgi_span.data.http.path_tpl) + self.assertIsNone(wsgi_span.data["http"]["path_tpl"]) def test_404(self): with tracer.start_active_span('test'): @@ -384,26 +384,26 @@ def test_404(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/11111111111', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(404, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/11111111111', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(404, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(404, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/11111111111', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(404, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/11111111111', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should NOT have a path template for this route - self.assertIsNone(wsgi_span.data.http.path_tpl) + self.assertIsNone(wsgi_span.data["http"]["path_tpl"]) def test_500(self): with tracer.start_active_span('test'): @@ -455,26 +455,26 @@ def test_500(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/500', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(500, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/500', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(500, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(500, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/500', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(500, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/500', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should NOT have a path template for this route - self.assertIsNone(wsgi_span.data.http.path_tpl) + self.assertIsNone(wsgi_span.data["http"]["path_tpl"]) def test_render_error(self): if signals_available is True: @@ -530,31 +530,31 @@ def test_render_error(self): # error log self.assertEqual("log", log_span.n) - self.assertEqual('Exception on /render_error [GET]', log_span.data.log['message']) - self.assertEqual(" unexpected '}'", log_span.data.log['parameters']) + self.assertEqual('Exception on /render_error [GET]', log_span.data["log"]['message']) + self.assertEqual(" unexpected '}'", log_span.data["log"]['parameters']) # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/render_error', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(500, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/render_error', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(500, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(500, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/render_error', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(500, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/render_error', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should NOT have a path template for this route - self.assertIsNone(wsgi_span.data.http.path_tpl) + self.assertIsNone(wsgi_span.data["http"]["path_tpl"]) def test_exception(self): if signals_available is True: @@ -598,35 +598,35 @@ def test_exception(self): # error log self.assertEqual("log", log_span.n) - self.assertEqual('Exception on /exception [GET]', log_span.data.log['message']) + self.assertEqual('Exception on /exception [GET]', log_span.data["log"]['message']) if sys.version_info < (3, 0): - self.assertEqual(" fake error", log_span.data.log['parameters']) + self.assertEqual(" fake error", log_span.data["log"]['parameters']) else: - self.assertEqual(" fake error", log_span.data.log['parameters']) + self.assertEqual(" fake error", log_span.data["log"]['parameters']) # wsgis self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/exception', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(500, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/exception', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(500, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(500, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/exception', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(500, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/exception', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should NOT have a path template for this route - self.assertIsNone(wsgi_span.data.http.path_tpl) + self.assertIsNone(wsgi_span.data["http"]["path_tpl"]) def test_custom_exception_with_log(self): with tracer.start_active_span('test'): @@ -681,31 +681,31 @@ def test_custom_exception_with_log(self): # error log self.assertEqual("log", log_span.n) - self.assertEqual('InvalidUsage error handler invoked', log_span.data.log['message']) - self.assertEqual(" ", log_span.data.log['parameters']) + self.assertEqual('InvalidUsage error handler invoked', log_span.data["log"]['message']) + self.assertEqual(" ", log_span.data["log"]['parameters']) # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/exception-invalid-usage', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(502, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/exception-invalid-usage', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(502, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(502, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/exception-invalid-usage', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(502, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/exception-invalid-usage', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should NOT have a path template for this route - self.assertIsNone(wsgi_span.data.http.path_tpl) + self.assertIsNone(wsgi_span.data["http"]["path_tpl"]) def test_path_templates(self): with tracer.start_active_span('test'): @@ -756,24 +756,24 @@ def test_path_templates(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/users/Ricky/sayhello', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/users/Ricky/sayhello', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + '/users/Ricky/sayhello', urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + '/users/Ricky/sayhello', urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) # We should have a reported path template for this route - self.assertEqual("/users/{username}/sayhello", wsgi_span.data.http.path_tpl) + self.assertEqual("/users/{username}/sayhello", wsgi_span.data["http"]["path_tpl"]) diff --git a/tests/test_grpcio.py b/tests/test_grpcio.py index 493c78fa..38a9ac63 100644 --- a/tests/test_grpcio.py +++ b/tests/test_grpcio.py @@ -89,26 +89,26 @@ def test_unary_one_to_one(self): self.assertEqual(server_span.k, 1) self.assertIsNotNone(server_span.stack) self.assertEqual(2, len(server_span.stack)) - self.assertEqual(server_span.data.rpc.flavor, 'grpc') - self.assertEqual(server_span.data.rpc.call, '/stan.Stan/OneQuestionOneResponse') - self.assertEqual(server_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(server_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertIsNone(server_span.data.rpc.error) + self.assertEqual(server_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(server_span.data["rpc"]["call"], '/stan.Stan/OneQuestionOneResponse') + self.assertEqual(server_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(server_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertIsNone(server_span.data["rpc"]["error"]) # rpc-client self.assertEqual(client_span.n, 'rpc-client') self.assertEqual(client_span.k, 2) self.assertIsNotNone(client_span.stack) - self.assertEqual(client_span.data.rpc.flavor, 'grpc') - self.assertEqual(client_span.data.rpc.call, '/stan.Stan/OneQuestionOneResponse') - self.assertEqual(client_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(client_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertEqual(client_span.data.rpc.call_type, 'unary') - self.assertIsNone(client_span.data.rpc.error) + self.assertEqual(client_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(client_span.data["rpc"]["call"], '/stan.Stan/OneQuestionOneResponse') + self.assertEqual(client_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(client_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertEqual(client_span.data["rpc"]["call_type"], 'unary') + self.assertIsNone(client_span.data["rpc"]["error"]) # test-span self.assertEqual(test_span.n, 'sdk') - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') def test_streaming_many_to_one(self): @@ -153,26 +153,26 @@ def test_streaming_many_to_one(self): self.assertEqual(server_span.k, 1) self.assertIsNotNone(server_span.stack) self.assertEqual(2, len(server_span.stack)) - self.assertEqual(server_span.data.rpc.flavor, 'grpc') - self.assertEqual(server_span.data.rpc.call, '/stan.Stan/ManyQuestionsOneResponse') - self.assertEqual(server_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(server_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertIsNone(server_span.data.rpc.error) + self.assertEqual(server_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(server_span.data["rpc"]["call"], '/stan.Stan/ManyQuestionsOneResponse') + self.assertEqual(server_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(server_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertIsNone(server_span.data["rpc"]["error"]) # rpc-client self.assertEqual(client_span.n, 'rpc-client') self.assertEqual(client_span.k, 2) self.assertIsNotNone(client_span.stack) - self.assertEqual(client_span.data.rpc.flavor, 'grpc') - self.assertEqual(client_span.data.rpc.call, '/stan.Stan/ManyQuestionsOneResponse') - self.assertEqual(client_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(client_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertEqual(client_span.data.rpc.call_type, 'stream') - self.assertIsNone(client_span.data.rpc.error) + self.assertEqual(client_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(client_span.data["rpc"]["call"], '/stan.Stan/ManyQuestionsOneResponse') + self.assertEqual(client_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(client_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertEqual(client_span.data["rpc"]["call_type"], 'stream') + self.assertIsNone(client_span.data["rpc"]["error"]) # test-span self.assertEqual(test_span.n, 'sdk') - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') def test_streaming_one_to_many(self): @@ -220,26 +220,26 @@ def test_streaming_one_to_many(self): self.assertEqual(server_span.k, 1) self.assertIsNotNone(server_span.stack) self.assertEqual(2, len(server_span.stack)) - self.assertEqual(server_span.data.rpc.flavor, 'grpc') - self.assertEqual(server_span.data.rpc.call, '/stan.Stan/OneQuestionManyResponses') - self.assertEqual(server_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(server_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertIsNone(server_span.data.rpc.error) + self.assertEqual(server_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(server_span.data["rpc"]["call"], '/stan.Stan/OneQuestionManyResponses') + self.assertEqual(server_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(server_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertIsNone(server_span.data["rpc"]["error"]) # rpc-client self.assertEqual(client_span.n, 'rpc-client') self.assertEqual(client_span.k, 2) self.assertIsNotNone(client_span.stack) - self.assertEqual(client_span.data.rpc.flavor, 'grpc') - self.assertEqual(client_span.data.rpc.call, '/stan.Stan/OneQuestionManyResponses') - self.assertEqual(client_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(client_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertEqual(client_span.data.rpc.call_type, 'stream') - self.assertIsNone(client_span.data.rpc.error) + self.assertEqual(client_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(client_span.data["rpc"]["call"], '/stan.Stan/OneQuestionManyResponses') + self.assertEqual(client_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(client_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertEqual(client_span.data["rpc"]["call_type"], 'stream') + self.assertIsNone(client_span.data["rpc"]["error"]) # test-span self.assertEqual(test_span.n, 'sdk') - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') def test_streaming_many_to_many(self): with tracer.start_active_span('test'): @@ -286,26 +286,26 @@ def test_streaming_many_to_many(self): self.assertEqual(server_span.k, 1) self.assertIsNotNone(server_span.stack) self.assertEqual(2, len(server_span.stack)) - self.assertEqual(server_span.data.rpc.flavor, 'grpc') - self.assertEqual(server_span.data.rpc.call, '/stan.Stan/ManyQuestionsManyReponses') - self.assertEqual(server_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(server_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertIsNone(server_span.data.rpc.error) + self.assertEqual(server_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(server_span.data["rpc"]["call"], '/stan.Stan/ManyQuestionsManyReponses') + self.assertEqual(server_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(server_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertIsNone(server_span.data["rpc"]["error"]) # rpc-client self.assertEqual(client_span.n, 'rpc-client') self.assertEqual(client_span.k, 2) self.assertIsNotNone(client_span.stack) - self.assertEqual(client_span.data.rpc.flavor, 'grpc') - self.assertEqual(client_span.data.rpc.call, '/stan.Stan/ManyQuestionsManyReponses') - self.assertEqual(client_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(client_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertEqual(client_span.data.rpc.call_type, 'stream') - self.assertIsNone(client_span.data.rpc.error) + self.assertEqual(client_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(client_span.data["rpc"]["call"], '/stan.Stan/ManyQuestionsManyReponses') + self.assertEqual(client_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(client_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertEqual(client_span.data["rpc"]["call_type"], 'stream') + self.assertIsNone(client_span.data["rpc"]["error"]) # test-span self.assertEqual(test_span.n, 'sdk') - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') def test_unary_one_to_one_with_call(self): with tracer.start_active_span('test'): @@ -348,26 +348,26 @@ def test_unary_one_to_one_with_call(self): self.assertEqual(server_span.k, 1) self.assertIsNotNone(server_span.stack) self.assertEqual(2, len(server_span.stack)) - self.assertEqual(server_span.data.rpc.flavor, 'grpc') - self.assertEqual(server_span.data.rpc.call, '/stan.Stan/OneQuestionOneResponse') - self.assertEqual(server_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(server_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertIsNone(server_span.data.rpc.error) + self.assertEqual(server_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(server_span.data["rpc"]["call"], '/stan.Stan/OneQuestionOneResponse') + self.assertEqual(server_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(server_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertIsNone(server_span.data["rpc"]["error"]) # rpc-client self.assertEqual(client_span.n, 'rpc-client') self.assertEqual(client_span.k, 2) self.assertIsNotNone(client_span.stack) - self.assertEqual(client_span.data.rpc.flavor, 'grpc') - self.assertEqual(client_span.data.rpc.call, '/stan.Stan/OneQuestionOneResponse') - self.assertEqual(client_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(client_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertEqual(client_span.data.rpc.call_type, 'unary') - self.assertIsNone(client_span.data.rpc.error) + self.assertEqual(client_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(client_span.data["rpc"]["call"], '/stan.Stan/OneQuestionOneResponse') + self.assertEqual(client_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(client_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertEqual(client_span.data["rpc"]["call_type"], 'unary') + self.assertIsNone(client_span.data["rpc"]["error"]) # test-span self.assertEqual(test_span.n, 'sdk') - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') def test_streaming_many_to_one_with_call(self): with tracer.start_active_span('test'): @@ -411,26 +411,26 @@ def test_streaming_many_to_one_with_call(self): self.assertEqual(server_span.k, 1) self.assertIsNotNone(server_span.stack) self.assertEqual(2, len(server_span.stack)) - self.assertEqual(server_span.data.rpc.flavor, 'grpc') - self.assertEqual(server_span.data.rpc.call, '/stan.Stan/ManyQuestionsOneResponse') - self.assertEqual(server_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(server_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertIsNone(server_span.data.rpc.error) + self.assertEqual(server_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(server_span.data["rpc"]["call"], '/stan.Stan/ManyQuestionsOneResponse') + self.assertEqual(server_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(server_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertIsNone(server_span.data["rpc"]["error"]) # rpc-client self.assertEqual(client_span.n, 'rpc-client') self.assertEqual(client_span.k, 2) self.assertIsNotNone(client_span.stack) - self.assertEqual(client_span.data.rpc.flavor, 'grpc') - self.assertEqual(client_span.data.rpc.call, '/stan.Stan/ManyQuestionsOneResponse') - self.assertEqual(client_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(client_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertEqual(client_span.data.rpc.call_type, 'stream') - self.assertIsNone(client_span.data.rpc.error) + self.assertEqual(client_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(client_span.data["rpc"]["call"], '/stan.Stan/ManyQuestionsOneResponse') + self.assertEqual(client_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(client_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertEqual(client_span.data["rpc"]["call_type"], 'stream') + self.assertIsNone(client_span.data["rpc"]["error"]) # test-span self.assertEqual(test_span.n, 'sdk') - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') def test_async_unary(self): def process_response(future): @@ -478,26 +478,26 @@ def process_response(future): self.assertEqual(server_span.k, 1) self.assertIsNotNone(server_span.stack) self.assertEqual(2, len(server_span.stack)) - self.assertEqual(server_span.data.rpc.flavor, 'grpc') - self.assertEqual(server_span.data.rpc.call, '/stan.Stan/OneQuestionOneResponse') - self.assertEqual(server_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(server_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertIsNone(server_span.data.rpc.error) + self.assertEqual(server_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(server_span.data["rpc"]["call"], '/stan.Stan/OneQuestionOneResponse') + self.assertEqual(server_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(server_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertIsNone(server_span.data["rpc"]["error"]) # rpc-client self.assertEqual(client_span.n, 'rpc-client') self.assertEqual(client_span.k, 2) self.assertIsNotNone(client_span.stack) - self.assertEqual(client_span.data.rpc.flavor, 'grpc') - self.assertEqual(client_span.data.rpc.call, '/stan.Stan/OneQuestionOneResponse') - self.assertEqual(client_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(client_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertEqual(client_span.data.rpc.call_type, 'unary') - self.assertIsNone(client_span.data.rpc.error) + self.assertEqual(client_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(client_span.data["rpc"]["call"], '/stan.Stan/OneQuestionOneResponse') + self.assertEqual(client_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(client_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertEqual(client_span.data["rpc"]["call_type"], 'unary') + self.assertIsNone(client_span.data["rpc"]["error"]) # test-span self.assertEqual(test_span.n, 'sdk') - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') def test_async_stream(self): def process_response(future): @@ -547,26 +547,26 @@ def process_response(future): self.assertEqual(server_span.k, 1) self.assertIsNotNone(server_span.stack) self.assertEqual(2, len(server_span.stack)) - self.assertEqual(server_span.data.rpc.flavor, 'grpc') - self.assertEqual(server_span.data.rpc.call, '/stan.Stan/ManyQuestionsOneResponse') - self.assertEqual(server_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(server_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertIsNone(server_span.data.rpc.error) + self.assertEqual(server_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(server_span.data["rpc"]["call"], '/stan.Stan/ManyQuestionsOneResponse') + self.assertEqual(server_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(server_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertIsNone(server_span.data["rpc"]["error"]) # rpc-client self.assertEqual(client_span.n, 'rpc-client') self.assertEqual(client_span.k, 2) self.assertIsNotNone(client_span.stack) - self.assertEqual(client_span.data.rpc.flavor, 'grpc') - self.assertEqual(client_span.data.rpc.call, '/stan.Stan/ManyQuestionsOneResponse') - self.assertEqual(client_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(client_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertEqual(client_span.data.rpc.call_type, 'stream') - self.assertIsNone(client_span.data.rpc.error) + self.assertEqual(client_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(client_span.data["rpc"]["call"], '/stan.Stan/ManyQuestionsOneResponse') + self.assertEqual(client_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(client_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertEqual(client_span.data["rpc"]["call_type"], 'stream') + self.assertIsNone(client_span.data["rpc"]["error"]) # test-span self.assertEqual(test_span.n, 'sdk') - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') def test_server_error(self): try: @@ -613,28 +613,28 @@ def test_server_error(self): self.assertEqual(server_span.k, 1) self.assertIsNotNone(server_span.stack) self.assertEqual(2, len(server_span.stack)) - self.assertEqual(server_span.data.rpc.flavor, 'grpc') - self.assertEqual(server_span.data.rpc.call, '/stan.Stan/OneQuestionOneErrorResponse') - self.assertEqual(server_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(server_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertIsNone(server_span.data.rpc.error) + self.assertEqual(server_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(server_span.data["rpc"]["call"], '/stan.Stan/OneQuestionOneErrorResponse') + self.assertEqual(server_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(server_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertIsNone(server_span.data["rpc"]["error"]) # rpc-client self.assertEqual(client_span.n, 'rpc-client') self.assertEqual(client_span.k, 2) self.assertIsNotNone(client_span.stack) - self.assertEqual(client_span.data.rpc.flavor, 'grpc') - self.assertEqual(client_span.data.rpc.call, '/stan.Stan/OneQuestionOneErrorResponse') - self.assertEqual(client_span.data.rpc.host, testenv["grpc_host"]) - self.assertEqual(client_span.data.rpc.port, str(testenv["grpc_port"])) - self.assertEqual(client_span.data.rpc.call_type, 'unary') - self.assertIsNotNone(client_span.data.rpc.error) + self.assertEqual(client_span.data["rpc"]["flavor"], 'grpc') + self.assertEqual(client_span.data["rpc"]["call"], '/stan.Stan/OneQuestionOneErrorResponse') + self.assertEqual(client_span.data["rpc"]["host"], testenv["grpc_host"]) + self.assertEqual(client_span.data["rpc"]["port"], str(testenv["grpc_port"])) + self.assertEqual(client_span.data["rpc"]["call_type"], 'unary') + self.assertIsNotNone(client_span.data["rpc"]["error"]) # log self.assertEqual(log_span.n, 'log') - self.assertIsNotNone(log_span.data.log) - self.assertEqual(log_span.data.log['message'], 'Exception calling application: Simulated error') + self.assertIsNotNone(log_span.data["log"]) + self.assertEqual(log_span.data["log"]['message'], 'Exception calling application: Simulated error') # test-span self.assertEqual(test_span.n, 'sdk') - self.assertEqual(test_span.data.sdk.name, 'test') + self.assertEqual(test_span.data["sdk"]["name"], 'test') diff --git a/tests/test_logging.py b/tests/test_logging.py index 0171e2b6..fb646a53 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -31,7 +31,7 @@ def test_extra_span(self): self.assertEqual(2, len(spans)) self.assertEqual(2, spans[0].k) - self.assertEqual('foo bar', spans[0].data.log.get('message')) + self.assertEqual('foo bar', spans[0].data["log"].get('message')) def test_log_with_tuple(self): with tracer.start_active_span('test'): @@ -41,7 +41,7 @@ def test_log_with_tuple(self): self.assertEqual(2, len(spans)) self.assertEqual(2, spans[0].k) - self.assertEqual("foo ('bar',)", spans[0].data.log.get('message')) + self.assertEqual("foo ('bar',)", spans[0].data["log"].get('message')) def test_parameters(self): with tracer.start_active_span('test'): @@ -55,5 +55,5 @@ def test_parameters(self): spans = self.recorder.queued_spans() self.assertEqual(2, len(spans)) - self.assertIsNotNone(spans[0].data.log.get('parameters')) + self.assertIsNotNone(spans[0].data["log"].get('parameters')) diff --git a/tests/test_mysql-python.py b/tests/test_mysql-python.py index 9b38bc9c..14a151b2 100644 --- a/tests/test_mysql-python.py +++ b/tests/test_mysql-python.py @@ -89,7 +89,7 @@ def test_basic_query(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -97,11 +97,11 @@ def test_basic_query(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'SELECT * from users') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'SELECT * from users') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_basic_insert(self): result = None @@ -118,7 +118,7 @@ def test_basic_insert(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -126,11 +126,11 @@ def test_basic_insert(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'INSERT INTO users(name, email) VALUES(%s, %s)') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'INSERT INTO users(name, email) VALUES(%s, %s)') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_executemany(self): result = None @@ -147,7 +147,7 @@ def test_executemany(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -155,11 +155,11 @@ def test_executemany(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'INSERT INTO users(name, email) VALUES(%s, %s)') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'INSERT INTO users(name, email) VALUES(%s, %s)') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_call_proc(self): result = None @@ -174,7 +174,7 @@ def test_call_proc(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -182,11 +182,11 @@ def test_call_proc(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'test_proc') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'test_proc') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_error_capture(self): result = None @@ -209,17 +209,17 @@ def test_error_capture(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) assert_equals(True, db_span.error) assert_equals(1, db_span.ec) - assert_equals(db_span.data.mysql.error, '(1146, "Table \'%s.blah\' doesn\'t exist")' % testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["error"], '(1146, "Table \'%s.blah\' doesn\'t exist")' % testenv['mysql_db']) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'SELECT * from blah') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'SELECT * from blah') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) diff --git a/tests/test_mysqlclient.py b/tests/test_mysqlclient.py index f9207073..7c292fd0 100644 --- a/tests/test_mysqlclient.py +++ b/tests/test_mysqlclient.py @@ -89,7 +89,7 @@ def test_basic_query(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -97,11 +97,11 @@ def test_basic_query(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'SELECT * from users') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'SELECT * from users') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_basic_insert(self): result = None @@ -118,7 +118,7 @@ def test_basic_insert(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -126,11 +126,11 @@ def test_basic_insert(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'INSERT INTO users(name, email) VALUES(%s, %s)') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'INSERT INTO users(name, email) VALUES(%s, %s)') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_executemany(self): result = None @@ -147,7 +147,7 @@ def test_executemany(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -155,11 +155,11 @@ def test_executemany(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'INSERT INTO users(name, email) VALUES(%s, %s)') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'INSERT INTO users(name, email) VALUES(%s, %s)') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_call_proc(self): result = None @@ -174,7 +174,7 @@ def test_call_proc(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -182,11 +182,11 @@ def test_call_proc(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'test_proc') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'test_proc') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_error_capture(self): result = None @@ -209,17 +209,17 @@ def test_error_capture(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) assert_equals(True, db_span.error) assert_equals(1, db_span.ec) - assert_equals(db_span.data.mysql.error, '(1146, "Table \'%s.blah\' doesn\'t exist")' % testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["error"], '(1146, "Table \'%s.blah\' doesn\'t exist")' % testenv['mysql_db']) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'SELECT * from blah') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'SELECT * from blah') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) diff --git a/tests/test_ot_span.py b/tests/test_ot_span.py index f4993cf3..651ac906 100644 --- a/tests/test_ot_span.py +++ b/tests/test_ot_span.py @@ -81,11 +81,11 @@ def test_sdk_spans(self): assert sdk_span.d > 0 assert sdk_span.data - assert sdk_span.data.sdk - assert_equals('entry', sdk_span.data.sdk.Type) - assert_equals('custom_sdk_span', sdk_span.data.sdk.name) - assert sdk_span.data.sdk.custom - assert sdk_span.data.sdk.custom.tags + assert sdk_span.data["sdk"] + assert_equals('entry', sdk_span.data["sdk"]["type"]) + assert_equals('custom_sdk_span', sdk_span.data["sdk"]["name"]) + assert sdk_span.data["sdk"]["custom"] + assert sdk_span.data["sdk"]["custom"]["tags"] def test_span_kind(self): recorder = opentracing.tracer.recorder @@ -114,19 +114,19 @@ def test_span_kind(self): assert 5, len(spans) span = spans[0] - assert_equals('entry', span.data.sdk.Type) + assert_equals('entry', span.data["sdk"]["type"]) span = spans[1] - assert_equals('entry', span.data.sdk.Type) + assert_equals('entry', span.data["sdk"]["type"]) span = spans[2] - assert_equals('exit', span.data.sdk.Type) + assert_equals('exit', span.data["sdk"]["type"]) span = spans[3] - assert_equals('exit', span.data.sdk.Type) + assert_equals('exit', span.data["sdk"]["type"]) span = spans[4] - assert_equals('intermediate', span.data.sdk.Type) + assert_equals('intermediate', span.data["sdk"]["type"]) span = spans[0] assert_equals(1, span.k) diff --git a/tests/test_psycopg2.py b/tests/test_psycopg2.py index c756e9c7..5096ffd6 100644 --- a/tests/test_psycopg2.py +++ b/tests/test_psycopg2.py @@ -88,7 +88,7 @@ def test_basic_query(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -96,11 +96,11 @@ def test_basic_query(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "postgres") - assert_equals(db_span.data.pg.db, testenv['postgresql_db']) - assert_equals(db_span.data.pg.user, testenv['postgresql_user']) - assert_equals(db_span.data.pg.stmt, 'SELECT * from users') - assert_equals(db_span.data.pg.host, testenv['postgresql_host']) - assert_equals(db_span.data.pg.port, testenv['postgresql_port']) + assert_equals(db_span.data["pg"]["db"], testenv['postgresql_db']) + assert_equals(db_span.data["pg"]["user"], testenv['postgresql_user']) + assert_equals(db_span.data["pg"]["stmt"], 'SELECT * from users') + assert_equals(db_span.data["pg"]["host"], testenv['postgresql_host']) + assert_equals(db_span.data["pg"]["port"], testenv['postgresql_port']) def test_basic_insert(self): with tracer.start_active_span('test'): @@ -112,7 +112,7 @@ def test_basic_insert(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -120,11 +120,11 @@ def test_basic_insert(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "postgres") - assert_equals(db_span.data.pg.db, testenv['postgresql_db']) - assert_equals(db_span.data.pg.user, testenv['postgresql_user']) - assert_equals(db_span.data.pg.stmt, 'INSERT INTO users(name, email) VALUES(%s, %s)') - assert_equals(db_span.data.pg.host, testenv['postgresql_host']) - assert_equals(db_span.data.pg.port, testenv['postgresql_port']) + assert_equals(db_span.data["pg"]["db"], testenv['postgresql_db']) + assert_equals(db_span.data["pg"]["user"], testenv['postgresql_user']) + assert_equals(db_span.data["pg"]["stmt"], 'INSERT INTO users(name, email) VALUES(%s, %s)') + assert_equals(db_span.data["pg"]["host"], testenv['postgresql_host']) + assert_equals(db_span.data["pg"]["port"], testenv['postgresql_port']) def test_executemany(self): result = None @@ -139,7 +139,7 @@ def test_executemany(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -147,11 +147,11 @@ def test_executemany(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "postgres") - assert_equals(db_span.data.pg.db, testenv['postgresql_db']) - assert_equals(db_span.data.pg.user, testenv['postgresql_user']) - assert_equals(db_span.data.pg.stmt, 'INSERT INTO users(name, email) VALUES(%s, %s)') - assert_equals(db_span.data.pg.host, testenv['postgresql_host']) - assert_equals(db_span.data.pg.port, testenv['postgresql_port']) + assert_equals(db_span.data["pg"]["db"], testenv['postgresql_db']) + assert_equals(db_span.data["pg"]["user"], testenv['postgresql_user']) + assert_equals(db_span.data["pg"]["stmt"], 'INSERT INTO users(name, email) VALUES(%s, %s)') + assert_equals(db_span.data["pg"]["host"], testenv['postgresql_host']) + assert_equals(db_span.data["pg"]["port"], testenv['postgresql_port']) def test_call_proc(self): result = None @@ -166,7 +166,7 @@ def test_call_proc(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -174,24 +174,20 @@ def test_call_proc(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "postgres") - assert_equals(db_span.data.pg.db, testenv['postgresql_db']) - assert_equals(db_span.data.pg.user, testenv['postgresql_user']) - assert_equals(db_span.data.pg.stmt, 'test_proc') - assert_equals(db_span.data.pg.host, testenv['postgresql_host']) - assert_equals(db_span.data.pg.port, testenv['postgresql_port']) + assert_equals(db_span.data["pg"]["db"], testenv['postgresql_db']) + assert_equals(db_span.data["pg"]["user"], testenv['postgresql_user']) + assert_equals(db_span.data["pg"]["stmt"], 'test_proc') + assert_equals(db_span.data["pg"]["host"], testenv['postgresql_host']) + assert_equals(db_span.data["pg"]["port"], testenv['postgresql_port']) def test_error_capture(self): result = None - span = None try: with tracer.start_active_span('test'): result = self.cursor.execute("""SELECT * from blah""") self.cursor.fetchone() except Exception: pass - finally: - if span: - span.finish() assert(result is None) @@ -201,20 +197,20 @@ def test_error_capture(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) assert_equals(True, db_span.error) assert_equals(1, db_span.ec) - assert_equals(db_span.data.pg.error, 'relation "blah" does not exist\nLINE 1: SELECT * from blah\n ^\n') + assert_equals(db_span.data["pg"]["error"], 'relation "blah" does not exist\nLINE 1: SELECT * from blah\n ^\n') assert_equals(db_span.n, "postgres") - assert_equals(db_span.data.pg.db, testenv['postgresql_db']) - assert_equals(db_span.data.pg.user, testenv['postgresql_user']) - assert_equals(db_span.data.pg.stmt, 'SELECT * from blah') - assert_equals(db_span.data.pg.host, testenv['postgresql_host']) - assert_equals(db_span.data.pg.port, testenv['postgresql_port']) + assert_equals(db_span.data["pg"]["db"], testenv['postgresql_db']) + assert_equals(db_span.data["pg"]["user"], testenv['postgresql_user']) + assert_equals(db_span.data["pg"]["stmt"], 'SELECT * from blah') + assert_equals(db_span.data["pg"]["host"], testenv['postgresql_host']) + assert_equals(db_span.data["pg"]["port"], testenv['postgresql_port']) # Added to validate unicode support and register_type. def test_unicode(self): diff --git a/tests/test_pymongo.py b/tests/test_pymongo.py index 5324f6f0..c34d29bc 100644 --- a/tests/test_pymongo.py +++ b/tests/test_pymongo.py @@ -8,13 +8,13 @@ from .helpers import testenv from instana.singletons import tracer -from instana.util import to_json import pymongo import bson logger = logging.getLogger(__name__) + class TestPyMongo: def setUp(self): logger.warn("Connecting to MongoDB mongo://%s:@%s:%s", @@ -49,12 +49,12 @@ def test_successful_find_query(self): assert_is_none(db_span.ec) assert_equals(db_span.n, "mongo") - assert_equals(db_span.data.mongo.service, "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) - assert_equals(db_span.data.mongo.namespace, "test.records") - assert_equals(db_span.data.mongo.command, "find") + assert_equals(db_span.data["mongo"]["service"], "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) + assert_equals(db_span.data["mongo"]["namespace"], "test.records") + assert_equals(db_span.data["mongo"]["command"], "find") - assert_equals(db_span.data.mongo.filter, '{"type": "string"}') - assert_is_none(db_span.data.mongo.json) + assert_equals(db_span.data["mongo"]["filter"], '{"type": "string"}') + assert_is_none(db_span.data["mongo"]["json"]) def test_successful_insert_query(self): with tracer.start_active_span("test"): @@ -75,11 +75,11 @@ def test_successful_insert_query(self): assert_is_none(db_span.ec) assert_equals(db_span.n, "mongo") - assert_equals(db_span.data.mongo.service, "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) - assert_equals(db_span.data.mongo.namespace, "test.records") - assert_equals(db_span.data.mongo.command, "insert") + assert_equals(db_span.data["mongo"]["service"], "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) + assert_equals(db_span.data["mongo"]["namespace"], "test.records") + assert_equals(db_span.data["mongo"]["command"], "insert") - assert_is_none(db_span.data.mongo.filter) + assert_is_none(db_span.data["mongo"]["filter"]) def test_successful_update_query(self): with tracer.start_active_span("test"): @@ -100,20 +100,20 @@ def test_successful_update_query(self): assert_is_none(db_span.ec) assert_equals(db_span.n, "mongo") - assert_equals(db_span.data.mongo.service, "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) - assert_equals(db_span.data.mongo.namespace, "test.records") - assert_equals(db_span.data.mongo.command, "update") + assert_equals(db_span.data["mongo"]["service"], "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) + assert_equals(db_span.data["mongo"]["namespace"], "test.records") + assert_equals(db_span.data["mongo"]["command"], "update") - assert_is_none(db_span.data.mongo.filter) - assert_is_not_none(db_span.data.mongo.json) + assert_is_none(db_span.data["mongo"]["filter"]) + assert_is_not_none(db_span.data["mongo"]["json"]) - payload = json.loads(db_span.data.mongo.json) + payload = json.loads(db_span.data["mongo"]["json"]) assert_true({ "q": {"type": "string"}, "u": {"$set": {"type": "int"}}, "multi": False, "upsert": False - } in payload, db_span.data.mongo.json) + } in payload, db_span.data["mongo"]["json"]) def test_successful_delete_query(self): with tracer.start_active_span("test"): @@ -134,15 +134,15 @@ def test_successful_delete_query(self): assert_is_none(db_span.ec) assert_equals(db_span.n, "mongo") - assert_equals(db_span.data.mongo.service, "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) - assert_equals(db_span.data.mongo.namespace, "test.records") - assert_equals(db_span.data.mongo.command, "delete") + assert_equals(db_span.data["mongo"]["service"], "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) + assert_equals(db_span.data["mongo"]["namespace"], "test.records") + assert_equals(db_span.data["mongo"]["command"], "delete") - assert_is_none(db_span.data.mongo.filter) - assert_is_not_none(db_span.data.mongo.json) + assert_is_none(db_span.data["mongo"]["filter"]) + assert_is_not_none(db_span.data["mongo"]["json"]) - payload = json.loads(db_span.data.mongo.json) - assert_true({"q": {"type": "string"}, "limit": 1} in payload, db_span.data.mongo.json) + payload = json.loads(db_span.data["mongo"]["json"]) + assert_true({"q": {"type": "string"}, "limit": 1} in payload, db_span.data["mongo"]["json"]) def test_successful_aggregate_query(self): with tracer.start_active_span("test"): @@ -163,15 +163,15 @@ def test_successful_aggregate_query(self): assert_is_none(db_span.ec) assert_equals(db_span.n, "mongo") - assert_equals(db_span.data.mongo.service, "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) - assert_equals(db_span.data.mongo.namespace, "test.records") - assert_equals(db_span.data.mongo.command, "aggregate") + assert_equals(db_span.data["mongo"]["service"], "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) + assert_equals(db_span.data["mongo"]["namespace"], "test.records") + assert_equals(db_span.data["mongo"]["command"], "aggregate") - assert_is_none(db_span.data.mongo.filter) - assert_is_not_none(db_span.data.mongo.json) + assert_is_none(db_span.data["mongo"]["filter"]) + assert_is_not_none(db_span.data["mongo"]["json"]) - payload = json.loads(db_span.data.mongo.json) - assert_true({"$match": {"type": "string"}} in payload, db_span.data.mongo.json) + payload = json.loads(db_span.data["mongo"]["json"]) + assert_true({"$match": {"type": "string"}} in payload, db_span.data["mongo"]["json"]) def test_successful_map_reduce_query(self): mapper = "function () { this.tags.forEach(function(z) { emit(z, 1); }); }" @@ -195,16 +195,16 @@ def test_successful_map_reduce_query(self): assert_is_none(db_span.ec) assert_equals(db_span.n, "mongo") - assert_equals(db_span.data.mongo.service, "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) - assert_equals(db_span.data.mongo.namespace, "test.records") - assert_equals(db_span.data.mongo.command.lower(), "mapreduce") # mapreduce command was renamed to mapReduce in pymongo 3.9.0 + assert_equals(db_span.data["mongo"]["service"], "%s:%s" % (testenv['mongodb_host'], testenv['mongodb_port'])) + assert_equals(db_span.data["mongo"]["namespace"], "test.records") + assert_equals(db_span.data["mongo"]["command"].lower(), "mapreduce") # mapreduce command was renamed to mapReduce in pymongo 3.9.0 - assert_equals(db_span.data.mongo.filter, '{"x": {"$lt": 2}}') - assert_is_not_none(db_span.data.mongo.json) + assert_equals(db_span.data["mongo"]["filter"], '{"x": {"$lt": 2}}') + assert_is_not_none(db_span.data["mongo"]["json"]) - payload = json.loads(db_span.data.mongo.json) - assert_equals(payload["map"], {"$code": mapper}, db_span.data.mongo.json) - assert_equals(payload["reduce"], {"$code": reducer}, db_span.data.mongo.json) + payload = json.loads(db_span.data["mongo"]["json"]) + assert_equals(payload["map"], {"$code": mapper}, db_span.data["mongo"]["json"]) + assert_equals(payload["reduce"], {"$code": reducer}, db_span.data["mongo"]["json"]) def test_successful_mutiple_queries(self): with tracer.start_active_span("test"): @@ -229,7 +229,7 @@ def test_successful_mutiple_queries(self): assert_false(span.s in seen_span_ids) seen_span_ids.add(span.s) - commands.append(span.data.mongo.command) + commands.append(span.data["mongo"]["command"]) # ensure spans are ordered the same way as commands assert_list_equal(commands, ["insert", "update", "delete"]) diff --git a/tests/test_pymysql.py b/tests/test_pymysql.py index 0443919e..d291823a 100644 --- a/tests/test_pymysql.py +++ b/tests/test_pymysql.py @@ -85,7 +85,7 @@ def test_basic_query(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -93,11 +93,11 @@ def test_basic_query(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'SELECT * from users') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'SELECT * from users') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_query_with_params(self): result = None @@ -113,7 +113,7 @@ def test_query_with_params(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -121,11 +121,11 @@ def test_query_with_params(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'SELECT * from users where id=?') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'SELECT * from users where id=?') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_basic_insert(self): result = None @@ -142,7 +142,7 @@ def test_basic_insert(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -150,11 +150,11 @@ def test_basic_insert(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'INSERT INTO users(name, email) VALUES(%s, %s)') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'INSERT INTO users(name, email) VALUES(%s, %s)') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_executemany(self): result = None @@ -171,7 +171,7 @@ def test_executemany(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -179,11 +179,11 @@ def test_executemany(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'INSERT INTO users(name, email) VALUES(%s, %s)') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'INSERT INTO users(name, email) VALUES(%s, %s)') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_call_proc(self): result = None @@ -198,7 +198,7 @@ def test_call_proc(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) @@ -206,11 +206,11 @@ def test_call_proc(self): assert_equals(None, db_span.ec) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'test_proc') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'test_proc') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) def test_error_capture(self): result = None @@ -233,23 +233,22 @@ def test_error_capture(self): db_span = spans[0] test_span = spans[1] - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, db_span.t) assert_equals(db_span.p, test_span.s) - assert_equals(True, db_span.error) assert_equals(1, db_span.ec) if sys.version_info[0] >= 3: # Python 3 - assert_equals(db_span.data.mysql.error, u'(1146, "Table \'%s.blah\' doesn\'t exist")' % testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["error"], u'(1146, "Table \'%s.blah\' doesn\'t exist")' % testenv['mysql_db']) else: # Python 2 - assert_equals(db_span.data.mysql.error, u'(1146, u"Table \'%s.blah\' doesn\'t exist")' % testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["error"], u'(1146, u"Table \'%s.blah\' doesn\'t exist")' % testenv['mysql_db']) assert_equals(db_span.n, "mysql") - assert_equals(db_span.data.mysql.db, testenv['mysql_db']) - assert_equals(db_span.data.mysql.user, testenv['mysql_user']) - assert_equals(db_span.data.mysql.stmt, 'SELECT * from blah') - assert_equals(db_span.data.mysql.host, testenv['mysql_host']) - assert_equals(db_span.data.mysql.port, testenv['mysql_port']) + assert_equals(db_span.data["mysql"]["db"], testenv['mysql_db']) + assert_equals(db_span.data["mysql"]["user"], testenv['mysql_user']) + assert_equals(db_span.data["mysql"]["stmt"], 'SELECT * from blah') + assert_equals(db_span.data["mysql"]["host"], testenv['mysql_host']) + assert_equals(db_span.data["mysql"]["port"], testenv['mysql_port']) diff --git a/tests/test_redis.py b/tests/test_redis.py index 746e9283..7ec3a24e 100644 --- a/tests/test_redis.py +++ b/tests/test_redis.py @@ -69,13 +69,13 @@ def test_set_get(self): # Redis span 1 self.assertEqual('redis', rs1_span.n) - self.assertFalse('custom' in rs1_span.data.__dict__) - self.assertTrue('redis' in rs1_span.data.__dict__) + self.assertFalse('custom' in rs1_span.data) + self.assertTrue('redis' in rs1_span.data) - self.assertEqual('redis-py', rs1_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs1_span.data.redis.connection) - self.assertEqual("SET", rs1_span.data.redis.command) - self.assertIsNone(rs1_span.data.redis.error) + self.assertEqual('redis-py', rs1_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs1_span.data["redis"]["connection"]) + self.assertEqual("SET", rs1_span.data["redis"]["command"]) + self.assertIsNone(rs1_span.data["redis"]["error"]) self.assertIsNotNone(rs1_span.stack) self.assertTrue(type(rs1_span.stack) is list) @@ -83,13 +83,13 @@ def test_set_get(self): # Redis span 2 self.assertEqual('redis', rs2_span.n) - self.assertFalse('custom' in rs2_span.data.__dict__) - self.assertTrue('redis' in rs2_span.data.__dict__) + self.assertFalse('custom' in rs2_span.data) + self.assertTrue('redis' in rs2_span.data) - self.assertEqual('redis-py', rs2_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs2_span.data.redis.connection) - self.assertEqual("SET", rs2_span.data.redis.command) - self.assertIsNone(rs2_span.data.redis.error) + self.assertEqual('redis-py', rs2_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs2_span.data["redis"]["connection"]) + self.assertEqual("SET", rs2_span.data["redis"]["command"]) + self.assertIsNone(rs2_span.data["redis"]["error"]) self.assertIsNotNone(rs2_span.stack) self.assertTrue(type(rs2_span.stack) is list) @@ -97,13 +97,13 @@ def test_set_get(self): # Redis span 3 self.assertEqual('redis', rs3_span.n) - self.assertFalse('custom' in rs3_span.data.__dict__) - self.assertTrue('redis' in rs3_span.data.__dict__) + self.assertFalse('custom' in rs3_span.data) + self.assertTrue('redis' in rs3_span.data) - self.assertEqual('redis-py', rs3_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs3_span.data.redis.connection) - self.assertEqual("GET", rs3_span.data.redis.command) - self.assertIsNone(rs3_span.data.redis.error) + self.assertEqual('redis-py', rs3_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs3_span.data["redis"]["connection"]) + self.assertEqual("GET", rs3_span.data["redis"]["command"]) + self.assertIsNone(rs3_span.data["redis"]["error"]) self.assertIsNotNone(rs3_span.stack) self.assertTrue(type(rs3_span.stack) is list) @@ -150,13 +150,13 @@ def test_set_incr_get(self): # Redis span 1 self.assertEqual('redis', rs1_span.n) - self.assertFalse('custom' in rs1_span.data.__dict__) - self.assertTrue('redis' in rs1_span.data.__dict__) + self.assertFalse('custom' in rs1_span.data) + self.assertTrue('redis' in rs1_span.data) - self.assertEqual('redis-py', rs1_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs1_span.data.redis.connection) - self.assertEqual("SET", rs1_span.data.redis.command) - self.assertIsNone(rs1_span.data.redis.error) + self.assertEqual('redis-py', rs1_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs1_span.data["redis"]["connection"]) + self.assertEqual("SET", rs1_span.data["redis"]["command"]) + self.assertIsNone(rs1_span.data["redis"]["error"]) self.assertIsNotNone(rs1_span.stack) self.assertTrue(type(rs1_span.stack) is list) @@ -164,13 +164,13 @@ def test_set_incr_get(self): # Redis span 2 self.assertEqual('redis', rs2_span.n) - self.assertFalse('custom' in rs2_span.data.__dict__) - self.assertTrue('redis' in rs2_span.data.__dict__) + self.assertFalse('custom' in rs2_span.data) + self.assertTrue('redis' in rs2_span.data) - self.assertEqual('redis-py', rs2_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs2_span.data.redis.connection) - self.assertEqual("INCRBY", rs2_span.data.redis.command) - self.assertIsNone(rs2_span.data.redis.error) + self.assertEqual('redis-py', rs2_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs2_span.data["redis"]["connection"]) + self.assertEqual("INCRBY", rs2_span.data["redis"]["command"]) + self.assertIsNone(rs2_span.data["redis"]["error"]) self.assertIsNotNone(rs2_span.stack) self.assertTrue(type(rs2_span.stack) is list) @@ -178,13 +178,13 @@ def test_set_incr_get(self): # Redis span 3 self.assertEqual('redis', rs3_span.n) - self.assertFalse('custom' in rs3_span.data.__dict__) - self.assertTrue('redis' in rs3_span.data.__dict__) + self.assertFalse('custom' in rs3_span.data) + self.assertTrue('redis' in rs3_span.data) - self.assertEqual('redis-py', rs3_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs3_span.data.redis.connection) - self.assertEqual("GET", rs3_span.data.redis.command) - self.assertIsNone(rs3_span.data.redis.error) + self.assertEqual('redis-py', rs3_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs3_span.data["redis"]["connection"]) + self.assertEqual("GET", rs3_span.data["redis"]["command"]) + self.assertIsNone(rs3_span.data["redis"]["error"]) self.assertIsNotNone(rs3_span.stack) self.assertTrue(type(rs3_span.stack) is list) @@ -231,13 +231,13 @@ def test_old_redis_client(self): # Redis span 1 self.assertEqual('redis', rs1_span.n) - self.assertFalse('custom' in rs1_span.data.__dict__) - self.assertTrue('redis' in rs1_span.data.__dict__) + self.assertFalse('custom' in rs1_span.data) + self.assertTrue('redis' in rs1_span.data) - self.assertEqual('redis-py', rs1_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs1_span.data.redis.connection) - self.assertEqual("SET", rs1_span.data.redis.command) - self.assertIsNone(rs1_span.data.redis.error) + self.assertEqual('redis-py', rs1_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs1_span.data["redis"]["connection"]) + self.assertEqual("SET", rs1_span.data["redis"]["command"]) + self.assertIsNone(rs1_span.data["redis"]["error"]) self.assertIsNotNone(rs1_span.stack) self.assertTrue(type(rs1_span.stack) is list) @@ -245,13 +245,13 @@ def test_old_redis_client(self): # Redis span 2 self.assertEqual('redis', rs2_span.n) - self.assertFalse('custom' in rs2_span.data.__dict__) - self.assertTrue('redis' in rs2_span.data.__dict__) + self.assertFalse('custom' in rs2_span.data) + self.assertTrue('redis' in rs2_span.data) - self.assertEqual('redis-py', rs2_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs2_span.data.redis.connection) - self.assertEqual("SET", rs2_span.data.redis.command) - self.assertIsNone(rs2_span.data.redis.error) + self.assertEqual('redis-py', rs2_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs2_span.data["redis"]["connection"]) + self.assertEqual("SET", rs2_span.data["redis"]["command"]) + self.assertIsNone(rs2_span.data["redis"]["error"]) self.assertIsNotNone(rs2_span.stack) self.assertTrue(type(rs2_span.stack) is list) @@ -259,13 +259,13 @@ def test_old_redis_client(self): # Redis span 3 self.assertEqual('redis', rs3_span.n) - self.assertFalse('custom' in rs3_span.data.__dict__) - self.assertTrue('redis' in rs3_span.data.__dict__) + self.assertFalse('custom' in rs3_span.data) + self.assertTrue('redis' in rs3_span.data) - self.assertEqual('redis-py', rs3_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs3_span.data.redis.connection) - self.assertEqual("GET", rs3_span.data.redis.command) - self.assertIsNone(rs3_span.data.redis.error) + self.assertEqual('redis-py', rs3_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs3_span.data["redis"]["connection"]) + self.assertEqual("GET", rs3_span.data["redis"]["command"]) + self.assertIsNone(rs3_span.data["redis"]["error"]) self.assertIsNotNone(rs3_span.stack) self.assertTrue(type(rs3_span.stack) is list) @@ -304,14 +304,14 @@ def test_pipelined_requests(self): # Redis span 1 self.assertEqual('redis', rs1_span.n) - self.assertFalse('custom' in rs1_span.data.__dict__) - self.assertTrue('redis' in rs1_span.data.__dict__) - - self.assertEqual('redis-py', rs1_span.data.redis.driver) - self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs1_span.data.redis.connection) - self.assertEqual("PIPELINE", rs1_span.data.redis.command) - self.assertEqual(['SET', 'SET', 'GET'], rs1_span.data.redis.subCommands) - self.assertIsNone(rs1_span.data.redis.error) + self.assertFalse('custom' in rs1_span.data) + self.assertTrue('redis' in rs1_span.data) + + self.assertEqual('redis-py', rs1_span.data["redis"]["driver"]) + self.assertEqual("redis://%s:6379/0" % testenv['redis_host'], rs1_span.data["redis"]["connection"]) + self.assertEqual("PIPELINE", rs1_span.data["redis"]["command"]) + self.assertEqual(['SET', 'SET', 'GET'], rs1_span.data["redis"]["subCommands"]) + self.assertIsNone(rs1_span.data["redis"]["error"]) self.assertIsNotNone(rs1_span.stack) self.assertTrue(type(rs1_span.stack) is list) diff --git a/tests/test_sqlalchemy.py b/tests/test_sqlalchemy.py index bc52cfa6..6318f9db 100644 --- a/tests/test_sqlalchemy.py +++ b/tests/test_sqlalchemy.py @@ -73,13 +73,13 @@ def test_session_add(self): # SQLAlchemy span self.assertEqual('sqlalchemy', sql_span.n) - self.assertFalse('custom' in sql_span.data.__dict__) - self.assertTrue('sqlalchemy' in sql_span.data.__dict__) + self.assertFalse('custom' in sql_span.data) + self.assertTrue('sqlalchemy' in sql_span.data) - self.assertEqual('postgresql', sql_span.data.sqlalchemy.eng) - self.assertEqual(sqlalchemy_url, sql_span.data.sqlalchemy.url) - self.assertEqual('INSERT INTO churchofstan (name, fullname, password) VALUES (%(name)s, %(fullname)s, %(password)s) RETURNING churchofstan.id', sql_span.data.sqlalchemy.sql) - self.assertIsNone(sql_span.data.sqlalchemy.err) + self.assertEqual('postgresql', sql_span.data["sqlalchemy"]["eng"]) + self.assertEqual(sqlalchemy_url, sql_span.data["sqlalchemy"]["url"]) + self.assertEqual('INSERT INTO churchofstan (name, fullname, password) VALUES (%(name)s, %(fullname)s, %(password)s) RETURNING churchofstan.id', sql_span.data["sqlalchemy"]["sql"]) + self.assertIsNone(sql_span.data["sqlalchemy"]["err"]) self.assertIsNotNone(sql_span.stack) self.assertTrue(type(sql_span.stack) is list) @@ -119,13 +119,13 @@ def test_transaction(self): # SQLAlchemy span0 self.assertEqual('sqlalchemy', sql_span0.n) - self.assertFalse('custom' in sql_span0.data.__dict__) - self.assertTrue('sqlalchemy' in sql_span0.data.__dict__) + self.assertFalse('custom' in sql_span0.data) + self.assertTrue('sqlalchemy' in sql_span0.data) - self.assertEqual('postgresql', sql_span0.data.sqlalchemy.eng) - self.assertEqual(sqlalchemy_url, sql_span0.data.sqlalchemy.url) - self.assertEqual('select 1', sql_span0.data.sqlalchemy.sql) - self.assertIsNone(sql_span0.data.sqlalchemy.err) + self.assertEqual('postgresql', sql_span0.data["sqlalchemy"]["eng"]) + self.assertEqual(sqlalchemy_url, sql_span0.data["sqlalchemy"]["url"]) + self.assertEqual('select 1', sql_span0.data["sqlalchemy"]["sql"]) + self.assertIsNone(sql_span0.data["sqlalchemy"]["err"]) self.assertIsNotNone(sql_span0.stack) self.assertTrue(type(sql_span0.stack) is list) @@ -133,25 +133,25 @@ def test_transaction(self): # SQLAlchemy span1 self.assertEqual('sqlalchemy', sql_span1.n) - self.assertFalse('custom' in sql_span1.data.__dict__) - self.assertTrue('sqlalchemy' in sql_span1.data.__dict__) + self.assertFalse('custom' in sql_span1.data) + self.assertTrue('sqlalchemy' in sql_span1.data) - self.assertEqual('postgresql', sql_span1.data.sqlalchemy.eng) - self.assertEqual(sqlalchemy_url, sql_span1.data.sqlalchemy.url) - self.assertEqual("select (name, fullname, password) from churchofstan where name='doesntexist'", sql_span1.data.sqlalchemy.sql) - self.assertIsNone(sql_span1.data.sqlalchemy.err) + self.assertEqual('postgresql', sql_span1.data["sqlalchemy"]["eng"]) + self.assertEqual(sqlalchemy_url, sql_span1.data["sqlalchemy"]["url"]) + self.assertEqual("select (name, fullname, password) from churchofstan where name='doesntexist'", sql_span1.data["sqlalchemy"]["sql"]) + self.assertIsNone(sql_span1.data["sqlalchemy"]["err"]) self.assertIsNotNone(sql_span1.stack) self.assertTrue(type(sql_span1.stack) is list) self.assertGreater(len(sql_span1.stack), 0) def test_error_logging(self): - try: - with tracer.start_active_span('test'): + with tracer.start_active_span('test'): + try: self.session.execute("htVwGrCwVThisIsInvalidSQLaw4ijXd88") self.session.commit() - except: - pass + except: + pass spans = self.recorder.queued_spans() self.assertEqual(2, len(spans)) @@ -176,13 +176,13 @@ def test_error_logging(self): # SQLAlchemy span self.assertEqual('sqlalchemy', sql_span.n) - self.assertFalse('custom' in sql_span.data.__dict__) - self.assertTrue('sqlalchemy' in sql_span.data.__dict__) + self.assertFalse('custom' in sql_span.data) + self.assertTrue('sqlalchemy' in sql_span.data) - self.assertEqual('postgresql', sql_span.data.sqlalchemy.eng) - self.assertEqual(sqlalchemy_url, sql_span.data.sqlalchemy.url) - self.assertEqual('htVwGrCwVThisIsInvalidSQLaw4ijXd88', sql_span.data.sqlalchemy.sql) - self.assertEqual('syntax error at or near "htVwGrCwVThisIsInvalidSQLaw4ijXd88"\nLINE 1: htVwGrCwVThisIsInvalidSQLaw4ijXd88\n ^\n', sql_span.data.sqlalchemy.err) + self.assertEqual('postgresql', sql_span.data["sqlalchemy"]["eng"]) + self.assertEqual(sqlalchemy_url, sql_span.data["sqlalchemy"]["url"]) + self.assertEqual('htVwGrCwVThisIsInvalidSQLaw4ijXd88', sql_span.data["sqlalchemy"]["sql"]) + self.assertEqual('syntax error at or near "htVwGrCwVThisIsInvalidSQLaw4ijXd88"\nLINE 1: htVwGrCwVThisIsInvalidSQLaw4ijXd88\n ^\n', sql_span.data["sqlalchemy"]["err"]) self.assertIsNotNone(sql_span.stack) self.assertTrue(type(sql_span.stack) is list) diff --git a/tests/test_sudsjurko.py b/tests/test_sudsjurko.py index 99bb6f5d..b42d9bbe 100644 --- a/tests/test_sudsjurko.py +++ b/tests/test_sudsjurko.py @@ -45,7 +45,7 @@ def test_basic_request(self): assert_equals(1, len(response[0])) assert(type(response[0]) is list) - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, soap_span.t) assert_equals(soap_span.p, test_span.s) assert_equals(wsgi_span.t, soap_span.t) @@ -54,8 +54,8 @@ def test_basic_request(self): assert_equals(None, soap_span.error) assert_equals(None, soap_span.ec) - assert_equals('ask_question', soap_span.data.soap.action) - assert_equals(testenv["soap_server"] + '/', soap_span.data.http.url) + assert_equals('ask_question', soap_span.data["soap"]["action"]) + assert_equals(testenv["soap_server"] + '/', soap_span.data["http"]["url"]) def test_server_exception(self): response = None @@ -75,7 +75,7 @@ def test_server_exception(self): test_span = spans[4] assert_equals(None, response) - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, soap_span.t) assert_equals(soap_span.p, test_span.s) assert_equals(wsgi_span.t, soap_span.t) @@ -83,16 +83,16 @@ def test_server_exception(self): assert_equals(True, soap_span.error) assert_equals(1, soap_span.ec) - assert('logs' in soap_span.data.custom.__dict__) - assert_equals(1, len(soap_span.data.custom.logs.keys())) + assert('logs' in soap_span.data["custom"]) + assert_equals(1, len(soap_span.data["custom"]["logs"].keys())) - tskey = list(soap_span.data.custom.logs.keys())[0] - assert('message' in soap_span.data.custom.logs[tskey]) + tskey = list(soap_span.data["custom"]["logs"].keys())[0] + assert('message' in soap_span.data["custom"]["logs"][tskey]) assert_equals(u"Server raised fault: 'Internal Error'", - soap_span.data.custom.logs[tskey]['message']) + soap_span.data["custom"]["logs"][tskey]['message']) - assert_equals('server_exception', soap_span.data.soap.action) - assert_equals(testenv["soap_server"] + '/', soap_span.data.http.url) + assert_equals('server_exception', soap_span.data["soap"]["action"]) + assert_equals(testenv["soap_server"] + '/', soap_span.data["http"]["url"]) def test_server_fault(self): response = None @@ -111,7 +111,7 @@ def test_server_fault(self): test_span = spans[4] assert_equals(None, response) - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, soap_span.t) assert_equals(soap_span.p, test_span.s) assert_equals(wsgi_span.t, soap_span.t) @@ -119,16 +119,16 @@ def test_server_fault(self): assert_equals(True, soap_span.error) assert_equals(1, soap_span.ec) - assert('logs' in soap_span.data.custom.__dict__) - assert_equals(1, len(soap_span.data.custom.logs.keys())) + assert('logs' in soap_span.data["custom"]) + assert_equals(1, len(soap_span.data["custom"]["logs"].keys())) - tskey = list(soap_span.data.custom.logs.keys())[0] - assert('message' in soap_span.data.custom.logs[tskey]) + tskey = list(soap_span.data["custom"]["logs"].keys())[0] + assert('message' in soap_span.data["custom"]["logs"][tskey]) assert_equals(u"Server raised fault: 'Server side fault example.'", - soap_span.data.custom.logs[tskey]['message']) + soap_span.data["custom"]["logs"][tskey]['message']) - assert_equals('server_fault', soap_span.data.soap.action) - assert_equals(testenv["soap_server"] + '/', soap_span.data.http.url) + assert_equals('server_fault', soap_span.data["soap"]["action"]) + assert_equals(testenv["soap_server"] + '/', soap_span.data["http"]["url"]) def test_client_fault(self): response = None @@ -148,7 +148,7 @@ def test_client_fault(self): test_span = spans[4] assert_equals(None, response) - assert_equals("test", test_span.data.sdk.name) + assert_equals("test", test_span.data["sdk"]["name"]) assert_equals(test_span.t, soap_span.t) assert_equals(soap_span.p, test_span.s) assert_equals(wsgi_span.t, soap_span.t) @@ -156,12 +156,12 @@ def test_client_fault(self): assert_equals(True, soap_span.error) assert_equals(1, soap_span.ec) - assert('logs' in soap_span.data.custom.__dict__) + assert('logs' in soap_span.data["custom"]) - tskey = list(soap_span.data.custom.logs.keys())[0] - assert('message' in soap_span.data.custom.logs[tskey]) + tskey = list(soap_span.data["custom"]["logs"].keys())[0] + assert('message' in soap_span.data["custom"]["logs"][tskey]) assert_equals(u"Server raised fault: 'Client side fault example'", - soap_span.data.custom.logs[tskey]['message']) + soap_span.data["custom"]["logs"][tskey]['message']) - assert_equals('client_fault', soap_span.data.soap.action) - assert_equals(testenv["soap_server"] + '/', soap_span.data.http.url) + assert_equals('client_fault', soap_span.data["soap"]["action"]) + assert_equals(testenv["soap_server"] + '/', soap_span.data["http"]["url"]) diff --git a/tests/test_tornado_client.py b/tests/test_tornado_client.py index c895dfa9..c67f3b53 100644 --- a/tests/test_tornado_client.py +++ b/tests/test_tornado_client.py @@ -67,18 +67,18 @@ async def test(): self.assertIsNone(server_span.ec) self.assertEqual("tornado-server", server_span.n) - self.assertEqual(200, server_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", server_span.data.http.url) - self.assertIsNone(server_span.data.http.params) - self.assertEqual("GET", server_span.data.http.method) + self.assertEqual(200, server_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", server_span.data["http"]["url"]) + self.assertIsNone(server_span.data["http"]["params"]) + self.assertEqual("GET", server_span.data["http"]["method"]) self.assertIsNotNone(server_span.stack) self.assertTrue(type(server_span.stack) is list) self.assertTrue(len(server_span.stack) > 1) self.assertEqual("tornado-client", client_span.n) - self.assertEqual(200, client_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", client_span.data.http.url) - self.assertEqual("GET", client_span.data.http.method) + self.assertEqual(200, client_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", client_span.data["http"]["url"]) + self.assertEqual("GET", client_span.data["http"]["method"]) self.assertIsNotNone(client_span.stack) self.assertTrue(type(client_span.stack) is list) self.assertTrue(len(client_span.stack) > 1) @@ -127,18 +127,18 @@ async def test(): self.assertIsNone(server_span.ec) self.assertEqual("tornado-server", server_span.n) - self.assertEqual(200, server_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", server_span.data.http.url) - self.assertIsNone(server_span.data.http.params) - self.assertEqual("POST", server_span.data.http.method) + self.assertEqual(200, server_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", server_span.data["http"]["url"]) + self.assertIsNone(server_span.data["http"]["params"]) + self.assertEqual("POST", server_span.data["http"]["method"]) self.assertIsNotNone(server_span.stack) self.assertTrue(type(server_span.stack) is list) self.assertTrue(len(server_span.stack) > 1) self.assertEqual("tornado-client", client_span.n) - self.assertEqual(200, client_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", client_span.data.http.url) - self.assertEqual("POST", client_span.data.http.method) + self.assertEqual(200, client_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", client_span.data["http"]["url"]) + self.assertEqual("POST", client_span.data["http"]["method"]) self.assertIsNotNone(client_span.stack) self.assertTrue(type(client_span.stack) is list) self.assertTrue(len(client_span.stack) > 1) @@ -191,27 +191,27 @@ async def test(): self.assertIsNone(server_span.ec) self.assertEqual("tornado-server", server_span.n) - self.assertEqual(200, server_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", server_span.data.http.url) - self.assertIsNone(server_span.data.http.params) - self.assertEqual("GET", server_span.data.http.method) + self.assertEqual(200, server_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", server_span.data["http"]["url"]) + self.assertIsNone(server_span.data["http"]["params"]) + self.assertEqual("GET", server_span.data["http"]["method"]) self.assertIsNotNone(server_span.stack) self.assertTrue(type(server_span.stack) is list) self.assertTrue(len(server_span.stack) > 1) self.assertEqual("tornado-server", server301_span.n) - self.assertEqual(301, server301_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/301", server301_span.data.http.url) - self.assertIsNone(server301_span.data.http.params) - self.assertEqual("GET", server301_span.data.http.method) + self.assertEqual(301, server301_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/301", server301_span.data["http"]["url"]) + self.assertIsNone(server301_span.data["http"]["params"]) + self.assertEqual("GET", server301_span.data["http"]["method"]) self.assertIsNotNone(server301_span.stack) self.assertTrue(type(server301_span.stack) is list) self.assertTrue(len(server301_span.stack) > 1) self.assertEqual("tornado-client", client_span.n) - self.assertEqual(200, client_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/301", client_span.data.http.url) - self.assertEqual("GET", client_span.data.http.method) + self.assertEqual(200, client_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/301", client_span.data["http"]["url"]) + self.assertEqual("GET", client_span.data["http"]["method"]) self.assertIsNotNone(client_span.stack) self.assertTrue(type(client_span.stack) is list) self.assertTrue(len(client_span.stack) > 1) @@ -263,18 +263,18 @@ async def test(): self.assertIsNone(server_span.ec) self.assertEqual("tornado-server", server_span.n) - self.assertEqual(405, server_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/405", server_span.data.http.url) - self.assertIsNone(server_span.data.http.params) - self.assertEqual("GET", server_span.data.http.method) + self.assertEqual(405, server_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/405", server_span.data["http"]["url"]) + self.assertIsNone(server_span.data["http"]["params"]) + self.assertEqual("GET", server_span.data["http"]["method"]) self.assertIsNotNone(server_span.stack) self.assertTrue(type(server_span.stack) is list) self.assertTrue(len(server_span.stack) > 1) self.assertEqual("tornado-client", client_span.n) - self.assertEqual(405, client_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/405", client_span.data.http.url) - self.assertEqual("GET", client_span.data.http.method) + self.assertEqual(405, client_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/405", client_span.data["http"]["url"]) + self.assertEqual("GET", client_span.data["http"]["method"]) self.assertIsNotNone(client_span.stack) self.assertTrue(type(client_span.stack) is list) self.assertTrue(len(client_span.stack) > 1) @@ -326,18 +326,18 @@ async def test(): self.assertEqual(server_span.ec, 1) self.assertEqual("tornado-server", server_span.n) - self.assertEqual(500, server_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/500", server_span.data.http.url) - self.assertIsNone(server_span.data.http.params) - self.assertEqual("GET", server_span.data.http.method) + self.assertEqual(500, server_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/500", server_span.data["http"]["url"]) + self.assertIsNone(server_span.data["http"]["params"]) + self.assertEqual("GET", server_span.data["http"]["method"]) self.assertIsNotNone(server_span.stack) self.assertTrue(type(server_span.stack) is list) self.assertTrue(len(server_span.stack) > 1) self.assertEqual("tornado-client", client_span.n) - self.assertEqual(500, client_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/500", client_span.data.http.url) - self.assertEqual("GET", client_span.data.http.method) + self.assertEqual(500, client_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/500", client_span.data["http"]["url"]) + self.assertEqual("GET", client_span.data["http"]["method"]) self.assertIsNotNone(client_span.stack) self.assertTrue(type(client_span.stack) is list) self.assertTrue(len(client_span.stack) > 1) @@ -389,18 +389,18 @@ async def test(): self.assertEqual(server_span.ec, 1) self.assertEqual("tornado-server", server_span.n) - self.assertEqual(504, server_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/504", server_span.data.http.url) - self.assertIsNone(server_span.data.http.params) - self.assertEqual("GET", server_span.data.http.method) + self.assertEqual(504, server_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/504", server_span.data["http"]["url"]) + self.assertIsNone(server_span.data["http"]["params"]) + self.assertEqual("GET", server_span.data["http"]["method"]) self.assertIsNotNone(server_span.stack) self.assertTrue(type(server_span.stack) is list) self.assertTrue(len(server_span.stack) > 1) self.assertEqual("tornado-client", client_span.n) - self.assertEqual(504, client_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/504", client_span.data.http.url) - self.assertEqual("GET", client_span.data.http.method) + self.assertEqual(504, client_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/504", client_span.data["http"]["url"]) + self.assertEqual("GET", client_span.data["http"]["method"]) self.assertIsNotNone(client_span.stack) self.assertTrue(type(client_span.stack) is list) self.assertTrue(len(client_span.stack) > 1) @@ -449,19 +449,19 @@ async def test(): self.assertIsNone(server_span.ec) self.assertEqual("tornado-server", server_span.n) - self.assertEqual(200, server_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", server_span.data.http.url) - self.assertEqual('secret=', server_span.data.http.params) - self.assertEqual("GET", server_span.data.http.method) + self.assertEqual(200, server_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", server_span.data["http"]["url"]) + self.assertEqual('secret=', server_span.data["http"]["params"]) + self.assertEqual("GET", server_span.data["http"]["method"]) self.assertIsNotNone(server_span.stack) self.assertTrue(type(server_span.stack) is list) self.assertTrue(len(server_span.stack) > 1) self.assertEqual("tornado-client", client_span.n) - self.assertEqual(200, client_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", client_span.data.http.url) - self.assertEqual('secret=', client_span.data.http.params) - self.assertEqual("GET", client_span.data.http.method) + self.assertEqual(200, client_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", client_span.data["http"]["url"]) + self.assertEqual('secret=', client_span.data["http"]["params"]) + self.assertEqual("GET", client_span.data["http"]["method"]) self.assertIsNotNone(client_span.stack) self.assertTrue(type(client_span.stack) is list) self.assertTrue(len(client_span.stack) > 1) diff --git a/tests/test_tornado_server.py b/tests/test_tornado_server.py index defcecfd..69c77658 100644 --- a/tests/test_tornado_server.py +++ b/tests/test_tornado_server.py @@ -80,17 +80,17 @@ async def test(): self.assertFalse(tornado_span.error) self.assertIsNone(tornado_span.ec) - self.assertEqual(200, tornado_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data.http.url) - self.assertIsNone(tornado_span.data.http.params) - self.assertEqual("GET", tornado_span.data.http.method) + self.assertEqual(200, tornado_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data["http"]["url"]) + self.assertIsNone(tornado_span.data["http"]["params"]) + self.assertEqual("GET", tornado_span.data["http"]["method"]) self.assertIsNotNone(tornado_span.stack) self.assertTrue(type(tornado_span.stack) is list) self.assertTrue(len(tornado_span.stack) > 1) - self.assertEqual(200, aiohttp_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) + self.assertEqual(200, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -146,17 +146,17 @@ async def test(): self.assertFalse(tornado_span.error) self.assertIsNone(tornado_span.ec) - self.assertEqual(200, tornado_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data.http.url) - self.assertIsNone(tornado_span.data.http.params) - self.assertEqual("POST", tornado_span.data.http.method) + self.assertEqual(200, tornado_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data["http"]["url"]) + self.assertIsNone(tornado_span.data["http"]["params"]) + self.assertEqual("POST", tornado_span.data["http"]["method"]) self.assertIsNotNone(tornado_span.stack) self.assertTrue(type(tornado_span.stack) is list) self.assertTrue(len(tornado_span.stack) > 1) - self.assertEqual(200, aiohttp_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", aiohttp_span.data.http.url) - self.assertEqual("POST", aiohttp_span.data.http.method) + self.assertEqual(200, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", aiohttp_span.data["http"]["url"]) + self.assertEqual("POST", aiohttp_span.data["http"]["method"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -181,9 +181,9 @@ async def test(): spans = self.recorder.queued_spans() self.assertEqual(4, len(spans)) - filter = lambda span: span.n == "tornado-server" and span.data.http.status == 301 + filter = lambda span: span.n == "tornado-server" and span.data["http"]["status"] == 301 tornado_301_span = get_span_by_filter(spans, filter) - filter = lambda span: span.n == "tornado-server" and span.data.http.status == 200 + filter = lambda span: span.n == "tornado-server" and span.data["http"]["status"] == 200 tornado_span = get_span_by_filter(spans, filter) aiohttp_span = get_first_span_by_name(spans, "aiohttp-client") test_span = get_first_span_by_name(spans, "sdk") @@ -221,24 +221,24 @@ async def test(): self.assertFalse(tornado_span.error) self.assertIsNone(tornado_span.ec) - self.assertEqual(301, tornado_301_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/301", tornado_301_span.data.http.url) - self.assertIsNone(tornado_span.data.http.params) - self.assertEqual("GET", tornado_301_span.data.http.method) + self.assertEqual(301, tornado_301_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/301", tornado_301_span.data["http"]["url"]) + self.assertIsNone(tornado_span.data["http"]["params"]) + self.assertEqual("GET", tornado_301_span.data["http"]["method"]) self.assertIsNotNone(tornado_301_span.stack) self.assertTrue(type(tornado_301_span.stack) is list) self.assertTrue(len(tornado_301_span.stack) > 1) - self.assertEqual(200, tornado_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data.http.url) - self.assertEqual("GET", tornado_span.data.http.method) + self.assertEqual(200, tornado_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data["http"]["url"]) + self.assertEqual("GET", tornado_span.data["http"]["method"]) self.assertIsNotNone(tornado_span.stack) self.assertTrue(type(tornado_span.stack) is list) self.assertTrue(len(tornado_span.stack) > 1) - self.assertEqual(200, aiohttp_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/301", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) + self.assertEqual(200, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/301", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -294,17 +294,17 @@ async def test(): self.assertFalse(tornado_span.error) self.assertIsNone(tornado_span.ec) - self.assertEqual(405, tornado_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/405", tornado_span.data.http.url) - self.assertIsNone(tornado_span.data.http.params) - self.assertEqual("GET", tornado_span.data.http.method) + self.assertEqual(405, tornado_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/405", tornado_span.data["http"]["url"]) + self.assertIsNone(tornado_span.data["http"]["params"]) + self.assertEqual("GET", tornado_span.data["http"]["method"]) self.assertIsNotNone(tornado_span.stack) self.assertTrue(type(tornado_span.stack) is list) self.assertTrue(len(tornado_span.stack) > 1) - self.assertEqual(405, aiohttp_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/405", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) + self.assertEqual(405, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/405", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -360,18 +360,18 @@ async def test(): self.assertTrue(tornado_span.error) self.assertEqual(tornado_span.ec, 1) - self.assertEqual(500, tornado_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/500", tornado_span.data.http.url) - self.assertIsNone(tornado_span.data.http.params) - self.assertEqual("GET", tornado_span.data.http.method) + self.assertEqual(500, tornado_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/500", tornado_span.data["http"]["url"]) + self.assertIsNone(tornado_span.data["http"]["params"]) + self.assertEqual("GET", tornado_span.data["http"]["method"]) self.assertIsNotNone(tornado_span.stack) self.assertTrue(type(tornado_span.stack) is list) self.assertTrue(len(tornado_span.stack) > 1) - self.assertEqual(500, aiohttp_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/500", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) - self.assertEqual('Internal Server Error', aiohttp_span.data.http.error) + self.assertEqual(500, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/500", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) + self.assertEqual('Internal Server Error', aiohttp_span.data["http"]["error"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -427,18 +427,18 @@ async def test(): self.assertTrue(tornado_span.error) self.assertEqual(tornado_span.ec, 1) - self.assertEqual(504, tornado_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/504", tornado_span.data.http.url) - self.assertIsNone(tornado_span.data.http.params) - self.assertEqual("GET", tornado_span.data.http.method) + self.assertEqual(504, tornado_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/504", tornado_span.data["http"]["url"]) + self.assertIsNone(tornado_span.data["http"]["params"]) + self.assertEqual("GET", tornado_span.data["http"]["method"]) self.assertIsNotNone(tornado_span.stack) self.assertTrue(type(tornado_span.stack) is list) self.assertTrue(len(tornado_span.stack) > 1) - self.assertEqual(504, aiohttp_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/504", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) - self.assertEqual('Gateway Timeout', aiohttp_span.data.http.error) + self.assertEqual(504, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/504", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) + self.assertEqual('Gateway Timeout', aiohttp_span.data["http"]["error"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -494,18 +494,18 @@ async def test(): self.assertFalse(tornado_span.error) self.assertIsNone(tornado_span.ec) - self.assertEqual(200, tornado_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data.http.url) - self.assertEqual("secret=", tornado_span.data.http.params) - self.assertEqual("GET", tornado_span.data.http.method) + self.assertEqual(200, tornado_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data["http"]["url"]) + self.assertEqual("secret=", tornado_span.data["http"]["params"]) + self.assertEqual("GET", tornado_span.data["http"]["method"]) self.assertIsNotNone(tornado_span.stack) self.assertTrue(type(tornado_span.stack) is list) self.assertTrue(len(tornado_span.stack) > 1) - self.assertEqual(200, aiohttp_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) - self.assertEqual("secret=", aiohttp_span.data.http.params) + self.assertEqual(200, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) + self.assertEqual("secret=", aiohttp_span.data["http"]["params"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -568,18 +568,18 @@ async def test(): self.assertFalse(tornado_span.error) self.assertIsNone(tornado_span.ec) - self.assertEqual(200, tornado_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data.http.url) - self.assertEqual("secret=", tornado_span.data.http.params) - self.assertEqual("GET", tornado_span.data.http.method) + self.assertEqual(200, tornado_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", tornado_span.data["http"]["url"]) + self.assertEqual("secret=", tornado_span.data["http"]["params"]) + self.assertEqual("GET", tornado_span.data["http"]["method"]) self.assertIsNotNone(tornado_span.stack) self.assertTrue(type(tornado_span.stack) is list) self.assertTrue(len(tornado_span.stack) > 1) - self.assertEqual(200, aiohttp_span.data.http.status) - self.assertEqual(testenv["tornado_server"] + "/", aiohttp_span.data.http.url) - self.assertEqual("GET", aiohttp_span.data.http.method) - self.assertEqual("secret=", aiohttp_span.data.http.params) + self.assertEqual(200, aiohttp_span.data["http"]["status"]) + self.assertEqual(testenv["tornado_server"] + "/", aiohttp_span.data["http"]["url"]) + self.assertEqual("GET", aiohttp_span.data["http"]["method"]) + self.assertEqual("secret=", aiohttp_span.data["http"]["params"]) self.assertIsNotNone(aiohttp_span.stack) self.assertTrue(type(aiohttp_span.stack) is list) self.assertTrue(len(aiohttp_span.stack) > 1) @@ -593,7 +593,7 @@ async def test(): self.assertTrue("Server-Timing" in response.headers) self.assertEqual(response.headers["Server-Timing"], "intid;desc=%s" % traceId) - self.assertTrue("http.X-Capture-This" in tornado_span.data.custom.tags) - self.assertEqual('this', tornado_span.data.custom.tags['http.X-Capture-This']) - self.assertTrue("http.X-Capture-That" in tornado_span.data.custom.tags) - self.assertEqual('that', tornado_span.data.custom.tags['http.X-Capture-That']) + self.assertTrue("http.X-Capture-This" in tornado_span.data["custom"]["tags"]) + self.assertEqual('this', tornado_span.data["custom"]["tags"]['http.X-Capture-This']) + self.assertTrue("http.X-Capture-That" in tornado_span.data["custom"]["tags"]) + self.assertEqual('that', tornado_span.data["custom"]["tags"]['http.X-Capture-That']) diff --git a/tests/test_urllib3.py b/tests/test_urllib3.py index accf7ed1..9667d989 100644 --- a/tests/test_urllib3.py +++ b/tests/test_urllib3.py @@ -60,20 +60,20 @@ def test_get_request(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -111,21 +111,21 @@ def test_get_request_with_query(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data.http.url) - self.assertTrue(urllib3_span.data.http.params in ["one=1&two=2", "two=2&one=1"] ) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data["http"]["url"]) + self.assertTrue(urllib3_span.data["http"]["params"] in ["one=1&two=2", "two=2&one=1"] ) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -163,21 +163,21 @@ def test_get_request_with_alt_query(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data.http.url) - self.assertTrue(urllib3_span.data.http.params in ["one=1&two=2", "two=2&one=1"] ) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data["http"]["url"]) + self.assertTrue(urllib3_span.data["http"]["params"] in ["one=1&two=2", "two=2&one=1"] ) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -215,20 +215,20 @@ def test_put_request(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/notfound', wsgi_span.data.http.url) - self.assertEqual('PUT', wsgi_span.data.http.method) - self.assertEqual(404, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/notfound', wsgi_span.data["http"]["url"]) + self.assertEqual('PUT', wsgi_span.data["http"]["method"]) + self.assertEqual(404, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(404, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/notfound", urllib3_span.data.http.url) - self.assertEqual("PUT", urllib3_span.data.http.method) + self.assertEqual(404, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/notfound", urllib3_span.data["http"]["url"]) + self.assertEqual("PUT", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -277,37 +277,37 @@ def test_301_redirect(self): # wsgi self.assertEqual("wsgi", wsgi_span1.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span1.data.http.host) - self.assertEqual('/', wsgi_span1.data.http.url) - self.assertEqual('GET', wsgi_span1.data.http.method) - self.assertEqual(200, wsgi_span1.data.http.status) - self.assertIsNone(wsgi_span1.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span1.data["http"]["host"]) + self.assertEqual('/', wsgi_span1.data["http"]["url"]) + self.assertEqual('GET', wsgi_span1.data["http"]["method"]) + self.assertEqual(200, wsgi_span1.data["http"]["status"]) + self.assertIsNone(wsgi_span1.data["http"]["error"]) self.assertIsNotNone(wsgi_span1.stack) self.assertEqual(2, len(wsgi_span1.stack)) self.assertEqual("wsgi", wsgi_span2.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span2.data.http.host) - self.assertEqual('/301', wsgi_span2.data.http.url) - self.assertEqual('GET', wsgi_span2.data.http.method) - self.assertEqual(301, wsgi_span2.data.http.status) - self.assertIsNone(wsgi_span2.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span2.data["http"]["host"]) + self.assertEqual('/301', wsgi_span2.data["http"]["url"]) + self.assertEqual('GET', wsgi_span2.data["http"]["method"]) + self.assertEqual(301, wsgi_span2.data["http"]["status"]) + self.assertIsNone(wsgi_span2.data["http"]["error"]) self.assertIsNotNone(wsgi_span2.stack) self.assertEqual(2, len(wsgi_span2.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span1.n) - self.assertEqual(200, urllib3_span1.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span1.data.http.url) - self.assertEqual("GET", urllib3_span1.data.http.method) + self.assertEqual(200, urllib3_span1.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span1.data["http"]["url"]) + self.assertEqual("GET", urllib3_span1.data["http"]["method"]) self.assertIsNotNone(urllib3_span1.stack) self.assertTrue(type(urllib3_span1.stack) is list) self.assertTrue(len(urllib3_span1.stack) > 1) self.assertEqual("urllib3", urllib3_span2.n) - self.assertEqual(301, urllib3_span2.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/301", urllib3_span2.data.http.url) - self.assertEqual("GET", urllib3_span2.data.http.method) + self.assertEqual(301, urllib3_span2.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/301", urllib3_span2.data["http"]["url"]) + self.assertEqual("GET", urllib3_span2.data["http"]["method"]) self.assertIsNotNone(urllib3_span2.stack) self.assertTrue(type(urllib3_span2.stack) is list) self.assertTrue(len(urllib3_span2.stack) > 1) @@ -356,37 +356,37 @@ def test_302_redirect(self): # wsgi self.assertEqual("wsgi", wsgi_span1.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span1.data.http.host) - self.assertEqual('/', wsgi_span1.data.http.url) - self.assertEqual('GET', wsgi_span1.data.http.method) - self.assertEqual(200, wsgi_span1.data.http.status) - self.assertIsNone(wsgi_span1.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span1.data["http"]["host"]) + self.assertEqual('/', wsgi_span1.data["http"]["url"]) + self.assertEqual('GET', wsgi_span1.data["http"]["method"]) + self.assertEqual(200, wsgi_span1.data["http"]["status"]) + self.assertIsNone(wsgi_span1.data["http"]["error"]) self.assertIsNotNone(wsgi_span1.stack) self.assertEqual(2, len(wsgi_span1.stack)) self.assertEqual("wsgi", wsgi_span2.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span2.data.http.host) - self.assertEqual('/302', wsgi_span2.data.http.url) - self.assertEqual('GET', wsgi_span2.data.http.method) - self.assertEqual(302, wsgi_span2.data.http.status) - self.assertIsNone(wsgi_span2.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span2.data["http"]["host"]) + self.assertEqual('/302', wsgi_span2.data["http"]["url"]) + self.assertEqual('GET', wsgi_span2.data["http"]["method"]) + self.assertEqual(302, wsgi_span2.data["http"]["status"]) + self.assertIsNone(wsgi_span2.data["http"]["error"]) self.assertIsNotNone(wsgi_span2.stack) self.assertEqual(2, len(wsgi_span2.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span1.n) - self.assertEqual(200, urllib3_span1.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span1.data.http.url) - self.assertEqual("GET", urllib3_span1.data.http.method) + self.assertEqual(200, urllib3_span1.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span1.data["http"]["url"]) + self.assertEqual("GET", urllib3_span1.data["http"]["method"]) self.assertIsNotNone(urllib3_span1.stack) self.assertTrue(type(urllib3_span1.stack) is list) self.assertTrue(len(urllib3_span1.stack) > 1) self.assertEqual("urllib3", urllib3_span2.n) - self.assertEqual(302, urllib3_span2.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/302", urllib3_span2.data.http.url) - self.assertEqual("GET", urllib3_span2.data.http.method) + self.assertEqual(302, urllib3_span2.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/302", urllib3_span2.data["http"]["url"]) + self.assertEqual("GET", urllib3_span2.data["http"]["method"]) self.assertIsNotNone(urllib3_span2.stack) self.assertTrue(type(urllib3_span2.stack) is list) self.assertTrue(len(urllib3_span2.stack) > 1) @@ -425,20 +425,20 @@ def test_5xx_request(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/504', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(504, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/504', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(504, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(504, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/504", urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(504, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/504", urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -480,20 +480,20 @@ def test_exception_logging(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/exception', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(500, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/exception', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(500, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(500, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/exception", urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(500, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/exception", urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -523,11 +523,11 @@ def test_client_error(self): traceId = test_span.t self.assertEqual(traceId, urllib3_span.t) - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertIsNone(urllib3_span.data.http.status) - self.assertEqual("http://doesnotexist.asdf:5000/504", urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertIsNone(urllib3_span.data["http"]["status"]) + self.assertEqual("http://doesnotexist.asdf:5000/504", urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -571,20 +571,20 @@ def test_requestspkg_get(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -625,20 +625,20 @@ def test_requestspkg_get_with_custom_headers(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/", urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -675,20 +675,20 @@ def test_requestspkg_put(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/notfound', wsgi_span.data.http.url) - self.assertEqual('PUT', wsgi_span.data.http.method) - self.assertEqual(404, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/notfound', wsgi_span.data["http"]["url"]) + self.assertEqual('PUT', wsgi_span.data["http"]["method"]) + self.assertEqual(404, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(404, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/notfound", urllib3_span.data.http.url) - self.assertEqual("PUT", urllib3_span.data.http.method) + self.assertEqual(404, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/notfound", urllib3_span.data["http"]["url"]) + self.assertEqual("PUT", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) @@ -729,24 +729,24 @@ def test_response_header_capture(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data.http.host) - self.assertEqual('/response_headers', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv["wsgi_port"]), wsgi_span.data["http"]["host"]) + self.assertEqual('/response_headers', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) # urllib3 - self.assertEqual("test", test_span.data.sdk.name) + self.assertEqual("test", test_span.data["sdk"]["name"]) self.assertEqual("urllib3", urllib3_span.n) - self.assertEqual(200, urllib3_span.data.http.status) - self.assertEqual(testenv["wsgi_server"] + "/response_headers", urllib3_span.data.http.url) - self.assertEqual("GET", urllib3_span.data.http.method) + self.assertEqual(200, urllib3_span.data["http"]["status"]) + self.assertEqual(testenv["wsgi_server"] + "/response_headers", urllib3_span.data["http"]["url"]) + self.assertEqual("GET", urllib3_span.data["http"]["method"]) self.assertIsNotNone(urllib3_span.stack) self.assertTrue(type(urllib3_span.stack) is list) self.assertTrue(len(urllib3_span.stack) > 1) - self.assertTrue('http.X-Capture-This' in urllib3_span.data.custom.tags) + self.assertTrue('http.X-Capture-This' in urllib3_span.data["custom"]["tags"]) agent.extra_headers = original_extra_headers diff --git a/tests/test_wsgi.py b/tests/test_wsgi.py index c8fee900..d3a036d7 100644 --- a/tests/test_wsgi.py +++ b/tests/test_wsgi.py @@ -77,11 +77,11 @@ def test_get_request(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) @@ -144,11 +144,11 @@ def test_complex_request(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/complex', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/complex', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) @@ -208,18 +208,18 @@ def test_custom_header_capture(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/', wsgi_span.data.http.url) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/', wsgi_span.data["http"]["url"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) - self.assertEqual(True, "http.X-Capture-This" in wsgi_span.data.custom.__dict__['tags']) - self.assertEqual("this", wsgi_span.data.custom.__dict__['tags']["http.X-Capture-This"]) - self.assertEqual(True, "http.X-Capture-That" in wsgi_span.data.custom.__dict__['tags']) - self.assertEqual("that", wsgi_span.data.custom.__dict__['tags']["http.X-Capture-That"]) + self.assertEqual(True, "http.X-Capture-This" in wsgi_span.data["custom"]['tags']) + self.assertEqual("this", wsgi_span.data["custom"]['tags']["http.X-Capture-This"]) + self.assertEqual(True, "http.X-Capture-That" in wsgi_span.data["custom"]['tags']) + self.assertEqual("that", wsgi_span.data["custom"]['tags']["http.X-Capture-That"]) def test_secret_scrubbing(self): with tracer.start_active_span('test'): @@ -270,12 +270,12 @@ def test_secret_scrubbing(self): # wsgi self.assertEqual("wsgi", wsgi_span.n) - self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data.http.host) - self.assertEqual('/', wsgi_span.data.http.url) - self.assertEqual('secret=', wsgi_span.data.http.params) - self.assertEqual('GET', wsgi_span.data.http.method) - self.assertEqual(200, wsgi_span.data.http.status) - self.assertIsNone(wsgi_span.data.http.error) + self.assertEqual('127.0.0.1:' + str(testenv['wsgi_port']), wsgi_span.data["http"]["host"]) + self.assertEqual('/', wsgi_span.data["http"]["url"]) + self.assertEqual('secret=', wsgi_span.data["http"]["params"]) + self.assertEqual('GET', wsgi_span.data["http"]["method"]) + self.assertEqual(200, wsgi_span.data["http"]["status"]) + self.assertIsNone(wsgi_span.data["http"]["error"]) self.assertIsNotNone(wsgi_span.stack) self.assertEqual(2, len(wsgi_span.stack)) From cc3dd0afbfb7031c8a0e7397a0a14426abd3d454 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 3 Mar 2020 14:31:03 +0100 Subject: [PATCH 07/29] Update suds and grpcio tests. Unify spans in span.py --- instana/json_span.py | 270 --------------------------------------- instana/recorder.py | 7 +- instana/span.py | 276 +++++++++++++++++++++++++++++++++++++++- instana/tracer.py | 3 +- tests/test_grpcio.py | 3 + tests/test_sudsjurko.py | 26 +--- 6 files changed, 282 insertions(+), 303 deletions(-) delete mode 100644 instana/json_span.py diff --git a/instana/json_span.py b/instana/json_span.py deleted file mode 100644 index 01ab888c..00000000 --- a/instana/json_span.py +++ /dev/null @@ -1,270 +0,0 @@ -from .log import logger -from .util import DictionaryOfStan -import opentracing.ext.tags as ot_tags - - -class BaseSpan(object): - def __str__(self): - return "BaseSpan(%s)" % self.__dict__.__str__() - - def __repr__(self): - return self.__dict__.__str__() - - def __init__(self, span, source, **kwargs): - self.t = span.context.trace_id - self.p = span.parent_id - self.s = span.context.span_id - self.ts = int(round(span.start_time * 1000)) - self.d = int(round(span.duration * 1000)) - self.f = source - self.ec = span.tags.pop("ec", None) - self.error = span.tags.pop("error", None) - - if span.stack: - self.stack = span.stack - - self.__dict__.update(kwargs) - - -class SDKSpan(BaseSpan): - ENTRY_KIND = ["entry", "server", "consumer"] - EXIT_KIND = ["exit", "client", "producer"] - - def __init__(self, span, source, service_name, **kwargs): - super(SDKSpan, self).__init__(span, source, **kwargs) - self.n = "sdk" - self.k = self.get_span_kind_as_int(span) - - self.data = DictionaryOfStan() - self.data["sdk"]["name"] = span.operation_name - self.data["sdk"]["type"] = self.get_span_kind_as_string(span) - self.data["sdk"]["custom"]["tags"] = span.tags - self.data["sdk"]["custom"]["logs"] = span.logs - self.data["service"] = service_name - - # self.data = Data() - # self.data.sdk = SDKData(name=span.operation_name, Type=self.get_span_kind_as_string(span)) - # self.data.sdk.custom = CustomData(tags=span.tags, logs=span.collect_logs()) - # self.data.service = service_name - - if "arguments" in span.tags: - self.data.sdk.arguments = span.tags["arguments"] - - if "return" in span.tags: - self.data.sdk.Return = span.tags["return"] - - if len(span.context.baggage) > 0: - self.data["baggage"] = span.context.baggage - - def get_span_kind_as_string(self, span): - """ - Will retrieve the `span.kind` tag and return the appropriate string value for the Instana backend or - None if the tag is set to something we don't recognize. - - :param span: The span to search for the `span.kind` tag - :return: String - """ - kind = None - if "span.kind" in span.tags: - if span.tags["span.kind"] in self.ENTRY_KIND: - kind = "entry" - elif span.tags["span.kind"] in self.EXIT_KIND: - kind = "exit" - else: - kind = "intermediate" - return kind - - def get_span_kind_as_int(self, span): - """ - Will retrieve the `span.kind` tag and return the appropriate integer value for the Instana backend or - None if the tag is set to something we don't recognize. - - :param span: The span to search for the `span.kind` tag - :return: Integer - """ - kind = None - if "span.kind" in span.tags: - if span.tags["span.kind"] in self.ENTRY_KIND: - kind = 1 - elif span.tags["span.kind"] in self.EXIT_KIND: - kind = 2 - else: - kind = 3 - return kind - - -class RegisteredSpan(BaseSpan): - HTTP_SPANS = ("aiohttp-client", "aiohttp-server", "django", "http", "soap", "tornado-client", - "tornado-server", "urllib3", "wsgi") - - EXIT_SPANS = ("aiohttp-client", "cassandra", "couchbase", "log", "memcache", "mongo", "mysql", "postgres", - "rabbitmq", "redis", "rpc-client", "sqlalchemy", "soap", "tornado-client", "urllib3", - "pymongo") - - ENTRY_SPANS = ("aiohttp-server", "aws.lambda.entry", "django", "wsgi", "rabbitmq", "rpc-server", "tornado-server") - - LOCAL_SPANS = ("render") - - def __init__(self, span, source, **kwargs): - super(RegisteredSpan, self).__init__(span, source, **kwargs) - self.n = span.operation_name - self.data = DictionaryOfStan() - - self.k = 1 - if span.operation_name in self.ENTRY_SPANS: - # entry - self._populate_entry_span_data(span) - elif span.operation_name in self.EXIT_SPANS: - self.k = 2 # exit - self._populate_exit_span_data(span) - elif span.operation_name in self.LOCAL_SPANS: - self.k = 3 # intermediate span - self._populate_local_span_data(span) - - if "rabbitmq" in self.data and self.data["rabbitmq"]["sort"] == "consume": - self.k = 1 # entry - - # Store any leftover tags in the custom section - if len(span.tags): - self.data["custom"]["tags"] = span.tags - - - def _populate_entry_span_data(self, span): - if span.operation_name in self.HTTP_SPANS: - self._collect_http_tags(span) - elif span.operation_name == "aws.lambda.entry": - self.data["lambda"]["arn"] = span.tags.pop('lambda.arn', "Unknown") - self.data["lambda"]["alias"] = None - self.data["lambda"]["runtime"] = "python" - self.data["lambda"]["functionName"] = span.tags.pop('lambda.name', "Unknown") - self.data["lambda"]["functionVersion"] = span.tags.pop('lambda.version', "Unknown") - self.data["lambda"]["error"] = None - - elif span.operation_name == "rabbitmq": - self.data["rabbitmq"]["exchange"] = span.tags.pop('exchange', None) - self.data["rabbitmq"]["queue"] = span.tags.pop('queue', None) - self.data["rabbitmq"]["sort"] = span.tags.pop('sort', None) - self.data["rabbitmq"]["address"] = span.tags.pop('address', None) - self.data["rabbitmq"]["key"] = span.tags.pop('key', None) - - elif span.operation_name == "rpc-server": - self.data["rpc"]["flavor"] = span.tags.pop('rpc.flavor', None) - self.data["rpc"]["host"] = span.tags.pop('rpc.host', None) - self.data["rpc"]["port"] = span.tags.pop('rpc.port', None) - self.data["rpc"]["call"] = span.tags.pop('rpc.call', None) - self.data["rpc"]["call_type"] = span.tags.pop('rpc.call_type', None) - self.data["rpc"]["params"] = span.tags.pop('rpc.params', None) - self.data["rpc"]["baggage"] = span.tags.pop('rpc.baggage', None) - self.data["rpc"]["error"] = span.tags.pop('rpc.error', None) - else: - logger.debug("SpanRecorder: Unknown entry span: %s" % span.operation_name) - - def _populate_local_span_data(self, span): - if span.operation_name == "render": - self.data["render"]["name"] = span.tags.pop('name', None) - self.data["render"]["type"] = span.tags.pop('type', None) - self.data["log"]["message"] = span.tags.pop('message', None) - self.data["log"]["parameters"] = span.tags.pop('parameters', None) - else: - logger.debug("SpanRecorder: Unknown local span: %s" % span.operation_name) - - def _populate_exit_span_data(self, span): - if span.operation_name in self.HTTP_SPANS: - self._collect_http_tags(span) - elif span.operation_name == "rabbitmq": - self.data["rabbitmq"]["exchange"] = span.tags.pop('exchange', None) - self.data["rabbitmq"]["queue"] = span.tags.pop('queue', None) - self.data["rabbitmq"]["sort"] = span.tags.pop('sort', None) - self.data["rabbitmq"]["address"] = span.tags.pop('address', None) - self.data["rabbitmq"]["key"] = span.tags.pop('key', None) - - elif span.operation_name == "cassandra": - self.data["cassandra"]["cluster"] = span.tags.pop('cassandra.cluster', None) - self.data["cassandra"]["query"] = span.tags.pop('cassandra.query', None) - self.data["cassandra"]["keyspace"] = span.tags.pop('cassandra.keyspace', None) - self.data["cassandra"]["fetchSize"] = span.tags.pop('cassandra.fetchSize', None) - self.data["cassandra"]["achievedConsistency"] = span.tags.pop('cassandra.achievedConsistency', None) - self.data["cassandra"]["triedHosts"] = span.tags.pop('cassandra.triedHosts', None) - self.data["cassandra"]["fullyFetched"] = span.tags.pop('cassandra.fullyFetched', None) - self.data["cassandra"]["error"] = span.tags.pop('cassandra.error', None) - - elif span.operation_name == "couchbase": - self.data["couchbase"]["hostname"] = span.tags.pop('couchbase.hostname', None) - self.data["couchbase"]["bucket"] = span.tags.pop('couchbase.bucket', None) - self.data["couchbase"]["type"] = span.tags.pop('couchbase.type', None) - self.data["couchbase"]["error"] = span.tags.pop('couchbase.error', None) - self.data["couchbase"]["error_type"] = span.tags.pop('couchbase.error_type', None) - self.data["couchbase"]["sql"] = span.tags.pop('couchbase.sql', None) - - elif span.operation_name == "redis": - self.data["redis"]["connection"] = span.tags.pop('connection', None) - self.data["redis"]["driver"] = span.tags.pop('driver', None) - self.data["redis"]["command"] = span.tags.pop('command', None) - self.data["redis"]["error"] = span.tags.pop('redis.error', None) - self.data["redis"]["subCommands"] = span.tags.pop('subCommands', None) - - elif span.operation_name == "rpc-client": - self.data["rpc"]["flavor"] = span.tags.pop('rpc.flavor', None) - self.data["rpc"]["host"] = span.tags.pop('rpc.host', None) - self.data["rpc"]["port"] = span.tags.pop('rpc.port', None) - self.data["rpc"]["call"] = span.tags.pop('rpc.call', None) - self.data["rpc"]["call_type"] = span.tags.pop('rpc.call_type', None) - self.data["rpc"]["params"] = span.tags.pop('rpc.params', None) - self.data["rpc"]["baggage"] = span.tags.pop('rpc.baggage', None) - self.data["rpc"]["error"] = span.tags.pop('rpc.error', None) - - elif span.operation_name == "sqlalchemy": - self.data["sqlalchemy"]["sql"] = span.tags.pop('sqlalchemy.sql', None) - self.data["sqlalchemy"]["eng"] = span.tags.pop('sqlalchemy.eng', None) - self.data["sqlalchemy"]["url"] = span.tags.pop('sqlalchemy.url', None) - self.data["sqlalchemy"]["err"] = span.tags.pop('sqlalchemy.err', None) - - elif span.operation_name == "mysql": - self.data["mysql"]["host"] = span.tags.pop('host', None) - self.data["mysql"]["port"] = span.tags.pop('port', None) - self.data["mysql"]["db"] = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) - self.data["mysql"]["user"] = span.tags.pop(ot_tags.DATABASE_USER, None) - self.data["mysql"]["stmt"] = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) - self.data["mysql"]["error"] = span.tags.pop('mysql.error', None) - - elif span.operation_name == "postgres": - self.data["pg"]["host"] = span.tags.pop('host', None) - self.data["pg"]["port"] = span.tags.pop('port', None) - self.data["pg"]["db"] = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) - self.data["pg"]["user"] = span.tags.pop(ot_tags.DATABASE_USER, None) - self.data["pg"]["stmt"] = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) - self.data["pg"]["error"] = span.tags.pop('pg.error', None) - - elif span.operation_name == "mongo": - service = "%s:%s" % (span.tags.pop('host', None), span.tags.pop('port', None)) - namespace = "%s.%s" % (span.tags.pop('db', "?"), span.tags.pop('collection', "?")) - - self.data["mongo"]["service"] = service - self.data["mongo"]["namespace"] = namespace - self.data["mongo"]["command"] = span.tags.pop('command', None) - self.data["mongo"]["filter"] = span.tags.pop('filter', None) - self.data["mongo"]["json"] = span.tags.pop('json', None) - self.data["mongo"]["error"] = span.tags.pop('error', None) - - elif span.operation_name == "log": - # use last special key values - for l in span.logs: - if "message" in l.key_values: - self.data["log"]["message"] = l.key_values.pop("message", None) - if "parameters" in l.key_values: - self.data["log"]["parameters"] = l.key_values.pop("parameters", None) - else: - logger.debug("SpanRecorder: Unknown exit span: %s" % span.operation_name) - - def _collect_http_tags(self, span): - self.data["http"]["host"] = span.tags.pop("http.host", None) - self.data["http"]["url"] = span.tags.pop(ot_tags.HTTP_URL, None) - self.data["http"]["path"] = span.tags.pop("http.path", None) - self.data["http"]["params"] = span.tags.pop('http.params', None) - self.data["http"]["method"] = span.tags.pop(ot_tags.HTTP_METHOD, None) - self.data["http"]["status"] = span.tags.pop(ot_tags.HTTP_STATUS_CODE, None) - self.data["http"]["path_tpl"] = span.tags.pop("http.path_tpl", None) - self.data["http"]["error"] = span.tags.pop('http.error', None) - - if span.operation_name == "soap": - self.data["soap"]["action"] = span.tags.pop('soap.action', None) diff --git a/instana/recorder.py b/instana/recorder.py index eb82a0f6..6e767881 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -7,10 +7,8 @@ from .log import logger from .util import every import instana.singletons - from basictracer import Sampler - -from .json_span import (RegisteredSpan, SDKSpan) +from .span import (RegisteredSpan, SDKSpan) if sys.version_info.major == 2: import Queue as queue @@ -74,7 +72,8 @@ def span_work(): logger.debug("reported %d spans", queue_size) return True - every(2, span_work, "Span Reporting") + if "INSTANA_TEST" not in os.environ: + every(2, span_work, "Span Reporting") def queue_size(self): """ Return the size of the queue; how may spans are queued, """ diff --git a/instana/span.py b/instana/span.py index 3f4c4de3..dedca9de 100644 --- a/instana/span.py +++ b/instana/span.py @@ -1,5 +1,7 @@ -from basictracer.span import BasicSpan from .log import logger +from .util import DictionaryOfStan +from basictracer.span import BasicSpan +import opentracing.ext.tags as ot_tags class InstanaSpan(BasicSpan): @@ -10,7 +12,6 @@ def finish(self, finish_time=None): def log_exception(self, e): try: - logger.debug("Logging error for span %s" % self.operation_name) message = "" self.set_tag("error", True) @@ -24,10 +25,12 @@ def log_exception(self, e): if self.operation_name in ['rpc-server', 'rpc-client']: self.set_tag('rpc.error', message) - elif self.operation_name == "postgres": - self.set_tag('pg.error', message) elif self.operation_name == "mysql": self.set_tag('mysql.error', message) + elif self.operation_name == "postgres": + self.set_tag('pg.error', message) + elif self.operation_name == "soap": + self.set_tag('http.error', message) else: self.log_kv({'message': message}) except Exception: @@ -57,3 +60,268 @@ def collect_logs(self): return logs +class BaseSpan(object): + def __str__(self): + return "BaseSpan(%s)" % self.__dict__.__str__() + + def __repr__(self): + return self.__dict__.__str__() + + def __init__(self, span, source, **kwargs): + self.t = span.context.trace_id + self.p = span.parent_id + self.s = span.context.span_id + self.ts = int(round(span.start_time * 1000)) + self.d = int(round(span.duration * 1000)) + self.f = source + self.ec = span.tags.pop("ec", None) + self.error = span.tags.pop("error", None) + + if span.stack: + self.stack = span.stack + + self.__dict__.update(kwargs) + + +class SDKSpan(BaseSpan): + ENTRY_KIND = ["entry", "server", "consumer"] + EXIT_KIND = ["exit", "client", "producer"] + + def __init__(self, span, source, service_name, **kwargs): + super(SDKSpan, self).__init__(span, source, **kwargs) + self.n = "sdk" + self.k = self.get_span_kind_as_int(span) + + self.data = DictionaryOfStan() + self.data["sdk"]["name"] = span.operation_name + self.data["sdk"]["type"] = self.get_span_kind_as_string(span) + self.data["sdk"]["custom"]["tags"] = span.tags + self.data["sdk"]["custom"]["logs"] = span.logs + self.data["service"] = service_name + + # self.data = Data() + # self.data.sdk = SDKData(name=span.operation_name, Type=self.get_span_kind_as_string(span)) + # self.data.sdk.custom = CustomData(tags=span.tags, logs=span.collect_logs()) + # self.data.service = service_name + + if "arguments" in span.tags: + self.data.sdk.arguments = span.tags["arguments"] + + if "return" in span.tags: + self.data.sdk.Return = span.tags["return"] + + if len(span.context.baggage) > 0: + self.data["baggage"] = span.context.baggage + + def get_span_kind_as_string(self, span): + """ + Will retrieve the `span.kind` tag and return the appropriate string value for the Instana backend or + None if the tag is set to something we don't recognize. + + :param span: The span to search for the `span.kind` tag + :return: String + """ + kind = None + if "span.kind" in span.tags: + if span.tags["span.kind"] in self.ENTRY_KIND: + kind = "entry" + elif span.tags["span.kind"] in self.EXIT_KIND: + kind = "exit" + else: + kind = "intermediate" + return kind + + def get_span_kind_as_int(self, span): + """ + Will retrieve the `span.kind` tag and return the appropriate integer value for the Instana backend or + None if the tag is set to something we don't recognize. + + :param span: The span to search for the `span.kind` tag + :return: Integer + """ + kind = None + if "span.kind" in span.tags: + if span.tags["span.kind"] in self.ENTRY_KIND: + kind = 1 + elif span.tags["span.kind"] in self.EXIT_KIND: + kind = 2 + else: + kind = 3 + return kind + + +class RegisteredSpan(BaseSpan): + HTTP_SPANS = ("aiohttp-client", "aiohttp-server", "django", "http", "soap", "tornado-client", + "tornado-server", "urllib3", "wsgi") + + EXIT_SPANS = ("aiohttp-client", "cassandra", "couchbase", "log", "memcache", "mongo", "mysql", "postgres", + "rabbitmq", "redis", "rpc-client", "sqlalchemy", "soap", "tornado-client", "urllib3", + "pymongo") + + ENTRY_SPANS = ("aiohttp-server", "aws.lambda.entry", "django", "wsgi", "rabbitmq", "rpc-server", "tornado-server") + + LOCAL_SPANS = ("render") + + def __init__(self, span, source, **kwargs): + super(RegisteredSpan, self).__init__(span, source, **kwargs) + self.n = span.operation_name + self.data = DictionaryOfStan() + + self.k = 1 + if span.operation_name in self.ENTRY_SPANS: + # entry + self._populate_entry_span_data(span) + elif span.operation_name in self.EXIT_SPANS: + self.k = 2 # exit + self._populate_exit_span_data(span) + elif span.operation_name in self.LOCAL_SPANS: + self.k = 3 # intermediate span + self._populate_local_span_data(span) + + if "rabbitmq" in self.data and self.data["rabbitmq"]["sort"] == "consume": + self.k = 1 # entry + + # Store any leftover tags in the custom section + if len(span.tags): + self.data["custom"]["tags"] = span.tags + + + def _populate_entry_span_data(self, span): + if span.operation_name in self.HTTP_SPANS: + self._collect_http_tags(span) + elif span.operation_name == "aws.lambda.entry": + self.data["lambda"]["arn"] = span.tags.pop('lambda.arn', "Unknown") + self.data["lambda"]["alias"] = None + self.data["lambda"]["runtime"] = "python" + self.data["lambda"]["functionName"] = span.tags.pop('lambda.name', "Unknown") + self.data["lambda"]["functionVersion"] = span.tags.pop('lambda.version', "Unknown") + self.data["lambda"]["error"] = None + + elif span.operation_name == "rabbitmq": + self.data["rabbitmq"]["exchange"] = span.tags.pop('exchange', None) + self.data["rabbitmq"]["queue"] = span.tags.pop('queue', None) + self.data["rabbitmq"]["sort"] = span.tags.pop('sort', None) + self.data["rabbitmq"]["address"] = span.tags.pop('address', None) + self.data["rabbitmq"]["key"] = span.tags.pop('key', None) + + elif span.operation_name == "rpc-server": + self.data["rpc"]["flavor"] = span.tags.pop('rpc.flavor', None) + self.data["rpc"]["host"] = span.tags.pop('rpc.host', None) + self.data["rpc"]["port"] = span.tags.pop('rpc.port', None) + self.data["rpc"]["call"] = span.tags.pop('rpc.call', None) + self.data["rpc"]["call_type"] = span.tags.pop('rpc.call_type', None) + self.data["rpc"]["params"] = span.tags.pop('rpc.params', None) + self.data["rpc"]["baggage"] = span.tags.pop('rpc.baggage', None) + self.data["rpc"]["error"] = span.tags.pop('rpc.error', None) + else: + logger.debug("SpanRecorder: Unknown entry span: %s" % span.operation_name) + + def _populate_local_span_data(self, span): + if span.operation_name == "render": + self.data["render"]["name"] = span.tags.pop('name', None) + self.data["render"]["type"] = span.tags.pop('type', None) + self.data["log"]["message"] = span.tags.pop('message', None) + self.data["log"]["parameters"] = span.tags.pop('parameters', None) + else: + logger.debug("SpanRecorder: Unknown local span: %s" % span.operation_name) + + def _populate_exit_span_data(self, span): + if span.operation_name in self.HTTP_SPANS: + self._collect_http_tags(span) + elif span.operation_name == "rabbitmq": + self.data["rabbitmq"]["exchange"] = span.tags.pop('exchange', None) + self.data["rabbitmq"]["queue"] = span.tags.pop('queue', None) + self.data["rabbitmq"]["sort"] = span.tags.pop('sort', None) + self.data["rabbitmq"]["address"] = span.tags.pop('address', None) + self.data["rabbitmq"]["key"] = span.tags.pop('key', None) + + elif span.operation_name == "cassandra": + self.data["cassandra"]["cluster"] = span.tags.pop('cassandra.cluster', None) + self.data["cassandra"]["query"] = span.tags.pop('cassandra.query', None) + self.data["cassandra"]["keyspace"] = span.tags.pop('cassandra.keyspace', None) + self.data["cassandra"]["fetchSize"] = span.tags.pop('cassandra.fetchSize', None) + self.data["cassandra"]["achievedConsistency"] = span.tags.pop('cassandra.achievedConsistency', None) + self.data["cassandra"]["triedHosts"] = span.tags.pop('cassandra.triedHosts', None) + self.data["cassandra"]["fullyFetched"] = span.tags.pop('cassandra.fullyFetched', None) + self.data["cassandra"]["error"] = span.tags.pop('cassandra.error', None) + + elif span.operation_name == "couchbase": + self.data["couchbase"]["hostname"] = span.tags.pop('couchbase.hostname', None) + self.data["couchbase"]["bucket"] = span.tags.pop('couchbase.bucket', None) + self.data["couchbase"]["type"] = span.tags.pop('couchbase.type', None) + self.data["couchbase"]["error"] = span.tags.pop('couchbase.error', None) + self.data["couchbase"]["error_type"] = span.tags.pop('couchbase.error_type', None) + self.data["couchbase"]["sql"] = span.tags.pop('couchbase.sql', None) + + elif span.operation_name == "redis": + self.data["redis"]["connection"] = span.tags.pop('connection', None) + self.data["redis"]["driver"] = span.tags.pop('driver', None) + self.data["redis"]["command"] = span.tags.pop('command', None) + self.data["redis"]["error"] = span.tags.pop('redis.error', None) + self.data["redis"]["subCommands"] = span.tags.pop('subCommands', None) + + elif span.operation_name == "rpc-client": + self.data["rpc"]["flavor"] = span.tags.pop('rpc.flavor', None) + self.data["rpc"]["host"] = span.tags.pop('rpc.host', None) + self.data["rpc"]["port"] = span.tags.pop('rpc.port', None) + self.data["rpc"]["call"] = span.tags.pop('rpc.call', None) + self.data["rpc"]["call_type"] = span.tags.pop('rpc.call_type', None) + self.data["rpc"]["params"] = span.tags.pop('rpc.params', None) + self.data["rpc"]["baggage"] = span.tags.pop('rpc.baggage', None) + self.data["rpc"]["error"] = span.tags.pop('rpc.error', None) + + elif span.operation_name == "sqlalchemy": + self.data["sqlalchemy"]["sql"] = span.tags.pop('sqlalchemy.sql', None) + self.data["sqlalchemy"]["eng"] = span.tags.pop('sqlalchemy.eng', None) + self.data["sqlalchemy"]["url"] = span.tags.pop('sqlalchemy.url', None) + self.data["sqlalchemy"]["err"] = span.tags.pop('sqlalchemy.err', None) + + elif span.operation_name == "mysql": + self.data["mysql"]["host"] = span.tags.pop('host', None) + self.data["mysql"]["port"] = span.tags.pop('port', None) + self.data["mysql"]["db"] = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) + self.data["mysql"]["user"] = span.tags.pop(ot_tags.DATABASE_USER, None) + self.data["mysql"]["stmt"] = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) + self.data["mysql"]["error"] = span.tags.pop('mysql.error', None) + + elif span.operation_name == "postgres": + self.data["pg"]["host"] = span.tags.pop('host', None) + self.data["pg"]["port"] = span.tags.pop('port', None) + self.data["pg"]["db"] = span.tags.pop(ot_tags.DATABASE_INSTANCE, None) + self.data["pg"]["user"] = span.tags.pop(ot_tags.DATABASE_USER, None) + self.data["pg"]["stmt"] = span.tags.pop(ot_tags.DATABASE_STATEMENT, None) + self.data["pg"]["error"] = span.tags.pop('pg.error', None) + + elif span.operation_name == "mongo": + service = "%s:%s" % (span.tags.pop('host', None), span.tags.pop('port', None)) + namespace = "%s.%s" % (span.tags.pop('db', "?"), span.tags.pop('collection', "?")) + + self.data["mongo"]["service"] = service + self.data["mongo"]["namespace"] = namespace + self.data["mongo"]["command"] = span.tags.pop('command', None) + self.data["mongo"]["filter"] = span.tags.pop('filter', None) + self.data["mongo"]["json"] = span.tags.pop('json', None) + self.data["mongo"]["error"] = span.tags.pop('error', None) + + elif span.operation_name == "log": + # use last special key values + for l in span.logs: + if "message" in l.key_values: + self.data["log"]["message"] = l.key_values.pop("message", None) + if "parameters" in l.key_values: + self.data["log"]["parameters"] = l.key_values.pop("parameters", None) + else: + logger.debug("SpanRecorder: Unknown exit span: %s" % span.operation_name) + + def _collect_http_tags(self, span): + self.data["http"]["host"] = span.tags.pop("http.host", None) + self.data["http"]["url"] = span.tags.pop(ot_tags.HTTP_URL, None) + self.data["http"]["path"] = span.tags.pop("http.path", None) + self.data["http"]["params"] = span.tags.pop('http.params', None) + self.data["http"]["method"] = span.tags.pop(ot_tags.HTTP_METHOD, None) + self.data["http"]["status"] = span.tags.pop(ot_tags.HTTP_STATUS_CODE, None) + self.data["http"]["path_tpl"] = span.tags.pop("http.path_tpl", None) + self.data["http"]["error"] = span.tags.pop('http.error', None) + + if span.operation_name == "soap": + self.data["soap"]["action"] = span.tags.pop('soap.action', None) diff --git a/instana/tracer.py b/instana/tracer.py index 3cb1a35b..62c431f5 100644 --- a/instana/tracer.py +++ b/instana/tracer.py @@ -13,9 +13,8 @@ from .text_propagator import TextPropagator from .span_context import InstanaSpanContext from .recorder import InstanaRecorder, InstanaSampler -from .span import InstanaSpan +from .span import InstanaSpan, RegisteredSpan from .util import generate_id -from .json_span import RegisteredSpan class InstanaTracer(BasicTracer): diff --git a/tests/test_grpcio.py b/tests/test_grpcio.py index 38a9ac63..525c5640 100644 --- a/tests/test_grpcio.py +++ b/tests/test_grpcio.py @@ -587,6 +587,9 @@ def test_server_error(self): client_span = get_first_span_by_name(spans, 'rpc-client') test_span = get_first_span_by_name(spans, 'sdk') + import ipdb; + ipdb.set_trace() + assert(log_span) assert(server_span) assert(client_span) diff --git a/tests/test_sudsjurko.py b/tests/test_sudsjurko.py index b42d9bbe..8c32fcf3 100644 --- a/tests/test_sudsjurko.py +++ b/tests/test_sudsjurko.py @@ -83,14 +83,7 @@ def test_server_exception(self): assert_equals(True, soap_span.error) assert_equals(1, soap_span.ec) - assert('logs' in soap_span.data["custom"]) - assert_equals(1, len(soap_span.data["custom"]["logs"].keys())) - - tskey = list(soap_span.data["custom"]["logs"].keys())[0] - assert('message' in soap_span.data["custom"]["logs"][tskey]) - assert_equals(u"Server raised fault: 'Internal Error'", - soap_span.data["custom"]["logs"][tskey]['message']) - + assert_equals(u"Server raised fault: 'Internal Error'", soap_span.data["http"]["error"]) assert_equals('server_exception', soap_span.data["soap"]["action"]) assert_equals(testenv["soap_server"] + '/', soap_span.data["http"]["url"]) @@ -119,14 +112,7 @@ def test_server_fault(self): assert_equals(True, soap_span.error) assert_equals(1, soap_span.ec) - assert('logs' in soap_span.data["custom"]) - assert_equals(1, len(soap_span.data["custom"]["logs"].keys())) - - tskey = list(soap_span.data["custom"]["logs"].keys())[0] - assert('message' in soap_span.data["custom"]["logs"][tskey]) - assert_equals(u"Server raised fault: 'Server side fault example.'", - soap_span.data["custom"]["logs"][tskey]['message']) - + assert_equals(u"Server raised fault: 'Server side fault example.'", soap_span.data["http"]["error"]) assert_equals('server_fault', soap_span.data["soap"]["action"]) assert_equals(testenv["soap_server"] + '/', soap_span.data["http"]["url"]) @@ -156,12 +142,6 @@ def test_client_fault(self): assert_equals(True, soap_span.error) assert_equals(1, soap_span.ec) - assert('logs' in soap_span.data["custom"]) - - tskey = list(soap_span.data["custom"]["logs"].keys())[0] - assert('message' in soap_span.data["custom"]["logs"][tskey]) - assert_equals(u"Server raised fault: 'Client side fault example'", - soap_span.data["custom"]["logs"][tskey]['message']) - + assert_equals(u"Server raised fault: 'Client side fault example'", soap_span.data["http"]["error"]) assert_equals('client_fault', soap_span.data["soap"]["action"]) assert_equals(testenv["soap_server"] + '/', soap_span.data["http"]["url"]) From 2b641ea7eb80585e84732f35d81ae262b28b1a8b Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 3 Mar 2020 15:09:29 +0100 Subject: [PATCH 08/29] Remove debug remnants --- tests/test_aiohttp.py | 2 +- tests/test_grpcio.py | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/test_aiohttp.py b/tests/test_aiohttp.py index ed8d62b0..6543eac1 100644 --- a/tests/test_aiohttp.py +++ b/tests/test_aiohttp.py @@ -429,7 +429,7 @@ async def test(): self.assertEqual(aiohttp_span.p, test_span.s) # Error logging - self.assertFalse(test_span.error) + self.assertTrue(test_span.error) self.assertIsNone(test_span.ec) self.assertTrue(aiohttp_span.error) self.assertEqual(aiohttp_span.ec, 1) diff --git a/tests/test_grpcio.py b/tests/test_grpcio.py index 525c5640..e166201b 100644 --- a/tests/test_grpcio.py +++ b/tests/test_grpcio.py @@ -569,12 +569,12 @@ def process_response(future): self.assertEqual(test_span.data["sdk"]["name"], 'test') def test_server_error(self): - try: - response = None - with tracer.start_active_span('test'): + response = None + with tracer.start_active_span('test'): + try: response = self.server_stub.OneQuestionOneErrorResponse(stan_pb2.QuestionRequest(question="Do u error?")) - except: - pass + except: + pass self.assertIsNone(tracer.active_span) self.assertIsNone(response) @@ -587,9 +587,6 @@ def test_server_error(self): client_span = get_first_span_by_name(spans, 'rpc-client') test_span = get_first_span_by_name(spans, 'sdk') - import ipdb; - ipdb.set_trace() - assert(log_span) assert(server_span) assert(client_span) From 63c4dd67d1207c303f72773ec5db40b7dc4f8309 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 3 Mar 2020 16:31:39 +0100 Subject: [PATCH 09/29] Update/fix cassandra tests --- docker-compose.yml | 6 ++++ tests/test_cassandra-driver.py | 60 +++++++++++++++++----------------- tests/test_tornado_server.py | 2 ++ 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 69abaf9b..b2a3c07e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,6 +40,12 @@ services: - ./bin:/nodejs-collector-bin # command: ["/nodejs-collector-bin/wait-for-it.sh", "-s", "-t", "120", "zookeeper:2181", "--", "start-kafka.sh"] + cassandra: + image: cassandra:3.11.5 + ports: + - 9042:9042 + + couchbase: image: couchbase ports: diff --git a/tests/test_cassandra-driver.py b/tests/test_cassandra-driver.py index 8ec8122c..9bb63719 100644 --- a/tests/test_cassandra-driver.py +++ b/tests/test_cassandra-driver.py @@ -86,12 +86,12 @@ def test_execute(self): self.assertFalse(cspan.error) self.assertIsNone(cspan.ec) - self.assertEqual(cspan.data.cassandra.cluster, 'Test Cluster') - self.assertEqual(cspan.data.cassandra.query, 'SELECT name, age, email FROM users') - self.assertEqual(cspan.data.cassandra.keyspace, 'instana_tests') - self.assertIsNone(cspan.data.cassandra.achievedConsistency) - self.assertIsNotNone(cspan.data.cassandra.triedHosts) - self.assertIsNone(cspan.data.cassandra.error) + self.assertEqual(cspan.data["cassandra"]["cluster"], 'Test Cluster') + self.assertEqual(cspan.data["cassandra"]["query"], 'SELECT name, age, email FROM users') + self.assertEqual(cspan.data["cassandra"]["keyspace"], 'instana_tests') + self.assertIsNone(cspan.data["cassandra"]["achievedConsistency"]) + self.assertIsNotNone(cspan.data["cassandra"]["triedHosts"]) + self.assertIsNone(cspan.data["cassandra"]["error"]) def test_execute_async(self): res = None @@ -120,12 +120,12 @@ def test_execute_async(self): self.assertFalse(cspan.error) self.assertIsNone(cspan.ec) - self.assertEqual(cspan.data.cassandra.cluster, 'Test Cluster') - self.assertEqual(cspan.data.cassandra.query, 'SELECT name, age, email FROM users') - self.assertEqual(cspan.data.cassandra.keyspace, 'instana_tests') - self.assertIsNone(cspan.data.cassandra.achievedConsistency) - self.assertIsNotNone(cspan.data.cassandra.triedHosts) - self.assertIsNone(cspan.data.cassandra.error) + self.assertEqual(cspan.data["cassandra"]["cluster"], 'Test Cluster') + self.assertEqual(cspan.data["cassandra"]["query"], 'SELECT name, age, email FROM users') + self.assertEqual(cspan.data["cassandra"]["keyspace"], 'instana_tests') + self.assertIsNone(cspan.data["cassandra"]["achievedConsistency"]) + self.assertIsNotNone(cspan.data["cassandra"]["triedHosts"]) + self.assertIsNone(cspan.data["cassandra"]["error"]) def test_simple_statement(self): res = None @@ -158,12 +158,12 @@ def test_simple_statement(self): self.assertFalse(cspan.error) self.assertIsNone(cspan.ec) - self.assertEqual(cspan.data.cassandra.cluster, 'Test Cluster') - self.assertEqual(cspan.data.cassandra.query, 'SELECT name, age, email FROM users') - self.assertEqual(cspan.data.cassandra.keyspace, 'instana_tests') - self.assertIsNone(cspan.data.cassandra.achievedConsistency) - self.assertIsNotNone(cspan.data.cassandra.triedHosts) - self.assertIsNone(cspan.data.cassandra.error) + self.assertEqual(cspan.data["cassandra"]["cluster"], 'Test Cluster') + self.assertEqual(cspan.data["cassandra"]["query"], 'SELECT name, age, email FROM users') + self.assertEqual(cspan.data["cassandra"]["keyspace"], 'instana_tests') + self.assertIsNone(cspan.data["cassandra"]["achievedConsistency"]) + self.assertIsNotNone(cspan.data["cassandra"]["triedHosts"]) + self.assertIsNone(cspan.data["cassandra"]["error"]) def test_execute_error(self): res = None @@ -196,12 +196,12 @@ def test_execute_error(self): self.assertTrue(cspan.error) self.assertEqual(cspan.ec, 1) - self.assertEqual(cspan.data.cassandra.cluster, 'Test Cluster') - self.assertEqual(cspan.data.cassandra.query, 'Not a real query') - self.assertEqual(cspan.data.cassandra.keyspace, 'instana_tests') - self.assertIsNone(cspan.data.cassandra.achievedConsistency) - self.assertIsNotNone(cspan.data.cassandra.triedHosts) - self.assertIsNotNone(cspan.data.cassandra.error) + self.assertEqual(cspan.data["cassandra"]["cluster"], 'Test Cluster') + self.assertEqual(cspan.data["cassandra"]["query"], 'Not a real query') + self.assertEqual(cspan.data["cassandra"]["keyspace"], 'instana_tests') + self.assertIsNone(cspan.data["cassandra"]["achievedConsistency"]) + self.assertIsNotNone(cspan.data["cassandra"]["triedHosts"]) + self.assertIsNotNone(cspan.data["cassandra"]["error"]) def test_prepared_statement(self): prepared = None @@ -235,9 +235,9 @@ def test_prepared_statement(self): self.assertFalse(cspan.error) self.assertIsNone(cspan.ec) - self.assertEqual(cspan.data.cassandra.cluster, 'Test Cluster') - self.assertEqual(cspan.data.cassandra.query, 'INSERT INTO users (id, name, age) VALUES (?, ?, ?)') - self.assertEqual(cspan.data.cassandra.keyspace, 'instana_tests') - self.assertEqual(cspan.data.cassandra.achievedConsistency, "QUORUM") - self.assertIsNotNone(cspan.data.cassandra.triedHosts) - self.assertIsNone(cspan.data.cassandra.error) + self.assertEqual(cspan.data["cassandra"]["cluster"], 'Test Cluster') + self.assertEqual(cspan.data["cassandra"]["query"], 'INSERT INTO users (id, name, age) VALUES (?, ?, ?)') + self.assertEqual(cspan.data["cassandra"]["keyspace"], 'instana_tests') + self.assertEqual(cspan.data["cassandra"]["achievedConsistency"], "QUORUM") + self.assertIsNotNone(cspan.data["cassandra"]["triedHosts"]) + self.assertIsNone(cspan.data["cassandra"]["error"]) diff --git a/tests/test_tornado_server.py b/tests/test_tornado_server.py index 69c77658..a63025b8 100644 --- a/tests/test_tornado_server.py +++ b/tests/test_tornado_server.py @@ -3,6 +3,7 @@ import asyncio import aiohttp import unittest +import time import tornado from tornado.httpclient import AsyncHTTPClient @@ -112,6 +113,7 @@ async def test(): response = tornado.ioloop.IOLoop.current().run_sync(test) + time.sleep(0.5) spans = self.recorder.queued_spans() self.assertEqual(3, len(spans)) From 1e7f77582bd395315ee9cc4236b1f63bae215ed5 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Thu, 5 Mar 2020 16:29:32 +0100 Subject: [PATCH 10/29] Check if agent supports extra_headers before proceeding --- instana/instrumentation/aiohttp/client.py | 2 +- instana/instrumentation/aiohttp/server.py | 2 +- instana/instrumentation/aws_lambda.py | 6 ------ instana/instrumentation/django/middleware.py | 2 +- instana/instrumentation/flask/vanilla.py | 2 +- instana/instrumentation/flask/with_blinker.py | 2 +- instana/instrumentation/tornado/server.py | 2 +- instana/instrumentation/urllib3.py | 2 +- instana/instrumentation/webapp2_inst.py | 2 +- instana/wsgi.py | 2 +- 10 files changed, 9 insertions(+), 15 deletions(-) diff --git a/instana/instrumentation/aiohttp/client.py b/instana/instrumentation/aiohttp/client.py index d99b178c..2b8fc6f9 100644 --- a/instana/instrumentation/aiohttp/client.py +++ b/instana/instrumentation/aiohttp/client.py @@ -41,7 +41,7 @@ async def stan_request_end(session, trace_config_ctx, params): if scope is not None: scope.span.set_tag('http.status_code', params.response.status) - if agent.extra_headers is not None: + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: for custom_header in agent.extra_headers: if custom_header in params.response.headers: scope.span.set_tag("http.%s" % custom_header, params.response.headers[custom_header]) diff --git a/instana/instrumentation/aiohttp/server.py b/instana/instrumentation/aiohttp/server.py index 2e6ccef3..032b5f23 100644 --- a/instana/instrumentation/aiohttp/server.py +++ b/instana/instrumentation/aiohttp/server.py @@ -32,7 +32,7 @@ async def stan_middleware(request, handler): scope.span.set_tag("http.method", request.method) # Custom header tracking support - if agent.extra_headers is not None: + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: for custom_header in agent.extra_headers: if custom_header in request.headers: scope.span.set_tag("http.%s" % custom_header, request.headers[custom_header]) diff --git a/instana/instrumentation/aws_lambda.py b/instana/instrumentation/aws_lambda.py index b77b45d7..f5e3e546 100644 --- a/instana/instrumentation/aws_lambda.py +++ b/instana/instrumentation/aws_lambda.py @@ -18,12 +18,6 @@ sys.path.insert(0, '/var/runtime') sys.path.insert(0, '/var/task') - # try: - # import importlib - # module = importlib.import_module(handler_module, package=None) - # except ImportError: - # logger.warn("Couldn't do the manual import") - @wrapt.patch_function_wrapper(handler_module, handler_function) def lambda_handler_with_instana(wrapped, instance, args, kwargs): agent.collector.collect_snapshot(*args) diff --git a/instana/instrumentation/django/middleware.py b/instana/instrumentation/django/middleware.py index 98593e94..0308f653 100644 --- a/instana/instrumentation/django/middleware.py +++ b/instana/instrumentation/django/middleware.py @@ -31,7 +31,7 @@ def process_request(self, request): ctx = tracer.extract(ot.Format.HTTP_HEADERS, env) request.iscope = tracer.start_active_span('django', child_of=ctx) - if agent.extra_headers is not None: + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: for custom_header in agent.extra_headers: # Headers are available in this format: HTTP_X_CAPTURE_THIS django_header = ('HTTP_' + custom_header.upper()).replace('-', '_') diff --git a/instana/instrumentation/flask/vanilla.py b/instana/instrumentation/flask/vanilla.py index e92766e4..1fa8b641 100644 --- a/instana/instrumentation/flask/vanilla.py +++ b/instana/instrumentation/flask/vanilla.py @@ -25,7 +25,7 @@ def before_request_with_instana(*argv, **kwargs): flask.g.scope = tracer.start_active_span('wsgi', child_of=ctx) span = flask.g.scope.span - if agent.extra_headers is not None: + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: for custom_header in agent.extra_headers: # Headers are available in this format: HTTP_X_CAPTURE_THIS header = ('HTTP_' + custom_header.upper()).replace('-', '_') diff --git a/instana/instrumentation/flask/with_blinker.py b/instana/instrumentation/flask/with_blinker.py index 81e74e3b..40adec6f 100644 --- a/instana/instrumentation/flask/with_blinker.py +++ b/instana/instrumentation/flask/with_blinker.py @@ -26,7 +26,7 @@ def request_started_with_instana(sender, **extra): flask.g.scope = tracer.start_active_span('wsgi', child_of=ctx) span = flask.g.scope.span - if agent.extra_headers is not None: + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: for custom_header in agent.extra_headers: # Headers are available in this format: HTTP_X_CAPTURE_THIS header = ('HTTP_' + custom_header.upper()).replace('-', '_') diff --git a/instana/instrumentation/tornado/server.py b/instana/instrumentation/tornado/server.py index c2e99512..4f4bed7c 100644 --- a/instana/instrumentation/tornado/server.py +++ b/instana/instrumentation/tornado/server.py @@ -39,7 +39,7 @@ def execute_with_instana(wrapped, instance, argv, kwargs): scope.span.set_tag("handler", instance.__class__.__name__) # Custom header tracking support - if agent.extra_headers is not None: + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: for custom_header in agent.extra_headers: if custom_header in instance.request.headers: scope.span.set_tag("http.%s" % custom_header, instance.request.headers[custom_header]) diff --git a/instana/instrumentation/urllib3.py b/instana/instrumentation/urllib3.py index a54327d1..b0743ac7 100644 --- a/instana/instrumentation/urllib3.py +++ b/instana/instrumentation/urllib3.py @@ -48,7 +48,7 @@ def collect_response(scope, response): try: scope.span.set_tag(ext.HTTP_STATUS_CODE, response.status) - if agent.extra_headers is not None: + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: for custom_header in agent.extra_headers: if custom_header in response.headers: scope.span.set_tag("http.%s" % custom_header, response.headers[custom_header]) diff --git a/instana/instrumentation/webapp2_inst.py b/instana/instrumentation/webapp2_inst.py index e1faab7a..16c93ba8 100644 --- a/instana/instrumentation/webapp2_inst.py +++ b/instana/instrumentation/webapp2_inst.py @@ -43,7 +43,7 @@ def new_start_response(status, headers, exc_info=None): ctx = tracer.extract(ot.Format.HTTP_HEADERS, env) scope = env['stan_scope'] = tracer.start_active_span("wsgi", child_of=ctx) - if agent.extra_headers is not None: + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: for custom_header in agent.extra_headers: # Headers are available in this format: HTTP_X_CAPTURE_THIS wsgi_header = ('HTTP_' + custom_header.upper()).replace('-', '_') diff --git a/instana/wsgi.py b/instana/wsgi.py index d9a939a7..b5285087 100644 --- a/instana/wsgi.py +++ b/instana/wsgi.py @@ -37,7 +37,7 @@ def new_start_response(status, headers, exc_info=None): ctx = tracer.extract(ot.Format.HTTP_HEADERS, env) self.scope = tracer.start_active_span("wsgi", child_of=ctx) - if agent.extra_headers is not None: + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: for custom_header in agent.extra_headers: # Headers are available in this format: HTTP_X_CAPTURE_THIS wsgi_header = ('HTTP_' + custom_header.upper()).replace('-', '_') From ddd45ce542f1e3aff2762eca9fbf79e72a57e007 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 10 Mar 2020 11:39:25 +0100 Subject: [PATCH 11/29] Centralize all lambda instrumentation --- instana/instrumentation/aws_lambda.py | 93 +++++++++++++++++++-------- 1 file changed, 65 insertions(+), 28 deletions(-) diff --git a/instana/instrumentation/aws_lambda.py b/instana/instrumentation/aws_lambda.py index f5e3e546..745f5475 100644 --- a/instana/instrumentation/aws_lambda.py +++ b/instana/instrumentation/aws_lambda.py @@ -3,37 +3,74 @@ import wrapt from ..log import logger -from ..singletons import agent, tracer +from ..singletons import get_agent, get_tracer +from .. import get_lambda_handler_or_default -if os.environ.get("INSTANA_ENDPOINT_URL", False): - handler = os.environ.get("_HANDLER", False) - if handler: - parts = handler.split(".") - handler_function = parts.pop() - handler_module = ".".join(parts) +def get_context(tracer, event): + # TODO: Search for more types of trigger context + return tracer.extract('http_headers', event) + + +def _is_api_gateway_proxy_trigger(event): + for key in ["resource", "path", "httpMethod"]: + if key not in event: + return False + return True + + +def enrich_lambda_span(agent, span, event, context): + try: + span.set_tag('lambda.arn', context.invoked_function_arn) + span.set_tag('lambda.name', context.function_name) + span.set_tag('lambda.version', context.function_version) + + if _is_api_gateway_proxy_trigger(event): + span.set_tag('lambda.trigger', 'aws:api.gateway') + span.set_tag('http.method', event["httpMethod"]) + span.set_tag('http.url', event["path"]) + span.set_tag('http.path_tpl', event["resource"]) + span.set_tag('http.params', event["httpMethod"]) + + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: + for custom_header in agent.extra_headers: + for key in event: + if key.lower() == custom_header: + span.set_tag("http.%s" % custom_header, event[key]) + except: + logger.debug("enrich_lambda_span: ", exc_info=True) + - logger.debug("AWS Lambda: Instrumenting handler %s.%s" % (handler_module, handler_function)) +def lambda_handler_with_instana(wrapped, instance, args, kwargs): + event = args[0] + context = args[1] + agent = get_agent() + tracer = get_tracer() + agent.collector.collect_snapshot(*args) + incoming_ctx = get_context(tracer, event) + + result = None + with tracer.start_active_span("aws.lambda.entry", child_of=incoming_ctx) as scope: + enrich_lambda_span(agent, scope.span, *args) + try: + result = wrapped(*args, **kwargs) + except Exception as e: + if scope.span: + scope.span.log_exception(e) + raise + + agent.collector.shutdown() + return result + + +if os.environ.get("INSTANA_ENDPOINT_URL", False): + handler_module, handler_function = get_lambda_handler_or_default() + + if handler_module is not None and handler_function is not None: + logger.debug("Instrumenting AWS Lambda handler (%s.%s)" % (handler_module, handler_function)) sys.path.insert(0, '/var/runtime') sys.path.insert(0, '/var/task') - - @wrapt.patch_function_wrapper(handler_module, handler_function) - def lambda_handler_with_instana(wrapped, instance, args, kwargs): - agent.collector.collect_snapshot(*args) - - result = None - with tracer.start_active_span("aws.lambda.entry") as scope: - try: - scope.span.set_tag('lambda.arn', agent.collector.context.invoked_function_arn) - scope.span.set_tag('lambda.name', agent.collector.context.function_name) - scope.span.set_tag('lambda.version', agent.collector.context.function_version) - - result = wrapped(*args, **kwargs) - except Exception as e: - if scope.span: - scope.span.log_exception(e) - raise - - agent.collector.shutdown() - return result + wrapt.wrap_function_wrapper(handler_module, handler_function, lambda_handler_with_instana) + else: + logger.debug("Couldn't determine AWS Lambda Handler. Not monitoring.") From 130e931482d7ea6b46d2da7accffd00a92508271 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 10 Mar 2020 11:40:25 +0100 Subject: [PATCH 12/29] New Lambda test suite --- tests/test_lambda.py | 124 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 tests/test_lambda.py diff --git a/tests/test_lambda.py b/tests/test_lambda.py new file mode 100644 index 00000000..3511b294 --- /dev/null +++ b/tests/test_lambda.py @@ -0,0 +1,124 @@ +from __future__ import absolute_import + +import os +import wrapt +import unittest +from instana.singletons import set_agent, set_tracer +from instana.tracer import InstanaTracer +from instana.agent import AWSLambdaAgent +from instana.recorder import AWSLambdaRecorder +from instana import lambda_handler +from instana import get_lambda_handler_or_default +from instana.instrumentation.aws_lambda import lambda_handler_with_instana + + +# Mock Context object +class TestContext(dict): + def __init__(self): + self.invoked_function_arn = "arn:aws:lambda:us-east-2:12345:function:TestPython:1" + self.function_name = "TestPython" + self.function_version = "1" + + +# This is the target handler that will be instrumented for these tests +def test_lambda_handler(event, context): + print("target_handler called") + return "All Ok" + + +class TestLambda(unittest.TestCase): + def setUp(self): + """ Clear all spans before a test run """ + pass + + def tearDown(self): + """ Reset all environment variables of consequence """ + if "LAMBDA_HANDLER" in os.environ: + os.environ.pop("LAMBDA_HANDLER") + if "INSTANA_EXTRA_HTTP_HEADERS" in os.environ: + os.environ.pop("INSTANA_EXTRA_HTTP_HEADERS") + if "INSTANA_ENDPOINT_URL" in os.environ: + os.environ.pop("INSTANA_ENDPOINT_URL") + if "INSTANA_AGENT_KEY" in os.environ: + os.environ.pop("INSTANA_AGENT_KEY") + + def create_agent_and_setup_tracer(self): + self.agent = AWSLambdaAgent() + self.span_recorder = AWSLambdaRecorder(self.agent) + self.tracer = InstanaTracer(recorder=self.span_recorder) + set_agent(self.agent) + set_tracer(self.tracer) + + def test_invalid_options(self): + # None of the required env vars are available... + agent = AWSLambdaAgent() + self.assertFalse(agent._can_send) + self.assertIsNone(agent.collector) + + def test_get_handler(self): + os.environ["LAMBDA_HANDLER"] = "tests.lambda_handler" + handler_module, handler_function = get_lambda_handler_or_default() + + self.assertEqual("tests", handler_module) + self.assertEqual("lambda_handler", handler_function) + + def test_agent_extra_headers(self): + os.environ['INSTANA_EXTRA_HTTP_HEADERS'] = "X-Test-Header;X-Another-Header;X-And-Another-Header" + self.create_agent_and_setup_tracer() + self.assertIsNotNone(self.agent.extra_headers) + should_headers = ['x-test-header', 'x-another-header', 'x-and-another-header'] + self.assertEqual(should_headers, self.agent.extra_headers) + + def test_api_gateway_tracing(self): + os.environ["LAMBDA_HANDLER"] = "tests.test_lambda.test_lambda_handler" + os.environ["INSTANA_ENDPOINT_URL"] = "https://localhost/notreal" + os.environ["INSTANA_AGENT_KEY"] = "Fake_Key" + + self.create_agent_and_setup_tracer() + + module_name, function_name = get_lambda_handler_or_default() + self.assertEqual("tests.test_lambda", module_name) + self.assertEqual("test_lambda_handler", function_name) + + wrapt.wrap_function_wrapper(module_name, function_name, lambda_handler_with_instana) + + event = dict() + context = TestContext() + result = lambda_handler(event, context) + + self.assertEqual('All Ok', result) + payload = self.agent.collector.prepare_payload() + + self.assertTrue("metrics" in payload) + self.assertTrue("spans" in payload) + self.assertEqual(2, len(payload.keys())) + self.assertEqual('com.instana.plugin.aws.lambda', payload['metrics']['plugins']['name']) + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', payload['metrics']['plugins']['entityId']) + + self.assertEqual(1, len(payload['spans'])) + + span = payload['spans'][0] + self.assertEqual('aws.lambda.entry', span.n) + self.assertIsNotNone(span.t) + self.assertIsNotNone(span.s) + self.assertIsNone(span.p) + self.assertIsNotNone(span.ts) + self.assertIsNotNone(span.d) + + self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'}, span.f) + + self.assertIsNone(span.ec) + self.assertIsNone(span.error) + self.assertIsNone(span.data['lambda']['error']) + + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', span.data['lambda']['arn']) + self.assertEqual(None, span.data['lambda']['alias']) + self.assertEqual('python', span.data['lambda']['runtime']) + self.assertEqual('TestPython', span.data['lambda']['functionName']) + self.assertEqual('1', span.data['lambda']['functionVersion']) + + + + + + From 6d27d429aaa467c06bc6f77686374dce88a7a97b Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 10 Mar 2020 11:42:53 +0100 Subject: [PATCH 13/29] New and improved lambda handler and handler parsing --- instana/__init__.py | 51 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/instana/__init__.py b/instana/__init__.py index 18230cff..b5945f76 100644 --- a/instana/__init__.py +++ b/instana/__init__.py @@ -21,8 +21,9 @@ import os import sys -from threading import Timer +import importlib import pkg_resources +from threading import Timer __author__ = 'Instana Inc.' __copyright__ = 'Copyright 2020 Instana Inc.' @@ -49,16 +50,52 @@ def load(_): print("load: detected lambda environment") +def get_lambda_handler_or_default(): + """ + For instrumenting AWS Lambda, users specify their original lambda handler in the LAMBDA_HANDLER environment + variable. This function searches for and parses that environment variable or returns the defaults. + + The default handler value for AWS Lambda is 'lambda_function.lambda_handler' which + equates to the function "lambda_handler in a file named "lambda_function.py" or in Python + terms "from lambda_function import lambda_handler" + """ + handler_module = "lambda_function" + handler_function = "lambda_handler" + + try: + handler = os.environ.get("LAMBDA_HANDLER", False) + + if handler: + parts = handler.split(".") + handler_function = parts.pop() + handler_module = ".".join(parts) + except: + pass + + return handler_module, handler_function + + def lambda_handler(event, context): - print("Instana Python lives!") - print("Attempting import of default handler") + """ + Entry point for AWS Lambda monitoring. + + This function will trigger the initialization of Instana monitoring and then call + the original user specified lambda handler function. + """ + module_name, function_name = get_lambda_handler_or_default() + try: - from lambda_function import lambda_handler as original_lambda_handler + # Import the module specified in module_name + handler_module = importlib.import_module(module_name) except ImportError: - print("couldn't import default lambda handler") + print("Couldn't determine and locate default module handler: %s.%s", module_name, function_name) else: - print("found default lambda handler!") - original_lambda_handler(event, context) + # Now get the function and execute it + if hasattr(handler_module, function_name): + handler_function = getattr(handler_module, function_name) + return handler_function(event, context) + else: + print("Couldn't determine and locate default function handler: %s.%s", module_name, function_name) def boot_agent(): From e3c5f9236c4231a0e44302def84d894aa7ecf05d Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 10 Mar 2020 11:44:27 +0100 Subject: [PATCH 14/29] Fix trailing slash bug reported by Justyn --- instana/agent.py | 16 +++++++--------- instana/options.py | 5 +++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/instana/agent.py b/instana/agent.py index 758cc030..0c30155b 100644 --- a/instana/agent.py +++ b/instana/agent.py @@ -322,16 +322,18 @@ def __response_url(self, message_id): class AWSLambdaAgent(BaseAgent): - # AGENT_DATA_PATH = "com.instana.plugin.python.%d" - # AGENT_HEADER = "Instana Agent" - def __init__(self): super(AWSLambdaAgent, self).__init__() self.from_ = AWSLambdaFrom() + self.collector = None self.options = AWSLambdaOptions() self.report_headers = None self._can_send = False + self.extra_headers = None + + if "INSTANA_EXTRA_HTTP_HEADERS" in os.environ: + self.extra_headers = str(os.environ["INSTANA_EXTRA_HTTP_HEADERS"]).lower().split(';') if self._validate_options(): self._can_send = True @@ -353,8 +355,6 @@ def report_data_payload(self, payload): """ response = None try: - logger.debug("report_data_payload entry: %s" % self.__data_bundle_url()) - if self.report_headers is None: # Prepare request headers self.report_headers = dict() @@ -372,8 +372,7 @@ def report_data_payload(self, payload): logger.debug("report_data_payload: response.status_code is %s" % response.status_code) except (requests.ConnectTimeout, requests.ConnectionError): - logger.debug("report_traces: Instana host agent connection error") - # FIXME: Larger exception capture space + logger.debug("report_data_payload: ", exc_info=True) except: logger.debug("report_data_payload: ", exc_info=True) finally: @@ -383,8 +382,7 @@ def _validate_options(self): """ Validate that the options used by this Agent are valid. e.g. can we report data? """ - # TODO: Endpoint and Agent key validation - return True + return self.options.endpoint_url is not None and self.options.agent_key is not None def __data_bundle_url(self): """ diff --git a/instana/options.py b/instana/options.py index 98863d74..7e8cc1dd 100644 --- a/instana/options.py +++ b/instana/options.py @@ -43,6 +43,11 @@ def __init__(self, **kwds): self.debug = True self.endpoint_url = os.environ.get("INSTANA_ENDPOINT_URL", None) + + # Remove any trailing slash (if any) + if self.endpoint_url is not None and self.endpoint_url[-1] == "/": + self.endpoint_url = self.endpoint_url[:-1] + self.agent_key = os.environ.get("INSTANA_AGENT_KEY", None) self.extra_http_headers = os.environ.get("INSTANA_EXTRA_HTTP_HEADERS", None) From a2f9ae46072f6ff2f195230d27ba0ccd021590d1 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 10 Mar 2020 11:45:44 +0100 Subject: [PATCH 15/29] Refinement and additions for the test suite --- instana/collector.py | 34 ++++++++++++++++++++++------------ instana/recorder.py | 8 ++++---- instana/tracer.py | 4 ++-- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/instana/collector.py b/instana/collector.py index 821e872e..0189f50d 100644 --- a/instana/collector.py +++ b/instana/collector.py @@ -1,8 +1,9 @@ +import os import sys import threading from .log import logger -from .util import every, to_json, DictionaryOfStan +from .util import every, DictionaryOfStan if sys.version_info.major == 2: @@ -46,20 +47,29 @@ def background_report(self): return False return self.prepare_and_report_data() + def prepare_payload(self): + payload = DictionaryOfStan() + payload["spans"] = None + payload["metrics"] = None + + if not self.span_queue.empty(): + payload["spans"] = self.__queued_spans() + + if self.snapshot_data and self.snapshot_data_sent is False: + payload["metrics"] = self.snapshot_data + self.snapshot_data_sent = True + + return payload + def prepare_and_report_data(self): + if "INSTANA_TEST" in os.environ: + return True + lock_acquired = self.lock.acquire(False) if lock_acquired: - payload = DictionaryOfStan() - - if not self.span_queue.empty(): - payload["spans"] = self.__queued_spans() - - if self.snapshot_data and self.snapshot_data_sent is False: - payload["metrics"] = self.snapshot_data - self.snapshot_data_sent = True + payload = self.prepare_payload() if len(payload) > 0: - logger.debug(to_json(payload)) self.agent.report_data_payload(payload) else: logger.debug("prepare_and_report_data: No data to report") @@ -70,7 +80,6 @@ def prepare_and_report_data(self): def collect_snapshot(self, event, context): self.snapshot_data = DictionaryOfStan() - metrics = DictionaryOfStan() self.context = context self.event = event @@ -80,7 +89,8 @@ def collect_snapshot(self, event, context): self.snapshot_data["plugins"]["entityId"] = self.context.invoked_function_arn except: logger.debug("collect_snapshot error", exc_info=True) - + finally: + return self.snapshot_data def __queued_spans(self): """ Get all of the spans in the queue """ diff --git a/instana/recorder.py b/instana/recorder.py index 6e767881..c9ea267c 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -16,7 +16,7 @@ import queue -class InstanaRecorder(object): +class StandardRecorder(object): THREAD_NAME = "Instana Span Reporting" REGISTERED_SPANS = ("aiohttp-client", "aiohttp-server", "aws.lambda.entry", "cassandra", "couchbase", @@ -112,7 +112,7 @@ def record_span(self, span): self.queue.put(json_span) -class AWSLambdaRecorder(InstanaRecorder): +class AWSLambdaRecorder(StandardRecorder): def __init__(self, agent): self.agent = agent super(AWSLambdaRecorder, self).__init__() @@ -121,12 +121,12 @@ def record_span(self, span): """ Convert the passed BasicSpan and add it to the span queue """ - source = instana.singletons.agent.get_from_structure() + source = self.agent.get_from_structure() if span.operation_name in self.REGISTERED_SPANS: json_span = RegisteredSpan(span, source) else: - service_name = instana.singletons.agent.options.service_name + service_name = self.agent.options.service_name json_span = SDKSpan(span, source, service_name) logger.debug("Recorded span: %s", json_span) diff --git a/instana/tracer.py b/instana/tracer.py index 62c431f5..35362eeb 100644 --- a/instana/tracer.py +++ b/instana/tracer.py @@ -12,7 +12,7 @@ from .http_propagator import HTTPPropagator from .text_propagator import TextPropagator from .span_context import InstanaSpanContext -from .recorder import InstanaRecorder, InstanaSampler +from .recorder import StandardRecorder, InstanaSampler from .span import InstanaSpan, RegisteredSpan from .util import generate_id @@ -21,7 +21,7 @@ class InstanaTracer(BasicTracer): def __init__(self, scope_manager=None, recorder=None): if recorder is None: - recorder = InstanaRecorder() + recorder = StandardRecorder() super(InstanaTracer, self).__init__( recorder, InstanaSampler(), scope_manager) From d7189a473e8dff277313a063af5099c6753077e5 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 10 Mar 2020 12:45:51 +0100 Subject: [PATCH 16/29] Linter love --- instana/instrumentation/aws_lambda.py | 4 ++-- tests/test_lambda.py | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/instana/instrumentation/aws_lambda.py b/instana/instrumentation/aws_lambda.py index 745f5475..34630501 100644 --- a/instana/instrumentation/aws_lambda.py +++ b/instana/instrumentation/aws_lambda.py @@ -55,9 +55,9 @@ def lambda_handler_with_instana(wrapped, instance, args, kwargs): enrich_lambda_span(agent, scope.span, *args) try: result = wrapped(*args, **kwargs) - except Exception as e: + except Exception as exc: if scope.span: - scope.span.log_exception(e) + scope.span.log_exception(exc) raise agent.collector.shutdown() diff --git a/tests/test_lambda.py b/tests/test_lambda.py index 3511b294..20208ec4 100644 --- a/tests/test_lambda.py +++ b/tests/test_lambda.py @@ -14,7 +14,8 @@ # Mock Context object class TestContext(dict): - def __init__(self): + def __init__(self, **kwargs): + super(TestContext, self).__init__(**kwargs) self.invoked_function_arn = "arn:aws:lambda:us-east-2:12345:function:TestPython:1" self.function_name = "TestPython" self.function_version = "1" @@ -27,9 +28,11 @@ def test_lambda_handler(event, context): class TestLambda(unittest.TestCase): - def setUp(self): - """ Clear all spans before a test run """ - pass + def __init__(self, methodName='runTest'): + super(TestLambda, self).__init__(methodName) + self.agent = None + self.span_recorder = None + self.tracer = None def tearDown(self): """ Reset all environment variables of consequence """ @@ -105,7 +108,8 @@ def test_api_gateway_tracing(self): self.assertIsNotNone(span.ts) self.assertIsNotNone(span.d) - self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'}, span.f) + self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'}, + span.f) self.assertIsNone(span.ec) self.assertIsNone(span.error) @@ -118,7 +122,3 @@ def test_api_gateway_tracing(self): self.assertEqual('1', span.data['lambda']['functionVersion']) - - - - From 46df7777d5a95b2f89bc750bb4ef0c0af2b3b8a9 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 10 Mar 2020 12:46:21 +0100 Subject: [PATCH 17/29] Allow get/set of agent & tracer for tests --- instana/singletons.py | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/instana/singletons.py b/instana/singletons.py index bf49072d..00342c4e 100644 --- a/instana/singletons.py +++ b/instana/singletons.py @@ -4,10 +4,10 @@ from .agent import StandardAgent, AWSLambdaAgent from .tracer import InstanaTracer -from .recorder import InstanaRecorder, AWSLambdaRecorder - +from .recorder import StandardRecorder, AWSLambdaRecorder agent = None +tracer = None span_recorder = None if os.environ.get("INSTANA_ENDPOINT_URL", False): @@ -17,20 +17,27 @@ else: print("Standard host environment") agent = StandardAgent() - span_recorder = InstanaRecorder() + span_recorder = StandardRecorder() + + +# Retrieve the globally configured agent +def get_agent(): + global agent + return agent + + +# Set the global agent for the Instana package. This is used for the +# test suite only currently. +def set_agent(new_agent): + global agent + agent = new_agent # The global OpenTracing compatible tracer used internally by # this package. -# -# Usage example: -# -# import instana -# instana.tracer.start_span(...) -# tracer = InstanaTracer(recorder=span_recorder) -if sys.version_info >= (3,4): +if sys.version_info >= (3, 4): from opentracing.scope_managers.asyncio import AsyncioScopeManager async_tracer = InstanaTracer(scope_manager=AsyncioScopeManager(), recorder=span_recorder) @@ -47,3 +54,16 @@ def setup_tornado_tracer(): # Set ourselves as the tracer. opentracing.tracer = tracer + + +# Retrieve the globally configured tracer +def get_tracer(): + global tracer + return tracer + + +# Set the global tracer for the Instana package. This is used for the +# test suite only currently. +def set_tracer(new_tracer): + global tracer + tracer = new_tracer From a28c1aef10070b25327413d781c07e95de2e1add Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 10 Mar 2020 12:47:08 +0100 Subject: [PATCH 18/29] Updated build script --- bin/build_lambda_layer.py | 48 +++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/bin/build_lambda_layer.py b/bin/build_lambda_layer.py index 7ca8dbdd..df22fc96 100755 --- a/bin/build_lambda_layer.py +++ b/bin/build_lambda_layer.py @@ -1,10 +1,14 @@ #!/usr/bin/env python import os +import json import shutil import time import distutils.spawn -from subprocess import call +from subprocess import call, check_output + +# Disable aws CLI pagination +os.environ["AWS_PAGER"] = "" # Check requirements first for cmd in ["pip", "zip"]: @@ -51,11 +55,45 @@ fq_zip_filename = os.getcwd() + '/%s' % zip_filename aws_zip_filename = "fileb://%s" % fq_zip_filename +print("Zipfile should be at: ", fq_zip_filename) -print("===> Uploading zipfile to AWS as a new lambda layer version") -call(["aws", "lambda", "publish-layer-version", "--layer-name", "instana-py-test", "--zip-file", aws_zip_filename, - "--compatible-runtimes", "python2.7", "python3.6", "python3.7", "python3.8"]) +# regions = ['ap-northeast-1', 'ap-northeast-2', 'ap-south-1', 'ap-southeast-1', 'ap-southeast-2', 'ca-central-1', +# 'eu-central-1', 'eu-north-1', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'sa-east-1', 'us-east-1', +# 'us-east-2', 'us-west-1', 'us-west-2'] -print("Zipfile should be at: ", fq_zip_filename) +regions = ['us-west-1'] +# regions = ['us-east-2'] + +LAYER_NAME = "instana-py-test" + +published = dict() + +# response = check_output(["aws", "lambda", "list-layers"]) + +for region in regions: + print("===> Uploading layer to AWS %s " % region) + response = check_output(["aws", "--region", region, "lambda", "publish-layer-version", + "--description", + "Provides Instana tracing and monitoring of AWS Lambda functions built with Python", + "--license-info", "MIT", "--output", "json", + "--layer-name", LAYER_NAME, "--zip-file", aws_zip_filename, + "--compatible-runtimes", "python2.7", "python3.6", "python3.7", "python3.8"]) + + json_data = json.loads(response) + version = json_data['Version'] + print("===> Uploaded version is %s" % version) + + # print("===> Making layer public...") + # response = check_output(["aws", "--region", region, "lambda", "add-layer-version-permission", + # "--layer-name", LAYER_NAME, "--version-number", str(version), + # "--statement-id", "public-permission-all-accounts", + # "--principal", "*", + # "--action", "lambda:GetLayerVersion", + # "--output", "text"]) + + published[region] = json_data['LayerVersionArn'] +print("===> Published list:") +for key in published.keys(): + print("%s\t%s" % (key, published[key])) From 2c824adfa28cd37b529da8534f2342e41d9c2bcb Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 10 Mar 2020 15:17:25 +0100 Subject: [PATCH 19/29] Restore agent and tracer after each test; lint fixes --- tests/test_lambda.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/tests/test_lambda.py b/tests/test_lambda.py index 20208ec4..6a95c9fb 100644 --- a/tests/test_lambda.py +++ b/tests/test_lambda.py @@ -1,9 +1,9 @@ from __future__ import absolute_import import os -import wrapt import unittest -from instana.singletons import set_agent, set_tracer +import wrapt +from instana.singletons import get_agent, set_agent, get_tracer, set_tracer from instana.tracer import InstanaTracer from instana.agent import AWSLambdaAgent from instana.recorder import AWSLambdaRecorder @@ -22,7 +22,7 @@ def __init__(self, **kwargs): # This is the target handler that will be instrumented for these tests -def test_lambda_handler(event, context): +def my_lambda_handler(event, context): print("target_handler called") return "All Ok" @@ -34,6 +34,9 @@ def __init__(self, methodName='runTest'): self.span_recorder = None self.tracer = None + self.original_agent = get_agent() + self.original_tracer = get_tracer() + def tearDown(self): """ Reset all environment variables of consequence """ if "LAMBDA_HANDLER" in os.environ: @@ -45,6 +48,9 @@ def tearDown(self): if "INSTANA_AGENT_KEY" in os.environ: os.environ.pop("INSTANA_AGENT_KEY") + set_agent(self.original_agent) + set_tracer(self.original_tracer) + def create_agent_and_setup_tracer(self): self.agent = AWSLambdaAgent() self.span_recorder = AWSLambdaRecorder(self.agent) @@ -73,7 +79,7 @@ def test_agent_extra_headers(self): self.assertEqual(should_headers, self.agent.extra_headers) def test_api_gateway_tracing(self): - os.environ["LAMBDA_HANDLER"] = "tests.test_lambda.test_lambda_handler" + os.environ["LAMBDA_HANDLER"] = "tests.test_lambda.my_lambda_handler" os.environ["INSTANA_ENDPOINT_URL"] = "https://localhost/notreal" os.environ["INSTANA_AGENT_KEY"] = "Fake_Key" @@ -81,7 +87,7 @@ def test_api_gateway_tracing(self): module_name, function_name = get_lambda_handler_or_default() self.assertEqual("tests.test_lambda", module_name) - self.assertEqual("test_lambda_handler", function_name) + self.assertEqual("my_lambda_handler", function_name) wrapt.wrap_function_wrapper(module_name, function_name, lambda_handler_with_instana) @@ -96,7 +102,8 @@ def test_api_gateway_tracing(self): self.assertTrue("spans" in payload) self.assertEqual(2, len(payload.keys())) self.assertEqual('com.instana.plugin.aws.lambda', payload['metrics']['plugins']['name']) - self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', payload['metrics']['plugins']['entityId']) + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', + payload['metrics']['plugins']['entityId']) self.assertEqual(1, len(payload['spans'])) @@ -119,6 +126,4 @@ def test_api_gateway_tracing(self): self.assertEqual(None, span.data['lambda']['alias']) self.assertEqual('python', span.data['lambda']['runtime']) self.assertEqual('TestPython', span.data['lambda']['functionName']) - self.assertEqual('1', span.data['lambda']['functionVersion']) - - + self.assertEqual('1', span.data['lambda']['functionVersion']) \ No newline at end of file From cdd15b048dff9bd4147390779080899dba22dae3 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Fri, 13 Mar 2020 11:04:24 +0100 Subject: [PATCH 20/29] Enable script for all regions --- bin/build_lambda_layer.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/bin/build_lambda_layer.py b/bin/build_lambda_layer.py index df22fc96..ebc7e15b 100755 --- a/bin/build_lambda_layer.py +++ b/bin/build_lambda_layer.py @@ -57,18 +57,20 @@ aws_zip_filename = "fileb://%s" % fq_zip_filename print("Zipfile should be at: ", fq_zip_filename) -# regions = ['ap-northeast-1', 'ap-northeast-2', 'ap-south-1', 'ap-southeast-1', 'ap-southeast-2', 'ca-central-1', -# 'eu-central-1', 'eu-north-1', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'sa-east-1', 'us-east-1', -# 'us-east-2', 'us-west-1', 'us-west-2'] +regions = ['ap-northeast-1', 'ap-northeast-2', 'ap-south-1', 'ap-southeast-1', 'ap-southeast-2', 'ca-central-1', + 'eu-central-1', 'eu-north-1', 'eu-west-1', 'eu-west-2', 'eu-west-3', 'sa-east-1', 'us-east-1', + 'us-east-2', 'us-west-1', 'us-west-2'] -regions = ['us-west-1'] -# regions = ['us-east-2'] +# regions = ['us-west-1'] -LAYER_NAME = "instana-py-test" +# LAYER_NAME = "instana-py-test" +LAYER_NAME = "instana-python" published = dict() # response = check_output(["aws", "lambda", "list-layers"]) +# To update a Function +# aws lambda update-function-configuration --function-name CanaryInACoalMine --layers arn:aws:lambda:us-west-1:410797082306:layer:instana-py-test:22 for region in regions: print("===> Uploading layer to AWS %s " % region) @@ -83,13 +85,13 @@ version = json_data['Version'] print("===> Uploaded version is %s" % version) - # print("===> Making layer public...") - # response = check_output(["aws", "--region", region, "lambda", "add-layer-version-permission", - # "--layer-name", LAYER_NAME, "--version-number", str(version), - # "--statement-id", "public-permission-all-accounts", - # "--principal", "*", - # "--action", "lambda:GetLayerVersion", - # "--output", "text"]) + print("===> Making layer public...") + response = check_output(["aws", "--region", region, "lambda", "add-layer-version-permission", + "--layer-name", LAYER_NAME, "--version-number", str(version), + "--statement-id", "public-permission-all-accounts", + "--principal", "*", + "--action", "lambda:GetLayerVersion", + "--output", "text"]) published[region] = json_data['LayerVersionArn'] From 26888d0aa9d696c847863a23c474ccca0c684d80 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Fri, 13 Mar 2020 11:04:56 +0100 Subject: [PATCH 21/29] Better script name --- bin/{build_lambda_layer.py => lambda_build_publish_layer.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename bin/{build_lambda_layer.py => lambda_build_publish_layer.py} (100%) diff --git a/bin/build_lambda_layer.py b/bin/lambda_build_publish_layer.py similarity index 100% rename from bin/build_lambda_layer.py rename to bin/lambda_build_publish_layer.py From e70ae15bfd6508b11067f1e1c7640328709a5e66 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 17 Mar 2020 11:53:31 +0100 Subject: [PATCH 22/29] Trigger support & tests --- instana/instrumentation/aws_lambda.py | 164 +++++++++- instana/recorder.py | 2 +- instana/span.py | 23 +- tests/__init__.py | 3 + tests/data/lambda/api_gateway_event.json | 135 ++++++++ tests/data/lambda/cloudwatch_event.json | 12 + tests/data/lambda/cloudwatch_logs_event.json | 5 + tests/data/lambda/s3_event.json | 38 +++ tests/data/lambda/sqs_event.json | 20 ++ tests/test_lambda.py | 307 ++++++++++++++++++- 10 files changed, 687 insertions(+), 22 deletions(-) create mode 100644 tests/data/lambda/api_gateway_event.json create mode 100644 tests/data/lambda/cloudwatch_event.json create mode 100644 tests/data/lambda/cloudwatch_logs_event.json create mode 100644 tests/data/lambda/s3_event.json create mode 100644 tests/data/lambda/sqs_event.json diff --git a/instana/instrumentation/aws_lambda.py b/instana/instrumentation/aws_lambda.py index 34630501..aa4bd82d 100644 --- a/instana/instrumentation/aws_lambda.py +++ b/instana/instrumentation/aws_lambda.py @@ -1,6 +1,9 @@ import os import sys +import gzip +import json import wrapt +import base64 from ..log import logger from ..singletons import get_agent, get_tracer @@ -12,31 +15,178 @@ def get_context(tracer, event): return tracer.extract('http_headers', event) -def _is_api_gateway_proxy_trigger(event): +def is_api_gateway_proxy_trigger(event): for key in ["resource", "path", "httpMethod"]: if key not in event: return False return True +def is_application_load_balancer_trigger(event): + if 'requestContext' in event and event['requestContext']['elb']: + return True + return False + + +def is_cloudwatch_trigger(event): + if "source" in event and 'detail-type' in event: + if event["source"] == 'aws.events' and event['detail-type'] == 'Scheduled Event': + return True + return False + + +def is_cloudwatch_logs_trigger(event): + if "awslogs" in event and event["awslogs"] != None: + return True + return False + + +def is_s3_trigger(event): + if "Records" in event: + if len(event["Records"]) > 0 and event["Records"][0]["eventSource"] == 'aws:s3': + return True + return False + + +def is_sqs_trigger(event): + if "Records" in event: + if len(event["Records"]) > 0 and event["Records"][0]["eventSource"] == 'aws:sqs': + return True + return False + + +def read_http_query_params(event): + """ + Used to parse the Lambda QueryString formats. + + @param event: lambda event dict + @return: String in the form of "a=b&c=d" + """ + # print("multiValueQueryStringParameters=%s" % event['multiValueQueryStringParameters']) + # print("queryStringParameters=%s" % event['queryStringParameters']) + + params = [] + if 'multiValueQueryStringParameters' in event: + for key in event['multiValueQueryStringParameters']: + params.append("%s=%s" % (key, event['multiValueQueryStringParameters'][key])) + return "&".join(params) + elif 'queryStringParameters' in event: + for key in event['queryStringParameters']: + params.append("%s=%s" % (key, event['queryStringParameters'][key])) + return "&".join(params) + else: + return "" + + +def capture_extra_headers(event, span, extra_headers): + for custom_header in extra_headers: + for key in event["headers"]: + if key.lower() == custom_header.lower(): + span.set_tag("http.%s" % custom_header, event["headers"][key]) + + def enrich_lambda_span(agent, span, event, context): try: span.set_tag('lambda.arn', context.invoked_function_arn) span.set_tag('lambda.name', context.function_name) span.set_tag('lambda.version', context.function_version) - if _is_api_gateway_proxy_trigger(event): + if is_api_gateway_proxy_trigger(event): span.set_tag('lambda.trigger', 'aws:api.gateway') span.set_tag('http.method', event["httpMethod"]) span.set_tag('http.url', event["path"]) span.set_tag('http.path_tpl', event["resource"]) - span.set_tag('http.params', event["httpMethod"]) + span.set_tag('http.params', read_http_query_params(event)) if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: - for custom_header in agent.extra_headers: - for key in event: - if key.lower() == custom_header: - span.set_tag("http.%s" % custom_header, event[key]) + capture_extra_headers(event, span, agent.extra_headers) + + elif is_application_load_balancer_trigger(event): + span.set_tag('lambda.trigger', 'aws:application.load.balancer') + span.set_tag('http.method', event["httpMethod"]) + span.set_tag('http.url', event["path"]) + span.set_tag('http.params', read_http_query_params(event)) + + if hasattr(agent, 'extra_headers') and agent.extra_headers is not None: + capture_extra_headers(event, span, agent.extra_headers) + + elif is_cloudwatch_trigger(event): + span.set_tag('lambda.trigger', 'aws:cloudwatch.events') + span.set_tag('data.lambda.cw.events.id', event['id']) + + resources = event['resources'] + resource_count = len(event['resources']) + if resource_count > 3: + resources = event['resources'][:3] + span.set_tag('lambda.cw.events.more', True) + else: + span.set_tag('lambda.cw.events.more', False) + + report = [] + for item in resources: + if len(item) > 200: + item = item[:200] + report.append(item) + span.set_tag('lambda.cw.events.resources', report) + + elif is_cloudwatch_logs_trigger(event): + span.set_tag('lambda.trigger', 'aws:cloudwatch.logs') + + try: + if 'awslogs' in event and 'data' in event['awslogs']: + data = event['awslogs']['data'] + decoded_data = base64.b64decode(data) + decompressed_data = gzip.decompress(decoded_data) + log_data = json.loads(decompressed_data) + + span.set_tag('lambda.cw.logs.group', log_data.get('logGroup', None)) + span.set_tag('lambda.cw.logs.stream', log_data.get('logStream', None)) + if len(log_data['logEvents']) > 3: + span.set_tag('lambda.cw.logs.more', True) + events = log_data['logEvents'][:3] + else: + events = log_data['logEvents'] + + event_data = [] + for item in events: + msg = item.get('message', None) + if len(msg) > 200: + msg = msg[:200] + event_data.append(msg) + span.set_tag('lambda.cw.logs.events', event_data) + except Exception as e: + span.set_tag('lambda.cw.logs.decodingError', repr(e)) + elif is_s3_trigger(event): + span.set_tag('lambda.trigger', 'aws:s3') + + if "Records" in event: + events = [] + for item in event["Records"][:3]: + bucket_name = "Unknown" + if "s3" in item and "bucket" in item["s3"]: + bucket_name = item["s3"]["bucket"]["name"] + + object_name = "" + if "s3" in item and "object" in item["s3"]: + object_name = item["s3"]["object"].get("key", "Unknown") + + if len(object_name) > 200: + object_name = object_name[:200] + + events.append({"event": item['eventName'], + "bucket": bucket_name, + "object": object_name}) + span.set_tag('lambda.s3.events', events) + + elif is_sqs_trigger(event): + span.set_tag('lambda.trigger', 'aws:sqs') + + if "Records" in event: + events = [] + for item in event["Records"][:3]: + events.append({'queue': item['eventSourceARN']}) + span.set_tag('lambda.sqs.messages', events) + except: logger.debug("enrich_lambda_span: ", exc_info=True) diff --git a/instana/recorder.py b/instana/recorder.py index c9ea267c..334d4bf9 100644 --- a/instana/recorder.py +++ b/instana/recorder.py @@ -129,7 +129,7 @@ def record_span(self, span): service_name = self.agent.options.service_name json_span = SDKSpan(span, source, service_name) - logger.debug("Recorded span: %s", json_span) + # logger.debug("Recorded span: %s", json_span) self.agent.collector.span_queue.put(json_span) diff --git a/instana/span.py b/instana/span.py index dedca9de..032614f6 100644 --- a/instana/span.py +++ b/instana/span.py @@ -185,18 +185,39 @@ def __init__(self, span, source, **kwargs): if len(span.tags): self.data["custom"]["tags"] = span.tags - def _populate_entry_span_data(self, span): if span.operation_name in self.HTTP_SPANS: self._collect_http_tags(span) + elif span.operation_name == "aws.lambda.entry": self.data["lambda"]["arn"] = span.tags.pop('lambda.arn', "Unknown") self.data["lambda"]["alias"] = None self.data["lambda"]["runtime"] = "python" self.data["lambda"]["functionName"] = span.tags.pop('lambda.name', "Unknown") self.data["lambda"]["functionVersion"] = span.tags.pop('lambda.version', "Unknown") + self.data["lambda"]["trigger"] = span.tags.pop('lambda.trigger', None) self.data["lambda"]["error"] = None + trigger_type = self.data["lambda"]["trigger"] + + if trigger_type in ["aws:api.gateway", "aws:application.load.balancer"]: + self._collect_http_tags(span) + elif trigger_type == 'aws:cloudwatch.events': + self.data["lambda"]["cw"]["events"]["id"] = span.tags.pop('data.lambda.cw.events.id', None) + self.data["lambda"]["cw"]["events"]["more"] = span.tags.pop('lambda.cw.events.more', False) + self.data["lambda"]["cw"]["events"]["resources"] = span.tags.pop('lambda.cw.events.resources', None) + + elif trigger_type == 'aws:cloudwatch.logs': + self.data["lambda"]["cw"]["logs"]["group"] = span.tags.pop('lambda.cw.logs.group', None) + self.data["lambda"]["cw"]["logs"]["stream"] = span.tags.pop('lambda.cw.logs.stream', None) + self.data["lambda"]["cw"]["logs"]["more"] = span.tags.pop('lambda.cw.logs.more', None) + self.data["lambda"]["cw"]["logs"]["events"] = span.tags.pop('lambda.cw.logs.events', None) + + elif trigger_type == 'aws:s3': + self.data["lambda"]["s3"]["events"] = span.tags.pop('lambda.s3.events', None) + elif trigger_type == 'aws:sqs': + self.data["lambda"]["sqs"]["messages"] = span.tags.pop('lambda.sqs.messages', None) + elif span.operation_name == "rabbitmq": self.data["rabbitmq"]["exchange"] = span.tags.pop('exchange', None) self.data["rabbitmq"]["queue"] = span.tags.pop('queue', None) diff --git a/tests/__init__.py b/tests/__init__.py index a70d1a22..9a302514 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -3,10 +3,13 @@ import sys import time import threading +import logging +from instana.log import logger from .apps.flaskalino import flask_server os.environ["INSTANA_TEST"] = "true" +logger.setLevel(logging.DEBUG) # Background Flask application diff --git a/tests/data/lambda/api_gateway_event.json b/tests/data/lambda/api_gateway_event.json new file mode 100644 index 00000000..623d3dd2 --- /dev/null +++ b/tests/data/lambda/api_gateway_event.json @@ -0,0 +1,135 @@ +{ + "body": "eyJ0ZXN0IjoiYm9keSJ9", + "resource": "/{proxy+}", + "path": "/path/to/resource", + "httpMethod": "POST", + "isBase64Encoded": true, + "queryStringParameters": { + "foo": "bar" + }, + "multiValueQueryStringParameters": { + "foo": [ + "bar" + ] + }, + "pathParameters": { + "proxy": "/path/to/resource" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-west-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https", + "X-Instana-T": "d5cb361b256413a9", + "X-Instana-S": "0901d8ae4fbf1529", + "X-Instana-L": "1" + }, + "multiValueHeaders": { + "Accept": [ + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" + ], + "Accept-Encoding": [ + "gzip, deflate, sdch" + ], + "Accept-Language": [ + "en-US,en;q=0.8" + ], + "Cache-Control": [ + "max-age=0" + ], + "CloudFront-Forwarded-Proto": [ + "https" + ], + "CloudFront-Is-Desktop-Viewer": [ + "true" + ], + "CloudFront-Is-Mobile-Viewer": [ + "false" + ], + "CloudFront-Is-SmartTV-Viewer": [ + "false" + ], + "CloudFront-Is-Tablet-Viewer": [ + "false" + ], + "CloudFront-Viewer-Country": [ + "US" + ], + "Host": [ + "0123456789.execute-api.us-west-1.amazonaws.com" + ], + "Upgrade-Insecure-Requests": [ + "1" + ], + "User-Agent": [ + "Custom User Agent String" + ], + "Via": [ + "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)" + ], + "X-Amz-Cf-Id": [ + "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==" + ], + "X-Forwarded-For": [ + "127.0.0.1, 127.0.0.2" + ], + "X-Forwarded-Port": [ + "443" + ], + "X-Forwarded-Proto": [ + "https" + ], + "X-Instana-T": [ + "d5cb361b256413a9" + ], + "X-Instana-S": [ + "0901d8ae4fbf1529" + ], + "X-Instana-L": [ + "1" + ] + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/prod/path/to/resource", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } +} \ No newline at end of file diff --git a/tests/data/lambda/cloudwatch_event.json b/tests/data/lambda/cloudwatch_event.json new file mode 100644 index 00000000..625110d6 --- /dev/null +++ b/tests/data/lambda/cloudwatch_event.json @@ -0,0 +1,12 @@ +{ + "id": "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c", + "detail-type": "Scheduled Event", + "source": "aws.events", + "account": "{{{account-id}}}", + "time": "1970-01-01T00:00:00Z", + "region": "eu-west-1", + "resources": [ + "arn:aws:events:eu-west-1:123456789012:rule/ExampleRule" + ], + "detail": {} +} \ No newline at end of file diff --git a/tests/data/lambda/cloudwatch_logs_event.json b/tests/data/lambda/cloudwatch_logs_event.json new file mode 100644 index 00000000..2b455b9b --- /dev/null +++ b/tests/data/lambda/cloudwatch_logs_event.json @@ -0,0 +1,5 @@ +{ + "awslogs": { + "data": "H4sIAAAAAAAAAHWPwQqCQBCGX0Xm7EFtK+smZBEUgXoLCdMhFtKV3akI8d0bLYmibvPPN3wz00CJxmQnTO41whwWQRIctmEcB6sQbFC3CjW3XW8kxpOpP+OC22d1Wml1qZkQGtoMsScxaczKN3plG8zlaHIta5KqWsozoTYw3/djzwhpLwivWFGHGpAFe7DL68JlBUk+l7KSN7tCOEJ4M3/qOI49vMHj+zCKdlFqLaU2ZHV2a4Ct/an0/ivdX8oYc1UVX860fQDQiMdxRQEAAA==" + } +} \ No newline at end of file diff --git a/tests/data/lambda/s3_event.json b/tests/data/lambda/s3_event.json new file mode 100644 index 00000000..26eef6ca --- /dev/null +++ b/tests/data/lambda/s3_event.json @@ -0,0 +1,38 @@ +{ + "Records": [ + { + "eventVersion": "2.0", + "eventSource": "aws:s3", + "awsRegion": "us-west-1", + "eventTime": "1970-01-01T00:00:00.000Z", + "eventName": "ObjectCreated:Put", + "userIdentity": { + "principalId": "EXAMPLE" + }, + "requestParameters": { + "sourceIPAddress": "127.0.0.1" + }, + "responseElements": { + "x-amz-request-id": "EXAMPLE123456789", + "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH" + }, + "s3": { + "s3SchemaVersion": "1.0", + "configurationId": "testConfigRule", + "bucket": { + "name": "example-bucket", + "ownerIdentity": { + "principalId": "EXAMPLE" + }, + "arn": "arn:aws:s3:::example-bucket" + }, + "object": { + "key": "test/key", + "size": 1024, + "eTag": "0123456789abcdef0123456789abcdef", + "sequencer": "0A1B2C3D4E5F678901" + } + } + } + ] +} \ No newline at end of file diff --git a/tests/data/lambda/sqs_event.json b/tests/data/lambda/sqs_event.json new file mode 100644 index 00000000..a28939a7 --- /dev/null +++ b/tests/data/lambda/sqs_event.json @@ -0,0 +1,20 @@ +{ + "Records": [ + { + "messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", + "receiptHandle": "MessageReceiptHandle", + "body": "Hello from SQS!", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1523232000000", + "SenderId": "123456789012", + "ApproximateFirstReceiveTimestamp": "1523232000001" + }, + "messageAttributes": {}, + "md5OfBody": "7b270e59b47ff90a553787216d55d91d", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-west-1:123456789012:MyQueue", + "awsRegion": "us-west-1" + } + ] +} \ No newline at end of file diff --git a/tests/test_lambda.py b/tests/test_lambda.py index 6a95c9fb..bb1a4b46 100644 --- a/tests/test_lambda.py +++ b/tests/test_lambda.py @@ -2,6 +2,7 @@ import os import unittest +import json import wrapt from instana.singletons import get_agent, set_agent, get_tracer, set_tracer from instana.tracer import InstanaTracer @@ -23,9 +24,14 @@ def __init__(self, **kwargs): # This is the target handler that will be instrumented for these tests def my_lambda_handler(event, context): - print("target_handler called") + # print("target_handler called") return "All Ok" +# We only want to monkey patch the test handler once so do it here +os.environ["LAMBDA_HANDLER"] = "tests.test_lambda.my_lambda_handler" +module_name, function_name = get_lambda_handler_or_default() +wrapt.wrap_function_wrapper(module_name, function_name, lambda_handler_with_instana) + class TestLambda(unittest.TestCase): def __init__(self, methodName='runTest'): @@ -33,10 +39,17 @@ def __init__(self, methodName='runTest'): self.agent = None self.span_recorder = None self.tracer = None + self.pwd = os.path.dirname(os.path.realpath(__file__)) self.original_agent = get_agent() self.original_tracer = get_tracer() + def setUp(self) -> None: + os.environ["LAMBDA_HANDLER"] = "tests.test_lambda.my_lambda_handler" + os.environ["INSTANA_ENDPOINT_URL"] = "https://localhost/notreal" + os.environ["INSTANA_AGENT_KEY"] = "Fake_Key" + self.context = TestContext() + def tearDown(self): """ Reset all environment variables of consequence """ if "LAMBDA_HANDLER" in os.environ: @@ -60,6 +73,15 @@ def create_agent_and_setup_tracer(self): def test_invalid_options(self): # None of the required env vars are available... + if "LAMBDA_HANDLER" in os.environ: + os.environ.pop("LAMBDA_HANDLER") + if "INSTANA_EXTRA_HTTP_HEADERS" in os.environ: + os.environ.pop("INSTANA_EXTRA_HTTP_HEADERS") + if "INSTANA_ENDPOINT_URL" in os.environ: + os.environ.pop("INSTANA_ENDPOINT_URL") + if "INSTANA_AGENT_KEY" in os.environ: + os.environ.pop("INSTANA_AGENT_KEY") + agent = AWSLambdaAgent() self.assertFalse(agent._can_send) self.assertIsNone(agent.collector) @@ -78,22 +100,273 @@ def test_agent_extra_headers(self): should_headers = ['x-test-header', 'x-another-header', 'x-and-another-header'] self.assertEqual(should_headers, self.agent.extra_headers) - def test_api_gateway_tracing(self): - os.environ["LAMBDA_HANDLER"] = "tests.test_lambda.my_lambda_handler" - os.environ["INSTANA_ENDPOINT_URL"] = "https://localhost/notreal" - os.environ["INSTANA_AGENT_KEY"] = "Fake_Key" + def test_api_gateway_trigger_tracing(self): + with open(self.pwd + '/data/lambda/api_gateway_event.json', 'r') as json_file: + event = json.load(json_file) + + self.create_agent_and_setup_tracer() + + # Call the Instana Lambda Handler as we do in the real world. It will initiate tracing and then + # figure out the original (the users') Lambda Handler and execute it. + # The original Lambda handler is set in os.environ["LAMBDA_HANDLER"] + result = lambda_handler(event, self.context) + + self.assertEqual('All Ok', result) + payload = self.agent.collector.prepare_payload() + + self.assertTrue("metrics" in payload) + self.assertTrue("spans" in payload) + self.assertEqual(2, len(payload.keys())) + self.assertEqual('com.instana.plugin.aws.lambda', payload['metrics']['plugins']['name']) + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', + payload['metrics']['plugins']['entityId']) + + self.assertEqual(1, len(payload['spans'])) + + span = payload['spans'][0] + self.assertEqual('aws.lambda.entry', span.n) + self.assertIsNotNone(span.t) + self.assertIsNotNone(span.s) + self.assertIsNone(span.p) + self.assertIsNotNone(span.ts) + self.assertIsNotNone(span.d) + + self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'}, + span.f) + + self.assertIsNone(span.ec) + self.assertIsNone(span.error) + self.assertIsNone(span.data['lambda']['error']) + + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', span.data['lambda']['arn']) + self.assertEqual(None, span.data['lambda']['alias']) + self.assertEqual('python', span.data['lambda']['runtime']) + self.assertEqual('TestPython', span.data['lambda']['functionName']) + self.assertEqual('1', span.data['lambda']['functionVersion']) + + self.assertEqual('aws:api.gateway', span.data['lambda']['trigger']) + self.assertEqual('POST', span.data['http']['method']) + self.assertEqual('/path/to/resource', span.data['http']['url']) + self.assertEqual('/{proxy+}', span.data['http']['path_tpl']) + self.assertEqual("foo=['bar']", span.data['http']['params']) + + def test_application_lb_trigger_tracing(self): + with open(self.pwd + '/data/lambda/api_gateway_event.json', 'r') as json_file: + event = json.load(json_file) + + self.create_agent_and_setup_tracer() + + # Call the Instana Lambda Handler as we do in the real world. It will initiate tracing and then + # figure out the original (the users') Lambda Handler and execute it. + # The original Lambda handler is set in os.environ["LAMBDA_HANDLER"] + result = lambda_handler(event, self.context) + + self.assertEqual('All Ok', result) + payload = self.agent.collector.prepare_payload() + + self.assertTrue("metrics" in payload) + self.assertTrue("spans" in payload) + self.assertEqual(2, len(payload.keys())) + self.assertEqual('com.instana.plugin.aws.lambda', payload['metrics']['plugins']['name']) + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', + payload['metrics']['plugins']['entityId']) + + self.assertEqual(1, len(payload['spans'])) + + span = payload['spans'][0] + self.assertEqual('aws.lambda.entry', span.n) + self.assertIsNotNone(span.t) + self.assertIsNotNone(span.s) + self.assertIsNone(span.p) + self.assertIsNotNone(span.ts) + self.assertIsNotNone(span.d) + + self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'}, + span.f) + + self.assertIsNone(span.ec) + self.assertIsNone(span.error) + self.assertIsNone(span.data['lambda']['error']) + + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', span.data['lambda']['arn']) + self.assertEqual(None, span.data['lambda']['alias']) + self.assertEqual('python', span.data['lambda']['runtime']) + self.assertEqual('TestPython', span.data['lambda']['functionName']) + self.assertEqual('1', span.data['lambda']['functionVersion']) + + self.assertEqual('aws:api.gateway', span.data['lambda']['trigger']) + self.assertEqual('POST', span.data['http']['method']) + self.assertEqual('/path/to/resource', span.data['http']['url']) + self.assertEqual("foo=['bar']", span.data['http']['params']) + + def test_cloudwatch_trigger_tracing(self): + with open(self.pwd + '/data/lambda/cloudwatch_event.json', 'r') as json_file: + event = json.load(json_file) + + self.create_agent_and_setup_tracer() + + # Call the Instana Lambda Handler as we do in the real world. It will initiate tracing and then + # figure out the original (the users') Lambda Handler and execute it. + # The original Lambda handler is set in os.environ["LAMBDA_HANDLER"] + result = lambda_handler(event, self.context) + + self.assertEqual('All Ok', result) + payload = self.agent.collector.prepare_payload() + + self.assertTrue("metrics" in payload) + self.assertTrue("spans" in payload) + self.assertEqual(2, len(payload.keys())) + self.assertEqual('com.instana.plugin.aws.lambda', payload['metrics']['plugins']['name']) + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', + payload['metrics']['plugins']['entityId']) + + self.assertEqual(1, len(payload['spans'])) + + span = payload['spans'][0] + self.assertEqual('aws.lambda.entry', span.n) + self.assertIsNotNone(span.t) + self.assertIsNotNone(span.s) + self.assertIsNone(span.p) + self.assertIsNotNone(span.ts) + self.assertIsNotNone(span.d) + + self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'}, + span.f) + + self.assertIsNone(span.ec) + self.assertIsNone(span.error) + self.assertIsNone(span.data['lambda']['error']) + + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', span.data['lambda']['arn']) + self.assertEqual(None, span.data['lambda']['alias']) + self.assertEqual('python', span.data['lambda']['runtime']) + self.assertEqual('TestPython', span.data['lambda']['functionName']) + self.assertEqual('1', span.data['lambda']['functionVersion']) + + self.assertEqual('aws:cloudwatch.events', span.data['lambda']['trigger']) + self.assertEqual('cdc73f9d-aea9-11e3-9d5a-835b769c0d9c', span.data["lambda"]["cw"]["events"]["id"]) + self.assertEqual(False, span.data["lambda"]["cw"]["events"]["more"]) + self.assertTrue(type(span.data["lambda"]["cw"]["events"]["resources"]) is list) + self.assertEqual(1, len(span.data["lambda"]["cw"]["events"]["resources"])) + self.assertEqual('arn:aws:events:eu-west-1:123456789012:rule/ExampleRule', + span.data["lambda"]["cw"]["events"]["resources"][0]) + + def test_cloudwatch_logs_trigger_tracing(self): + with open(self.pwd + '/data/lambda/cloudwatch_logs_event.json', 'r') as json_file: + event = json.load(json_file) self.create_agent_and_setup_tracer() - module_name, function_name = get_lambda_handler_or_default() - self.assertEqual("tests.test_lambda", module_name) - self.assertEqual("my_lambda_handler", function_name) + # Call the Instana Lambda Handler as we do in the real world. It will initiate tracing and then + # figure out the original (the users') Lambda Handler and execute it. + # The original Lambda handler is set in os.environ["LAMBDA_HANDLER"] + result = lambda_handler(event, self.context) - wrapt.wrap_function_wrapper(module_name, function_name, lambda_handler_with_instana) + self.assertEqual('All Ok', result) + payload = self.agent.collector.prepare_payload() - event = dict() - context = TestContext() - result = lambda_handler(event, context) + self.assertTrue("metrics" in payload) + self.assertTrue("spans" in payload) + self.assertEqual(2, len(payload.keys())) + self.assertEqual('com.instana.plugin.aws.lambda', payload['metrics']['plugins']['name']) + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', + payload['metrics']['plugins']['entityId']) + + self.assertEqual(1, len(payload['spans'])) + + span = payload['spans'][0] + self.assertEqual('aws.lambda.entry', span.n) + self.assertIsNotNone(span.t) + self.assertIsNotNone(span.s) + self.assertIsNone(span.p) + self.assertIsNotNone(span.ts) + self.assertIsNotNone(span.d) + + self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'}, + span.f) + + self.assertIsNone(span.ec) + self.assertIsNone(span.error) + self.assertIsNone(span.data['lambda']['error']) + + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', span.data['lambda']['arn']) + self.assertEqual(None, span.data['lambda']['alias']) + self.assertEqual('python', span.data['lambda']['runtime']) + self.assertEqual('TestPython', span.data['lambda']['functionName']) + self.assertEqual('1', span.data['lambda']['functionVersion']) + + self.assertEqual('aws:cloudwatch.logs', span.data['lambda']['trigger']) + self.assertEqual('testLogGroup', span.data['lambda']['cw']['logs']['group']) + self.assertEqual('testLogStream', span.data['lambda']['cw']['logs']['stream']) + self.assertEqual(None, span.data['lambda']['cw']['logs']['more']) + self.assertTrue(type(span.data['lambda']['cw']['logs']['events']) is list) + self.assertEqual(2, len(span.data['lambda']['cw']['logs']['events'])) + self.assertEqual('[ERROR] First test message', span.data['lambda']['cw']['logs']['events'][0]) + self.assertEqual('[ERROR] Second test message', span.data['lambda']['cw']['logs']['events'][1]) + + def test_s3_trigger_tracing(self): + with open(self.pwd + '/data/lambda/s3_event.json', 'r') as json_file: + event = json.load(json_file) + + self.create_agent_and_setup_tracer() + + # Call the Instana Lambda Handler as we do in the real world. It will initiate tracing and then + # figure out the original (the users') Lambda Handler and execute it. + # The original Lambda handler is set in os.environ["LAMBDA_HANDLER"] + result = lambda_handler(event, self.context) + + self.assertEqual('All Ok', result) + payload = self.agent.collector.prepare_payload() + + self.assertTrue("metrics" in payload) + self.assertTrue("spans" in payload) + self.assertEqual(2, len(payload.keys())) + self.assertEqual('com.instana.plugin.aws.lambda', payload['metrics']['plugins']['name']) + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', + payload['metrics']['plugins']['entityId']) + + self.assertEqual(1, len(payload['spans'])) + + span = payload['spans'][0] + self.assertEqual('aws.lambda.entry', span.n) + self.assertIsNotNone(span.t) + self.assertIsNotNone(span.s) + self.assertIsNone(span.p) + self.assertIsNotNone(span.ts) + self.assertIsNotNone(span.d) + + self.assertEqual({'hl': True, 'cp': 'aws', 'e': 'arn:aws:lambda:us-east-2:12345:function:TestPython:1'}, + span.f) + + self.assertIsNone(span.ec) + self.assertIsNone(span.error) + self.assertIsNone(span.data['lambda']['error']) + + self.assertEqual('arn:aws:lambda:us-east-2:12345:function:TestPython:1', span.data['lambda']['arn']) + self.assertEqual(None, span.data['lambda']['alias']) + self.assertEqual('python', span.data['lambda']['runtime']) + self.assertEqual('TestPython', span.data['lambda']['functionName']) + self.assertEqual('1', span.data['lambda']['functionVersion']) + + self.assertEqual('aws:s3', span.data['lambda']['trigger']) + self.assertTrue(type(span.data["lambda"]["s3"]["events"]) is list) + events = span.data["lambda"]["s3"]["events"] + self.assertEqual(1, len(events)) + event = events[0] + self.assertEqual('ObjectCreated:Put', event['event']) + self.assertEqual('example-bucket', event['bucket']) + self.assertEqual('test/key', event['object']) + + def test_sqs_trigger_tracing(self): + with open(self.pwd + '/data/lambda/sqs_event.json', 'r') as json_file: + event = json.load(json_file) + + self.create_agent_and_setup_tracer() + + # Call the Instana Lambda Handler as we do in the real world. It will initiate tracing and then + # figure out the original (the users') Lambda Handler and execute it. + # The original Lambda handler is set in os.environ["LAMBDA_HANDLER"] + result = lambda_handler(event, self.context) self.assertEqual('All Ok', result) payload = self.agent.collector.prepare_payload() @@ -126,4 +399,12 @@ def test_api_gateway_tracing(self): self.assertEqual(None, span.data['lambda']['alias']) self.assertEqual('python', span.data['lambda']['runtime']) self.assertEqual('TestPython', span.data['lambda']['functionName']) - self.assertEqual('1', span.data['lambda']['functionVersion']) \ No newline at end of file + self.assertEqual('1', span.data['lambda']['functionVersion']) + + self.assertEqual('aws:sqs', span.data['lambda']['trigger']) + self.assertTrue(type(span.data["lambda"]["sqs"]["messages"]) is list) + messages = span.data["lambda"]["sqs"]["messages"] + self.assertEqual(1, len(messages)) + message = messages[0] + self.assertEqual('arn:aws:sqs:us-west-1:123456789012:MyQueue', message['queue']) + From e214cebc9f620a0b54360d9ab88448f019e4de41 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Tue, 17 Mar 2020 15:22:28 +0100 Subject: [PATCH 23/29] Move Lambda inst into it's own package --- instana/__init__.py | 2 +- instana/instrumentation/aws/__init__.py | 0 instana/instrumentation/aws/lambda_inst.py | 44 +++++++++++++++++++ .../{aws_lambda.py => aws/triggers.py} | 42 +----------------- 4 files changed, 46 insertions(+), 42 deletions(-) create mode 100644 instana/instrumentation/aws/__init__.py create mode 100644 instana/instrumentation/aws/lambda_inst.py rename instana/instrumentation/{aws_lambda.py => aws/triggers.py} (83%) diff --git a/instana/__init__.py b/instana/__init__.py index b5945f76..89496c15 100644 --- a/instana/__init__.py +++ b/instana/__init__.py @@ -108,7 +108,7 @@ def boot_agent(): # Instrumentation if "INSTANA_DISABLE_AUTO_INSTR" not in os.environ: # Import & initialize instrumentation - from .instrumentation import aws_lambda + from .instrumentation.aws import lambda_inst if sys.version_info >= (3, 5, 3): from .instrumentation import asyncio diff --git a/instana/instrumentation/aws/__init__.py b/instana/instrumentation/aws/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/instana/instrumentation/aws/lambda_inst.py b/instana/instrumentation/aws/lambda_inst.py new file mode 100644 index 00000000..ecebed25 --- /dev/null +++ b/instana/instrumentation/aws/lambda_inst.py @@ -0,0 +1,44 @@ +import os +import sys +import wrapt + +from .triggers import enrich_lambda_span, get_context + +from ...log import logger +from ...singletons import get_agent, get_tracer +from ... import get_lambda_handler_or_default + + +def lambda_handler_with_instana(wrapped, instance, args, kwargs): + event = args[0] + context = args[1] + agent = get_agent() + tracer = get_tracer() + + agent.collector.collect_snapshot(*args) + incoming_ctx = get_context(tracer, event) + + result = None + with tracer.start_active_span("aws.lambda.entry", child_of=incoming_ctx) as scope: + enrich_lambda_span(agent, scope.span, *args) + try: + result = wrapped(*args, **kwargs) + except Exception as exc: + if scope.span: + scope.span.log_exception(exc) + raise + + agent.collector.shutdown() + return result + + +if os.environ.get("INSTANA_ENDPOINT_URL", False): + handler_module, handler_function = get_lambda_handler_or_default() + + if handler_module is not None and handler_function is not None: + logger.debug("Instrumenting AWS Lambda handler (%s.%s)" % (handler_module, handler_function)) + sys.path.insert(0, '/var/runtime') + sys.path.insert(0, '/var/task') + wrapt.wrap_function_wrapper(handler_module, handler_function, lambda_handler_with_instana) + else: + logger.debug("Couldn't determine AWS Lambda Handler. Not monitoring.") diff --git a/instana/instrumentation/aws_lambda.py b/instana/instrumentation/aws/triggers.py similarity index 83% rename from instana/instrumentation/aws_lambda.py rename to instana/instrumentation/aws/triggers.py index aa4bd82d..7d5748b8 100644 --- a/instana/instrumentation/aws_lambda.py +++ b/instana/instrumentation/aws/triggers.py @@ -1,13 +1,8 @@ -import os -import sys import gzip import json -import wrapt import base64 -from ..log import logger -from ..singletons import get_agent, get_tracer -from .. import get_lambda_handler_or_default +from ...log import logger def get_context(tracer, event): @@ -189,38 +184,3 @@ def enrich_lambda_span(agent, span, event, context): except: logger.debug("enrich_lambda_span: ", exc_info=True) - - -def lambda_handler_with_instana(wrapped, instance, args, kwargs): - event = args[0] - context = args[1] - agent = get_agent() - tracer = get_tracer() - - agent.collector.collect_snapshot(*args) - incoming_ctx = get_context(tracer, event) - - result = None - with tracer.start_active_span("aws.lambda.entry", child_of=incoming_ctx) as scope: - enrich_lambda_span(agent, scope.span, *args) - try: - result = wrapped(*args, **kwargs) - except Exception as exc: - if scope.span: - scope.span.log_exception(exc) - raise - - agent.collector.shutdown() - return result - - -if os.environ.get("INSTANA_ENDPOINT_URL", False): - handler_module, handler_function = get_lambda_handler_or_default() - - if handler_module is not None and handler_function is not None: - logger.debug("Instrumenting AWS Lambda handler (%s.%s)" % (handler_module, handler_function)) - sys.path.insert(0, '/var/runtime') - sys.path.insert(0, '/var/task') - wrapt.wrap_function_wrapper(handler_module, handler_function, lambda_handler_with_instana) - else: - logger.debug("Couldn't determine AWS Lambda Handler. Not monitoring.") From d5836263ee564839dc485ef901d95679f83e18bf Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Wed, 18 Mar 2020 10:37:42 +0100 Subject: [PATCH 24/29] Code documentation --- instana/instrumentation/aws/lambda_inst.py | 3 +++ instana/instrumentation/aws/triggers.py | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/instana/instrumentation/aws/lambda_inst.py b/instana/instrumentation/aws/lambda_inst.py index ecebed25..630a7a8a 100644 --- a/instana/instrumentation/aws/lambda_inst.py +++ b/instana/instrumentation/aws/lambda_inst.py @@ -1,3 +1,6 @@ +""" +Instrumentation for AWS Lambda functions +""" import os import sys import wrapt diff --git a/instana/instrumentation/aws/triggers.py b/instana/instrumentation/aws/triggers.py index 7d5748b8..b8f0f16c 100644 --- a/instana/instrumentation/aws/triggers.py +++ b/instana/instrumentation/aws/triggers.py @@ -1,3 +1,6 @@ +""" +Module to handle the work related to the many AWS Lambda Triggers. +""" import gzip import json import base64 @@ -74,6 +77,15 @@ def read_http_query_params(event): def capture_extra_headers(event, span, extra_headers): + """ + Capture the headers specified in `extra_headers` from `event` and log them + as a tag in the span. + + @param event: the lambda event + @param span: the lambda entry span + @param extra_headers: a list of http headers to capture + @return: None + """ for custom_header in extra_headers: for key in event["headers"]: if key.lower() == custom_header.lower(): @@ -81,6 +93,16 @@ def capture_extra_headers(event, span, extra_headers): def enrich_lambda_span(agent, span, event, context): + """ + Extract the required information about this Lambda run (and the trigger) and store the data + on `span`. + + @param agent: the AWSLambdaAgent in use + @param span: the Lambda entry span + @param event: the lambda handler event + @param context: the lambda handler context + @return: None + """ try: span.set_tag('lambda.arn', context.invoked_function_arn) span.set_tag('lambda.name', context.function_name) From 61d80ce036da845ff055c79ae3dc4ce0b042e948 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Wed, 18 Mar 2020 15:14:19 +0100 Subject: [PATCH 25/29] Update import path --- tests/test_lambda.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_lambda.py b/tests/test_lambda.py index bb1a4b46..892a51a7 100644 --- a/tests/test_lambda.py +++ b/tests/test_lambda.py @@ -10,7 +10,7 @@ from instana.recorder import AWSLambdaRecorder from instana import lambda_handler from instana import get_lambda_handler_or_default -from instana.instrumentation.aws_lambda import lambda_handler_with_instana +from instana.instrumentation.aws.lambda_inst import lambda_handler_with_instana # Mock Context object From 372672de9191acf6e51c8d12c45b678f893fb393 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Wed, 18 Mar 2020 16:23:35 +0100 Subject: [PATCH 26/29] Keep 2.7 compatible: no type hints --- tests/test_lambda.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_lambda.py b/tests/test_lambda.py index 892a51a7..b6a903ff 100644 --- a/tests/test_lambda.py +++ b/tests/test_lambda.py @@ -44,7 +44,7 @@ def __init__(self, methodName='runTest'): self.original_agent = get_agent() self.original_tracer = get_tracer() - def setUp(self) -> None: + def setUp(self): os.environ["LAMBDA_HANDLER"] = "tests.test_lambda.my_lambda_handler" os.environ["INSTANA_ENDPOINT_URL"] = "https://localhost/notreal" os.environ["INSTANA_AGENT_KEY"] = "Fake_Key" From 06be7e8990deadb80360e9a5659b610f6f29ad90 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Wed, 18 Mar 2020 17:30:16 +0100 Subject: [PATCH 27/29] Py 2.7 compatible decompression --- instana/instrumentation/aws/triggers.py | 3 ++- tests/test_lambda.py | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/instana/instrumentation/aws/triggers.py b/instana/instrumentation/aws/triggers.py index b8f0f16c..07f656ea 100644 --- a/instana/instrumentation/aws/triggers.py +++ b/instana/instrumentation/aws/triggers.py @@ -4,6 +4,7 @@ import gzip import json import base64 +from io import BytesIO from ...log import logger @@ -153,7 +154,7 @@ def enrich_lambda_span(agent, span, event, context): if 'awslogs' in event and 'data' in event['awslogs']: data = event['awslogs']['data'] decoded_data = base64.b64decode(data) - decompressed_data = gzip.decompress(decoded_data) + decompressed_data = gzip.GzipFile(fileobj=BytesIO(decoded_data)).read() log_data = json.loads(decompressed_data) span.set_tag('lambda.cw.logs.group', log_data.get('logGroup', None)) diff --git a/tests/test_lambda.py b/tests/test_lambda.py index b6a903ff..f8b91c67 100644 --- a/tests/test_lambda.py +++ b/tests/test_lambda.py @@ -1,9 +1,11 @@ from __future__ import absolute_import import os -import unittest +import sys import json import wrapt +import unittest + from instana.singletons import get_agent, set_agent, get_tracer, set_tracer from instana.tracer import InstanaTracer from instana.agent import AWSLambdaAgent @@ -148,7 +150,10 @@ def test_api_gateway_trigger_tracing(self): self.assertEqual('POST', span.data['http']['method']) self.assertEqual('/path/to/resource', span.data['http']['url']) self.assertEqual('/{proxy+}', span.data['http']['path_tpl']) - self.assertEqual("foo=['bar']", span.data['http']['params']) + if sys.version[:3] == '2.7': + self.assertEqual(u"foo=[u'bar']", span.data['http']['params']) + else: + self.assertEqual("foo=['bar']", span.data['http']['params']) def test_application_lb_trigger_tracing(self): with open(self.pwd + '/data/lambda/api_gateway_event.json', 'r') as json_file: @@ -197,7 +202,10 @@ def test_application_lb_trigger_tracing(self): self.assertEqual('aws:api.gateway', span.data['lambda']['trigger']) self.assertEqual('POST', span.data['http']['method']) self.assertEqual('/path/to/resource', span.data['http']['url']) - self.assertEqual("foo=['bar']", span.data['http']['params']) + if sys.version[:3] == '2.7': + self.assertEqual(u"foo=[u'bar']", span.data['http']['params']) + else: + self.assertEqual("foo=['bar']", span.data['http']['params']) def test_cloudwatch_trigger_tracing(self): with open(self.pwd + '/data/lambda/cloudwatch_event.json', 'r') as json_file: @@ -296,6 +304,7 @@ def test_cloudwatch_logs_trigger_tracing(self): self.assertEqual('1', span.data['lambda']['functionVersion']) self.assertEqual('aws:cloudwatch.logs', span.data['lambda']['trigger']) + self.assertFalse("decodingError" in span.data['lambda']['cw']['logs']) self.assertEqual('testLogGroup', span.data['lambda']['cw']['logs']['group']) self.assertEqual('testLogStream', span.data['lambda']['cw']['logs']['stream']) self.assertEqual(None, span.data['lambda']['cw']['logs']['more']) From 58abc627ac45f36b345efaa4549d9bcf00b8aea2 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Thu, 19 Mar 2020 12:31:26 +0100 Subject: [PATCH 28/29] Fix Python 3.5 compatibility --- instana/instrumentation/aws/triggers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instana/instrumentation/aws/triggers.py b/instana/instrumentation/aws/triggers.py index 07f656ea..0ab51af5 100644 --- a/instana/instrumentation/aws/triggers.py +++ b/instana/instrumentation/aws/triggers.py @@ -155,7 +155,7 @@ def enrich_lambda_span(agent, span, event, context): data = event['awslogs']['data'] decoded_data = base64.b64decode(data) decompressed_data = gzip.GzipFile(fileobj=BytesIO(decoded_data)).read() - log_data = json.loads(decompressed_data) + log_data = json.loads(decompressed_data.decode('utf-8')) span.set_tag('lambda.cw.logs.group', log_data.get('logGroup', None)) span.set_tag('lambda.cw.logs.stream', log_data.get('logStream', None)) From 4e0571e87077ddbdf10cd0192325d45bbdd0dec4 Mon Sep 17 00:00:00 2001 From: Peter Giacomo Lombardo Date: Thu, 19 Mar 2020 12:52:38 +0100 Subject: [PATCH 29/29] Remove comment --- bin/lambda_build_publish_layer.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bin/lambda_build_publish_layer.py b/bin/lambda_build_publish_layer.py index ebc7e15b..32344a8f 100755 --- a/bin/lambda_build_publish_layer.py +++ b/bin/lambda_build_publish_layer.py @@ -68,10 +68,6 @@ published = dict() -# response = check_output(["aws", "lambda", "list-layers"]) -# To update a Function -# aws lambda update-function-configuration --function-name CanaryInACoalMine --layers arn:aws:lambda:us-west-1:410797082306:layer:instana-py-test:22 - for region in regions: print("===> Uploading layer to AWS %s " % region) response = check_output(["aws", "--region", region, "lambda", "publish-layer-version",