diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 567ad81d..82d09d56 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,11 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.7.0 + rev: v0.15.9 hooks: # Run the linter. - - id: ruff + - id: ruff-check args: [ --fix ] # Run the formatter. - id: ruff-format + types_or: [python, markdown] diff --git a/pyproject.toml b/pyproject.toml index 9743dc41..8fa29c53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,7 @@ dev = [ "pytest-mock", "pre-commit>=3.0.0", "ruff", + "gunicorn", ] [project.urls] @@ -94,3 +95,32 @@ exclude_also = [ "except Exception:", "except Exception as exc:", ] + +[tool.ruff] +# https://docs.astral.sh/ruff/configuration/ +target-version = "py39" +# In addition to the standard set of exclusions, omit all tests, plus a specific file. +extend-exclude = [".bob", "bin", ".github", ".circleci", ".tekton"] +preview = true +output-format = "concise" + +[tool.ruff.lint] +# https://docs.astral.sh/ruff/rules/ +select = [ + "E", # pycodestyle + "F", # Pyflakes + "I", # isort + "CPY", # flake8-copyright + "SIM", # flake8-simplify + "FLY", # flynt (static-join-to-f-string) + "UP031", # printf-string-formatting + "UP032", # f-string +] +ignore = ["E501", "I001"] + +[tool.ruff.lint.flake8-copyright] +notice-rgx = "(?i)#\\s?(\\(c\\)\\s+)?Copyright\\s+IBM Corp\\.\\s+(\\d{4}((-|,\\s)\\d{4})?)" +min-file-size = 1024 + +# [tool.ruff.format] +# preview = true diff --git a/src/instana/agent/aws_eks_fargate.py b/src/instana/agent/aws_eks_fargate.py index d404c3f9..a88a08b1 100644 --- a/src/instana/agent/aws_eks_fargate.py +++ b/src/instana/agent/aws_eks_fargate.py @@ -4,19 +4,19 @@ The Instana agent (for AWS EKS Fargate) that manages monitoring state and reporting that data. """ -import os -import time -from instana.options import EKSFargateOptions + +from instana.agent.base import BaseAgent from instana.collector.aws_eks_fargate import EKSFargateCollector from instana.collector.helpers.eks.process import get_pod_name from instana.log import logger +from instana.options import EKSFargateOptions from instana.util import to_json -from instana.agent.base import BaseAgent from instana.version import VERSION class EKSFargateAgent(BaseAgent): - """ In-process agent for AWS Fargate """ + """In-process agent for AWS Fargate""" + def __init__(self): super(EKSFargateAgent, self).__init__() @@ -29,15 +29,20 @@ def __init__(self): # Update log level (if INSTANA_LOG_LEVEL was set) self.update_log_level() - logger.info("Stan is on the EKS Pod on AWS Fargate scene. Starting Instana instrumentation version: %s", VERSION) + logger.info( + "Stan is on the EKS Pod on AWS Fargate scene. Starting Instana instrumentation version: %s", + VERSION, + ) if self._validate_options(): self._can_send = True self.collector = EKSFargateCollector(self) self.collector.start() else: - logger.warning("Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. " - "We will not be able to monitor this Pod.") + logger.warning( + "Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. " + "We will not be able to monitor this Pod." + ) def can_send(self): """ @@ -52,7 +57,7 @@ def get_from_structure(self): @return: dict() """ - return {'hl': True, 'cp': 'k8s', 'e': self.podname} + return {"hl": True, "cp": "k8s", "e": self.podname} def report_data_payload(self, payload): """ @@ -67,15 +72,20 @@ def report_data_payload(self, payload): self.report_headers["X-Instana-Host"] = self.podname self.report_headers["X-Instana-Key"] = self.options.agent_key - response = self.client.post(self.__data_bundle_url(), - data=to_json(payload), - headers=self.report_headers, - timeout=self.options.timeout, - verify=self.options.ssl_verify, - proxies=self.options.endpoint_proxy) + response = self.client.post( + self.__data_bundle_url(), + data=to_json(payload), + headers=self.report_headers, + timeout=self.options.timeout, + verify=self.options.ssl_verify, + proxies=self.options.endpoint_proxy, + ) if not 200 <= response.status_code < 300: - logger.info("report_data_payload: Instana responded with status code %s", response.status_code) + logger.info( + "report_data_payload: Instana responded with status code %s", + response.status_code, + ) except Exception as exc: logger.debug("report_data_payload: connection error (%s)", type(exc)) return response @@ -84,10 +94,12 @@ def _validate_options(self): """ Validate that the options used by this Agent are valid. e.g. can we report data? """ - return self.options.endpoint_url is not None and self.options.agent_key is not None + return ( + self.options.endpoint_url is not None and self.options.agent_key is not None + ) def __data_bundle_url(self): """ URL for posting metrics to the host agent. Only valid when announced. """ - return "%s/bundle" % self.options.endpoint_url + return f"{self.options.endpoint_url}/bundle" diff --git a/src/instana/agent/aws_fargate.py b/src/instana/agent/aws_fargate.py index c38024c4..9aabc757 100644 --- a/src/instana/agent/aws_fargate.py +++ b/src/instana/agent/aws_fargate.py @@ -5,17 +5,19 @@ The Instana agent (for AWS Fargate) that manages monitoring state and reporting that data. """ -import time -from instana.options import AWSFargateOptions + from instana.collector.aws_fargate import AWSFargateCollector +from instana.options import AWSFargateOptions + from ..log import logger from ..util import to_json -from .base import BaseAgent from ..version import VERSION +from .base import BaseAgent class AWSFargateAgent(BaseAgent): - """ In-process agent for AWS Fargate """ + """In-process agent for AWS Fargate""" + def __init__(self): super(AWSFargateAgent, self).__init__() @@ -27,15 +29,20 @@ def __init__(self): # Update log level (if INSTANA_LOG_LEVEL was set) self.update_log_level() - logger.info("Stan is on the AWS Fargate scene. Starting Instana instrumentation version: %s", VERSION) + logger.info( + "Stan is on the AWS Fargate scene. Starting Instana instrumentation version: %s", + VERSION, + ) if self._validate_options(): self._can_send = True self.collector = AWSFargateCollector(self) self.collector.start() else: - logger.warning("Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. " - "We will not be able monitor this AWS Fargate cluster.") + logger.warning( + "Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. " + "We will not be able monitor this AWS Fargate cluster." + ) def can_send(self): """ @@ -49,7 +56,7 @@ def get_from_structure(self): Retrieves the From data that is reported alongside monitoring data. @return: dict() """ - return {'hl': True, 'cp': 'aws', 'e': self.collector.get_fq_arn()} + return {"hl": True, "cp": "aws", "e": self.collector.get_fq_arn()} def report_data_payload(self, payload): """ @@ -64,15 +71,20 @@ def report_data_payload(self, payload): self.report_headers["X-Instana-Host"] = self.collector.get_fq_arn() self.report_headers["X-Instana-Key"] = self.options.agent_key - response = self.client.post(self.__data_bundle_url(), - data=to_json(payload), - headers=self.report_headers, - timeout=self.options.timeout, - verify=self.options.ssl_verify, - proxies=self.options.endpoint_proxy) + response = self.client.post( + self.__data_bundle_url(), + data=to_json(payload), + headers=self.report_headers, + timeout=self.options.timeout, + verify=self.options.ssl_verify, + proxies=self.options.endpoint_proxy, + ) if not 200 <= response.status_code < 300: - logger.info("report_data_payload: Instana responded with status code %s", response.status_code) + logger.info( + "report_data_payload: Instana responded with status code %s", + response.status_code, + ) except Exception as exc: logger.debug("report_data_payload: connection error (%s)", type(exc)) return response @@ -81,10 +93,12 @@ def _validate_options(self): """ Validate that the options used by this Agent are valid. e.g. can we report data? """ - return self.options.endpoint_url is not None and self.options.agent_key is not None + return ( + self.options.endpoint_url is not None and self.options.agent_key is not None + ) def __data_bundle_url(self): """ URL for posting metrics to the host agent. Only valid when announced. """ - return "%s/bundle" % self.options.endpoint_url + return f"{self.options.endpoint_url}/bundle" diff --git a/src/instana/agent/google_cloud_run.py b/src/instana/agent/google_cloud_run.py index 59d6d9a0..4bfddfae 100644 --- a/src/instana/agent/google_cloud_run.py +++ b/src/instana/agent/google_cloud_run.py @@ -5,7 +5,7 @@ The Instana agent (for GCR) that manages monitoring state and reporting that data. """ -import time + from instana.options import GCROptions from instana.collector.google_cloud_run import GCRCollector from instana.log import logger @@ -15,7 +15,7 @@ class GCRAgent(BaseAgent): - """ In-process agent for Google Cloud Run """ + """In-process agent for Google Cloud Run""" def __init__(self, service, configuration, revision): super(GCRAgent, self).__init__() @@ -28,15 +28,20 @@ def __init__(self, service, configuration, revision): # Update log level (if INSTANA_LOG_LEVEL was set) self.update_log_level() - logger.info("Stan is on the AWS Fargate scene. Starting Instana instrumentation version: %s", VERSION) + logger.info( + "Stan is on the AWS Fargate scene. Starting Instana instrumentation version: %s", + VERSION, + ) if self._validate_options(): self._can_send = True self.collector = GCRCollector(self, service, configuration, revision) self.collector.start() else: - logger.warning("Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. " - "We will not be able monitor this GCR cluster.") + logger.warning( + "Required INSTANA_AGENT_KEY and/or INSTANA_ENDPOINT_URL environment variables not set. " + "We will not be able monitor this GCR cluster." + ) def can_send(self): """ @@ -50,7 +55,7 @@ def get_from_structure(self): Retrieves the From data that is reported alongside monitoring data. @return: dict() """ - return {'hl': True, 'cp': 'gcp', 'e': self.collector.get_instance_id()} + return {"hl": True, "cp": "gcp", "e": self.collector.get_instance_id()} def report_data_payload(self, payload): """ @@ -62,20 +67,24 @@ def report_data_payload(self, payload): # Prepare request headers self.report_headers = { "Content-Type": "application/json", - "X-Instana-Host": "gcp:cloud-run:revision:{revision}".format( - revision=self.collector.revision), - "X-Instana-Key": self.options.agent_key + "X-Instana-Host": f"gcp:cloud-run:revision:{self.collector.revision}", + "X-Instana-Key": self.options.agent_key, } - response = self.client.post(self.__data_bundle_url(), - data=to_json(payload), - headers=self.report_headers, - timeout=self.options.timeout, - verify=self.options.ssl_verify, - proxies=self.options.endpoint_proxy) + response = self.client.post( + self.__data_bundle_url(), + data=to_json(payload), + headers=self.report_headers, + timeout=self.options.timeout, + verify=self.options.ssl_verify, + proxies=self.options.endpoint_proxy, + ) if response.status_code >= 400: - logger.info("report_data_payload: Instana responded with status code %s", response.status_code) + logger.info( + "report_data_payload: Instana responded with status code %s", + response.status_code, + ) except Exception as exc: logger.debug("report_data_payload: connection error (%s)", type(exc)) return response @@ -84,10 +93,12 @@ def _validate_options(self): """ Validate that the options used by this Agent are valid. e.g. can we report data? """ - return self.options.endpoint_url is not None and self.options.agent_key is not None + return ( + self.options.endpoint_url is not None and self.options.agent_key is not None + ) def __data_bundle_url(self): """ URL for posting metrics to the host agent. Only valid when announced. """ - return "{endpoint_url}/bundle".format(endpoint_url=self.options.endpoint_url) + return f"{self.options.endpoint_url}/bundle" diff --git a/src/instana/agent/host.py b/src/instana/agent/host.py index 926f7e03..282bbf53 100644 --- a/src/instana/agent/host.py +++ b/src/instana/agent/host.py @@ -123,10 +123,7 @@ def can_send(self) -> bool: logger.debug("Fork detected; Handling like a pro...") self.handle_fork() - if self.machine.fsm.current in ["wait4init", "good2go"]: - return True - - return False + return self.machine.fsm.current in ["wait4init", "good2go"] def set_from( self, @@ -371,7 +368,7 @@ def filter_spans(self, spans: List[Dict[str, Any]]) -> List[Dict[str, Any]]: service_name = "" # Set the service name - for span_value in span.data.keys(): + for span_value in span.data: if isinstance(span.data[span_value], dict): service_name = span_value @@ -413,13 +410,12 @@ def __is_endpoint_ignored(self, span_attributes: dict) -> bool: # Check exclude rules exclude_rules = filters.get("exclude", []) - if any( - matches_rule(rule.get("attributes", []), span_attributes) - for rule in exclude_rules - ): - return True - - return False + return bool( + any( + matches_rule(rule.get("attributes", []), span_attributes) + for rule in exclude_rules + ) + ) def handle_agent_tasks(self, task: Dict[str, Any]) -> None: """ diff --git a/src/instana/autoprofile/frame_cache.py b/src/instana/autoprofile/frame_cache.py index 166c2de6..17e416c9 100644 --- a/src/instana/autoprofile/frame_cache.py +++ b/src/instana/autoprofile/frame_cache.py @@ -33,9 +33,8 @@ def is_profiler_frame(self, filename: str) -> bool: profiler_frame = False - if not self.include_profiler_frames: - if filename.startswith(self.profiler_dir): - profiler_frame = True + if not self.include_profiler_frames and filename.startswith(self.profiler_dir): + profiler_frame = True if len(self.profiler_frame_cache) < self.MAX_CACHE_SIZE: self.profiler_frame_cache[filename] = profiler_frame diff --git a/src/instana/autoprofile/runtime.py b/src/instana/autoprofile/runtime.py index e296e103..80179113 100644 --- a/src/instana/autoprofile/runtime.py +++ b/src/instana/autoprofile/runtime.py @@ -9,6 +9,7 @@ if TYPE_CHECKING: from types import FrameType + class RuntimeInfo(object): OS_LINUX = sys.platform.startswith("linux") OS_DARWIN = sys.platform == "darwin" diff --git a/src/instana/autoprofile/samplers/cpu_sampler.py b/src/instana/autoprofile/samplers/cpu_sampler.py index 2743a475..8dae3679 100644 --- a/src/instana/autoprofile/samplers/cpu_sampler.py +++ b/src/instana/autoprofile/samplers/cpu_sampler.py @@ -82,13 +82,12 @@ def build_profile(self, duration: int, timespan: int) -> Profile: return profile def process_sample(self, signal_frame: "FrameType") -> None: - if self.top: - if signal_frame: - stack = self.recover_stack(signal_frame) - if stack: - self.update_profile(self.top, stack) + if self.top and signal_frame: + stack = self.recover_stack(signal_frame) + if stack: + self.update_profile(self.top, stack) - stack = None + stack = None def recover_stack( self, signal_frame: "FrameType" diff --git a/src/instana/collector/helpers/base.py b/src/instana/collector/helpers/base.py index e2cea3d5..e8a01c3c 100644 --- a/src/instana/collector/helpers/base.py +++ b/src/instana/collector/helpers/base.py @@ -36,10 +36,7 @@ def get_delta(self, source, previous, metric): src_metric = metric dst_metric = metric - if isinstance(source, dict): - new_value = source.get(src_metric, None) - else: - new_value = source + new_value = source.get(src_metric, None) if isinstance(source, dict) else source if previous[dst_metric] != new_value: return new_value @@ -66,10 +63,7 @@ def apply_delta(self, source, previous, new, metric, with_snapshot): src_metric = metric dst_metric = metric - if isinstance(source, dict): - new_value = source.get(src_metric, None) - else: - new_value = source + new_value = source.get(src_metric, None) if isinstance(source, dict) else source previous_value = previous.get(dst_metric, 0) diff --git a/src/instana/collector/helpers/fargate/container.py b/src/instana/collector/helpers/fargate/container.py index 82ad7bea..e2865372 100644 --- a/src/instana/collector/helpers/fargate/container.py +++ b/src/instana/collector/helpers/fargate/container.py @@ -28,7 +28,7 @@ def collect_metrics(self, **kwargs): labels = container.get("Labels", {}) name = container.get("Name", "") task_arn = labels.get("com.amazonaws.ecs.task-arn", "") - plugin_data["entityId"] = "%s::%s" % (task_arn, name) + plugin_data["entityId"] = f"{task_arn}::{name}" plugin_data["data"] = DictionaryOfStan() if self.collector.root_metadata["Name"] == name: diff --git a/src/instana/collector/helpers/fargate/docker.py b/src/instana/collector/helpers/fargate/docker.py index e654772d..cb4f0af8 100644 --- a/src/instana/collector/helpers/fargate/docker.py +++ b/src/instana/collector/helpers/fargate/docker.py @@ -1,15 +1,18 @@ # (c) Copyright IBM Corp. 2021 # (c) Copyright Instana Inc. 2020 -""" Module to handle the collection of Docker metrics in AWS Fargate """ +"""Module to handle the collection of Docker metrics in AWS Fargate""" + from __future__ import division + from ....log import logger -from ..base import BaseHelper from ....util import DictionaryOfStan +from ..base import BaseHelper class DockerHelper(BaseHelper): - """ This class acts as a helper to collect Docker snapshot and metric information """ + """This class acts as a helper to collect Docker snapshot and metric information""" + def __init__(self, collector): super(DockerHelper, self).__init__(collector) @@ -38,20 +41,22 @@ def collect_metrics(self, **kwargs): labels = container.get("Labels", {}) task_arn = labels.get("com.amazonaws.ecs.task-arn", "") - plugin_data["entityId"] = "%s::%s" % (task_arn, name) + plugin_data["entityId"] = f"{task_arn}::{name}" plugin_data["data"] = DictionaryOfStan() plugin_data["data"]["Id"] = container.get("DockerId", None) with_snapshot = kwargs.get("with_snapshot", False) # Metrics - self._collect_container_metrics(plugin_data, docker_id, with_snapshot) + self._collect_container_metrics( + plugin_data, docker_id, with_snapshot + ) # Snapshot if with_snapshot: self._collect_container_snapshot(plugin_data, container) plugins.append(plugin_data) - #logger.debug(to_pretty_json(plugin_data)) + # logger.debug(to_pretty_json(plugin_data)) except Exception: logger.debug("DockerHelper.collect_metrics: ", exc_info=True) return plugins @@ -67,26 +72,36 @@ def _collect_container_snapshot(self, plugin_data, container): networks = container.get("Networks", []) if len(networks) >= 1: - plugin_data["data"]["NetworkMode"] = networks[0].get("NetworkMode", None) + plugin_data["data"]["NetworkMode"] = networks[0].get( + "NetworkMode", None + ) except Exception: logger.debug("_collect_container_snapshot: ", exc_info=True) def _collect_container_metrics(self, plugin_data, docker_id, with_snapshot): container = self.collector.task_stats_metadata.get(docker_id, None) if container is not None: - self._collect_network_metrics(container, plugin_data, docker_id, with_snapshot) + self._collect_network_metrics( + container, plugin_data, docker_id, with_snapshot + ) self._collect_cpu_metrics(container, plugin_data, docker_id, with_snapshot) - self._collect_memory_metrics(container, plugin_data, docker_id, with_snapshot) - self._collect_blkio_metrics(container, plugin_data, docker_id, with_snapshot) + self._collect_memory_metrics( + container, plugin_data, docker_id, with_snapshot + ) + self._collect_blkio_metrics( + container, plugin_data, docker_id, with_snapshot + ) - def _collect_network_metrics(self, container, plugin_data, docker_id, with_snapshot): + def _collect_network_metrics( + self, container, plugin_data, docker_id, with_snapshot + ): try: networks = container.get("networks", None) tx_bytes_total = tx_dropped_total = tx_errors_total = tx_packets_total = 0 rx_bytes_total = rx_dropped_total = rx_errors_total = rx_packets_total = 0 if networks is not None: - for key in networks.keys(): + for key in networks: if "eth" in key: tx_bytes_total += networks[key].get("tx_bytes", 0) tx_dropped_total += networks[key].get("tx_dropped", 0) @@ -98,23 +113,63 @@ def _collect_network_metrics(self, container, plugin_data, docker_id, with_snaps rx_errors_total += networks[key].get("rx_errors", 0) rx_packets_total += networks[key].get("rx_packets", 0) - self.apply_delta(tx_bytes_total, self.previous[docker_id]["network"]["tx"], - plugin_data["data"]["tx"], "bytes", with_snapshot) - self.apply_delta(tx_dropped_total, self.previous[docker_id]["network"]["tx"], - plugin_data["data"]["tx"], "dropped", with_snapshot) - self.apply_delta(tx_errors_total, self.previous[docker_id]["network"]["tx"], - plugin_data["data"]["tx"], "errors", with_snapshot) - self.apply_delta(tx_packets_total, self.previous[docker_id]["network"]["tx"], - plugin_data["data"]["tx"], "packets", with_snapshot) - - self.apply_delta(rx_bytes_total, self.previous[docker_id]["network"]["rx"], - plugin_data["data"]["rx"], "bytes", with_snapshot) - self.apply_delta(rx_dropped_total, self.previous[docker_id]["network"]["rx"], - plugin_data["data"]["rx"], "dropped", with_snapshot) - self.apply_delta(rx_errors_total, self.previous[docker_id]["network"]["rx"], - plugin_data["data"]["rx"], "errors", with_snapshot) - self.apply_delta(rx_packets_total, self.previous[docker_id]["network"]["rx"], - plugin_data["data"]["rx"], "packets", with_snapshot) + self.apply_delta( + tx_bytes_total, + self.previous[docker_id]["network"]["tx"], + plugin_data["data"]["tx"], + "bytes", + with_snapshot, + ) + self.apply_delta( + tx_dropped_total, + self.previous[docker_id]["network"]["tx"], + plugin_data["data"]["tx"], + "dropped", + with_snapshot, + ) + self.apply_delta( + tx_errors_total, + self.previous[docker_id]["network"]["tx"], + plugin_data["data"]["tx"], + "errors", + with_snapshot, + ) + self.apply_delta( + tx_packets_total, + self.previous[docker_id]["network"]["tx"], + plugin_data["data"]["tx"], + "packets", + with_snapshot, + ) + + self.apply_delta( + rx_bytes_total, + self.previous[docker_id]["network"]["rx"], + plugin_data["data"]["rx"], + "bytes", + with_snapshot, + ) + self.apply_delta( + rx_dropped_total, + self.previous[docker_id]["network"]["rx"], + plugin_data["data"]["rx"], + "dropped", + with_snapshot, + ) + self.apply_delta( + rx_errors_total, + self.previous[docker_id]["network"]["rx"], + plugin_data["data"]["rx"], + "errors", + with_snapshot, + ) + self.apply_delta( + rx_packets_total, + self.previous[docker_id]["network"]["rx"], + plugin_data["data"]["rx"], + "packets", + with_snapshot, + ) except Exception: logger.debug("_collect_network_metrics: ", exc_info=True) @@ -128,28 +183,54 @@ def _collect_cpu_metrics(self, container, plugin_data, docker_id, with_snapshot) online_cpus = cpu_stats.get("online_cpus", 1) system_cpu_usage = cpu_stats.get("system_cpu_usage", 0) - metric_value = (cpu_usage["total_usage"] / system_cpu_usage) * online_cpus - self.apply_delta(round(metric_value, 6), - self.previous[docker_id]["cpu"], - plugin_data["data"]["cpu"], "total_usage", with_snapshot) + metric_value = ( + cpu_usage["total_usage"] / system_cpu_usage + ) * online_cpus + self.apply_delta( + round(metric_value, 6), + self.previous[docker_id]["cpu"], + plugin_data["data"]["cpu"], + "total_usage", + with_snapshot, + ) - metric_value = (cpu_usage["usage_in_usermode"] / system_cpu_usage) * online_cpus - self.apply_delta(round(metric_value, 6), - self.previous[docker_id]["cpu"], - plugin_data["data"]["cpu"], "user_usage", with_snapshot) + metric_value = ( + cpu_usage["usage_in_usermode"] / system_cpu_usage + ) * online_cpus + self.apply_delta( + round(metric_value, 6), + self.previous[docker_id]["cpu"], + plugin_data["data"]["cpu"], + "user_usage", + with_snapshot, + ) - metric_value = (cpu_usage["usage_in_kernelmode"] / system_cpu_usage) * online_cpus - self.apply_delta(round(metric_value, 6), - self.previous[docker_id]["cpu"], - plugin_data["data"]["cpu"], "system_usage", with_snapshot) + metric_value = ( + cpu_usage["usage_in_kernelmode"] / system_cpu_usage + ) * online_cpus + self.apply_delta( + round(metric_value, 6), + self.previous[docker_id]["cpu"], + plugin_data["data"]["cpu"], + "system_usage", + with_snapshot, + ) if throttling_data is not None: - self.apply_delta(throttling_data, - self.previous[docker_id]["cpu"], - plugin_data["data"]["cpu"], ("periods", "throttling_count"), with_snapshot) - self.apply_delta(throttling_data, - self.previous[docker_id]["cpu"], - plugin_data["data"]["cpu"], ("throttled_time", "throttling_time"), with_snapshot) + self.apply_delta( + throttling_data, + self.previous[docker_id]["cpu"], + plugin_data["data"]["cpu"], + ("periods", "throttling_count"), + with_snapshot, + ) + self.apply_delta( + throttling_data, + self.previous[docker_id]["cpu"], + plugin_data["data"]["cpu"], + ("throttled_time", "throttling_time"), + with_snapshot, + ) except Exception: logger.debug("_collect_cpu_metrics: ", exc_info=True) @@ -158,26 +239,71 @@ def _collect_memory_metrics(self, container, plugin_data, docker_id, with_snapsh memory = container.get("memory_stats", {}) memory_stats = memory.get("stats", None) - self.apply_delta(memory, self.previous[docker_id]["memory"], - plugin_data["data"]["memory"], "usage", with_snapshot) - self.apply_delta(memory, self.previous[docker_id]["memory"], - plugin_data["data"]["memory"], "max_usage", with_snapshot) - self.apply_delta(memory, self.previous[docker_id]["memory"], - plugin_data["data"]["memory"], "limit", with_snapshot) + self.apply_delta( + memory, + self.previous[docker_id]["memory"], + plugin_data["data"]["memory"], + "usage", + with_snapshot, + ) + self.apply_delta( + memory, + self.previous[docker_id]["memory"], + plugin_data["data"]["memory"], + "max_usage", + with_snapshot, + ) + self.apply_delta( + memory, + self.previous[docker_id]["memory"], + plugin_data["data"]["memory"], + "limit", + with_snapshot, + ) if memory_stats is not None: - self.apply_delta(memory_stats, self.previous[docker_id]["memory"], - plugin_data["data"]["memory"], "active_anon", with_snapshot) - self.apply_delta(memory_stats, self.previous[docker_id]["memory"], - plugin_data["data"]["memory"], "active_file", with_snapshot) - self.apply_delta(memory_stats, self.previous[docker_id]["memory"], - plugin_data["data"]["memory"], "inactive_anon", with_snapshot) - self.apply_delta(memory_stats, self.previous[docker_id]["memory"], - plugin_data["data"]["memory"], "inactive_file", with_snapshot) - self.apply_delta(memory_stats, self.previous[docker_id]["memory"], - plugin_data["data"]["memory"], "total_cache", with_snapshot) - self.apply_delta(memory_stats, self.previous[docker_id]["memory"], - plugin_data["data"]["memory"], "total_rss", with_snapshot) + self.apply_delta( + memory_stats, + self.previous[docker_id]["memory"], + plugin_data["data"]["memory"], + "active_anon", + with_snapshot, + ) + self.apply_delta( + memory_stats, + self.previous[docker_id]["memory"], + plugin_data["data"]["memory"], + "active_file", + with_snapshot, + ) + self.apply_delta( + memory_stats, + self.previous[docker_id]["memory"], + plugin_data["data"]["memory"], + "inactive_anon", + with_snapshot, + ) + self.apply_delta( + memory_stats, + self.previous[docker_id]["memory"], + plugin_data["data"]["memory"], + "inactive_file", + with_snapshot, + ) + self.apply_delta( + memory_stats, + self.previous[docker_id]["memory"], + plugin_data["data"]["memory"], + "total_cache", + with_snapshot, + ) + self.apply_delta( + memory_stats, + self.previous[docker_id]["memory"], + plugin_data["data"]["memory"], + "total_rss", + with_snapshot, + ) except Exception: logger.debug("_collect_memory_metrics: ", exc_info=True) @@ -189,16 +315,30 @@ def _collect_blkio_metrics(self, container, plugin_data, docker_id, with_snapsho if service_bytes is not None: for entry in service_bytes: if entry["op"] == "Read": - previous_value = self.previous_blkio[docker_id].get("blk_read", 0) + previous_value = self.previous_blkio[docker_id].get( + "blk_read", 0 + ) value_diff = entry["value"] - previous_value - self.apply_delta(value_diff, self.previous[docker_id]["blkio"], - plugin_data["data"]["blkio"], "blk_read", with_snapshot) + self.apply_delta( + value_diff, + self.previous[docker_id]["blkio"], + plugin_data["data"]["blkio"], + "blk_read", + with_snapshot, + ) self.previous_blkio[docker_id]["blk_read"] = entry["value"] elif entry["op"] == "Write": - previous_value = self.previous_blkio[docker_id].get("blk_write", 0) + previous_value = self.previous_blkio[docker_id].get( + "blk_write", 0 + ) value_diff = entry["value"] - previous_value - self.apply_delta(value_diff, self.previous[docker_id]["blkio"], - plugin_data["data"]["blkio"], "blk_write", with_snapshot) + self.apply_delta( + value_diff, + self.previous[docker_id]["blkio"], + plugin_data["data"]["blkio"], + "blk_write", + with_snapshot, + ) self.previous_blkio[docker_id]["blk_write"] = entry["value"] except Exception: logger.debug("_collect_blkio_metrics: ", exc_info=True) diff --git a/src/instana/collector/helpers/fargate/process.py b/src/instana/collector/helpers/fargate/process.py index abadab5f..799a24f6 100644 --- a/src/instana/collector/helpers/fargate/process.py +++ b/src/instana/collector/helpers/fargate/process.py @@ -6,7 +6,7 @@ class FargateProcessHelper(ProcessHelper): - """ Helper class to extend the generic process helper class with the corresponding fargate attributes """ + """Helper class to extend the generic process helper class with the corresponding fargate attributes""" def collect_metrics(self, **kwargs): plugin_data = dict() @@ -14,11 +14,14 @@ def collect_metrics(self, **kwargs): plugin_data = super(FargateProcessHelper, self).collect_metrics(**kwargs) plugin_data["data"]["containerType"] = "docker" if self.collector.root_metadata is not None: - plugin_data["data"]["container"] = self.collector.root_metadata.get("DockerId") + plugin_data["data"]["container"] = self.collector.root_metadata.get( + "DockerId" + ) - if kwargs.get("with_snapshot"): - if self.collector.task_metadata is not None: - plugin_data["data"]["com.instana.plugin.host.name"] = self.collector.task_metadata.get("TaskArn") + if kwargs.get("with_snapshot") and self.collector.task_metadata is not None: + plugin_data["data"]["com.instana.plugin.host.name"] = ( + self.collector.task_metadata.get("TaskArn") + ) except Exception: logger.debug("FargateProcessHelper.collect_metrics: ", exc_info=True) return [plugin_data] diff --git a/src/instana/collector/helpers/google_cloud_run/process.py b/src/instana/collector/helpers/google_cloud_run/process.py index 443339ef..2c61f2f1 100644 --- a/src/instana/collector/helpers/google_cloud_run/process.py +++ b/src/instana/collector/helpers/google_cloud_run/process.py @@ -6,7 +6,7 @@ class GCRProcessHelper(ProcessHelper): - """ Helper class to extend the generic process helper class with the corresponding Google Cloud Run attributes """ + """Helper class to extend the generic process helper class with the corresponding Google Cloud Run attributes""" def collect_metrics(self, **kwargs): plugin_data = dict() @@ -14,8 +14,9 @@ def collect_metrics(self, **kwargs): plugin_data = super(GCRProcessHelper, self).collect_metrics(**kwargs) plugin_data["data"]["containerType"] = "gcpCloudRunInstance" plugin_data["data"]["container"] = self.collector.get_instance_id() - plugin_data["data"]["com.instana.plugin.host.name"] = "gcp:cloud-run:revision:{revision}".format( - revision=self.collector.revision) + plugin_data["data"]["com.instana.plugin.host.name"] = ( + f"gcp:cloud-run:revision:{self.collector.revision}" + ) except Exception: logger.debug("GCRProcessHelper.collect_metrics: ", exc_info=True) return [plugin_data] diff --git a/src/instana/collector/host.py b/src/instana/collector/host.py index 66e5681f..b3df855e 100644 --- a/src/instana/collector/host.py +++ b/src/instana/collector/host.py @@ -70,9 +70,7 @@ def prepare_and_report_data(self) -> None: def should_send_snapshot_data(self) -> bool: delta = int(time()) - self.snapshot_data_last_sent - if delta > self.snapshot_data_interval: - return True - return False + return delta > self.snapshot_data_interval def prepare_payload(self) -> DefaultDict[Any, Any]: payload = DictionaryOfStan() diff --git a/src/instana/collector/utils.py b/src/instana/collector/utils.py index 1da5892b..ff37ffc4 100644 --- a/src/instana/collector/utils.py +++ b/src/instana/collector/utils.py @@ -1,11 +1,12 @@ # (c) Copyright IBM Corp. 2024 -from typing import TYPE_CHECKING, Type, List +from typing import TYPE_CHECKING, List, Type -from opentelemetry.trace.span import format_span_id from opentelemetry.trace import SpanKind +from opentelemetry.trace.span import format_span_id from instana.util.ids import hex_id + if TYPE_CHECKING: from instana.span.base_span import BaseSpan @@ -25,6 +26,6 @@ def format_span( span.p = format_span_id(span.p) if span.p else None span.lt = hex_id(span.lt) if hasattr(span, "lt") else None if isinstance(span.k, SpanKind): - span.k = span.k.value if not span.k is SpanKind.INTERNAL else 3 + span.k = span.k.value if span.k is not SpanKind.INTERNAL else 3 spans.append(span) return spans diff --git a/src/instana/fsm.py b/src/instana/fsm.py index e49b7abb..529439b1 100644 --- a/src/instana/fsm.py +++ b/src/instana/fsm.py @@ -33,25 +33,23 @@ def __init__(self, agent: "HostAgent") -> None: self._warned_periodic = False self.agent = agent - self.fsm = Fysom( - { - "initial": "*", - "events": [ - ("lookup", "*", "found"), - ("announce", "found", "announced"), - ("pending", "announced", "wait4init"), - ("ready", "wait4init", "good2go"), - ], - "callbacks": { - # Can add the following to debug - # "onchangestate": self.print_state_change, - "onlookup": self.lookup_agent_host, - "onannounce": self.announce_sensor, - "onpending": self.on_ready, - "ongood2go": self.on_good2go, - }, - } - ) + self.fsm = Fysom({ + "initial": "*", + "events": [ + ("lookup", "*", "found"), + ("announce", "found", "announced"), + ("pending", "announced", "wait4init"), + ("ready", "wait4init", "good2go"), + ], + "callbacks": { + # Can add the following to debug + # "onchangestate": self.print_state_change, + "onlookup": self.lookup_agent_host, + "onannounce": self.announce_sensor, + "onpending": self.on_ready, + "ongood2go": self.on_good2go, + }, + }) with self._lock: self.timer = threading.Timer(1, self._safe_fsm_lookup) @@ -103,12 +101,11 @@ def lookup_agent_host(self, e: Any) -> bool: if os.path.exists("/proc/"): host = get_default_gateway() - if host: - if self.agent.is_agent_listening(host, port): - self.agent.options.agent_host = host - self.agent.options.agent_port = port - self._safe_fsm_announce() - return True + if host and self.agent.is_agent_listening(host, port): + self.agent.options.agent_host = host + self.agent.options.agent_port = port + self._safe_fsm_announce() + return True with self._lock: if self._warned_periodic is False: @@ -141,9 +138,10 @@ def announce_sensor(self, e: Any) -> bool: # PermissionError: [Errno 13] Permission denied: '/proc/6/fd/8' # Use a try/except as a safety sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect( - (self.agent.options.agent_host, self.agent.options.agent_port) - ) + sock.connect(( + self.agent.options.agent_host, + self.agent.options.agent_port, + )) path = f"/proc/{pid}/fd/{sock.fileno()}" d.fd = sock.fileno() d.inode = os.readlink(path) diff --git a/src/instana/helpers.py b/src/instana/helpers.py index d5ddecaf..bf8c5c3d 100644 --- a/src/instana/helpers.py +++ b/src/instana/helpers.py @@ -1,12 +1,6 @@ # (c) Copyright IBM Corp. 2021 # (c) Copyright Instana Inc. 2018 -import os -from string import Template - -from instana import eum_api_key as global_eum_api_key -from .singletons import tracer -from instana.log import logger # Usage: # @@ -26,7 +20,7 @@ def eum_snippet(trace_id=None, eum_api_key=None, meta=None): @return string """ - return '' + return "" def eum_test_snippet(trace_id=None, eum_api_key=None, meta=None): @@ -40,4 +34,4 @@ def eum_test_snippet(trace_id=None, eum_api_key=None, meta=None): @return string """ - return '' + return "" diff --git a/src/instana/instrumentation/aiohttp/client.py b/src/instana/instrumentation/aiohttp/client.py index 3b4e833a..ca29d7a3 100644 --- a/src/instana/instrumentation/aiohttp/client.py +++ b/src/instana/instrumentation/aiohttp/client.py @@ -65,7 +65,7 @@ async def stan_request_end( extract_custom_headers(span, params.response.headers) - if 500 <= params.response.status: + if params.response.status >= 500: span.mark_as_errored({"http.error": params.response.reason}) if span.is_recording(): diff --git a/src/instana/instrumentation/aiohttp/server.py b/src/instana/instrumentation/aiohttp/server.py index b021d799..a58bffeb 100644 --- a/src/instana/instrumentation/aiohttp/server.py +++ b/src/instana/instrumentation/aiohttp/server.py @@ -17,7 +17,7 @@ from instana.span.span import InstanaSpan try: - import aiohttp + import aiohttp # noqa: F401 from aiohttp.web import middleware if TYPE_CHECKING: @@ -60,7 +60,7 @@ async def stan_middleware( if response is not None: # Mark 500 responses as errored - if 500 <= response.status: + if response.status >= 500: span.mark_as_errored() span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, response.status) diff --git a/src/instana/instrumentation/asgi.py b/src/instana/instrumentation/asgi.py index e7e5e207..7c420e9d 100644 --- a/src/instana/instrumentation/asgi.py +++ b/src/instana/instrumentation/asgi.py @@ -17,6 +17,7 @@ if TYPE_CHECKING: from starlette.middleware.exceptions import ExceptionMiddleware + from instana.span.span import InstanaSpan @@ -34,7 +35,7 @@ def _collect_kvs(self, scope: Dict[str, Any], span: "InstanaSpan") -> None: span.set_attribute(SpanAttributes.HTTP_METHOD, scope.get("method")) server = scope.get("server") - if isinstance(server, tuple) or isinstance(server, list): + if isinstance(server, (tuple, list)): span.set_attribute(SpanAttributes.HTTP_HOST, server[0]) query = scope.get("query_string") @@ -102,7 +103,7 @@ async def send_wrapper(response: Dict[str, Any]) -> Awaitable[None]: try: status_code = response.get("status") if status_code: - if 500 <= int(status_code): + if int(status_code) >= 500: current_span.mark_as_errored() current_span.set_attribute( SpanAttributes.HTTP_STATUS_CODE, status_code diff --git a/src/instana/instrumentation/aws/dynamodb.py b/src/instana/instrumentation/aws/dynamodb.py index 722ce83c..343cef65 100644 --- a/src/instana/instrumentation/aws/dynamodb.py +++ b/src/instana/instrumentation/aws/dynamodb.py @@ -23,7 +23,7 @@ def create_dynamodb_span( try: span.set_attribute("dynamodb.op", args[0]) span.set_attribute("dynamodb.region", instance._client_config.region_name) - if "TableName" in args[1].keys(): + if "TableName" in args[1]: span.set_attribute("dynamodb.table", args[1]["TableName"]) except Exception as exc: span.record_exception(exc) diff --git a/src/instana/instrumentation/aws/lambda_inst.py b/src/instana/instrumentation/aws/lambda_inst.py index 086ad933..9b737e3b 100644 --- a/src/instana/instrumentation/aws/lambda_inst.py +++ b/src/instana/instrumentation/aws/lambda_inst.py @@ -55,7 +55,7 @@ def lambda_handler_with_instana( if "statusCode" in result and result.get("statusCode"): status_code = int(result["statusCode"]) span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) - if 500 <= status_code: + if status_code >= 500: span.record_exception(f"HTTP status {status_code}") except Exception as exc: logger.debug(f"AWS Lambda lambda_handler_with_instana error: {exc}") diff --git a/src/instana/instrumentation/aws/s3.py b/src/instana/instrumentation/aws/s3.py index 9b1557b5..12054bd5 100644 --- a/src/instana/instrumentation/aws/s3.py +++ b/src/instana/instrumentation/aws/s3.py @@ -35,7 +35,7 @@ def create_s3_span( with tracer.start_as_current_span("s3", context=parent_context) as span: try: span.set_attribute("s3.op", args[0]) - if "Bucket" in args[1].keys(): + if "Bucket" in args[1]: span.set_attribute("s3.bucket", args[1]["Bucket"]) except Exception as exc: span.record_exception(exc) diff --git a/src/instana/instrumentation/aws/triggers.py b/src/instana/instrumentation/aws/triggers.py index 67ebcd39..366d2b79 100644 --- a/src/instana/instrumentation/aws/triggers.py +++ b/src/instana/instrumentation/aws/triggers.py @@ -45,10 +45,7 @@ def get_context(tracer: "InstanaTracer", event: Dict[str, Any]) -> Optional["Con def is_api_gateway_proxy_trigger(event: Dict[str, Any]) -> bool: - for key in ["resource", "path", "httpMethod"]: - if key not in event: - return False - return True + return all(key in event for key in ["resource", "path", "httpMethod"]) def is_api_gateway_v2_proxy_trigger(event: Dict[str, Any]) -> bool: @@ -59,51 +56,45 @@ def is_api_gateway_v2_proxy_trigger(event: Dict[str, Any]) -> bool: if event["version"] != "2.0": return False - for key in ["apiId", "stage", "http"]: - if key not in event["requestContext"]: - return False - - return True + return all(key in event["requestContext"] for key in ["apiId", "stage", "http"]) def is_application_load_balancer_trigger(event: Dict[str, Any]) -> bool: - if "requestContext" in event and "elb" in event["requestContext"]: - return True - return False + return bool("requestContext" in event and "elb" in event["requestContext"]) def is_cloudwatch_trigger(event: Dict[str, Any]) -> bool: - if "source" in event and "detail-type" in event: - if ( + return bool( + "source" in event + and "detail-type" in event + and ( event["source"] == "aws.events" and event["detail-type"] == "Scheduled Event" - ): - return True - return False + ) + ) def is_cloudwatch_logs_trigger(event: Dict[str, Any]) -> bool: - if hasattr(event, "get") and event.get("awslogs", "\b") != "\b": - return True - else: - return False + return bool(hasattr(event, "get") and event.get("awslogs", "\x08") != "\x08") def is_s3_trigger(event: Dict[str, Any]) -> bool: - if "Records" in event: - if len(event["Records"]) > 0 and event["Records"][0]["eventSource"] == "aws:s3": - return True - return False + return bool( + "Records" in event + and ( + len(event["Records"]) > 0 and event["Records"][0]["eventSource"] == "aws:s3" + ) + ) def is_sqs_trigger(event: Dict[str, Any]) -> bool: - if "Records" in event: - if ( + return bool( + "Records" in event + and ( len(event["Records"]) > 0 and event["Records"][0]["eventSource"] == "aws:sqs" - ): - return True - return False + ) + ) def read_http_query_params(event: Dict[str, Any]) -> str: @@ -118,8 +109,8 @@ def read_http_query_params(event: Dict[str, Any]) -> str: if event is None or type(event) is not dict: return "" - mvqsp = event.get("multiValueQueryStringParameters", None) - qsp = event.get("queryStringParameters", None) + mvqsp = event.get("multiValueQueryStringParameters") + qsp = event.get("queryStringParameters") if mvqsp is not None and type(mvqsp) is dict: for key in mvqsp: @@ -149,14 +140,14 @@ def capture_extra_headers( @return: None """ try: - event_headers = event.get("headers", None) + event_headers = event.get("headers") if event_headers: for custom_header in extra_headers: for key in event_headers: if key.lower() == custom_header.lower(): span.set_attribute( - "http.header.%s" % custom_header, event_headers[key] + f"http.header.{custom_header}", event_headers[key] ) except Exception: logger.debug("AWS Lambda capture_extra_headers error: ", exc_info=True) @@ -296,13 +287,11 @@ def enrich_lambda_span( if len(object_name) > 200: object_name = object_name[:200] - events.append( - { - "event": item["eventName"], - "bucket": bucket_name, - "object": object_name, - } - ) + events.append({ + "event": item["eventName"], + "bucket": bucket_name, + "object": object_name, + }) span.set_attribute("lambda.s3.events", events) elif is_sqs_trigger(event): diff --git a/src/instana/instrumentation/celery.py b/src/instana/instrumentation/celery.py index f0648212..748a0bdd 100644 --- a/src/instana/instrumentation/celery.py +++ b/src/instana/instrumentation/celery.py @@ -30,7 +30,7 @@ def _get_task_id( """ Across Celery versions, the task id can exist in a couple of places. """ - id = headers.get("id", None) + id = headers.get("id") if id is None: id = body.get("id", None) return id @@ -70,8 +70,8 @@ def task_prerun( ctx = None tracer = get_tracer() - task = kwargs.get("sender", None) - task_id = kwargs.get("task_id", None) + task = kwargs.get("sender") + task_id = kwargs.get("task_id") task = registry.tasks.get(task.name) headers = task.request.get("headers", {}) @@ -117,7 +117,7 @@ def task_failure( span = worker_span.get() if span.is_recording(): span.set_attribute("success", False) - exc = kwargs.get("exception", None) + exc = kwargs.get("exception") if exc: span.record_exception(exc) else: @@ -133,7 +133,7 @@ def task_retry( try: span = worker_span.get() if span.is_recording(): - reason = kwargs.get("reason", None) + reason = kwargs.get("reason") if reason: span.set_attribute("retry-reason", reason) except Exception: diff --git a/src/instana/instrumentation/django/middleware.py b/src/instana/instrumentation/django/middleware.py index 52a2981a..3037581a 100644 --- a/src/instana/instrumentation/django/middleware.py +++ b/src/instana/instrumentation/django/middleware.py @@ -94,7 +94,7 @@ def process_response( ) -> "HttpResponse": try: if request.span: - if 500 <= response.status_code: + if response.status_code >= 500: request.span.assure_errored() # for django >= 2.2 if request.resolver_match is not None and hasattr( diff --git a/src/instana/instrumentation/fastapi.py b/src/instana/instrumentation/fastapi.py index 68b19f6a..bb163129 100644 --- a/src/instana/instrumentation/fastapi.py +++ b/src/instana/instrumentation/fastapi.py @@ -16,15 +16,13 @@ import wrapt from fastapi import HTTPException from fastapi.exception_handlers import http_exception_handler + from opentelemetry.semconv.trace import SpanAttributes from starlette.middleware import Middleware from instana.instrumentation.asgi import InstanaASGIMiddleware - from instana.log import logger - from instana.util.gunicorn import running_in_gunicorn + from instana.log import logger, running_in_gunicorn from instana.util.traceutils import get_tracer_tuple - from opentelemetry.semconv.trace import SpanAttributes - if TYPE_CHECKING: from starlette.requests import Request from starlette.responses import Response @@ -51,7 +49,7 @@ async def instana_exception_handler( _, span, _ = get_tracer_tuple() if span: - if hasattr(exc, "detail") and 500 <= exc.status_code: + if hasattr(exc, "detail") and exc.status_code >= 500: span.set_attribute("http.error", exc.detail) span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, exc.status_code) except Exception: @@ -72,7 +70,7 @@ def init_with_instana( elif isinstance(middleware, list): middleware.append(Middleware(InstanaASGIMiddleware)) elif isinstance(middleware, tuple): - kwargs["middleware"] = (*middleware, Middleware(InstanaASGIMiddleware)) + kwargs["middleware"] = (*middleware, Middleware(InstanaASGIMiddleware)) else: logger.warning("Unsupported FastAPI middleware sequence type.") diff --git a/src/instana/instrumentation/flask/__init__.py b/src/instana/instrumentation/flask/__init__.py index 7d85abcd..4100ede7 100644 --- a/src/instana/instrumentation/flask/__init__.py +++ b/src/instana/instrumentation/flask/__init__.py @@ -10,7 +10,7 @@ # # Blinker support is preferred but we do the best we can when it's not available. # - if hasattr(flask.signals, 'signals_available'): + if hasattr(flask.signals, "signals_available"): from flask.signals import signals_available else: # Beginning from 2.3.0 as stated in the notes @@ -19,11 +19,11 @@ # The signals_available attribute is deprecated. #5056" signals_available = True - from instana.instrumentation.flask import common + from instana.instrumentation.flask import common # noqa: F401 if signals_available is True: import instana.instrumentation.flask.with_blinker else: - import instana.instrumentation.flask.vanilla + import instana.instrumentation.flask.vanilla # noqa: F401 except ImportError: pass diff --git a/src/instana/instrumentation/flask/common.py b/src/instana/instrumentation/flask/common.py index c2747a26..4be2403b 100644 --- a/src/instana/instrumentation/flask/common.py +++ b/src/instana/instrumentation/flask/common.py @@ -82,7 +82,7 @@ def handle_user_exception_with_instana( else: status_code = response.status_code - if 500 <= status_code: + if status_code >= 500: span.record_exception(exc) span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, int(status_code)) @@ -147,7 +147,7 @@ def inject_span( span = flask.g.span if span: - if 500 <= response.status_code: + if response.status_code >= 500: span.mark_as_errored() span.set_attribute( diff --git a/src/instana/instrumentation/google/cloud/collectors.py b/src/instana/instrumentation/google/cloud/collectors.py index 7ec44690..55b4e097 100644 --- a/src/instana/instrumentation/google/cloud/collectors.py +++ b/src/instana/instrumentation/google/cloud/collectors.py @@ -15,300 +15,337 @@ # # The API documentation can be found at https://cloud.google.com/storage/docs/json_api _storage_api = { - 'GET': { + "GET": { ##################### # Bucket operations # ##################### - '/b': lambda params, data: { - 'gcs.op': 'buckets.list', - 'gcs.projectId': params.get('project', None) + "/b": lambda params, data: { + "gcs.op": "buckets.list", + "gcs.projectId": params.get("project", None), }, - re.compile('^/b/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'buckets.get', - 'gcs.bucket': unquote(match.group('bucket')), + re.compile("^/b/(?P[^/]+)$"): lambda params, data, match: { + "gcs.op": "buckets.get", + "gcs.bucket": unquote(match.group("bucket")), }, - re.compile('^/b/(?P[^/]+)/iam$'): lambda params, data, match: { - 'gcs.op': 'buckets.getIamPolicy', - 'gcs.bucket': unquote(match.group('bucket')), + re.compile("^/b/(?P[^/]+)/iam$"): lambda params, data, match: { + "gcs.op": "buckets.getIamPolicy", + "gcs.bucket": unquote(match.group("bucket")), }, - re.compile('^/b/(?P[^/]+)/iam/testPermissions$'): lambda params, data, match: { - 'gcs.op': 'buckets.testIamPermissions', - 'gcs.bucket': unquote(match.group('bucket')), + re.compile( + "^/b/(?P[^/]+)/iam/testPermissions$" + ): lambda params, data, match: { + "gcs.op": "buckets.testIamPermissions", + "gcs.bucket": unquote(match.group("bucket")), }, - ########################## # Object/blob operations # ########################## - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': params.get('alt', 'json') == 'media' and 'objects.get' or 'objects.attrs', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')), - }, - re.compile('^/b/(?P[^/]+)/o$'): lambda params, data, match: { - 'gcs.op': 'objects.list', - 'gcs.bucket': unquote(match.group('bucket')) + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": params.get("alt", "json") == "media" + and "objects.get" + or "objects.attrs", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), + }, + re.compile("^/b/(?P[^/]+)/o$"): lambda params, data, match: { + "gcs.op": "objects.list", + "gcs.bucket": unquote(match.group("bucket")), }, - ################################## # Default object ACLs operations # ################################## - re.compile('^/b/(?P[^/]+)/defaultObjectAcl/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'defaultAcls.get', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.entity': unquote(match.group('entity')) - }, - re.compile('^/b/(?P[^/]+)/defaultObjectAcl$'): lambda params, data, match: { - 'gcs.op': 'defaultAcls.list', - 'gcs.bucket': unquote(match.group('bucket')), + re.compile( + "^/b/(?P[^/]+)/defaultObjectAcl/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "defaultAcls.get", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.entity": unquote(match.group("entity")), + }, + re.compile( + "^/b/(?P[^/]+)/defaultObjectAcl$" + ): lambda params, data, match: { + "gcs.op": "defaultAcls.list", + "gcs.bucket": unquote(match.group("bucket")), }, - ######################### # Object ACL operations # ######################### - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)/acl/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'objectAcls.get', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')), - 'gcs.entity': unquote(match.group('entity')) - }, - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)/acl$'): lambda params, data, match: { - 'gcs.op': 'objectAcls.list', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')) + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)/acl/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "objectAcls.get", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), + "gcs.entity": unquote(match.group("entity")), + }, + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)/acl$" + ): lambda params, data, match: { + "gcs.op": "objectAcls.list", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), }, - ######################## # HMAC keys operations # ######################## - re.compile('^/projects/(?P[^/]+)/hmacKeys$'): lambda params, data, match: { - 'gcs.op': 'hmacKeys.list', - 'gcs.projectId': unquote(match.group('project')) - }, - re.compile('^/projects/(?P[^/]+)/hmacKeys/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'hmacKeys.get', - 'gcs.projectId': unquote(match.group('project')), - 'gcs.accessId': unquote(match.group('accessId')) + re.compile( + "^/projects/(?P[^/]+)/hmacKeys$" + ): lambda params, data, match: { + "gcs.op": "hmacKeys.list", + "gcs.projectId": unquote(match.group("project")), + }, + re.compile( + "^/projects/(?P[^/]+)/hmacKeys/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "hmacKeys.get", + "gcs.projectId": unquote(match.group("project")), + "gcs.accessId": unquote(match.group("accessId")), }, - ############################## # Service account operations # ############################## - re.compile('^/projects/(?P[^/]+)/serviceAccount$'): lambda params, data, match: { - 'gcs.op': 'serviceAccount.get', - 'gcs.projectId': unquote(match.group('project')) - } + re.compile( + "^/projects/(?P[^/]+)/serviceAccount$" + ): lambda params, data, match: { + "gcs.op": "serviceAccount.get", + "gcs.projectId": unquote(match.group("project")), + }, }, - 'POST': { + "POST": { ##################### # Bucket operations # ##################### - '/b': lambda params, data: { - 'gcs.op': 'buckets.insert', - 'gcs.projectId': params.get('project', None), - 'gcs.bucket': data.get('name', None), + "/b": lambda params, data: { + "gcs.op": "buckets.insert", + "gcs.projectId": params.get("project", None), + "gcs.bucket": data.get("name", None), }, - re.compile('^/b/(?P[^/]+)/lockRetentionPolicy$'): lambda params, data, match: { - 'gcs.op': 'buckets.lockRetentionPolicy', - 'gcs.bucket': unquote(match.group('bucket')), + re.compile( + "^/b/(?P[^/]+)/lockRetentionPolicy$" + ): lambda params, data, match: { + "gcs.op": "buckets.lockRetentionPolicy", + "gcs.bucket": unquote(match.group("bucket")), }, - ########################## # Object/blob operations # ########################## - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)/compose$'): lambda params, data, match: { - 'gcs.op': 'objects.compose', - 'gcs.destinationBucket': unquote(match.group('bucket')), - 'gcs.destinationObject': unquote(match.group('object')), - 'gcs.sourceObjects': ','.join( - ['%s/%s' % (unquote(match.group('bucket')), o['name']) for o in data.get('sourceObjects', []) if 'name' in o] - ) - }, - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)/copyTo/b/(?P[^/]+)/o/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'objects.copy', - 'gcs.destinationBucket': unquote(match.group('destBucket')), - 'gcs.destinationObject': unquote(match.group('destObject')), - 'gcs.sourceBucket': unquote(match.group('srcBucket')), - 'gcs.sourceObject': unquote(match.group('srcObject')), - }, - re.compile('^/b/(?P[^/]+)/o$'): lambda params, data, match: { - 'gcs.op': 'objects.insert', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': params.get('name', data.get('name', None)), - }, - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)/rewriteTo/b/(?P[^/]+)/o/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'objects.rewrite', - 'gcs.destinationBucket': unquote(match.group('destBucket')), - 'gcs.destinationObject': unquote(match.group('destObject')), - 'gcs.sourceBucket': unquote(match.group('srcBucket')), - 'gcs.sourceObject': unquote(match.group('srcObject')), + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)/compose$" + ): lambda params, data, match: { + "gcs.op": "objects.compose", + "gcs.destinationBucket": unquote(match.group("bucket")), + "gcs.destinationObject": unquote(match.group("object")), + "gcs.sourceObjects": ",".join([ + "{}/{}".format(unquote(match.group("bucket")), o["name"]) + for o in data.get("sourceObjects", []) + if "name" in o + ]), + }, + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)/copyTo/b/(?P[^/]+)/o/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "objects.copy", + "gcs.destinationBucket": unquote(match.group("destBucket")), + "gcs.destinationObject": unquote(match.group("destObject")), + "gcs.sourceBucket": unquote(match.group("srcBucket")), + "gcs.sourceObject": unquote(match.group("srcObject")), + }, + re.compile("^/b/(?P[^/]+)/o$"): lambda params, data, match: { + "gcs.op": "objects.insert", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": params.get("name", data.get("name", None)), + }, + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)/rewriteTo/b/(?P[^/]+)/o/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "objects.rewrite", + "gcs.destinationBucket": unquote(match.group("destBucket")), + "gcs.destinationObject": unquote(match.group("destObject")), + "gcs.sourceBucket": unquote(match.group("srcBucket")), + "gcs.sourceObject": unquote(match.group("srcObject")), }, - ###################### # Channel operations # ###################### - '/channels/stop': lambda params, data: { - 'gcs.op': 'channels.stop', - 'gcs.entity': data.get('id', None) + "/channels/stop": lambda params, data: { + "gcs.op": "channels.stop", + "gcs.entity": data.get("id", None), }, - ################################## # Default object ACLs operations # ################################## - re.compile('^/b/(?P[^/]+)/defaultObjectAcl$'): lambda params, data, match: { - 'gcs.op': 'defaultAcls.insert', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.entity': data.get('entity', None) + re.compile( + "^/b/(?P[^/]+)/defaultObjectAcl$" + ): lambda params, data, match: { + "gcs.op": "defaultAcls.insert", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.entity": data.get("entity", None), }, - ######################### # Object ACL operations # ######################### - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)/acl$'): lambda params, data, match: { - 'gcs.op': 'objectAcls.insert', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')), - 'gcs.entity': data.get('entity', None) + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)/acl$" + ): lambda params, data, match: { + "gcs.op": "objectAcls.insert", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), + "gcs.entity": data.get("entity", None), }, - ######################## # HMAC keys operations # ######################## - re.compile('^/projects/(?P[^/]+)/hmacKeys$'): lambda params, data, match: { - 'gcs.op': 'hmacKeys.create', - 'gcs.projectId': unquote(match.group('project')) - } + re.compile( + "^/projects/(?P[^/]+)/hmacKeys$" + ): lambda params, data, match: { + "gcs.op": "hmacKeys.create", + "gcs.projectId": unquote(match.group("project")), + }, }, - 'PATCH': { + "PATCH": { ##################### # Bucket operations # ##################### - re.compile('^/b/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'buckets.patch', - 'gcs.bucket': unquote(match.group('bucket')), + re.compile("^/b/(?P[^/]+)$"): lambda params, data, match: { + "gcs.op": "buckets.patch", + "gcs.bucket": unquote(match.group("bucket")), }, - ########################## # Object/blob operations # ########################## - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'objects.patch', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')), + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "objects.patch", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), }, - ################################## # Default object ACLs operations # ################################## - re.compile('^/b/(?P[^/]+)/defaultObjectAcl/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'defaultAcls.patch', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.entity': unquote(match.group('entity')) + re.compile( + "^/b/(?P[^/]+)/defaultObjectAcl/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "defaultAcls.patch", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.entity": unquote(match.group("entity")), }, - ######################### # Object ACL operations # ######################### - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)/acl/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'objectAcls.patch', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')), - 'gcs.entity': unquote(match.group('entity')) - } + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)/acl/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "objectAcls.patch", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), + "gcs.entity": unquote(match.group("entity")), + }, }, - 'PUT': { + "PUT": { ##################### # Bucket operations # ##################### - re.compile('^/b/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'buckets.update', - 'gcs.bucket': unquote(match.group('bucket')), + re.compile("^/b/(?P[^/]+)$"): lambda params, data, match: { + "gcs.op": "buckets.update", + "gcs.bucket": unquote(match.group("bucket")), }, - re.compile('^/b/(?P[^/]+)/iam$'): lambda params, data, match: { - 'gcs.op': 'buckets.setIamPolicy', - 'gcs.bucket': unquote(match.group('bucket')), + re.compile("^/b/(?P[^/]+)/iam$"): lambda params, data, match: { + "gcs.op": "buckets.setIamPolicy", + "gcs.bucket": unquote(match.group("bucket")), }, - ########################## # Object/blob operations # ########################## - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'objects.update', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')), + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "objects.update", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), }, - ################################## # Default object ACLs operations # ################################## - re.compile('^/b/(?P[^/]+)/defaultObjectAcl/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'defaultAcls.update', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.entity': unquote(match.group('entity')) + re.compile( + "^/b/(?P[^/]+)/defaultObjectAcl/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "defaultAcls.update", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.entity": unquote(match.group("entity")), }, - ######################### # Object ACL operations # ######################### - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)/acl/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'objectAcls.update', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')), - 'gcs.entity': unquote(match.group('entity')) + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)/acl/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "objectAcls.update", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), + "gcs.entity": unquote(match.group("entity")), }, - ######################## # HMAC keys operations # ######################## - re.compile('^/projects/(?P[^/]+)/hmacKeys/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'hmacKeys.update', - 'gcs.projectId': unquote(match.group('project')), - 'gcs.accessId': unquote(match.group('accessId')) - } + re.compile( + "^/projects/(?P[^/]+)/hmacKeys/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "hmacKeys.update", + "gcs.projectId": unquote(match.group("project")), + "gcs.accessId": unquote(match.group("accessId")), + }, }, - 'DELETE': { + "DELETE": { ##################### # Bucket operations # ##################### - re.compile('^/b/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'buckets.delete', - 'gcs.bucket': unquote(match.group('bucket')), + re.compile("^/b/(?P[^/]+)$"): lambda params, data, match: { + "gcs.op": "buckets.delete", + "gcs.bucket": unquote(match.group("bucket")), }, - ########################## # Object/blob operations # ########################## - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'objects.delete', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')), + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "objects.delete", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), }, - ################################## # Default object ACLs operations # ################################## - re.compile('^/b/(?P[^/]+)/defaultObjectAcl/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'defaultAcls.delete', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.entity': unquote(match.group('entity')) + re.compile( + "^/b/(?P[^/]+)/defaultObjectAcl/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "defaultAcls.delete", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.entity": unquote(match.group("entity")), }, - ######################### # Object ACL operations # ######################### - re.compile('^/b/(?P[^/]+)/o/(?P[^/]+)/acl/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'objectAcls.delete', - 'gcs.bucket': unquote(match.group('bucket')), - 'gcs.object': unquote(match.group('object')), - 'gcs.entity': unquote(match.group('entity')) + re.compile( + "^/b/(?P[^/]+)/o/(?P[^/]+)/acl/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "objectAcls.delete", + "gcs.bucket": unquote(match.group("bucket")), + "gcs.object": unquote(match.group("object")), + "gcs.entity": unquote(match.group("entity")), }, - ######################## # HMAC keys operations # ######################## - re.compile('^/projects/(?P[^/]+)/hmacKeys/(?P[^/]+)$'): lambda params, data, match: { - 'gcs.op': 'hmacKeys.delete', - 'gcs.projectId': unquote(match.group('project')), - 'gcs.accessId': unquote(match.group('accessId')) - } - } + re.compile( + "^/projects/(?P[^/]+)/hmacKeys/(?P[^/]+)$" + ): lambda params, data, match: { + "gcs.op": "hmacKeys.delete", + "gcs.projectId": unquote(match.group("project")), + "gcs.accessId": unquote(match.group("accessId")), + }, + }, } diff --git a/src/instana/instrumentation/google/cloud/storage.py b/src/instana/instrumentation/google/cloud/storage.py index 0720c353..da24b1e1 100644 --- a/src/instana/instrumentation/google/cloud/storage.py +++ b/src/instana/instrumentation/google/cloud/storage.py @@ -27,7 +27,7 @@ def _collect_attributes( :param: dict :return: dict or None """ - method, path = api_request.get("method", None), api_request.get("path", None) + method, path = api_request.get("method"), api_request.get("path") if method not in _storage_api: return @@ -106,16 +106,16 @@ def download_with_instana( span.set_attribute("gcs.bucket", instance.bucket.name) span.set_attribute("gcs.object", instance.name) - start = len(args) > 4 and args[4] or kwargs.get("start", None) + start = len(args) > 4 and args[4] or kwargs.get("start") if start is None: start = "" - end = len(args) > 5 and args[5] or kwargs.get("end", None) + end = len(args) > 5 and args[5] or kwargs.get("end") if end is None: end = "" if start != "" or end != "": - span.set_attribute("gcs.range", "-".join((start, end))) + span.set_attribute("gcs.range", f"{start}-{end}") try: kv = wrapped(*args, **kwargs) diff --git a/src/instana/instrumentation/httpx.py b/src/instana/instrumentation/httpx.py index f74f1d13..67617d9f 100644 --- a/src/instana/instrumentation/httpx.py +++ b/src/instana/instrumentation/httpx.py @@ -58,7 +58,7 @@ def _set_response_span_attributes( status_code = response.status_code span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) - if 500 <= status_code: + if status_code >= 500: span.mark_as_errored() except Exception: logger.debug("httpx _set_request_span_attributes error: ", exc_info=True) diff --git a/src/instana/instrumentation/kafka/kafka_python.py b/src/instana/instrumentation/kafka/kafka_python.py index 44bd0ebd..2c63d39c 100644 --- a/src/instana/instrumentation/kafka/kafka_python.py +++ b/src/instana/instrumentation/kafka/kafka_python.py @@ -60,7 +60,7 @@ def trace_kafka_send( # Context propagation headers = kwargs.get("headers", []) - if not is_suppressed and ("x_instana_l_s", b"0") in headers: + if not is_suppressed and headers and ("x_instana_l_s", b"0") in headers: is_suppressed = True suppression_header = {"x_instana_l_s": "0" if is_suppressed else "1"} @@ -112,9 +112,8 @@ def create_span( attributes_to_check ) - if not is_suppressed and headers: - if ("x_instana_l_s", b"0") in headers: - is_suppressed = True + if not is_suppressed and headers and ("x_instana_l_s", b"0") in headers: + is_suppressed = True if is_suppressed: return diff --git a/src/instana/instrumentation/logging.py b/src/instana/instrumentation/logging.py index 0c8656d0..fc0c2568 100644 --- a/src/instana/instrumentation/logging.py +++ b/src/instana/instrumentation/logging.py @@ -56,7 +56,7 @@ def log_with_instana( parameters = None (t, v, tb) = sys.exc_info() if t is not None and v is not None: - parameters = "{} {}".format(t, v) + parameters = f"{t} {v}" parent_context = get_current() diff --git a/src/instana/instrumentation/psycopg2.py b/src/instana/instrumentation/psycopg2.py index 6045c4c9..2baf4d6f 100644 --- a/src/instana/instrumentation/psycopg2.py +++ b/src/instana/instrumentation/psycopg2.py @@ -3,15 +3,16 @@ import copy +from typing import Any, Callable, Dict, Optional, Tuple + import wrapt -from typing import Callable, Optional, Any, Tuple, Dict -from instana.log import logger from instana.instrumentation.pep0249 import ConnectionFactory +from instana.log import logger try: import psycopg2 - import psycopg2.extras + import psycopg2.extras # noqa: F401 cf = ConnectionFactory(connect_func=psycopg2.connect, module_name="postgres") @@ -40,9 +41,8 @@ def register_json_with_instana( args: Tuple[Any, ...], kwargs: Dict[str, Any], ) -> Callable[..., object]: - if "conn_or_curs" in kwargs: - if hasattr(kwargs["conn_or_curs"], "__wrapped__"): - kwargs["conn_or_curs"] = kwargs["conn_or_curs"].__wrapped__ + if "conn_or_curs" in kwargs and hasattr(kwargs["conn_or_curs"], "__wrapped__"): + kwargs["conn_or_curs"] = kwargs["conn_or_curs"].__wrapped__ return wrapped(*args, **kwargs) diff --git a/src/instana/instrumentation/pyramid.py b/src/instana/instrumentation/pyramid.py index 09e71462..2d67a72c 100644 --- a/src/instana/instrumentation/pyramid.py +++ b/src/instana/instrumentation/pyramid.py @@ -115,7 +115,7 @@ def init_with_instana( settings["pyramid.tweens"] = "\n".join(tweens) kwargs["settings"] = settings - if not kwargs.get("package", None): + if not kwargs.get("package"): kwargs["package"] = caller_package() wrapped(*args, **kwargs) diff --git a/src/instana/instrumentation/sanic.py b/src/instana/instrumentation/sanic.py index 6d5dce78..fc52af3a 100644 --- a/src/instana/instrumentation/sanic.py +++ b/src/instana/instrumentation/sanic.py @@ -92,7 +92,7 @@ def exception_with_instana(request: Request, exception: Exception) -> None: status_code = exception.status_code message = str(exception) - if all([span, status_code, message]) and 500 <= status_code: + if all([span, status_code, message]) and status_code >= 500: span.set_attribute("http.error", message) except Exception: logger.debug("exception_with_instana: ", exc_info=True) diff --git a/src/instana/instrumentation/spyne.py b/src/instana/instrumentation/spyne.py index 32d249d3..b237f413 100644 --- a/src/instana/instrumentation/spyne.py +++ b/src/instana/instrumentation/spyne.py @@ -47,7 +47,7 @@ def record_error( ) -> None: resp_code = int(response_string.split()[0]) - if 500 <= resp_code: + if resp_code >= 500: span.record_exception(error) @wrapt.patch_function_wrapper("spyne.server.wsgi", "WsgiApplication.handle_error") @@ -124,7 +124,7 @@ def process_request_with_instana( tracer.inject(span.context, Format.HTTP_HEADERS, response_headers) - ## Store the span in the user defined context object offered by Spyne + # Store the span in the user defined context object offered by Spyne if ctx.udc: ctx.udc.span = span else: diff --git a/src/instana/instrumentation/starlette.py b/src/instana/instrumentation/starlette.py index 9d4b1f8e..df9224d7 100644 --- a/src/instana/instrumentation/starlette.py +++ b/src/instana/instrumentation/starlette.py @@ -9,10 +9,10 @@ from typing import Any, Callable, Dict, Tuple try: - import starlette + import starlette # noqa: F401 + import starlette.applications import wrapt from starlette.middleware import Middleware - import starlette.applications from instana.instrumentation.asgi import InstanaASGIMiddleware from instana.log import logger diff --git a/src/instana/instrumentation/tornado/server.py b/src/instana/instrumentation/tornado/server.py index c1f5242c..55ce828a 100644 --- a/src/instana/instrumentation/tornado/server.py +++ b/src/instana/instrumentation/tornado/server.py @@ -96,7 +96,7 @@ def on_finish_with_instana( status_code = instance.get_status() # Mark 500 responses as errored - if 500 <= status_code: + if status_code >= 500: span.mark_as_errored() span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) diff --git a/src/instana/instrumentation/urllib3.py b/src/instana/instrumentation/urllib3.py index 05a7a52a..5db0e256 100644 --- a/src/instana/instrumentation/urllib3.py +++ b/src/instana/instrumentation/urllib3.py @@ -55,7 +55,7 @@ def _collect_kvs( # Only construct URL if host is not None if kvs.get("host") and kvs.get("path"): - url = f'{kvs["host"]}:{kvs["port"]}{kvs["path"]}' + url = f"{kvs['host']}:{kvs['port']}{kvs['path']}" if isinstance(instance, urllib3.connectionpool.HTTPSConnectionPool): kvs["url"] = f"https://{url}" else: @@ -74,7 +74,7 @@ def collect_response( extract_custom_headers(span, response.headers) - if 500 <= response.status: + if response.status >= 500: span.mark_as_errored() except Exception: logger.debug("urllib3 collect_response error: ", exc_info=True) diff --git a/src/instana/instrumentation/wsgi.py b/src/instana/instrumentation/wsgi.py index b2413eec..2af36143 100644 --- a/src/instana/instrumentation/wsgi.py +++ b/src/instana/instrumentation/wsgi.py @@ -62,7 +62,7 @@ def new_start_response( # Set status code attribute sc = status.split(" ")[0] - if 500 <= int(sc): + if int(sc) >= 500: span.mark_as_errored() span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, sc) diff --git a/src/instana/log.py b/src/instana/log.py index 173437cd..2dfcfdaf 100644 --- a/src/instana/log.py +++ b/src/instana/log.py @@ -1,15 +1,16 @@ -# (c) Copyright IBM Corp. 2021 +# (c) Copyright IBM Corp. 2021, 2026 # (c) Copyright Instana Inc. 2016 from __future__ import print_function + +import logging import os import sys -import logging logger = None -def get_standard_logger(): +def get_standard_logger() -> logging.Logger: """ Retrieves and configures a standard logger for the Instana package @@ -18,14 +19,16 @@ def get_standard_logger(): standard_logger = logging.getLogger("instana") ch = logging.StreamHandler() - f = logging.Formatter('%(asctime)s: %(process)d %(levelname)s %(name)s: %(message)s') + f = logging.Formatter( + "%(asctime)s: %(process)d %(levelname)s %(name)s: %(message)s" + ) ch.setFormatter(f) standard_logger.addHandler(ch) standard_logger.setLevel(logging.DEBUG) return standard_logger -def get_aws_lambda_logger(): +def get_aws_lambda_logger() -> logging.Logger: """ Retrieves the preferred logger for AWS Lambda @@ -35,7 +38,8 @@ def get_aws_lambda_logger(): aws_lambda_logger.setLevel(logging.INFO) return aws_lambda_logger -def glogging_available(): + +def glogging_available() -> bool: """ Determines if the gunicorn.glogging package is available @@ -45,15 +49,16 @@ def glogging_available(): # Is the glogging package available? try: - from gunicorn import glogging + from gunicorn import glogging # noqa: F401 except ImportError: pass else: package_check = True - + return package_check -def running_in_gunicorn(): + +def running_in_gunicorn() -> bool: """ Determines if we are running inside of a gunicorn process. @@ -63,29 +68,28 @@ def running_in_gunicorn(): try: # Is this a gunicorn process? - if hasattr(sys, 'argv'): + if hasattr(sys, "argv"): for arg in sys.argv: - if arg.find('gunicorn') >= 0: + if arg.find("gunicorn") >= 0: process_check = True elif os.path.isfile("/proc/self/cmdline"): with open("/proc/self/cmdline") as cmd: contents = cmd.read() - parts = contents.split('\0') + parts = contents.split("\0") parts.pop() cmdline = " ".join(parts) - if cmdline.find('gunicorn') >= 0: + if cmdline.find("gunicorn") >= 0: process_check = True return process_check except Exception: - logger.debug("Instana.log.running_in_gunicorn: ", exc_info=True) return False -aws_env = os.environ.get("AWS_EXECUTION_ENV", "") -env_is_aws_lambda = "AWS_Lambda_" in aws_env +env_is_aws_lambda = "AWS_Lambda_" in os.environ.get("AWS_EXECUTION_ENV", "") + if running_in_gunicorn() and glogging_available(): logger = logging.getLogger("gunicorn.error") diff --git a/src/instana/options.py b/src/instana/options.py index cb709918..ae2a229f 100644 --- a/src/instana/options.py +++ b/src/instana/options.py @@ -28,9 +28,9 @@ get_stack_trace_config_from_yaml, is_truthy, parse_filter_rules, + parse_filter_rules_env_vars, parse_filter_rules_yaml, parse_span_disabling, - parse_filter_rules_env_vars, parse_technology_stack_trace_config, validate_stack_trace_length, validate_stack_trace_level, @@ -123,45 +123,45 @@ def _add_instana_agent_span_filter(self) -> None: """Add Instana agent span filter to exclude internal spans.""" if "exclude" not in self.span_filters: self.span_filters["exclude"] = [] - self.span_filters["exclude"].extend( - [ - { - "name": "filter-internal-spans-by-url", - "attributes": [ - { - "key": "http.url", - "values": ["com.instana"], - "match_type": "contains", - } - ], - }, - { - "name": "filter-internal-spans-by-host", - "attributes": [ - { - "key": "http.host", - "values": ["com.instana"], - "match_type": "contains", - } - ], - }, - ] - ) + self.span_filters["exclude"].extend([ + { + "name": "filter-internal-spans-by-url", + "attributes": [ + { + "key": "http.url", + "values": ["com.instana"], + "match_type": "contains", + } + ], + }, + { + "name": "filter-internal-spans-by-host", + "attributes": [ + { + "key": "http.host", + "values": ["com.instana"], + "match_type": "contains", + } + ], + }, + ]) def _apply_env_stack_trace_config(self) -> None: """Apply stack trace configuration from environment variables.""" - if "INSTANA_STACK_TRACE" in os.environ: - if validated_level := validate_stack_trace_level( + if "INSTANA_STACK_TRACE" in os.environ and ( + validated_level := validate_stack_trace_level( os.environ["INSTANA_STACK_TRACE"], "from INSTANA_STACK_TRACE" - ): - self.stack_trace_level = validated_level + ) + ): + self.stack_trace_level = validated_level - if "INSTANA_STACK_TRACE_LENGTH" in os.environ: - if validated_length := validate_stack_trace_length( + if "INSTANA_STACK_TRACE_LENGTH" in os.environ and ( + validated_length := validate_stack_trace_length( os.environ["INSTANA_STACK_TRACE_LENGTH"], "from INSTANA_STACK_TRACE_LENGTH", - ): - self.stack_trace_length = validated_length + ) + ): + self.stack_trace_length = validated_length def _apply_yaml_stack_trace_config(self) -> None: """Apply stack trace configuration from YAML file.""" @@ -182,20 +182,26 @@ def _apply_in_code_stack_trace_config(self) -> None: global_config = config["tracing"]["global"] - if "INSTANA_STACK_TRACE" not in os.environ and "stack_trace" in global_config: - if validated_level := validate_stack_trace_level( - global_config["stack_trace"], "from in-code config" - ): - self.stack_trace_level = validated_level + if ( + "INSTANA_STACK_TRACE" not in os.environ + and "stack_trace" in global_config + and ( + validated_level := validate_stack_trace_level( + global_config["stack_trace"], "from in-code config" + ) + ) + ): + self.stack_trace_level = validated_level if ( "INSTANA_STACK_TRACE_LENGTH" not in os.environ and "stack_trace_length" in global_config - ): - if validated_length := validate_stack_trace_length( + ) and ( + validated_length := validate_stack_trace_length( global_config["stack_trace_length"], "from in-code config" - ): - self.stack_trace_length = validated_length + ) + ): + self.stack_trace_length = validated_length # Technology-specific overrides from in-code config for tech_name, tech_data in config["tracing"].items(): @@ -429,17 +435,19 @@ def _apply_agent_global_stack_trace_config( self, global_config: Dict[str, Any] ) -> None: """Apply global stack trace configuration from agent config.""" - if "stack-trace" in global_config: - if validated_level := validate_stack_trace_level( + if "stack-trace" in global_config and ( + validated_level := validate_stack_trace_level( global_config["stack-trace"], "in agent config" - ): - self.stack_trace_level = validated_level + ) + ): + self.stack_trace_level = validated_level - if "stack-trace-length" in global_config: - if validated_length := validate_stack_trace_length( + if "stack-trace-length" in global_config and ( + validated_length := validate_stack_trace_length( global_config["stack-trace-length"], "in agent config" - ): - self.stack_trace_length = validated_length + ) + ): + self.stack_trace_length = validated_length def _apply_agent_tech_stack_trace_config(self, tracing: Dict[str, Any]) -> None: """Apply technology-specific stack trace configuration from agent config.""" diff --git a/src/instana/sampling.py b/src/instana/sampling.py index 7f84f786..a8b02b78 100644 --- a/src/instana/sampling.py +++ b/src/instana/sampling.py @@ -40,4 +40,4 @@ def __init__(self) -> None: self._sampled: SamplingPolicy = SamplingPolicy.DROP def sampled(self) -> bool: - return False if self._sampled == SamplingPolicy.DROP else True + return self._sampled != SamplingPolicy.DROP diff --git a/src/instana/span/base_span.py b/src/instana/span/base_span.py index b0c58080..1d48303b 100644 --- a/src/instana/span/base_span.py +++ b/src/instana/span/base_span.py @@ -3,8 +3,8 @@ from typing import TYPE_CHECKING, Type from instana.log import logger -from instana.util import DictionaryOfStan from instana.span.kind import ENTRY_SPANS +from instana.util import DictionaryOfStan if TYPE_CHECKING: from opentelemetry.trace import Span @@ -14,7 +14,7 @@ class BaseSpan(object): sy = None def __str__(self) -> str: - return "BaseSpan(%s)" % self.__dict__.__str__() + return f"BaseSpan({self.__dict__.__str__()})" def __repr__(self) -> str: return self.__dict__.__str__() @@ -56,7 +56,7 @@ def _validate_attributes(self, attributes): :return: dict - a filtered set of attributes """ filtered_attributes = DictionaryOfStan() - for key in attributes.keys(): + for key in attributes: validated_key, validated_value = self._validate_attribute( key, attributes[key] ) diff --git a/src/instana/span/registered_span.py b/src/instana/span/registered_span.py index e6f7e60d..340546a2 100644 --- a/src/instana/span/registered_span.py +++ b/src/instana/span/registered_span.py @@ -169,7 +169,7 @@ def _populate_entry_span_data(self, span: "InstanaSpan") -> None: self._collect_kafka_attributes(span) else: - logger.debug("SpanRecorder: Unknown entry span: %s" % span.name) + logger.debug(f"SpanRecorder: Unknown entry span: {span.name}") def _populate_local_span_data(self, span: "InstanaSpan") -> None: if span.name == "render": @@ -178,7 +178,7 @@ def _populate_local_span_data(self, span: "InstanaSpan") -> None: self.data["log"]["message"] = span.attributes.pop("message", None) self.data["log"]["parameters"] = span.attributes.pop("parameters", None) else: - logger.debug("SpanRecorder: Unknown local span: %s" % span.name) + logger.debug(f"SpanRecorder: Unknown local span: {span.name}") def _populate_exit_span_data(self, span: "InstanaSpan") -> None: if span.name in HTTP_SPANS: @@ -374,7 +374,7 @@ def _populate_exit_span_data(self, span: "InstanaSpan") -> None: self._collect_kafka_attributes(span) else: - logger.debug("SpanRecorder: Unknown exit span: %s" % span.name) + logger.debug(f"SpanRecorder: Unknown exit span: {span.name}") def _collect_http_attributes(self, span: "InstanaSpan") -> None: self.data["http"]["host"] = span.attributes.pop("http.host", None) diff --git a/src/instana/span/stack_trace.py b/src/instana/span/stack_trace.py index ab2a0c59..0ab0cee8 100644 --- a/src/instana/span/stack_trace.py +++ b/src/instana/span/stack_trace.py @@ -26,31 +26,29 @@ def _should_collect_stack(level: str, is_errored: bool) -> bool: """ Determine if stack trace should be collected based on level and error state. - + Args: level: Stack trace collection level ("all", "error", or "none") is_errored: Whether the span has errors (ec > 0) - + Returns: True if stack trace should be collected, False otherwise """ if level == "all": return True - if level == "error" and is_errored: - return True - return False + return bool(level == "error" and is_errored) def _should_exclude_frame(frame) -> bool: """ Check if a frame should be excluded from the stack trace. - + Frames are excluded if they are part of Instana's internal code, unless INSTANA_DEBUG is set. - + Args: frame: A frame from traceback.extract_stack() - + Returns: True if frame should be excluded, False otherwise """ @@ -58,9 +56,7 @@ def _should_exclude_frame(frame) -> bool: return False if _re_tracer_frame.search(frame[0]): return True - if _re_with_stan_frame.search(frame[2]): - return True - return False + return bool(_re_with_stan_frame.search(frame[2])) def _apply_stack_limit( @@ -68,12 +64,12 @@ def _apply_stack_limit( ) -> List[dict]: """ Apply frame limit to the sanitized stack. - + Args: sanitized_stack: List of stack frames limit: Maximum number of frames to include use_full_stack: If True, ignore the limit - + Returns: Limited stack trace """ @@ -84,20 +80,18 @@ def _apply_stack_limit( return sanitized_stack[(limit * -1) :] -def add_stack( - level: str, limit: int, is_errored: bool = False -) -> Optional[List[dict]]: +def add_stack(level: str, limit: int, is_errored: bool = False) -> Optional[List[dict]]: """ Capture and return a stack trace based on configuration. - + This function collects the current call stack, filters out Instana internal frames, and applies the configured limit. - + Args: level: Stack trace collection level ("all", "error", or "none") limit: Maximum number of frames to include (1-40) is_errored: Whether the span has errors (ec > 0) - + Returns: List of stack frames in format [{"c": file, "n": line, "m": method}, ...] or None if stack trace should not be collected @@ -134,11 +128,11 @@ def add_stack( def add_stack_trace_if_needed(span: "InstanaSpan") -> None: """ Add stack trace to span based on configuration before span ends. - + This function checks if the span is an EXIT span and if so, captures a stack trace based on the configured level and limit. It supports technology-specific configuration overrides via get_stack_trace_config(). - + Args: span: The InstanaSpan to potentially add stack trace to """ @@ -146,13 +140,9 @@ def add_stack_trace_if_needed(span: "InstanaSpan") -> None: # Get configuration from agent options (with technology-specific overrides) options = span._span_processor.agent.options level, limit = options.get_stack_trace_config(span.name) - + # Check if span is errored is_errored = span.attributes.get("ec", 0) > 0 - + # Capture stack trace using add_stack function - span.stack = add_stack( - level=level, - limit=limit, - is_errored=is_errored - ) + span.stack = add_stack(level=level, limit=limit, is_errored=is_errored) diff --git a/src/instana/util/aws.py b/src/instana/util/aws.py index e1e773e6..f06476d0 100644 --- a/src/instana/util/aws.py +++ b/src/instana/util/aws.py @@ -3,6 +3,7 @@ from ..log import logger + def normalize_aws_lambda_arn(context): """ Parse the AWS Lambda context object for a fully qualified AWS Lambda function ARN. @@ -15,12 +16,12 @@ def normalize_aws_lambda_arn(context): """ try: arn = context.invoked_function_arn - parts = arn.split(':') + parts = arn.split(":") count = len(parts) if count == 7: # need to append version - arn = arn + ':' + context.function_version + arn = arn + ":" + context.function_version elif count != 8: logger.debug("Unexpected ARN parse issue: %s", arn) diff --git a/src/instana/util/config.py b/src/instana/util/config.py index 2b1abeb1..86f5299f 100644 --- a/src/instana/util/config.py +++ b/src/instana/util/config.py @@ -1,7 +1,7 @@ # (c) Copyright IBM Corp. 2025 import os -from typing import Any, Dict, List, Sequence, Tuple, Union, Optional +from typing import Any, Dict, List, Optional, Sequence, Tuple, Union from instana.configurator import config from instana.log import logger @@ -317,7 +317,7 @@ def parse_span_disabling_str(item: str) -> List[str]: @param item: String span disabling configuration @return: List of disabled spans """ - if item.lower() in SPAN_CATEGORIES or item.lower() in SPAN_TYPE_TO_CATEGORY.keys(): + if item.lower() in SPAN_CATEGORIES or item.lower() in SPAN_TYPE_TO_CATEGORY: return [item.lower()] else: logger.debug(f"set_span_disabling_str: Invalid span category/type: {item}") @@ -335,7 +335,7 @@ def parse_span_disabling_dict(items: Dict[str, bool]) -> Tuple[List[str], List[s enabled_spans = [] for key, value in items.items(): - if key in SPAN_CATEGORIES or key in SPAN_TYPE_TO_CATEGORY.keys(): + if key in SPAN_CATEGORIES or key in SPAN_TYPE_TO_CATEGORY: if is_truthy(value): disabled_spans.append(key) else: @@ -394,9 +394,10 @@ def get_disable_trace_configurations_from_yaml() -> Tuple[List[str], List[str]]: def get_disable_trace_configurations_from_local() -> Tuple[List[str], List[str]]: - if "tracing" in config: - if tracing_disable_config := config["tracing"].get("disable", None): - return parse_span_disabling(tracing_disable_config) + if "tracing" in config and ( + tracing_disable_config := config["tracing"].get("disable", None) + ): + return parse_span_disabling(tracing_disable_config) return [], [] @@ -472,15 +473,15 @@ def parse_technology_stack_trace_config( tech_stack_config = {} context = f"for {tech_name}" if tech_name else "" - if level_key in tech_data: - if validated_level := validate_stack_trace_level(tech_data[level_key], context): - tech_stack_config["level"] = validated_level + if level_key in tech_data and ( + validated_level := validate_stack_trace_level(tech_data[level_key], context) + ): + tech_stack_config["level"] = validated_level - if length_key in tech_data: - if validated_length := validate_stack_trace_length( - tech_data[length_key], context - ): - tech_stack_config["length"] = validated_length + if length_key in tech_data and ( + validated_length := validate_stack_trace_length(tech_data[length_key], context) + ): + tech_stack_config["length"] = validated_length return tech_stack_config @@ -498,17 +499,19 @@ def parse_global_stack_trace_config(global_config: Dict[str, Any]) -> Tuple[str, level = "all" length = 30 - if "stack-trace" in global_config: - if validated_level := validate_stack_trace_level( + if "stack-trace" in global_config and ( + validated_level := validate_stack_trace_level( global_config["stack-trace"], "in YAML config" - ): - level = validated_level + ) + ): + level = validated_level - if "stack-trace-length" in global_config: - if validated_length := validate_stack_trace_length( + if "stack-trace-length" in global_config and ( + validated_length := validate_stack_trace_length( global_config["stack-trace-length"], "in YAML config" - ): - length = validated_length + ) + ): + length = validated_length return level, length @@ -544,9 +547,9 @@ def parse_tech_specific_stack_trace_configs( return tech_config -def get_stack_trace_config_from_yaml() -> ( - Tuple[str, int, Dict[str, Dict[str, Union[str, int]]]] -): +def get_stack_trace_config_from_yaml() -> Tuple[ + str, int, Dict[str, Dict[str, Union[str, int]]] +]: """ Get stack trace configuration from YAML file specified by INSTANA_CONFIG_PATH. diff --git a/src/instana/util/gunicorn.py b/src/instana/util/gunicorn.py deleted file mode 100644 index 48883f32..00000000 --- a/src/instana/util/gunicorn.py +++ /dev/null @@ -1,36 +0,0 @@ -# (c) Copyright IBM Corp. 2021 -# (c) Copyright Instana Inc. 2020 - -import os -import sys -from ..log import logger - -def running_in_gunicorn(): - """ - Determines if we are running inside of a gunicorn process. - - @return: Boolean - """ - process_check = False - - try: - # Is this a gunicorn process? - if hasattr(sys, 'argv'): - for arg in sys.argv: - if arg.find('gunicorn') >= 0: - process_check = True - elif os.path.isfile("/proc/self/cmdline"): - with open("/proc/self/cmdline") as cmd: - contents = cmd.read() - - parts = contents.split('\0') - parts.pop() - cmdline = " ".join(parts) - - if cmdline.find('gunicorn') >= 0: - process_check = True - - return process_check - except Exception: - logger.debug("Instana.log.running_in_gunicorn: ", exc_info=True) - return False \ No newline at end of file diff --git a/src/instana/util/ids.py b/src/instana/util/ids.py index afbf8aa1..f3fba11b 100644 --- a/src/instana/util/ids.py +++ b/src/instana/util/ids.py @@ -6,7 +6,11 @@ import random from typing import Union -from opentelemetry.trace.span import _SPAN_ID_MAX_VALUE, INVALID_SPAN_ID, INVALID_TRACE_ID +from opentelemetry.trace.span import ( + _SPAN_ID_MAX_VALUE, + INVALID_SPAN_ID, + INVALID_TRACE_ID, +) _rnd = random.Random() _current_pid = 0 @@ -39,7 +43,7 @@ def header_to_long_id(header: Union[bytes, str]) -> int: :return: a valid ID to be used internal to the tracer """ if isinstance(header, bytes): - header = header.decode('utf-8') + header = header.decode("utf-8") if not isinstance(header, str): return INVALID_TRACE_ID @@ -67,7 +71,7 @@ def header_to_id(header: Union[bytes, str]) -> int: :return: a valid ID to be used internal to the tracer """ if isinstance(header, bytes): - header = header.decode('utf-8') + header = header.decode("utf-8") if not isinstance(header, str): return INVALID_SPAN_ID @@ -103,13 +107,14 @@ def hex_id(id: Union[int, str]) -> str: elif length > 16 and length < 32: hex_id = hex_id.zfill(32) return hex_id - except ValueError: # Handles ValueError: invalid literal for int() with base 10: + except ValueError: # Handles ValueError: invalid literal for int() with base 10: return id + def hex_id_limited(id: Union[int, str]) -> str: """ Returns the hexadecimal representation of the given ID. - Limit longer IDs to 16 characters + Limit longer IDs to 16 characters """ try: hex_id = hex(int(id))[2:] @@ -121,9 +126,10 @@ def hex_id_limited(id: Union[int, str]) -> str: # Phase 0: Discard everything but the last 16byte hex_id = hex_id[-16:] return hex_id - except ValueError: # Handles ValueError: invalid literal for int() with base 10: + except ValueError: # Handles ValueError: invalid literal for int() with base 10: return id + def define_server_timing(trace_id: Union[int, str]) -> str: # Note: The key `intid` is short for Instana Trace ID. return f"intid;desc={hex_id_limited(trace_id)}" @@ -135,7 +141,7 @@ def internal_id(id: Union[int, str]) -> int: """ if isinstance(id, int): return id - + length = len(id) if isinstance(id, str) and id.isdigit(): @@ -153,7 +159,8 @@ def internal_id(id: Union[int, str]) -> int: return int(id, 16) except ValueError: return INVALID_TRACE_ID - + + def internal_id_limited(id: Union[int, str]) -> int: """ Returns a valid id to be used internally. Handles both str and int types. diff --git a/src/instana/util/runtime.py b/src/instana/util/runtime.py index a49cdfa3..fd28feb0 100644 --- a/src/instana/util/runtime.py +++ b/src/instana/util/runtime.py @@ -124,10 +124,7 @@ def determine_service_name() -> str: try: import uwsgi - if app_name == "uwsgi": - app_name = "" - else: - app_name = " [%s]" % app_name + app_name = "" if app_name == "uwsgi" else f" [{app_name}]" if os.getpid() == uwsgi.masterpid(): uwsgi_type = "uWSGI master%s" diff --git a/src/instana/util/span_utils.py b/src/instana/util/span_utils.py index e736be0d..639c9884 100644 --- a/src/instana/util/span_utils.py +++ b/src/instana/util/span_utils.py @@ -32,9 +32,8 @@ def matches_rule(rule_attributes: List[Any], span_attributes: List[Any]) -> bool rule_matched = True elif key == "type": - if "type" in span_attributes: - if span_attributes["type"] in target_values: - rule_matched = True + if "type" in span_attributes and span_attributes["type"] in target_values: + rule_matched = True else: if key in span_attributes: @@ -56,18 +55,17 @@ def match_key_filter(span_value: str, rule_value: str, match_type: str) -> bool: if span_value is None: return False - if rule_value == "*": - return True - elif match_type == "strict" and span_value == rule_value: - return True - elif match_type == "contains" and rule_value in span_value: - return True - elif match_type == "startswith" and span_value.startswith(rule_value): - return True - elif match_type == "endswith" and span_value.endswith(rule_value): - return True - - return False + return bool( + rule_value == "*" + or match_type == "strict" + and span_value == rule_value + or match_type == "contains" + and rule_value in span_value + or match_type == "startswith" + and span_value.startswith(rule_value) + or match_type == "endswith" + and span_value.endswith(rule_value) + ) def get_span_kind(span_kind: Any) -> str: diff --git a/src/instana/util/sql.py b/src/instana/util/sql.py index 8e7ee2f9..c8d6cbbd 100644 --- a/src/instana/util/sql.py +++ b/src/instana/util/sql.py @@ -3,6 +3,7 @@ import re + def sql_sanitizer(sql): """ Removes values from valid SQL statements and returns a stripped version. @@ -10,8 +11,8 @@ def sql_sanitizer(sql): :param sql: The SQL statement to be sanitized :return: String - A sanitized SQL statement without values. """ - return regexp_sql_values.sub('?', sql) + return regexp_sql_values.sub("?", sql) # Used by sql_sanitizer -regexp_sql_values = re.compile(r"('[\s\S][^']*'|\d*\.\d+|\d+|NULL)") \ No newline at end of file +regexp_sql_values = re.compile(r"('[\s\S][^']*'|\d*\.\d+|\d+|NULL)") diff --git a/src/instana/w3c_trace_context/traceparent.py b/src/instana/w3c_trace_context/traceparent.py index 315bdd30..e85874a1 100644 --- a/src/instana/w3c_trace_context/traceparent.py +++ b/src/instana/w3c_trace_context/traceparent.py @@ -13,7 +13,8 @@ from instana.util.ids import header_to_id, header_to_long_id # See https://www.w3.org/TR/trace-context-2/#trace-flags for details on the bitmasks. -SAMPLED_BITMASK = 0b1; +SAMPLED_BITMASK = 0b1 + class Traceparent: SPECIFICATION_VERSION = "00" @@ -32,14 +33,14 @@ def validate(self, traceparent): return traceparent except Exception: logger.debug( - "traceparent does not follow version {} specification".format( - self.SPECIFICATION_VERSION - ) + f"traceparent does not follow version {self.SPECIFICATION_VERSION} specification" ) return None @staticmethod - def get_traceparent_fields(traceparent: str) -> Tuple[Optional[str], Optional[int], Optional[int], Optional[bool]]: + def get_traceparent_fields( + traceparent: str, + ) -> Tuple[Optional[str], Optional[int], Optional[int], Optional[bool]]: """ Parses the validated traceparent header into its fields and returns the fields :param traceparent: the original validated traceparent header @@ -56,7 +57,7 @@ def get_traceparent_fields(traceparent: str) -> Tuple[Optional[str], Optional[in except Exception as err: # This method is intended to be called with a version 00 validated traceparent # This exception handling is added just for making sure we do not throw any unhandled exception # if somebody calls the method in the future without a validated traceparent - logger.debug("Parsing the traceparent failed: {}".format(err)) + logger.debug(f"Parsing the traceparent failed: {err}") return None, None, None, None def update_traceparent( diff --git a/src/instana/w3c_trace_context/tracestate.py b/src/instana/w3c_trace_context/tracestate.py index f6eb32cb..0459b7a0 100644 --- a/src/instana/w3c_trace_context/tracestate.py +++ b/src/instana/w3c_trace_context/tracestate.py @@ -24,8 +24,10 @@ def get_instana_ancestor(tracestate): try: in_list_member = tracestate.strip().split("in=")[1].split(",")[0] - ia = InstanaAncestor(trace_id=in_list_member.split(";")[0], - parent_id=in_list_member.split(";")[1]) + ia = InstanaAncestor( + trace_id=in_list_member.split(";")[0], + parent_id=in_list_member.split(";")[1], + ) return ia except Exception: @@ -54,14 +56,16 @@ def update_tracestate(self, tracestate, in_trace_id, in_span_id): splitted = tracestate.split("in=") before_in = splitted[0] after_in = splitted[1].split(",")[1:] - tracestate = '{}{}'.format(before_in, ",".join(after_in)) + tracestate = "{}{}".format(before_in, ",".join(after_in)) # tracestate can contain a max of 32 list members, if it contains up to 31 # we can safely add the instana one without the need to truncate anything if len(tracestate.split(",")) <= self.MAX_NUMBER_OF_LIST_MEMBERS - 1: - tracestate = "{},{}".format(instana_tracestate, tracestate) + tracestate = f"{instana_tracestate},{tracestate}" else: list_members = tracestate.split(",") - list_members_to_remove = len(list_members) - self.MAX_NUMBER_OF_LIST_MEMBERS + 1 + list_members_to_remove = ( + len(list_members) - self.MAX_NUMBER_OF_LIST_MEMBERS + 1 + ) # Number 1 priority members to be removed are the ones larger than 128 characters for i, m in reversed(list(enumerate(list_members))): if len(m) > self.REMOVE_ENTRIES_LARGER_THAN: @@ -77,8 +81,11 @@ def update_tracestate(self, tracestate, in_trace_id, in_span_id): # update the tracestate containing just 31 list members tracestate = ",".join(list_members) # adding instana as first list member, total of 32 list members - tracestate = "{},{}".format(instana_tracestate, tracestate) + tracestate = f"{instana_tracestate},{tracestate}" except Exception: - logger.debug("Something went wrong while updating tracestate: {}:".format(tracestate), exc_info=True) + logger.debug( + f"Something went wrong while updating tracestate: {tracestate}:", + exc_info=True, + ) return tracestate diff --git a/tests/apps/bottle_app/app.py b/tests/apps/bottle_app/app.py index c0d29a3e..80b5f572 100644 --- a/tests/apps/bottle_app/app.py +++ b/tests/apps/bottle_app/app.py @@ -15,23 +15,26 @@ logger = logging.getLogger(__name__) testenv["wsgi_port"] = 10812 -testenv["wsgi_server"] = ("http://127.0.0.1:" + str(testenv["wsgi_port"])) +testenv["wsgi_server"] = "http://127.0.0.1:" + str(testenv["wsgi_port"]) app = default_app() + @app.route("/") def hello(): return "

🐍 Hello Stan! 🦄

" + @app.route("/response_headers") def response_headers(): response.set_header("X-Capture-This", "this") response.set_header("X-Capture-That", "that") return "Stan wuz here with headers!" + # Wrap the application with the Instana WSGI Middleware app = InstanaWSGIMiddleware(app) -bottle_server = make_server('127.0.0.1', testenv["wsgi_port"], app) +bottle_server = make_server("127.0.0.1", testenv["wsgi_port"], app) if __name__ == "__main__": bottle_server.request_queue_size = 20 diff --git a/tests/apps/fastapi_app/__init__.py b/tests/apps/fastapi_app/__init__.py index dded82bd..5eec1591 100644 --- a/tests/apps/fastapi_app/__init__.py +++ b/tests/apps/fastapi_app/__init__.py @@ -3,7 +3,7 @@ import uvicorn from ...helpers import testenv -from instana.log import logger +from instana.log import logger as logger testenv["fastapi_port"] = 10816 testenv["fastapi_server"] = "http://127.0.0.1:" + str(testenv["fastapi_port"]) diff --git a/tests/apps/fastapi_app/app2.py b/tests/apps/fastapi_app/app2.py index 8f9b7edd..cffe7c88 100644 --- a/tests/apps/fastapi_app/app2.py +++ b/tests/apps/fastapi_app/app2.py @@ -1,7 +1,6 @@ # (c) Copyright IBM Corp. 2024 -from fastapi import FastAPI, HTTPException, Response -from fastapi.concurrency import run_in_threadpool +from fastapi import FastAPI from fastapi.middleware import Middleware from fastapi.middleware.trustedhost import TrustedHostMiddleware diff --git a/tests/apps/flask_app/app.py b/tests/apps/flask_app/app.py index e49f8fa1..a6f50069 100755 --- a/tests/apps/flask_app/app.py +++ b/tests/apps/flask_app/app.py @@ -4,14 +4,18 @@ # (c) Copyright IBM Corp. 2021 # (c) Copyright Instana Inc. 2020 -import os import logging - -from opentelemetry.semconv.trace import SpanAttributes - -from flask import jsonify, Response +import os from wsgiref.simple_server import make_server -from flask import Flask, redirect, render_template, render_template_string + +from flask import ( + Flask, + Response, + jsonify, + redirect, + render_template, + render_template_string, +) try: import boto3 @@ -27,13 +31,13 @@ logger = logging.getLogger(__name__) testenv["flask_port"] = 10811 -testenv["flask_server"] = ("http://127.0.0.1:" + str(testenv["flask_port"])) +testenv["flask_server"] = "http://127.0.0.1:" + str(testenv["flask_port"]) app = Flask(__name__) app.debug = False app.use_reloader = False -flask_server = make_server('127.0.0.1', testenv["flask_port"], app.wsgi_app) +flask_server = make_server("127.0.0.1", testenv["flask_port"], app.wsgi_app) class InvalidUsage(Exception): @@ -48,7 +52,7 @@ def __init__(self, message, status_code=None, payload=None): def to_dict(self): rv = dict(self.payload or ()) - rv['message'] = self.message + rv["message"] = self.message return rv @@ -64,7 +68,7 @@ def __init__(self, message, status_code=None, payload=None): def to_dict(self): rv = dict(self.payload or ()) - rv['message'] = self.message + rv["message"] = self.message return rv @@ -75,17 +79,17 @@ def hello(): @app.route("/users//sayhello") def username_hello(username): - return u"

🐍 Hello %s! 🦄

" % username + return f"

🐍 Hello {username}! 🦄

" @app.route("/301") def threehundredone(): - return redirect('/', code=301) + return redirect("/", code=301) @app.route("/302") def threehundredtwo(): - return redirect('/', code=302) + return redirect("/", code=302) @app.route("/400") @@ -115,7 +119,7 @@ def fivehundredfour(): @app.route("/exception") def exception(): - raise Exception('fake error') + raise Exception("fake error") @app.route("/got_request_exception") @@ -130,59 +134,57 @@ def exception_invalid_usage(): @app.route("/render") def render(): - return render_template('flask_render_template.html', name="Peter") + return render_template("flask_render_template.html", name="Peter") @app.route("/render_string") def render_string(): - return render_template_string('hello {{ what }}', what='world') + return render_template_string("hello {{ what }}", what="world") @app.route("/render_error") def render_error(): - return render_template('flask_render_error.html', what='world') + return render_template("flask_render_error.html", what="world") @app.route("/response_headers") def response_headers(): - headers = { - 'X-Capture-This': 'Ok', - 'X-Capture-That': 'Ok too' - } + headers = {"X-Capture-This": "Ok", "X-Capture-That": "Ok too"} return Response("Stan wuz here with headers!", headers=headers) + @app.route("/boto3/sqs") def boto3_sqs(): - os.environ['AWS_ACCESS_KEY_ID'] = 'testing' - os.environ['AWS_SECRET_ACCESS_KEY'] = 'testing' - os.environ['AWS_SECURITY_TOKEN'] = 'testing' - os.environ['AWS_SESSION_TOKEN'] = 'testing' + os.environ["AWS_ACCESS_KEY_ID"] = "testing" + os.environ["AWS_SECRET_ACCESS_KEY"] = "testing" + os.environ["AWS_SECURITY_TOKEN"] = "testing" + os.environ["AWS_SESSION_TOKEN"] = "testing" with mock_aws(): - boto3_client = boto3.client('sqs', region_name='us-east-1') + boto3_client = boto3.client("sqs", region_name="us-east-1") response = boto3_client.create_queue( - QueueName='SQS_QUEUE_NAME', - Attributes={ - 'DelaySeconds': '60', - 'MessageRetentionPeriod': '600' - } + QueueName="SQS_QUEUE_NAME", + Attributes={"DelaySeconds": "60", "MessageRetentionPeriod": "600"}, ) - queue_url = response['QueueUrl'] + queue_url = response["QueueUrl"] response = boto3_client.send_message( - QueueUrl=queue_url, - DelaySeconds=10, - MessageAttributes={ - 'Website': { - 'DataType': 'String', - 'StringValue': 'https://www.instana.com' - }, + QueueUrl=queue_url, + DelaySeconds=10, + MessageAttributes={ + "Website": { + "DataType": "String", + "StringValue": "https://www.instana.com", }, - MessageBody=('Monitor any application, service, or request ' - 'with Instana Application Performance Monitoring') - ) + }, + MessageBody=( + "Monitor any application, service, or request " + "with Instana Application Performance Monitoring" + ), + ) return Response(response) + @app.errorhandler(InvalidUsage) def handle_invalid_usage(error): logger.error("InvalidUsage error handler invoked") @@ -194,9 +196,9 @@ def handle_invalid_usage(error): @app.errorhandler(404) @app.errorhandler(NotFound) def handle_not_found(e): - return "blah: %s" % str(e), 404 + return f"blah: {str(e)}", 404 -if __name__ == '__main__': +if __name__ == "__main__": flask_server.request_queue_size = 20 flask_server.serve_forever() diff --git a/tests/apps/grpc_server/__init__.py b/tests/apps/grpc_server/__init__.py index 78439e5e..45fb4ecb 100644 --- a/tests/apps/grpc_server/__init__.py +++ b/tests/apps/grpc_server/__init__.py @@ -3,18 +3,22 @@ import os import sys -import time import threading +import time -if not any((os.environ.get('GEVENT_TEST'), - os.environ.get('CASSANDRA_TEST'), - sys.version_info < (3, 5, 3))): +if not any(( + os.environ.get("GEVENT_TEST"), + os.environ.get("CASSANDRA_TEST"), + sys.version_info < (3, 5, 3), +)): # Background RPC application # # Spawn the background RPC app that the tests will throw # requests at. - import tests.apps.grpc_server + import tests.apps.grpc_server # noqa: F401 + from .stan_server import StanServicer + stan_servicer = StanServicer() rpc_server_thread = threading.Thread(target=stan_servicer.start_server) rpc_server_thread.daemon = True diff --git a/tests/apps/grpc_server/stan_server.py b/tests/apps/grpc_server/stan_server.py index e69de2a6..11c73a71 100644 --- a/tests/apps/grpc_server/stan_server.py +++ b/tests/apps/grpc_server/stan_server.py @@ -1,13 +1,14 @@ # (c) Copyright IBM Corp. 2021 # (c) Copyright Instana Inc. 2019 -import os import sys -import grpc import time +from concurrent import futures + +import grpc + import tests.apps.grpc_server.stan_pb2 as stan_pb2 import tests.apps.grpc_server.stan_pb2_grpc as stan_pb2_grpc -from concurrent import futures try: from ...helpers import testenv @@ -24,15 +25,16 @@ class StanServicer(stan_pb2_grpc.StanServicer): """ gRPC server for Stan Service """ + def __init__(self, *args, **kwargs): - self.server_port = testenv['grpc_port'] + self.server_port = testenv["grpc_port"] def OneQuestionOneResponse(self, request, context): # print("😇:I was asked: %s" % request.question) response = """\ Invention, my dear friends, is 93% perspiration, 6% electricity, \ 4% evaporation, and 2% butterscotch ripple. – Willy Wonka""" - result = {'answer': response, 'was_answered': True} + result = {"answer": response, "was_answered": True} return stan_pb2.QuestionResponse(**result) def ManyQuestionsOneResponse(self, request_iterator, context): @@ -40,26 +42,26 @@ def ManyQuestionsOneResponse(self, request_iterator, context): # print("😇:I was asked: %s" % request.question) pass - result = {'answer': 'Ok', 'was_answered': True} + result = {"answer": "Ok", "was_answered": True} return stan_pb2.QuestionResponse(**result) def OneQuestionManyResponses(self, request, context): # print("😇:I was asked: %s" % request.question) for count in range(6): - result = {'answer': 'Ok', 'was_answered': True} + result = {"answer": "Ok", "was_answered": True} yield stan_pb2.QuestionResponse(**result) def ManyQuestionsManyReponses(self, request_iterator, context): for request in request_iterator: # print("😇:I was asked: %s" % request.question) - result = {'answer': 'Ok', 'was_answered': True} + result = {"answer": "Ok", "was_answered": True} yield stan_pb2.QuestionResponse(**result) def OneQuestionOneErrorResponse(self, request, context): - # print("😇:I was asked: %s" % request.question) - raise Exception('Simulated error') - result = {'answer': "ThisError", 'was_answered': True} - return stan_pb2.QuestionResponse(**result) + # print("😇:I was asked: %s" % request.question) + raise Exception("Simulated error") + result = {"answer": "ThisError", "was_answered": True} + return stan_pb2.QuestionResponse(**result) def start_server(self): """ @@ -74,7 +76,7 @@ def start_server(self): stan_pb2_grpc.add_StanServicer_to_server(StanServicer(), rpc_server) # bind the server to the port defined above - rpc_server.add_insecure_port('[::]:{}'.format(self.server_port)) + rpc_server.add_insecure_port(f"[::]:{self.server_port}") # start the server rpc_server.start() @@ -84,14 +86,14 @@ def start_server(self): # code is non blocking, and if I don't do this # the program will exit while True: - time.sleep(60*60*60) + time.sleep(60 * 60 * 60) except KeyboardInterrupt: rpc_server.stop(0) - print('Stan as a Service RPC Server Stopped ...') + print("Stan as a Service RPC Server Stopped ...") if __name__ == "__main__": - print ("Booting foreground GRPC application...") + print("Booting foreground GRPC application...") if sys.version_info >= (3, 5, 3): StanServicer().start_server() diff --git a/tests/apps/pubsub_app/pubsub.py b/tests/apps/pubsub_app/pubsub.py index e3d86a15..61a18c37 100644 --- a/tests/apps/pubsub_app/pubsub.py +++ b/tests/apps/pubsub_app/pubsub.py @@ -6,11 +6,11 @@ import logging -import instana - from flask import Flask, request from google.cloud import pubsub_v1 +import instana # noqa: F401 + logging.basicConfig(level=logging.WARNING) logger = logging.getLogger(__name__) @@ -22,9 +22,9 @@ # Use PubSub Emulator exposed at :8432 for local testing and uncomment below # os.environ["PUBSUB_EMULATOR_HOST"] = "localhost:8432" -PROJECT_ID = 'k8s-brewery' -TOPIC_NAME = 'python-test-topic' -SUBSCRIPTION_ID = 'python-test-subscription' +PROJECT_ID = "k8s-brewery" +TOPIC_NAME = "python-test-topic" +SUBSCRIPTION_ID = "python-test-subscription" publisher = pubsub_v1.PublisherClient() subscriber = pubsub_v1.SubscriberClient() @@ -33,37 +33,37 @@ SUBSCRIPTION_PATH = subscriber.subscription_path(PROJECT_ID, SUBSCRIPTION_ID) -@app.route('/') +@app.route("/") def home(): return "Welcome to PubSub testing." -@app.route('/create') +@app.route("/create") def create_topic(): """ Usage: /create?topic= """ - topic = request.args.get('topic') + topic = request.args.get("topic") print(topic, type(topic)) try: publisher.create_topic(TOPIC_PATH) return "Topic Created" except Exception as e: - return "Topic Creation Failed: %s" % e + return f"Topic Creation Failed: {e}" -@app.route('/publish') +@app.route("/publish") def publish(): """ Usage: /publish?message= """ - msg = request.args.get('message').encode('utf-8') - publisher.publish(TOPIC_PATH, msg, origin='instana-test') - return "Published msg: %s" % msg + msg = request.args.get("message").encode("utf-8") + publisher.publish(TOPIC_PATH, msg, origin="instana-test") + return f"Published msg: {msg}" -@app.route('/consume') +@app.route("/consume") def consume(): """ Usage: /consume @@ -72,7 +72,7 @@ def consume(): # Async def callback_handler(message): - print('MESSAGE: ', message, type(message)) + print("MESSAGE: ", message, type(message)) print(message.data) message.ack() @@ -80,11 +80,11 @@ def callback_handler(message): try: res = future.result() - print('CALLBACK: ', res, type(res)) + print("CALLBACK: ", res, type(res)) except KeyboardInterrupt: future.cancel() return "Consumer closed." -if __name__ == '__main__': - app.run(host='127.0.0.1', port='10811') +if __name__ == "__main__": + app.run(host="127.0.0.1", port="10811") diff --git a/tests/apps/sanic_app/name.py b/tests/apps/sanic_app/name.py index 0838d29a..6a9f9826 100644 --- a/tests/apps/sanic_app/name.py +++ b/tests/apps/sanic_app/name.py @@ -8,4 +8,4 @@ class NameView(HTTPMethodView): def get(self, request, name): - return text("Hello {}".format(name)) + return text(f"Hello {name}") diff --git a/tests/apps/sanic_app/server.py b/tests/apps/sanic_app/server.py index a07dafc9..556b09e2 100644 --- a/tests/apps/sanic_app/server.py +++ b/tests/apps/sanic_app/server.py @@ -1,7 +1,6 @@ # (c) Copyright IBM Corp. 2021 # (c) Copyright Instana Inc. 2021 -import instana from sanic import Sanic from sanic.exceptions import SanicException @@ -15,7 +14,7 @@ @app.get("/foo/") async def uuid_handler(request, foo_id: int): - return text("INT - {}".format(foo_id)) + return text(f"INT - {foo_id}") @app.route("/response_headers") @@ -41,7 +40,7 @@ async def test_request_args_400(request): @app.get("/tag/") async def tag_handler(request, tag): - return text("Tag - {}".format(tag)) + return text(f"Tag - {tag}") app.add_route(SimpleView.as_view(), "/") diff --git a/tests/apps/spyne_app/app.py b/tests/apps/spyne_app/app.py index 366b88f9..b728b360 100644 --- a/tests/apps/spyne_app/app.py +++ b/tests/apps/spyne_app/app.py @@ -4,24 +4,30 @@ # (c) Copyright IBM Corp. 2025 import logging - from wsgiref.simple_server import make_server -from spyne import Application, rpc, ServiceBase, Iterable, UnsignedInteger, \ - String, Unicode -from spyne.protocol.json import JsonDocument +from spyne import ( + Application, + Iterable, + ServiceBase, + String, + Unicode, + UnsignedInteger, + rpc, +) +from spyne.error import ResourceNotFoundError from spyne.protocol.http import HttpRpc +from spyne.protocol.json import JsonDocument from spyne.server.wsgi import WsgiApplication -from spyne.error import ResourceNotFoundError - from tests.helpers import testenv logging.basicConfig(level=logging.WARNING) logger = logging.getLogger(__name__) testenv["spyne_port"] = 10818 -testenv["spyne_server"] = ("http://127.0.0.1:" + str(testenv["spyne_port"])) +testenv["spyne_server"] = "http://127.0.0.1:" + str(testenv["spyne_port"]) + class HelloWorldService(ServiceBase): @rpc(String, UnsignedInteger, _returns=Iterable(String)) @@ -34,34 +40,36 @@ def say_hello(ctx, name, times): """ for i in range(times): - yield 'Hello, %s' % name + yield f"Hello, {name}" @rpc(_returns=Unicode) def hello(ctx): return "

🐍 Hello Stan! 🦄

" - + @rpc(_returns=Unicode) def response_headers(ctx): ctx.transport.add_header("X-Capture-This", "this") ctx.transport.add_header("X-Capture-That", "that") return "Stan wuz here with headers!" - + @rpc(UnsignedInteger) def custom_404(ctx, user_id): raise ResourceNotFoundError(user_id) - + @rpc() def exception(ctx): - raise Exception('fake error') + raise Exception("fake error") -application = Application([HelloWorldService], 'instana.spyne.service.helloworld', - in_protocol=HttpRpc(validator='soft'), +application = Application( + [HelloWorldService], + "instana.spyne.service.helloworld", + in_protocol=HttpRpc(validator="soft"), out_protocol=JsonDocument(ignore_wrappers=True), ) wsgi_app = WsgiApplication(application) -spyne_server = make_server('127.0.0.1', testenv["spyne_port"], wsgi_app) +spyne_server = make_server("127.0.0.1", testenv["spyne_port"], wsgi_app) -if __name__ == '__main__': +if __name__ == "__main__": spyne_server.request_queue_size = 20 spyne_server.serve_forever() diff --git a/tests/apps/starlette_app/__init__.py b/tests/apps/starlette_app/__init__.py index 6b46de1c..91228754 100644 --- a/tests/apps/starlette_app/__init__.py +++ b/tests/apps/starlette_app/__init__.py @@ -7,8 +7,9 @@ testenv["starlette_host"] = "127.0.0.1" testenv["starlette_port"] = 10817 -testenv["starlette_server"] = "http://" + testenv["starlette_host"] + ":" + str(testenv["starlette_port"]) - +testenv["starlette_server"] = ( + "http://" + testenv["starlette_host"] + ":" + str(testenv["starlette_port"]) +) def launch_starlette(): @@ -17,7 +18,7 @@ def launch_starlette(): # Hack together a manual custom headers list; We'll use this in tests agent.options.extra_http_headers = [ - "X-Capture-This", + "X-Capture-This", "X-Capture-That", ] diff --git a/tests/apps/starlette_app/app.py b/tests/apps/starlette_app/app.py index 1ecb8a9c..5704eed3 100644 --- a/tests/apps/starlette_app/app.py +++ b/tests/apps/starlette_app/app.py @@ -17,7 +17,7 @@ def homepage(request): def user(request): user_id = request.path_params["user_id"] - return PlainTextResponse("Hello, user id %s!" % user_id) + return PlainTextResponse(f"Hello, user id {user_id}!") def response_headers(request): diff --git a/tests/apps/tornado_server/app.py b/tests/apps/tornado_server/app.py index cf71c677..a5af7545 100755 --- a/tests/apps/tornado_server/app.py +++ b/tests/apps/tornado_server/app.py @@ -5,11 +5,8 @@ # (c) Copyright Instana Inc. 2020 import os.path -import tornado.auth -import tornado.escape import tornado.httpserver import tornado.ioloop -import tornado.options import tornado.web import asyncio @@ -65,15 +62,14 @@ def get(self): class R504Handler(tornado.web.RequestHandler): def get(self): - raise tornado.web.HTTPError(status_code=504, log_message="Simulated Internal Server Errors") + raise tornado.web.HTTPError( + status_code=504, log_message="Simulated Internal Server Errors" + ) class ResponseHeadersHandler(tornado.web.RequestHandler): def get(self): - headers = { - 'X-Capture-This-Too': 'this too', - 'X-Capture-That-Too': 'that too' - } + headers = {"X-Capture-This-Too": "this too", "X-Capture-That-Too": "that too"} for key, value in headers.items(): self.set_header(key, value) self.write("Stan wuz here with headers!") diff --git a/tests/apps/utils.py b/tests/apps/utils.py index 25e64ce2..6a0e507d 100644 --- a/tests/apps/utils.py +++ b/tests/apps/utils.py @@ -5,11 +5,10 @@ def launch_background_thread(app, app_name, fun_args=(), fun_kwargs={}): - print("Starting background %s app..." % app_name) - app_thread = threading.Thread(target=app, - name=app_name, - args=fun_args, - kwargs=fun_kwargs) + print(f"Starting background {app_name} app...") + app_thread = threading.Thread( + target=app, name=app_name, args=fun_args, kwargs=fun_kwargs + ) app_thread.daemon = True app_thread.start() return app_thread diff --git a/tests/autoprofile/samplers/test_cpu_sampler.py b/tests/autoprofile/samplers/test_cpu_sampler.py index f0581d12..e398ff09 100644 --- a/tests/autoprofile/samplers/test_cpu_sampler.py +++ b/tests/autoprofile/samplers/test_cpu_sampler.py @@ -24,7 +24,6 @@ def _resources(self) -> Generator[None, None, None]: # teardown self.profiler.destroy() - def test_cpu_profile(self) -> None: if RuntimeInfo.OS_WIN: return @@ -52,4 +51,4 @@ def cpu_work_main_thread() -> None: profile = sampler.build_profile(2000, 120000).to_dict() - assert 'cpu_work_main_thread' in str(profile) + assert "cpu_work_main_thread" in str(profile) diff --git a/tests/clients/boto3/test_boto3_s3.py b/tests/clients/boto3/test_boto3_s3.py index b0c23ea2..74ead1fb 100644 --- a/tests/clients/boto3/test_boto3_s3.py +++ b/tests/clients/boto3/test_boto3_s3.py @@ -4,10 +4,10 @@ import os from io import BytesIO +from typing import Generator -import pytest import boto3 -from typing import Generator +import pytest from moto import mock_aws from instana.singletons import agent, get_tracer @@ -157,7 +157,7 @@ def test_s3_upload_file(self) -> None: def test_s3_upload_file_obj(self) -> None: self.s3.create_bucket(Bucket=self.bucket_name) - with self.tracer.start_as_current_span("test"): + with self.tracer.start_as_current_span("test"): # noqa: SIM117 with open(upload_filename, "rb") as fd: self.s3.upload_fileobj(fd, self.bucket_name, self.object_name) @@ -214,7 +214,7 @@ def test_s3_download_file_obj(self) -> None: self.s3.create_bucket(Bucket=self.bucket_name) self.s3.upload_file(upload_filename, self.bucket_name, self.object_name) - with self.tracer.start_as_current_span("test"): + with self.tracer.start_as_current_span("test"): # noqa: SIM117 with open(download_target_filename, "wb") as fd: self.s3.download_fileobj(self.bucket_name, self.object_name, fd) diff --git a/tests/clients/kafka/test_confluent_kafka.py b/tests/clients/kafka/test_confluent_kafka.py index 05817f4d..b1695d72 100644 --- a/tests/clients/kafka/test_confluent_kafka.py +++ b/tests/clients/kafka/test_confluent_kafka.py @@ -1,6 +1,7 @@ # (c) Copyright IBM Corp. 2025 +import contextlib import os import threading import time @@ -43,7 +44,7 @@ def _resource(self) -> Generator[None, None, None]: self.kafka_config = {"bootstrap.servers": testenv["kafka_bootstrap_servers"][0]} self.kafka_client = AdminClient(self.kafka_config) - try: + with contextlib.suppress(KafkaException): _ = self.kafka_client.create_topics( # noqa: F841 [ NewTopic( @@ -68,8 +69,6 @@ def _resource(self) -> Generator[None, None, None]: ), ] ) - except KafkaException: - pass # Kafka producer self.producer = Producer(self.kafka_config) @@ -83,14 +82,12 @@ def _resource(self) -> Generator[None, None, None]: clear_context() # Close connections - self.kafka_client.delete_topics( - [ - testenv["kafka_topic"], - testenv["kafka_topic"] + "_1", - testenv["kafka_topic"] + "_2", - testenv["kafka_topic"] + "_3", - ] - ) + self.kafka_client.delete_topics([ + testenv["kafka_topic"], + testenv["kafka_topic"] + "_1", + testenv["kafka_topic"] + "_2", + testenv["kafka_topic"] + "_3", + ]) time.sleep(3) if "tracing" in config: @@ -414,11 +411,9 @@ def test_filter_confluent_specific_topic(self) -> None: ) assert span_to_be_filtered not in filtered_spans - self.kafka_client.delete_topics( - [ - testenv["kafka_topic"] + "_1", - ] - ) + self.kafka_client.delete_topics([ + testenv["kafka_topic"] + "_1", + ]) def test_filter_confluent_specific_topic_with_config_file(self) -> None: agent.options.span_filters = parse_filter_rules_yaml( @@ -459,12 +454,10 @@ def test_confluent_kafka_consumer_root_exit(self) -> None: consumer_config["auto.offset.reset"] = "earliest" consumer = Consumer(consumer_config) - consumer.subscribe( - [ - testenv["kafka_topic"] + "_1", - testenv["kafka_topic"] + "_2", - ] - ) + consumer.subscribe([ + testenv["kafka_topic"] + "_1", + testenv["kafka_topic"] + "_2", + ]) consumer.consume(num_messages=2, timeout=60) # noqa: F841 @@ -515,12 +508,10 @@ def test_confluent_kafka_consumer_root_exit(self) -> None: assert producer_span_2.s == consumer_span_2.p assert producer_span_2.s != consumer_span_2.s - self.kafka_client.delete_topics( - [ - testenv["kafka_topic"] + "_1", - testenv["kafka_topic"] + "_2", - ] - ) + self.kafka_client.delete_topics([ + testenv["kafka_topic"] + "_1", + testenv["kafka_topic"] + "_2", + ]) def test_confluent_kafka_poll_root_exit_with_trace_correlation(self) -> None: agent.options.allow_exit_as_root = True @@ -698,12 +689,10 @@ def test_confluent_kafka_downstream_suppression(self) -> None: consumer_config["auto.offset.reset"] = "earliest" consumer = Consumer(consumer_config) - consumer.subscribe( - [ - testenv["kafka_topic"] + "_1", - testenv["kafka_topic"] + "_2", - ] - ) + consumer.subscribe([ + testenv["kafka_topic"] + "_1", + testenv["kafka_topic"] + "_2", + ]) messages = consumer.consume(num_messages=2, timeout=60) # noqa: F841 @@ -760,12 +749,10 @@ def test_confluent_kafka_downstream_suppression(self) -> None: ("x_instana_s", format_span_id(producer_span_2.s).encode("utf-8")), ] - self.kafka_client.delete_topics( - [ - testenv["kafka_topic"] + "_1", - testenv["kafka_topic"] + "_2", - ] - ) + self.kafka_client.delete_topics([ + testenv["kafka_topic"] + "_1", + testenv["kafka_topic"] + "_2", + ]) def test_save_consumer_span_into_context(self, span: "InstanaSpan") -> None: """Test save_consumer_span_into_context function.""" @@ -969,12 +956,10 @@ def test_confluent_kafka_poll_multithreaded_context_isolation(self) -> None: for i in range(num_threads): topic = f"{testenv['kafka_topic']}_thread_{i}" # Create topic - try: - self.kafka_client.create_topics( - [NewTopic(topic, num_partitions=1, replication_factor=1)] - ) - except KafkaException: - pass + with contextlib.suppress(KafkaException): + self.kafka_client.create_topics([ + NewTopic(topic, num_partitions=1, replication_factor=1) + ]) # Produce messages for j in range(messages_per_topic): @@ -1022,22 +1007,22 @@ def consume_from_topic(thread_id: int) -> None: consumer.close() with lock: - thread_results.append( - { - "thread_id": thread_id, - "topic": topic, - "messages_consumed": messages_consumed, - "none_polls": none_polls, - "success": True, - } - ) + thread_results.append({ + "thread_id": thread_id, + "topic": topic, + "messages_consumed": messages_consumed, + "none_polls": none_polls, + "success": True, + }) except Exception as e: with lock: thread_errors.append(e) - thread_results.append( - {"thread_id": thread_id, "success": False, "error": str(e)} - ) + thread_results.append({ + "thread_id": thread_id, + "success": False, + "error": str(e), + }) threads = [] for i in range(num_threads): @@ -1052,19 +1037,19 @@ def consume_from_topic(thread_id: int) -> None: assert len(thread_results) == num_threads for result in thread_results: - assert result[ - "success" - ], f"Thread {result['thread_id']} failed: {result.get('error')}" - assert ( - result["messages_consumed"] == messages_per_topic - ), f"Thread {result['thread_id']} consumed {result['messages_consumed']} messages, expected {messages_per_topic}" + assert result["success"], ( + f"Thread {result['thread_id']} failed: {result.get('error')}" + ) + assert result["messages_consumed"] == messages_per_topic, ( + f"Thread {result['thread_id']} consumed {result['messages_consumed']} messages, expected {messages_per_topic}" + ) spans = self.recorder.queued_spans() expected_min_spans = num_threads * (1 + messages_per_topic * 2) - assert ( - len(spans) >= expected_min_spans - ), f"Expected at least {expected_min_spans} spans, got {len(spans)}" + assert len(spans) >= expected_min_spans, ( + f"Expected at least {expected_min_spans} spans, got {len(spans)}" + ) for i in range(num_threads): topic = f"{testenv['kafka_topic']}_thread_{i}" @@ -1077,9 +1062,9 @@ def consume_from_topic(thread_id: int) -> None: and s.data.get("kafka", {}).get("service") == topic ] - assert ( - len(poll_spans) >= 1 - ), f"Expected poll spans for topic {topic}, got {len(poll_spans)}" + assert len(poll_spans) >= 1, ( + f"Expected poll spans for topic {topic}, got {len(poll_spans)}" + ) topics_to_delete = [ f"{testenv['kafka_topic']}_thread_{i}" for i in range(num_threads) @@ -1132,21 +1117,21 @@ def poll_empty_topic(thread_id: int) -> None: for thread in threads: thread.join(timeout=10) - assert ( - len(thread_errors) == 0 - ), f"Context errors in threads: {[str(e) for e in thread_errors]}" + assert len(thread_errors) == 0, ( + f"Context errors in threads: {[str(e) for e in thread_errors]}" + ) spans = self.recorder.queued_spans() test_spans = [s for s in spans if s.n == "sdk"] - assert ( - len(test_spans) == num_threads - ), f"Expected {num_threads} test spans, got {len(test_spans)}" + assert len(test_spans) == num_threads, ( + f"Expected {num_threads} test spans, got {len(test_spans)}" + ) kafka_spans = [s for s in spans if s.n == "kafka"] - assert ( - len(kafka_spans) == 0 - ), f"Expected no kafka spans for None polls, got {len(kafka_spans)}" + assert len(kafka_spans) == 0, ( + f"Expected no kafka spans for None polls, got {len(kafka_spans)}" + ) def test_filter_confluent_kafka_by_category(self) -> None: os.environ["INSTANA_TRACING_FILTER_EXCLUDE_CATEGORY_ATTRIBUTES"] = ( diff --git a/tests/clients/kafka/test_kafka_python.py b/tests/clients/kafka/test_kafka_python.py index eb36a03a..8b0f97ed 100644 --- a/tests/clients/kafka/test_kafka_python.py +++ b/tests/clients/kafka/test_kafka_python.py @@ -25,6 +25,7 @@ from instana.span.span import InstanaSpan from instana.util.config import parse_filter_rules_yaml from tests.helpers import get_first_span_by_filter, testenv +import contextlib class TestKafkaPython: @@ -43,33 +44,29 @@ def _resource(self) -> Generator[None, None, None]: client_id="test_kafka_python", ) - try: - self.kafka_client.create_topics( - [ - NewTopic( - name=testenv["kafka_topic"], - num_partitions=1, - replication_factor=1, - ), - NewTopic( - name=testenv["kafka_topic"] + "_1", - num_partitions=1, - replication_factor=1, - ), - NewTopic( - name=testenv["kafka_topic"] + "_2", - num_partitions=1, - replication_factor=1, - ), - NewTopic( - name=testenv["kafka_topic"] + "_3", - num_partitions=1, - replication_factor=1, - ), - ] - ) - except TopicAlreadyExistsError: - pass + with contextlib.suppress(TopicAlreadyExistsError): + self.kafka_client.create_topics([ + NewTopic( + name=testenv["kafka_topic"], + num_partitions=1, + replication_factor=1, + ), + NewTopic( + name=testenv["kafka_topic"] + "_1", + num_partitions=1, + replication_factor=1, + ), + NewTopic( + name=testenv["kafka_topic"] + "_2", + num_partitions=1, + replication_factor=1, + ), + NewTopic( + name=testenv["kafka_topic"] + "_3", + num_partitions=1, + replication_factor=1, + ), + ]) # Kafka producer self.producer = KafkaProducer( @@ -86,14 +83,12 @@ def _resource(self) -> Generator[None, None, None]: # Clear context clear_context() - self.kafka_client.delete_topics( - [ - testenv["kafka_topic"], - testenv["kafka_topic"] + "_1", - testenv["kafka_topic"] + "_2", - testenv["kafka_topic"] + "_3", - ] - ) + self.kafka_client.delete_topics([ + testenv["kafka_topic"], + testenv["kafka_topic"] + "_1", + testenv["kafka_topic"] + "_2", + testenv["kafka_topic"] + "_3", + ]) self.kafka_client.close() if "tracing" in config: diff --git a/tests/clients/test_cassandra-driver.py b/tests/clients/test_cassandra-driver.py index b433b578..416222bf 100644 --- a/tests/clients/test_cassandra-driver.py +++ b/tests/clients/test_cassandra-driver.py @@ -13,6 +13,7 @@ from instana.singletons import agent, get_tracer from tests.helpers import get_first_span_by_name, testenv +import contextlib cluster = Cluster([testenv["cassandra_host"]], load_balancing_policy=None) session = cluster.connect() @@ -54,10 +55,8 @@ def test_untraced_execute(self) -> None: def test_untraced_execute_error(self) -> None: res = None - try: + with contextlib.suppress(Exception): res = session.execute("Not a valid query") - except Exception: - pass assert not res diff --git a/tests/clients/test_couchbase.py b/tests/clients/test_couchbase.py index d941b656..2875197d 100644 --- a/tests/clients/test_couchbase.py +++ b/tests/clients/test_couchbase.py @@ -2,27 +2,27 @@ # (c) Copyright Instana Inc. 2020 +import contextlib import time from typing import Generator from unittest.mock import patch +import couchbase.subdocument as SD import pytest - -from instana.singletons import agent, get_tracer -from tests.helpers import testenv, get_first_span_by_name, get_first_span_by_filter - from couchbase.admin import Admin -from couchbase.cluster import Cluster from couchbase.bucket import Bucket +from couchbase.cluster import Cluster from couchbase.exceptions import ( CouchbaseTransientError, HTTPError, KeyExistsError, NotFoundError, ) -import couchbase.subdocument as SD from couchbase.n1ql import N1QLQuery +from instana.singletons import agent, get_tracer +from tests.helpers import get_first_span_by_filter, get_first_span_by_name, testenv + # Delete any pre-existing buckets. Create new. cb_adm = Admin( testenv["couchdb_username"], @@ -45,9 +45,9 @@ def _resource(self) -> Generator[None, None, None]: """Clear all spans before a test run""" self.tracer = get_tracer() self.recorder = self.tracer.span_processor - self.cluster = Cluster("couchbase://%s" % testenv["couchdb_host"]) + self.cluster = Cluster("couchbase://{}".format(testenv["couchdb_host"])) self.bucket = Bucket( - "couchbase://%s/travel-sample" % testenv["couchdb_host"], + "couchbase://{}/travel-sample".format(testenv["couchdb_host"]), username=testenv["couchdb_username"], password=testenv["couchdb_password"], ) @@ -155,10 +155,8 @@ def test_upsert_multi(self) -> None: def test_insert_new(self) -> None: res = None - try: + with contextlib.suppress(NotFoundError): self.bucket.remove("test_insert_new") - except NotFoundError: - pass with self.tracer.start_as_current_span("test"): res = self.bucket.insert("test_insert_new", 1) @@ -191,10 +189,8 @@ def test_insert_new(self) -> None: def test_insert_existing(self) -> None: res = None - try: + with contextlib.suppress(KeyExistsError): self.bucket.insert("test_insert", 1) - except KeyExistsError: - pass try: with self.tracer.start_as_current_span("test"): @@ -222,7 +218,7 @@ def test_insert_existing(self) -> None: assert cb_span.ec == 1 # Just search for the substring of the exception class found = cb_span.data["couchbase"]["error"].find("_KeyExistsError") - assert not found == -1 + assert found != -1 assert ( cb_span.data["couchbase"]["hostname"] == f"{testenv['couchdb_host']}:8091" @@ -275,10 +271,8 @@ def test_insert_multi(self) -> None: def test_replace(self) -> None: res = None - try: + with contextlib.suppress(KeyExistsError): self.bucket.insert("test_replace", 1) - except KeyExistsError: - pass with self.tracer.start_as_current_span("test"): res = self.bucket.replace("test_replace", 2) @@ -312,10 +306,8 @@ def test_replace(self) -> None: def test_replace_non_existent(self) -> None: res = None - try: + with contextlib.suppress(NotFoundError): self.bucket.remove("test_replace") - except NotFoundError: - pass try: with self.tracer.start_as_current_span("test"): @@ -343,7 +335,7 @@ def test_replace_non_existent(self) -> None: assert cb_span.ec == 1 # Just search for the substring of the exception class found = cb_span.data["couchbase"]["error"].find("NotFoundError") - assert not found == -1 + assert found != -1 assert ( cb_span.data["couchbase"]["hostname"] == f"{testenv['couchdb_host']}:8091" @@ -608,10 +600,8 @@ def test_rget(self) -> None: def test_get_not_found(self) -> None: res = None - try: + with contextlib.suppress(NotFoundError): self.bucket.remove("test_get_not_found") - except NotFoundError: - pass try: with self.tracer.start_as_current_span("test"): @@ -654,9 +644,10 @@ def test_get_multi(self) -> None: self.bucket.upsert("second_test_get_multi", "two") with self.tracer.start_as_current_span("test"): - res = self.bucket.get_multi( - ["first_test_get_multi", "second_test_get_multi"] - ) + res = self.bucket.get_multi([ + "first_test_get_multi", + "second_test_get_multi", + ]) assert res assert res["first_test_get_multi"].success @@ -725,9 +716,10 @@ def test_touch_multi(self) -> None: self.bucket.upsert("second_test_touch_multi", "two") with self.tracer.start_as_current_span("test"): - res = self.bucket.touch_multi( - ["first_test_touch_multi", "second_test_touch_multi"] - ) + res = self.bucket.touch_multi([ + "first_test_touch_multi", + "second_test_touch_multi", + ]) assert res assert res["first_test_touch_multi"].success @@ -1046,9 +1038,10 @@ def test_counter_multi(self) -> None: self.bucket.upsert("second_test_counter", 1) with self.tracer.start_as_current_span("test"): - res = self.bucket.counter_multi( - ("first_test_counter", "second_test_counter") - ) + res = self.bucket.counter_multi(( + "first_test_counter", + "second_test_counter", + )) assert res assert res["first_test_counter"].success @@ -1329,16 +1322,23 @@ def test_observe_multi(self) -> None: def test_query_with_instana_tracing_off(self) -> None: res = None - with self.tracer.start_as_current_span("test"), patch( - "instana.instrumentation.couchbase_inst.tracing_is_off", return_value=True + with ( + self.tracer.start_as_current_span("test"), + patch( + "instana.instrumentation.couchbase_inst.tracing_is_off", + return_value=True, + ), ): res = self.bucket.n1ql_query("SELECT 1") assert res def test_query_with_instana_exception(self) -> None: - with self.tracer.start_as_current_span("test"), patch( - "instana.instrumentation.couchbase_inst.collect_attributes", - side_effect=Exception("test-error"), + with ( + self.tracer.start_as_current_span("test"), + patch( + "instana.instrumentation.couchbase_inst.collect_attributes", + side_effect=Exception("test-error"), + ), ): self.bucket.n1ql_query("SELECT 1") diff --git a/tests/clients/test_google-cloud-storage.py b/tests/clients/test_google-cloud-storage.py index ea2f3009..b5afa70c 100644 --- a/tests/clients/test_google-cloud-storage.py +++ b/tests/clients/test_google-cloud-storage.py @@ -406,12 +406,10 @@ def test_objects_compose(self, mock_requests: Mock) -> None: ) with self.tracer.start_as_current_span("test"): - client.bucket("test bucket").blob("dest object").compose( - [ - storage.blob.Blob("object 1", "test bucket"), - storage.blob.Blob("object 2", "test bucket"), - ] - ) + client.bucket("test bucket").blob("dest object").compose([ + storage.blob.Blob("object 1", "test bucket"), + storage.blob.Blob("object 2", "test bucket"), + ]) spans = self.recorder.queued_spans() @@ -1046,10 +1044,9 @@ def test_batch_operation(self, mock_requests: Mock) -> None: ) bucket = client.bucket("test-bucket") - with self.tracer.start_as_current_span("test"): - with client.batch(): - for obj in ["obj1", "obj2"]: - bucket.delete_blob(obj) + with self.tracer.start_as_current_span("test"), client.batch(): + for obj in ["obj1", "obj2"]: + bucket.delete_blob(obj) spans = self.recorder.queued_spans() @@ -1064,9 +1061,12 @@ def test_execute_with_instana_without_tags(self, mock_requests: Mock) -> None: client = self._client( credentials=AnonymousCredentials(), project="test-project" ) - with self.tracer.start_as_current_span("test"), patch( - "instana.instrumentation.google.cloud.storage._collect_attributes", - return_value=None, + with ( + self.tracer.start_as_current_span("test"), + patch( + "instana.instrumentation.google.cloud.storage._collect_attributes", + return_value=None, + ), ): buckets = client.list_buckets() for b in buckets: @@ -1077,9 +1077,12 @@ def test_execute_with_instana_is_tracing_off(self) -> None: client = self._client( credentials=AnonymousCredentials(), project="test-project" ) - with self.tracer.start_as_current_span("test"), patch( - "instana.instrumentation.google.cloud.storage.get_tracer_tuple", - return_value=(None, None, None), + with ( + self.tracer.start_as_current_span("test"), + patch( + "instana.instrumentation.google.cloud.storage.get_tracer_tuple", + return_value=(None, None, None), + ), ): response = client.list_buckets() assert isinstance(response.client, storage.Client) @@ -1096,12 +1099,16 @@ def test_download_with_instana_is_tracing_off(self, mock_requests: Mock) -> None client = self._client( credentials=AnonymousCredentials(), project="test-project" ) - with self.tracer.start_as_current_span("test"), patch( - "instana.instrumentation.google.cloud.storage.get_tracer_tuple", - return_value=(None, None, None), + with ( + self.tracer.start_as_current_span("test"), + patch( + "instana.instrumentation.google.cloud.storage.get_tracer_tuple", + return_value=(None, None, None), + ), ): response = ( - client.bucket("test bucket") + client + .bucket("test bucket") .blob("test object") .download_to_file( io.BytesIO(), @@ -1120,12 +1127,16 @@ def test_upload_with_instana_is_tracing_off(self, mock_requests: Mock) -> None: credentials=AnonymousCredentials(), project="test-project" ) - with self.tracer.start_as_current_span("test"), patch( - "instana.instrumentation.google.cloud.storage.get_tracer_tuple", - return_value=(None, None, None), + with ( + self.tracer.start_as_current_span("test"), + patch( + "instana.instrumentation.google.cloud.storage.get_tracer_tuple", + return_value=(None, None, None), + ), ): response = ( - client.bucket("test bucket") + client + .bucket("test bucket") .blob("test object") .upload_from_string("CONTENT") ) @@ -1144,14 +1155,17 @@ def test_finish_batch_operation_is_tracing_off(self, mock_requests: Mock) -> Non ) bucket = client.bucket("test-bucket") - with self.tracer.start_as_current_span("test"), patch( - "instana.instrumentation.google.cloud.storage.get_tracer_tuple", - return_value=(None, None, None), + with ( + self.tracer.start_as_current_span("test"), + patch( + "instana.instrumentation.google.cloud.storage.get_tracer_tuple", + return_value=(None, None, None), + ), + client.batch() as batch_response, ): - with client.batch() as batch_response: - for obj in ["obj1", "obj2"]: - bucket.delete_blob(obj) - assert batch_response + for obj in ["obj1", "obj2"]: + bucket.delete_blob(obj) + assert batch_response def _client(self, *args, **kwargs) -> storage.Client: # override the HTTP client to bypass the authorization diff --git a/tests/clients/test_logging.py b/tests/clients/test_logging.py index dcd4a487..0d55c31f 100644 --- a/tests/clients/test_logging.py +++ b/tests/clients/test_logging.py @@ -100,12 +100,14 @@ def test_root_exit_span(self) -> None: assert spans[0].data["log"].get("message") == "foo bar" def test_exception(self) -> None: - with self.tracer.start_as_current_span("test"): - with patch( + with ( + self.tracer.start_as_current_span("test"), + patch( "instana.span.span.InstanaSpan.add_event", side_effect=Exception("mocked error"), - ): - self.logger.warning("foo %s", "bar") + ), + ): + self.logger.warning("foo %s", "bar") spans = self.recorder.queued_spans() diff --git a/tests/clients/test_mysqlclient.py b/tests/clients/test_mysqlclient.py index 231e449c..d9307fa4 100644 --- a/tests/clients/test_mysqlclient.py +++ b/tests/clients/test_mysqlclient.py @@ -3,6 +3,7 @@ import sys + import MySQLdb import pytest @@ -229,10 +230,9 @@ def test_error_capture(self): assert db_span.data["mysql"]["port"] == testenv["mysql_port"] def test_connect_cursor_ctx_mgr(self): - with self.tracer.start_as_current_span("test"): - with self.db as connection: - with connection.cursor() as cursor: - affected_rows = cursor.execute("""SELECT * from users""") + with self.tracer.start_as_current_span("test"), self.db as connection: # noqa: SIM117 + with connection.cursor() as cursor: + affected_rows = cursor.execute("""SELECT * from users""") assert affected_rows == 1 spans = self.recorder.queued_spans() @@ -254,10 +254,9 @@ def test_connect_cursor_ctx_mgr(self): assert db_span.data["mysql"]["port"] == testenv["mysql_port"] def test_connect_ctx_mgr(self): - with self.tracer.start_as_current_span("test"): - with self.db as connection: - cursor = connection.cursor() - cursor.execute("""SELECT * from users""") + with self.tracer.start_as_current_span("test"), self.db as connection: + cursor = connection.cursor() + cursor.execute("""SELECT * from users""") spans = self.recorder.queued_spans() assert len(spans) == 2 diff --git a/tests/clients/test_pep0249.py b/tests/clients/test_pep0249.py index ff78bf99..a8a1fa7c 100644 --- a/tests/clients/test_pep0249.py +++ b/tests/clients/test_pep0249.py @@ -6,7 +6,6 @@ from unittest.mock import patch import psycopg2 -import psycopg2.extras import pytest from instana.instrumentation.pep0249 import ( ConnectionFactory, @@ -166,9 +165,14 @@ def test_execute_with_tracing(self) -> None: assert last_inserted_row == sample_params # Exception Handling - with pytest.raises(Exception) as exc_info, patch.object( - CursorWrapper, "_collect_kvs", side_effect=Exception("test exception") - ) as mock_collect_kvs: + with ( + pytest.raises(Exception) as exc_info, + patch.object( + CursorWrapper, + "_collect_kvs", + side_effect=Exception("test exception"), + ) as mock_collect_kvs, + ): self.test_wrapper.execute(sample_sql) assert str(exc_info.value) == "test exception" mock_collect_kvs.assert_called_once() @@ -203,9 +207,14 @@ def test_executemany_with_tracing(self) -> None: self.test_wrapper.executemany(sample_sql, sample_seq_of_params) # Exception Handling - with pytest.raises(Exception) as exc_info, patch.object( - CursorWrapper, "_collect_kvs", side_effect=Exception("test exception") - ) as mock_collect_kvs: + with ( + pytest.raises(Exception) as exc_info, + patch.object( + CursorWrapper, + "_collect_kvs", + side_effect=Exception("test exception"), + ) as mock_collect_kvs, + ): self.test_wrapper.executemany( sample_sql, seq_of_parameters=sample_seq_of_params ) @@ -245,10 +254,13 @@ def test_callproc_with_tracing(self) -> None: # Exception Handling error_proc_name = "erroroeus command;" - with pytest.raises(Exception) as exc_info, patch.object( - InstanaSpan, - "record_exception", - ) as mock_exception: + with ( + pytest.raises(Exception) as exc_info, + patch.object( + InstanaSpan, + "record_exception", + ) as mock_exception, + ): self.test_wrapper.callproc(error_proc_name, sample_params) assert exc_info.typename == "SyntaxError" mock_exception.call_count == 2 diff --git a/tests/clients/test_psycopg2.py b/tests/clients/test_psycopg2.py index d7b80291..2dccbcc9 100644 --- a/tests/clients/test_psycopg2.py +++ b/tests/clients/test_psycopg2.py @@ -3,16 +3,16 @@ import logging -import pytest - from typing import Generator -from instana.instrumentation.psycopg2 import register_json_with_instana -from tests.helpers import testenv -from instana.singletons import agent, get_tracer import psycopg2 -import psycopg2.extras import psycopg2.extensions as ext +import psycopg2.extras +import pytest + +from instana.instrumentation.psycopg2 import register_json_with_instana +from instana.singletons import agent, get_tracer +from tests.helpers import testenv logger = logging.getLogger(__name__) @@ -267,7 +267,7 @@ def test_unicode(self) -> None: # unicode in statement psycopg2.extras.execute_batch( self.cursor, - "insert into users (id, name) values (%%s, %%s) -- %s" % snowman, + f"insert into users (id, name) values (%s, %s) -- {snowman}", [(1, "x")], ) self.cursor.execute("select id, name from users where id = 1") @@ -283,7 +283,7 @@ def test_unicode(self) -> None: # unicode in both psycopg2.extras.execute_batch( self.cursor, - "insert into users (id, name) values (%%s, %%s) -- %s" % snowman, + f"insert into users (id, name) values (%s, %s) -- {snowman}", [(3, snowman)], ) self.cursor.execute("select id, name from users where id = 3") @@ -304,12 +304,11 @@ def test_register_type(self) -> None: ext.register_type(ext.UUIDARRAY, self.cursor) def test_connect_cursor_ctx_mgr(self) -> None: - with self.tracer.start_as_current_span("test"): - with self.db as connection: - with connection.cursor() as cursor: - cursor.execute("""SELECT * from users""") - affected_rows = cursor.rowcount - result = cursor.fetchone() + with self.tracer.start_as_current_span("test"), self.db as connection: # noqa: SIM117 + with connection.cursor() as cursor: + cursor.execute("""SELECT * from users""") + affected_rows = cursor.rowcount + result = cursor.fetchone() assert affected_rows == 1 assert len(result) == 6 @@ -333,12 +332,11 @@ def test_connect_cursor_ctx_mgr(self) -> None: assert db_span.data["pg"]["port"] == testenv["postgresql_port"] def test_connect_ctx_mgr(self) -> None: - with self.tracer.start_as_current_span("test"): - with self.db as connection: - cursor = connection.cursor() - cursor.execute("""SELECT * from users""") - affected_rows = cursor.rowcount - result = cursor.fetchone() + with self.tracer.start_as_current_span("test"), self.db as connection: + cursor = connection.cursor() + cursor.execute("""SELECT * from users""") + affected_rows = cursor.rowcount + result = cursor.fetchone() assert affected_rows == 1 assert len(result) == 6 diff --git a/tests/clients/test_pymysql.py b/tests/clients/test_pymysql.py index 22af80a4..18ef20e3 100644 --- a/tests/clients/test_pymysql.py +++ b/tests/clients/test_pymysql.py @@ -2,13 +2,13 @@ # (c) Copyright Instana Inc. 2020 -import pytest +from typing import Generator import pymysql +import pytest -from typing import Generator -from tests.helpers import testenv from instana.singletons import agent, get_tracer +from tests.helpers import testenv class TestPyMySQL: @@ -255,10 +255,9 @@ def test_error_capture(self) -> None: assert db_span.data["mysql"]["port"] == testenv["mysql_port"] def test_connect_cursor_ctx_mgr(self) -> None: - with self.tracer.start_as_current_span("test"): - with self.db as connection: - with connection.cursor() as cursor: - affected_rows = cursor.execute("""SELECT * from users""") + with self.tracer.start_as_current_span("test"), self.db as connection: # noqa: SIM117 + with connection.cursor() as cursor: + affected_rows = cursor.execute("""SELECT * from users""") assert affected_rows == 1 spans = self.recorder.queued_spans() @@ -280,10 +279,9 @@ def test_connect_cursor_ctx_mgr(self) -> None: assert db_span.data["mysql"]["port"] == testenv["mysql_port"] def test_connect_ctx_mgr(self) -> None: - with self.tracer.start_as_current_span("test"): - with self.db as connection: - cursor = connection.cursor() - cursor.execute("""SELECT * from users""") + with self.tracer.start_as_current_span("test"), self.db as connection: + cursor = connection.cursor() + cursor.execute("""SELECT * from users""") spans = self.recorder.queued_spans() assert len(spans) == 2 diff --git a/tests/clients/test_redis.py b/tests/clients/test_redis.py index 74be9653..1fe91cc2 100644 --- a/tests/clients/test_redis.py +++ b/tests/clients/test_redis.py @@ -26,7 +26,7 @@ def _resource(self) -> Generator[None, None, None]: self.client = redis.Redis(host=testenv["redis_host"], db=testenv["redis_db"]) yield keys_to_remove = [ - k for k in os.environ.keys() if k.startswith("INSTANA_TRACING_FILTER_") + k for k in os.environ if k.startswith("INSTANA_TRACING_FILTER_") ] for k in keys_to_remove: del os.environ[k] diff --git a/tests/clients/test_sqlalchemy.py b/tests/clients/test_sqlalchemy.py index 3d4866b2..86b8a095 100644 --- a/tests/clients/test_sqlalchemy.py +++ b/tests/clients/test_sqlalchemy.py @@ -2,6 +2,7 @@ # (c) Copyright Instana Inc. 2020 +import contextlib from typing import Generator import pytest @@ -30,12 +31,8 @@ class StanUser(Base): fullname = Column(String) password = Column(String) - def __repr__(self) -> None: - return "" % ( - self.name, - self.fullname, - self.password, - ) + def __repr__(self) -> str: + return f"" @pytest.fixture(scope="class") @@ -105,8 +102,8 @@ def test_session_add(self) -> None: assert sql_span.data["sqlalchemy"]["eng"] == "postgresql" assert sqlalchemy_url == sql_span.data["sqlalchemy"]["url"] assert ( - "INSERT INTO churchofstan (name, fullname, password) VALUES (%(name)s, %(fullname)s, %(password)s) RETURNING churchofstan.id" - == sql_span.data["sqlalchemy"]["sql"] + sql_span.data["sqlalchemy"]["sql"] + == "INSERT INTO churchofstan (name, fullname, password) VALUES (%(name)s, %(fullname)s, %(password)s) RETURNING churchofstan.id" ) assert not sql_span.data["sqlalchemy"]["err"] @@ -141,8 +138,8 @@ def test_session_add_as_root_exit_span(self) -> None: assert sql_span.data["sqlalchemy"]["eng"] == "postgresql" assert sqlalchemy_url == sql_span.data["sqlalchemy"]["url"] assert ( - "INSERT INTO churchofstan (name, fullname, password) VALUES (%(name)s, %(fullname)s, %(password)s) RETURNING churchofstan.id" - == sql_span.data["sqlalchemy"]["sql"] + sql_span.data["sqlalchemy"]["sql"] + == "INSERT INTO churchofstan (name, fullname, password) VALUES (%(name)s, %(fullname)s, %(password)s) RETURNING churchofstan.id" ) assert not sql_span.data["sqlalchemy"]["err"] @@ -151,7 +148,7 @@ def test_session_add_as_root_exit_span(self) -> None: assert len(sql_span.stack) > 0 def test_transaction(self) -> None: - with self.tracer.start_as_current_span("test"): + with self.tracer.start_as_current_span("test"): # noqa: SIM117 with engine.begin() as connection: connection.execute(text("select 1")) connection.execute( @@ -205,8 +202,8 @@ def test_transaction(self) -> None: assert sql_span1.data["sqlalchemy"]["eng"] == "postgresql" assert sqlalchemy_url == sql_span1.data["sqlalchemy"]["url"] assert ( - "select (name, fullname, password) from churchofstan where name='doesntexist'" - == sql_span1.data["sqlalchemy"]["sql"] + sql_span1.data["sqlalchemy"]["sql"] + == "select (name, fullname, password) from churchofstan where name='doesntexist'" ) assert not sql_span1.data["sqlalchemy"]["err"] @@ -215,12 +212,10 @@ def test_transaction(self) -> None: assert len(sql_span1.stack) > 0 def test_error_logging(self) -> None: - with self.tracer.start_as_current_span("test"): - try: + with self.tracer.start_as_current_span("test"): # noqa: SIM117 + with contextlib.suppress(Exception): self.session.execute(text("htVwGrCwVThisIsInvalidSQLaw4ijXd88")) # self.session.commit() - except Exception: - pass spans = self.recorder.queued_spans() assert len(spans) == 2 @@ -250,7 +245,7 @@ def test_error_logging(self) -> None: assert sql_span.data["sqlalchemy"]["eng"] == "postgresql" assert sqlalchemy_url == sql_span.data["sqlalchemy"]["url"] assert ( - "htVwGrCwVThisIsInvalidSQLaw4ijXd88" == sql_span.data["sqlalchemy"]["sql"] + sql_span.data["sqlalchemy"]["sql"] == "htVwGrCwVThisIsInvalidSQLaw4ijXd88" ) assert ( 'syntax error at or near "htVwGrCwVThisIsInvalidSQLaw4ijXd88' diff --git a/tests/clients/test_urllib3.py b/tests/clients/test_urllib3.py index 9a740b50..203af820 100644 --- a/tests/clients/test_urllib3.py +++ b/tests/clients/test_urllib3.py @@ -2,6 +2,7 @@ # (c) Copyright Instana Inc. 2020 +import contextlib import logging import sys from multiprocessing.pool import ThreadPool @@ -11,20 +12,18 @@ import pytest import requests import urllib3 -from instana.instrumentation.urllib3 import ( - _collect_kvs as collect_kvs, - extract_custom_headers, - collect_response, -) -from instana.singletons import agent, get_tracer import tests.apps.flask_app # noqa: F401 +from instana.instrumentation.urllib3 import _collect_kvs as collect_kvs +from instana.instrumentation.urllib3 import collect_response, extract_custom_headers +from instana.singletons import agent, get_tracer from tests.helpers import testenv if TYPE_CHECKING: - from instana.span.span import InstanaSpan from pytest import LogCaptureFixture + from instana.span.span import InstanaSpan + class TestUrllib3: @pytest.fixture(autouse=True) @@ -571,11 +570,9 @@ def test_5xx_request(self): assert len(urllib3_span.stack) > 1 def test_exception_logging(self): - with self.tracer.start_as_current_span("test"): - try: + with self.tracer.start_as_current_span("test"): # noqa: SIM117 + with contextlib.suppress(Exception): r = self.http.request("GET", testenv["flask_server"] + "/exception") - except Exception: - pass spans = self.recorder.queued_spans() # Behind the "wsgi_server", currently there is Flask @@ -643,16 +640,14 @@ def test_exception_logging(self): def test_client_error(self): r = None - with self.tracer.start_as_current_span("test"): - try: + with self.tracer.start_as_current_span("test"): # noqa: SIM117 + with contextlib.suppress(Exception): r = self.http.request( "GET", "http://doesnotexist.asdf:5000/504", retries=False, timeout=urllib3.Timeout(connect=0.5, read=0.5), ) - except Exception: - pass spans = self.recorder.queued_spans() assert len(spans) == 2 @@ -998,11 +993,9 @@ def test_collect_kvs_exception( def test_internal_span_creation_with_url_in_hostname(self) -> None: internal_url = "https://com.instana.example.com/api/test" - with self.tracer.start_as_current_span("test"): - try: + with self.tracer.start_as_current_span("test"): # noqa: SIM117 + with contextlib.suppress(Exception): self.http.request("GET", internal_url, retries=False, timeout=1) - except Exception: - pass spans = self.recorder.queued_spans() @@ -1020,11 +1013,9 @@ def test_internal_span_creation_with_url_in_hostname(self) -> None: def test_internal_span_creation_with_url_in_path(self) -> None: internal_url_path = "https://example.com/com.instana/api/test" - with self.tracer.start_as_current_span("test"): - try: + with self.tracer.start_as_current_span("test"): # noqa: SIM117 + with contextlib.suppress(Exception): self.http.request("GET", internal_url_path, retries=False, timeout=1) - except Exception: - pass spans = self.recorder.queued_spans() assert len(spans) == 2 diff --git a/tests/collector/test_host_collector.py b/tests/collector/test_host_collector.py index e0c2c194..2a9d68e4 100644 --- a/tests/collector/test_host_collector.py +++ b/tests/collector/test_host_collector.py @@ -108,7 +108,7 @@ def test_prepare_payload_basics(self) -> None: assert "data" in python_plugin assert "snapshot" in python_plugin["data"] assert "m" in python_plugin["data"]["snapshot"] - assert "Manual" == python_plugin["data"]["snapshot"]["m"] + assert python_plugin["data"]["snapshot"]["m"] == "Manual" assert "metrics" in python_plugin["data"] assert "ru_utime" in python_plugin["data"]["metrics"] @@ -213,7 +213,7 @@ def test_prepare_payload_basics_disable_runtime_metrics(self) -> None: assert "data" in python_plugin assert "snapshot" in python_plugin["data"] assert "m" in python_plugin["data"]["snapshot"] - assert "Manual" == python_plugin["data"]["snapshot"]["m"] + assert python_plugin["data"]["snapshot"]["m"] == "Manual" assert "metrics" not in python_plugin["data"] def test_prepare_payload_with_snapshot_with_python_packages(self) -> None: @@ -223,7 +223,7 @@ def test_prepare_payload_with_snapshot_with_python_packages(self) -> None: snapshot = self.payload["metrics"]["plugins"][0]["data"]["snapshot"] assert snapshot assert "m" in snapshot - assert "Manual" == snapshot["m"] + assert snapshot["m"] == "Manual" assert "version" in snapshot assert len(snapshot["versions"]) > 5 assert snapshot["versions"]["instana"] == VERSION @@ -238,7 +238,7 @@ def test_prepare_payload_with_snapshot_disabled_python_packages(self) -> None: snapshot = self.payload["metrics"]["plugins"][0]["data"]["snapshot"] assert snapshot assert "m" in snapshot - assert "Manual" == snapshot["m"] + assert snapshot["m"] == "Manual" assert "version" in snapshot assert len(snapshot["versions"]) == 1 assert snapshot["versions"]["instana"] == VERSION @@ -251,14 +251,14 @@ def test_prepare_payload_with_autowrapt(self) -> None: snapshot = self.payload["metrics"]["plugins"][0]["data"]["snapshot"] assert snapshot assert "m" in snapshot - assert "Autowrapt" == snapshot["m"] + assert snapshot["m"] == "Autowrapt" assert "version" in snapshot assert len(snapshot["versions"]) > 5 expected_packages = ("instana", "wrapt", "fysom") for package in expected_packages: - assert ( - package in snapshot["versions"] - ), f"{package} not found in snapshot['versions']" + assert package in snapshot["versions"], ( + f"{package} not found in snapshot['versions']" + ) assert snapshot["versions"]["instana"] == VERSION def test_prepare_payload_with_autotrace(self) -> None: @@ -269,14 +269,14 @@ def test_prepare_payload_with_autotrace(self) -> None: snapshot = self.payload["metrics"]["plugins"][0]["data"]["snapshot"] assert snapshot assert "m" in snapshot - assert "AutoTrace" == snapshot["m"] + assert snapshot["m"] == "AutoTrace" assert "version" in snapshot assert len(snapshot["versions"]) > 5 expected_packages = ("instana", "wrapt", "fysom") for package in expected_packages: - assert ( - package in snapshot["versions"] - ), f"{package} not found in snapshot['versions']" + assert package in snapshot["versions"], ( + f"{package} not found in snapshot['versions']" + ) assert snapshot["versions"]["instana"] == VERSION def test_prepare_and_report_data_without_lock( diff --git a/tests/frameworks/test_aiohttp_client.py b/tests/frameworks/test_aiohttp_client.py index 349772fb..cac00bd7 100644 --- a/tests/frameworks/test_aiohttp_client.py +++ b/tests/frameworks/test_aiohttp_client.py @@ -14,6 +14,7 @@ import tests.apps.flask_app # noqa: F401 import tests.apps.aiohttp_app # noqa: F401 from tests.helpers import testenv +import contextlib class TestAiohttpClient: @@ -441,10 +442,8 @@ async def test(): return await self.fetch(session, "http://doesnotexist:10/") response = None - try: + with contextlib.suppress(Exception): response = self.loop.run_until_complete(test()) - except Exception: - pass spans = self.recorder.queued_spans() assert len(spans) == 2 diff --git a/tests/frameworks/test_celery.py b/tests/frameworks/test_celery.py index 90bd4318..e8919803 100644 --- a/tests/frameworks/test_celery.py +++ b/tests/frameworks/test_celery.py @@ -5,13 +5,11 @@ import time from typing import Generator, List -from celery import shared_task -import celery +import celery # noqa: F401 import celery.app -import celery.contrib -import celery.contrib.testing import celery.contrib.testing.worker import pytest +from celery import shared_task from instana.singletons import get_tracer from instana.span.span import InstanaSpan diff --git a/tests/frameworks/test_django.py b/tests/frameworks/test_django.py index 91e85715..767ea8db 100644 --- a/tests/frameworks/test_django.py +++ b/tests/frameworks/test_django.py @@ -3,22 +3,22 @@ import os +from typing import Generator -import urllib3 import pytest -from typing import Generator +import urllib3 from django.apps import apps from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from instana.instrumentation.django.middleware import url_pattern_route +from instana.singletons import agent, get_tracer from instana.util.ids import hex_id from tests.apps.app_django import INSTALLED_APPS -from instana.singletons import agent, get_tracer from tests.helpers import ( + drop_log_spans_from_list, fail_with_message_and_span_dump, get_first_span_by_filter, - drop_log_spans_from_list, ) -from instana.instrumentation.django.middleware import url_pattern_route apps.populate(INSTALLED_APPS) @@ -43,10 +43,10 @@ def test_basic_request(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 3 == len(spans) + assert len(spans) == 3 test_span = spans[2] urllib3_span = spans[1] @@ -67,9 +67,9 @@ def test_basic_request(self) -> None: server_timing_value = f"intid;desc={hex_id(django_span.t)}" assert response.headers["Server-Timing"] == server_timing_value - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert "django" == django_span.n + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert django_span.n == "django" assert test_span.t == urllib3_span.t assert urllib3_span.t == django_span.t @@ -82,11 +82,11 @@ def test_basic_request(self) -> None: assert test_span.sy is None assert django_span.ec is None - assert "/" == django_span.data["http"]["url"] - assert "GET" == django_span.data["http"]["method"] - assert 200 == django_span.data["http"]["status"] - assert "test=1" == django_span.data["http"]["params"] - assert "^$" == django_span.data["http"]["path_tpl"] + assert django_span.data["http"]["url"] == "/" + assert django_span.data["http"]["method"] == "GET" + assert django_span.data["http"]["status"] == 200 + assert django_span.data["http"]["params"] == "test=1" + assert django_span.data["http"]["path_tpl"] == "^$" assert django_span.stack is None @@ -99,16 +99,16 @@ def test_synthetic_request(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 3 == len(spans) + assert len(spans) == 3 test_span = spans[2] urllib3_span = spans[1] django_span = spans[0] - assert "^$" == django_span.data["http"]["path_tpl"] + assert django_span.data["http"]["path_tpl"] == "^$" assert django_span.sy assert urllib3_span.sy is None @@ -119,14 +119,14 @@ def test_request_with_error(self) -> None: response = self.http.request("GET", self.live_server_url + "/cause_error") assert response - assert 500 == response.status + assert response.status == 500 spans = self.recorder.queued_spans() spans = drop_log_spans_from_list(spans) span_count = len(spans) if span_count != 3: - msg = "Expected 3 spans but got %d" % span_count + msg = "Expected 3 spans but got {span_count}" fail_with_message_and_span_dump(msg, spans) def filter(span): @@ -162,9 +162,9 @@ def filter(span): server_timing_value = f"intid;desc={hex_id(django_span.t)}" assert response.headers["Server-Timing"] == server_timing_value - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert "django" == django_span.n + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert django_span.n == "django" assert test_span.t == urllib3_span.t assert urllib3_span.t == django_span.t @@ -172,13 +172,13 @@ def filter(span): assert urllib3_span.p == test_span.s assert django_span.p == urllib3_span.s - assert 1 == django_span.ec + assert django_span.ec == 1 - assert "/cause_error" == django_span.data["http"]["url"] - assert "GET" == django_span.data["http"]["method"] - assert 500 == django_span.data["http"]["status"] - assert "This is a fake error: /cause-error" == django_span.data["http"]["error"] - assert "^cause_error$" == django_span.data["http"]["path_tpl"] + assert django_span.data["http"]["url"] == "/cause_error" + assert django_span.data["http"]["method"] == "GET" + assert django_span.data["http"]["status"] == 500 + assert django_span.data["http"]["error"] == "This is a fake error: /cause-error" + assert django_span.data["http"]["path_tpl"] == "^cause_error$" assert django_span.stack is None def test_request_with_not_found(self) -> None: @@ -186,14 +186,14 @@ def test_request_with_not_found(self) -> None: response = self.http.request("GET", self.live_server_url + "/not_found") assert response - assert 404 == response.status + assert response.status == 404 spans = self.recorder.queued_spans() spans = drop_log_spans_from_list(spans) span_count = len(spans) if span_count != 3: - msg = "Expected 3 spans but got %d" % span_count + msg = f"Expected 3 spans but got {span_count}" fail_with_message_and_span_dump(msg, spans) def filter(span): @@ -203,21 +203,21 @@ def filter(span): assert django_span assert django_span.ec is None - assert 404 == django_span.data["http"]["status"] + assert django_span.data["http"]["status"] == 404 def test_request_with_not_found_no_route(self) -> None: with self.tracer.start_as_current_span("test"): response = self.http.request("GET", self.live_server_url + "/no_route") assert response - assert 404 == response.status + assert response.status == 404 spans = self.recorder.queued_spans() spans = drop_log_spans_from_list(spans) span_count = len(spans) if span_count != 3: - msg = "Expected 3 spans but got %d" % span_count + msg = f"Expected 3 spans but got {span_count}" fail_with_message_and_span_dump(msg, spans) def filter(span): @@ -227,16 +227,16 @@ def filter(span): assert django_span assert django_span.data["http"]["path_tpl"] is None assert django_span.ec is None - assert 404 == django_span.data["http"]["status"] + assert django_span.data["http"]["status"] == 404 def test_complex_request(self) -> None: with self.tracer.start_as_current_span("test"): response = self.http.request("GET", self.live_server_url + "/complex") assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 5 == len(spans) + assert len(spans) == 5 test_span = spans[4] urllib3_span = spans[3] @@ -259,11 +259,11 @@ def test_complex_request(self) -> None: server_timing_value = f"intid;desc={hex_id(django_span.t)}" assert response.headers["Server-Timing"] == server_timing_value - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert "django" == django_span.n - assert "sdk" == otel_span1.n - assert "sdk" == otel_span2.n + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert django_span.n == "django" + assert otel_span1.n == "sdk" + assert otel_span2.n == "sdk" assert test_span.t == urllib3_span.t assert urllib3_span.t == django_span.t @@ -283,10 +283,10 @@ def test_complex_request(self) -> None: otel_span1.data["sdk"]["name"] == "asteroid" otel_span2.data["sdk"]["name"] == "spacedust" - assert "/complex" == django_span.data["http"]["url"] - assert "GET" == django_span.data["http"]["method"] - assert 200 == django_span.data["http"]["status"] - assert "^complex$" == django_span.data["http"]["path_tpl"] + assert django_span.data["http"]["url"] == "/complex" + assert django_span.data["http"]["method"] == "GET" + assert django_span.data["http"]["status"] == 200 + assert django_span.data["http"]["path_tpl"] == "^complex$" def test_request_header_capture(self) -> None: # Hack together a manual custom headers list @@ -302,18 +302,18 @@ def test_request_header_capture(self) -> None: # response = self.client.get('/') assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 3 == len(spans) + assert len(spans) == 3 test_span = spans[2] urllib3_span = spans[1] django_span = spans[0] - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert "django" == django_span.n + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert django_span.n == "django" assert test_span.t == urllib3_span.t assert urllib3_span.t == django_span.t @@ -324,15 +324,15 @@ def test_request_header_capture(self) -> None: assert django_span.ec is None assert django_span.stack is None - assert "/" == django_span.data["http"]["url"] - assert "GET" == django_span.data["http"]["method"] - assert 200 == django_span.data["http"]["status"] - assert "^$" == django_span.data["http"]["path_tpl"] + assert django_span.data["http"]["url"] == "/" + assert django_span.data["http"]["method"] == "GET" + assert django_span.data["http"]["status"] == 200 + assert django_span.data["http"]["path_tpl"] == "^$" assert "X-Capture-This" in django_span.data["http"]["header"] - assert "this" == django_span.data["http"]["header"]["X-Capture-This"] + assert django_span.data["http"]["header"]["X-Capture-This"] == "this" assert "X-Capture-That" in django_span.data["http"]["header"] - assert "that" == django_span.data["http"]["header"]["X-Capture-That"] + assert django_span.data["http"]["header"]["X-Capture-That"] == "that" agent.options.extra_http_headers = original_extra_http_headers @@ -347,18 +347,18 @@ def test_response_header_capture(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 3 == len(spans) + assert len(spans) == 3 test_span = spans[2] urllib3_span = spans[1] django_span = spans[0] - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert "django" == django_span.n + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert django_span.n == "django" assert test_span.t == urllib3_span.t assert urllib3_span.t == django_span.t @@ -369,15 +369,15 @@ def test_response_header_capture(self) -> None: assert django_span.ec is None assert django_span.stack is None - assert "/response_with_headers" == django_span.data["http"]["url"] - assert "GET" == django_span.data["http"]["method"] - assert 200 == django_span.data["http"]["status"] - assert "^response_with_headers$" == django_span.data["http"]["path_tpl"] + assert django_span.data["http"]["url"] == "/response_with_headers" + assert django_span.data["http"]["method"] == "GET" + assert django_span.data["http"]["status"] == 200 + assert django_span.data["http"]["path_tpl"] == "^response_with_headers$" assert "X-Capture-This-Too" in django_span.data["http"]["header"] - assert "this too" == django_span.data["http"]["header"]["X-Capture-This-Too"] + assert django_span.data["http"]["header"]["X-Capture-This-Too"] == "this too" assert "X-Capture-That-Too" in django_span.data["http"]["header"] - assert "that too" == django_span.data["http"]["header"]["X-Capture-That-Too"] + assert django_span.data["http"]["header"]["X-Capture-That-Too"] == "that too" agent.options.extra_http_headers = original_extra_http_headers @@ -398,10 +398,10 @@ def test_with_incoming_context(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 1 == len(spans) + assert len(spans) == 1 django_span = spans[0] @@ -429,15 +429,13 @@ def test_with_incoming_context(self) -> None: # The incoming traceparent header had version 01 (which does not exist at the time of writing), but since we # support version 00, we also need to pass down 00 for the version field. assert ( - "00-4bf92f3577b34da6a3ce929d0e0e4736-{}-01".format(django_span.s) + f"00-4bf92f3577b34da6a3ce929d0e0e4736-{django_span.s}-01" == response.headers["traceparent"] ) assert "tracestate" in response.headers assert ( - "in={};{},rojo=00f067aa0ba902b7,congo=t61rcWkgMzE".format( - django_span.t, django_span.s - ) + f"in={django_span.t};{django_span.s},rojo=00f067aa0ba902b7,congo=t61rcWkgMzE" == response.headers["tracestate"] ) @@ -461,10 +459,10 @@ def test_with_incoming_context_and_correlation(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 1 == len(spans) + assert len(spans) == 1 django_span = spans[0] @@ -494,15 +492,13 @@ def test_with_incoming_context_and_correlation(self) -> None: assert "traceparent" in response.headers assert ( - "00-4bf92f3577b34da6a3ce929d0e0e4736-{}-01".format(django_span.s) + f"00-4bf92f3577b34da6a3ce929d0e0e4736-{django_span.s}-01" == response.headers["traceparent"] ) assert "tracestate" in response.headers assert ( - "in={};{},rojo=00f067aa0ba902b7,congo=t61rcWkgMzE".format( - django_span.t, django_span.s - ) + f"in={django_span.t};{django_span.s},rojo=00f067aa0ba902b7,congo=t61rcWkgMzE" == response.headers["tracestate"] ) @@ -521,10 +517,10 @@ def test_with_incoming_traceparent_tracestate(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 1 == len(spans) + assert len(spans) == 1 django_span = spans[0] @@ -554,15 +550,13 @@ def test_with_incoming_traceparent_tracestate(self) -> None: assert "traceparent" in response.headers assert ( - "00-4bf92f3577b34da6a3ce929d0e0e4736-{}-01".format(django_span.s) + f"00-4bf92f3577b34da6a3ce929d0e0e4736-{django_span.s}-01" == response.headers["traceparent"] ) assert "tracestate" in response.headers assert ( - "in=a3ce929d0e0e4736;{},rojo=00f067aa0ba902b7,congo=t61rcWkgMzE".format( - django_span.s - ) + f"in=a3ce929d0e0e4736;{django_span.s},rojo=00f067aa0ba902b7,congo=t61rcWkgMzE" == response.headers["tracestate"] ) @@ -582,10 +576,10 @@ def test_with_incoming_traceparent_tracestate_disable_traceparent(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 1 == len(spans) + assert len(spans) == 1 django_span = spans[0] @@ -611,15 +605,13 @@ def test_with_incoming_traceparent_tracestate_disable_traceparent(self) -> None: assert "traceparent" in response.headers assert ( - "00-4bf92f3577b34da6a3ce929d0e0e4736-{}-01".format(django_span.s) + f"00-4bf92f3577b34da6a3ce929d0e0e4736-{django_span.s}-01" == response.headers["traceparent"] ) assert "tracestate" in response.headers assert ( - "in={};{},rojo=00f067aa0ba902b7,congo=t61rcWkgMzE".format( - django_span.t, django_span.s - ) + f"in={django_span.t};{django_span.s},rojo=00f067aa0ba902b7,congo=t61rcWkgMzE" == response.headers["tracestate"] ) @@ -633,10 +625,10 @@ def test_with_incoming_mixed_case_context(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 1 == len(spans) + assert len(spans) == 1 django_span = spans[0] diff --git a/tests/frameworks/test_flask.py b/tests/frameworks/test_flask.py index 6b453d2a..f84867c5 100644 --- a/tests/frameworks/test_flask.py +++ b/tests/frameworks/test_flask.py @@ -94,22 +94,22 @@ def test_get_request(self) -> None: assert wsgi_span.ec is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert wsgi_span.data["http"]["host"] == "127.0.0.1:" + str( testenv["flask_port"] ) - assert "/" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 200 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 200 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 200 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 200 assert testenv["flask_server"] + "/" == urllib3_span.data["http"]["url"] - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -169,23 +169,23 @@ def test_get_request_with_query_params(self) -> None: assert wsgi_span.ec is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/" == wsgi_span.data["http"]["url"] + assert wsgi_span.data["http"]["url"] == "/" assert wsgi_span.data["http"]["params"] == "key1=&key2=" - assert "GET" == wsgi_span.data["http"]["method"] - assert 200 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 200 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 200 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 200 assert testenv["flask_server"] + "/" == urllib3_span.data["http"]["url"] - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -312,30 +312,30 @@ def test_render_template(self) -> None: assert render_span.ec is None # render - assert "render" == render_span.n - assert SpanKind.INTERNAL == render_span.k - assert "flask_render_template.html" == render_span.data["render"]["name"] - assert "template" == render_span.data["render"]["type"] + assert render_span.n == "render" + assert render_span.k == SpanKind.INTERNAL + assert render_span.data["render"]["name"] == "flask_render_template.html" + assert render_span.data["render"]["type"] == "template" assert render_span.data["log"]["message"] is None assert render_span.data["log"]["parameters"] is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/render" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 200 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/render" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 200 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 200 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 200 assert testenv["flask_server"] + "/render" == urllib3_span.data["http"]["url"] - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -394,33 +394,33 @@ def test_render_template_string(self) -> None: assert render_span.ec is None # render - assert "render" == render_span.n - assert SpanKind.INTERNAL == render_span.k - assert "(from string)" == render_span.data["render"]["name"] - assert "template" == render_span.data["render"]["type"] + assert render_span.n == "render" + assert render_span.k == SpanKind.INTERNAL + assert render_span.data["render"]["name"] == "(from string)" + assert render_span.data["render"]["type"] == "template" assert render_span.data["log"]["message"] is None assert render_span.data["log"]["parameters"] is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/render_string" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 200 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/render_string" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 200 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 200 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 200 assert ( testenv["flask_server"] + "/render_string" == urllib3_span.data["http"]["url"] ) - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -443,7 +443,7 @@ def test_301(self) -> None: test_span = spans[2] assert response - assert 301 == response.status + assert response.status == 301 assert "X-INSTANA-T" in response.headers assert int(response.headers["X-INSTANA-T"], 16) @@ -476,22 +476,22 @@ def test_301(self) -> None: assert wsgi_span.ec is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/301" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 301 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/301" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 301 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 301 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 301 assert testenv["flask_server"] + "/301" == urllib3_span.data["http"]["url"] - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -512,7 +512,7 @@ def test_custom_404(self) -> None: test_span = spans[2] assert response - assert 404 == response.status + assert response.status == 404 # assert 'X-INSTANA-T' in response.headers # assert int(response.headers['X-INSTANA-T']) == 16 @@ -545,24 +545,24 @@ def test_custom_404(self) -> None: assert wsgi_span.ec is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/custom-404" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 404 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/custom-404" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 404 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 404 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 404 assert ( testenv["flask_server"] + "/custom-404" == urllib3_span.data["http"]["url"] ) - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -585,7 +585,7 @@ def test_404(self) -> None: test_span = spans[2] assert response - assert 404 == response.status + assert response.status == 404 # assert 'X-INSTANA-T' in response.headers # assert int(response.headers['X-INSTANA-T']) == 16 @@ -618,24 +618,24 @@ def test_404(self) -> None: assert wsgi_span.ec is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/11111111111" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 404 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/11111111111" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 404 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 404 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 404 assert ( testenv["flask_server"] + "/11111111111" == urllib3_span.data["http"]["url"] ) - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -656,7 +656,7 @@ def test_500(self) -> None: test_span = spans[2] assert response - assert 500 == response.status + assert response.status == 500 assert "X-INSTANA-T" in response.headers assert int(response.headers["X-INSTANA-T"], 16) @@ -685,26 +685,26 @@ def test_500(self) -> None: # Error logging assert test_span.ec is None - assert 1 == urllib3_span.ec - assert 1 == wsgi_span.ec + assert urllib3_span.ec == 1 + assert wsgi_span.ec == 1 # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/500" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 500 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/500" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 500 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 500 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 500 assert testenv["flask_server"] + "/500" == urllib3_span.data["http"]["url"] - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -731,7 +731,7 @@ def test_render_error(self) -> None: test_span = spans[3] assert response - assert 500 == response.status + assert response.status == 500 # assert 'X-INSTANA-T' in response.headers # assert int(response.headers['X-INSTANA-T']) == 16 @@ -760,11 +760,11 @@ def test_render_error(self) -> None: # Error logging assert test_span.ec is None - assert 1 == urllib3_span.ec - assert 1 == wsgi_span.ec + assert urllib3_span.ec == 1 + assert wsgi_span.ec == 1 # error log - assert "log" == log_span.n + assert log_span.n == "log" assert log_span.data["log"]["message"] == "Exception on /render_error [GET]" assert ( log_span.data["log"]["parameters"] @@ -772,25 +772,25 @@ def test_render_error(self) -> None: ) # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/render_error" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 500 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/render_error" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 500 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 500 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 500 assert ( testenv["flask_server"] + "/render_error" == urllib3_span.data["http"]["url"] ) - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -815,7 +815,7 @@ def test_exception(self) -> None: test_span = spans[3] assert response - assert 500 == response.status + assert response.status == 500 assert get_current_span().is_recording() is False @@ -830,34 +830,34 @@ def test_exception(self) -> None: # Error logging assert test_span.ec is None - assert 1 == urllib3_span.ec - assert 1 == wsgi_span.ec - assert 1 == log_span.ec + assert urllib3_span.ec == 1 + assert wsgi_span.ec == 1 + assert log_span.ec == 1 # error log - assert "log" == log_span.n + assert log_span.n == "log" assert log_span.data["log"]["message"] == "Exception on /exception [GET]" assert log_span.data["log"]["parameters"] == " fake error" # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/exception" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 500 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/exception" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 500 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 500 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 500 assert ( testenv["flask_server"] + "/exception" == urllib3_span.data["http"]["url"] ) - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -881,7 +881,7 @@ def test_custom_exception_with_log(self) -> None: test_span = spans[3] assert response - assert 502 == response.status + assert response.status == 502 assert "X-INSTANA-T" in response.headers assert int(response.headers["X-INSTANA-T"], 16) @@ -910,12 +910,12 @@ def test_custom_exception_with_log(self) -> None: # Error logging assert test_span.ec is None - assert 1 == urllib3_span.ec - assert 1 == wsgi_span.ec - assert 1 == log_span.ec + assert urllib3_span.ec == 1 + assert wsgi_span.ec == 1 + assert log_span.ec == 1 # error log - assert "log" == log_span.n + assert log_span.n == "log" assert log_span.data["log"]["message"] == "InvalidUsage error handler invoked" assert ( log_span.data["log"]["parameters"] @@ -923,25 +923,25 @@ def test_custom_exception_with_log(self) -> None: ) # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/exception-invalid-usage" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 502 == wsgi_span.data["http"]["status"] - assert "Simulated custom exception" == wsgi_span.data["http"]["error"] + assert wsgi_span.data["http"]["url"] == "/exception-invalid-usage" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 502 + assert wsgi_span.data["http"]["error"] == "Simulated custom exception" assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 502 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 502 assert ( testenv["flask_server"] + "/exception-invalid-usage" == urllib3_span.data["http"]["url"] ) - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 @@ -996,31 +996,31 @@ def test_path_templates(self) -> None: assert wsgi_span.ec is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/users/Ricky/sayhello" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 200 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/users/Ricky/sayhello" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 200 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 200 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 200 assert ( testenv["flask_server"] + "/users/Ricky/sayhello" == urllib3_span.data["http"]["url"] ) - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 # We should have a reported path template for this route - assert "/users/{username}/sayhello" == wsgi_span.data["http"]["path_tpl"] + assert wsgi_span.data["http"]["path_tpl"] == "/users/{username}/sayhello" def test_request_header_capture(self) -> None: # Hack together a manual custom headers list @@ -1058,14 +1058,14 @@ def test_request_header_capture(self) -> None: assert wsgi_span.ec is None assert wsgi_span.stack is None - assert "/" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 200 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 200 assert "X-Capture-This-Too" in wsgi_span.data["http"]["header"] - assert "this too" == wsgi_span.data["http"]["header"]["X-Capture-This-Too"] + assert wsgi_span.data["http"]["header"]["X-Capture-This-Too"] == "this too" assert "X-Capture-That-Too" in wsgi_span.data["http"]["header"] - assert "that too" == wsgi_span.data["http"]["header"]["X-Capture-That-Too"] + assert wsgi_span.data["http"]["header"]["X-Capture-That-Too"] == "that too" agent.options.extra_http_headers = original_extra_http_headers @@ -1124,44 +1124,46 @@ def test_response_header_capture(self) -> None: assert wsgi_span.ec is None # urllib3 - assert "test" == test_span.data["sdk"]["name"] - assert "urllib3" == urllib3_span.n - assert 200 == urllib3_span.data["http"]["status"] + assert test_span.data["sdk"]["name"] == "test" + assert urllib3_span.n == "urllib3" + assert urllib3_span.data["http"]["status"] == 200 assert ( testenv["flask_server"] + "/response_headers" == urllib3_span.data["http"]["url"] ) - assert "GET" == urllib3_span.data["http"]["method"] + assert urllib3_span.data["http"]["method"] == "GET" assert urllib3_span.stack is not None assert type(urllib3_span.stack) is list assert len(urllib3_span.stack) > 1 # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/response_headers" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] - assert 200 == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["url"] == "/response_headers" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == 200 assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None assert "X-Capture-This" in wsgi_span.data["http"]["header"] - assert "Ok" == wsgi_span.data["http"]["header"]["X-Capture-This"] + assert wsgi_span.data["http"]["header"]["X-Capture-This"] == "Ok" assert "X-Capture-That" in wsgi_span.data["http"]["header"] - assert "Ok too" == wsgi_span.data["http"]["header"]["X-Capture-That"] + assert wsgi_span.data["http"]["header"]["X-Capture-That"] == "Ok too" agent.options.extra_http_headers = original_extra_http_headers def test_request_started_exception(self) -> None: - with self.tracer.start_as_current_span("test"): - with patch( + with ( + self.tracer.start_as_current_span("test"), + patch( "instana.singletons.tracer.extract", side_effect=Exception("mocked error"), - ): - self.http.request("GET", testenv["flask_server"] + "/") + ), + ): + self.http.request("GET", testenv["flask_server"] + "/") spans = self.recorder.queued_spans() assert len(spans) == 2 @@ -1181,7 +1183,7 @@ def test_got_request_exception(self) -> None: wsgi_span = spans[0] assert response - assert 500 == response.status + assert response.status == 500 assert get_current_span().is_recording() is False @@ -1193,8 +1195,8 @@ def test_got_request_exception(self) -> None: assert ( "127.0.0.1:" + str(testenv["flask_port"]) == wsgi_span.data["http"]["host"] ) - assert "/got_request_exception" == wsgi_span.data["http"]["url"] - assert "GET" == wsgi_span.data["http"]["method"] + assert wsgi_span.data["http"]["url"] == "/got_request_exception" + assert wsgi_span.data["http"]["method"] == "GET" assert wsgi_span.data["http"]["status"] == 500 assert wsgi_span.data["http"]["error"] == "RuntimeError()" assert wsgi_span.stack is None diff --git a/tests/frameworks/test_gevent_autotrace.py b/tests/frameworks/test_gevent_autotrace.py index 7a7a2b8b..a1db6182 100644 --- a/tests/frameworks/test_gevent_autotrace.py +++ b/tests/frameworks/test_gevent_autotrace.py @@ -3,37 +3,47 @@ import importlib import os -import pytest -import gevent +import gevent # noqa: F401 +import pytest from gevent import monkey + from instana import apply_gevent_monkey_patch + # Teardown not working as expected, run each testcase separately class TestGEventAutoTrace: - @pytest.fixture(autouse=True) def setup_environment(self): """Setup test environment before each test""" # Ensure that the test suite is operational even when Django is installed # but not running or configured - os.environ['DJANGO_SETTINGS_MODULE'] = '' - - self.default_patched_modules = ('socket', 'time', 'select', 'os', - 'threading', 'ssl', 'subprocess', 'signal', 'queue',) - + os.environ["DJANGO_SETTINGS_MODULE"] = "" + + self.default_patched_modules = ( + "socket", + "time", + "select", + "os", + "threading", + "ssl", + "subprocess", + "signal", + "queue", + ) + yield - + # Teardown - if os.environ.get('INSTANA_GEVENT_MONKEY_OPTIONS'): - os.environ.pop('INSTANA_GEVENT_MONKEY_OPTIONS') - + if os.environ.get("INSTANA_GEVENT_MONKEY_OPTIONS"): + os.environ.pop("INSTANA_GEVENT_MONKEY_OPTIONS") + # Clean up after gevent monkey patches, by restore from the saved dict - for modname in monkey.saved.keys(): + for modname in monkey.saved: try: mod = __import__(modname) importlib.reload(mod) - for key in monkey.saved[modname].keys(): + for key in monkey.saved[modname]: setattr(mod, key, monkey.saved[modname][key]) except ImportError: pass @@ -42,31 +52,41 @@ def setup_environment(self): def test_default_patch_all(self): apply_gevent_monkey_patch() for module_name in self.default_patched_modules: - assert monkey.is_module_patched(module_name), f"{module_name} is not patched" + assert monkey.is_module_patched(module_name), ( + f"{module_name} is not patched" + ) def test_instana_monkey_options_only_time(self): - os.environ['INSTANA_GEVENT_MONKEY_OPTIONS'] = ( - 'time,no-socket,no-select,no-os,no-select,no-threading,no-os,' - 'no-ssl,no-subprocess,''no-signal,no-queue') + os.environ["INSTANA_GEVENT_MONKEY_OPTIONS"] = ( + "time,no-socket,no-select,no-os,no-select,no-threading,no-os," + "no-ssl,no-subprocess," + "no-signal,no-queue" + ) apply_gevent_monkey_patch() - - assert monkey.is_module_patched('time'), "time module is not patched" - not_patched_modules = (m for m in self.default_patched_modules if m not in ('time', 'threading')) - + + assert monkey.is_module_patched("time"), "time module is not patched" + not_patched_modules = ( + m for m in self.default_patched_modules if m not in ("time", "threading") + ) + for module_name in not_patched_modules: - assert not monkey.is_module_patched(module_name), \ - f"{module_name} is patched, when it shouldn't be" + assert not monkey.is_module_patched(module_name), ( + f"{module_name} is patched, when it shouldn't be" + ) def test_instana_monkey_options_only_socket(self): - os.environ['INSTANA_GEVENT_MONKEY_OPTIONS'] = ( - '--socket, --no-time, --no-select, --no-os, --no-queue, --no-threading,' - '--no-os, --no-ssl, no-subprocess, --no-signal, --no-select,') + os.environ["INSTANA_GEVENT_MONKEY_OPTIONS"] = ( + "--socket, --no-time, --no-select, --no-os, --no-queue, --no-threading," + "--no-os, --no-ssl, no-subprocess, --no-signal, --no-select," + ) apply_gevent_monkey_patch() - - assert monkey.is_module_patched('socket'), "socket module is not patched" - not_patched_modules = (m for m in self.default_patched_modules if m not in ('socket', 'threading')) - - for module_name in not_patched_modules: - assert not monkey.is_module_patched(module_name), \ - f"{module_name} is patched, when it shouldn't be" + assert monkey.is_module_patched("socket"), "socket module is not patched" + not_patched_modules = ( + m for m in self.default_patched_modules if m not in ("socket", "threading") + ) + + for module_name in not_patched_modules: + assert not monkey.is_module_patched(module_name), ( + f"{module_name} is patched, when it shouldn't be" + ) diff --git a/tests/frameworks/test_grpcio.py b/tests/frameworks/test_grpcio.py index 2b716e1a..45b2a803 100644 --- a/tests/frameworks/test_grpcio.py +++ b/tests/frameworks/test_grpcio.py @@ -2,22 +2,21 @@ # (c) Copyright Instana Inc. 2020 -import time +import contextlib import random +import time from typing import Generator -import pytest import grpc - +import pytest from opentelemetry.trace import SpanKind import tests.apps.grpc_server # noqa: F401 import tests.apps.grpc_server.stan_pb2 as stan_pb2 import tests.apps.grpc_server.stan_pb2_grpc as stan_pb2_grpc -from tests.helpers import testenv, get_first_span_by_name - from instana.singletons import agent, get_tracer from instana.span.span import get_current_span +from tests.helpers import get_first_span_by_name, testenv class TestGRPCIO: @@ -584,13 +583,11 @@ def process_response(future): def test_server_error(self) -> None: response = None - with self.tracer.start_as_current_span("test"): - try: + with self.tracer.start_as_current_span("test"): # noqa: SIM117 + with contextlib.suppress(Exception): response = self.server_stub.OneQuestionOneErrorResponse( stan_pb2.QuestionRequest(question="Do u error?") ) - except Exception: - pass assert not get_current_span().is_recording() assert not response diff --git a/tests/frameworks/test_sanic.py b/tests/frameworks/test_sanic.py index 5fe57436..9d273ed4 100644 --- a/tests/frameworks/test_sanic.py +++ b/tests/frameworks/test_sanic.py @@ -515,9 +515,9 @@ def test_request_header_capture(self) -> None: assert not asgi_span.data["http"]["params"] assert "X-Capture-This" in asgi_span.data["http"]["header"] - assert "this" == asgi_span.data["http"]["header"]["X-Capture-This"] + assert asgi_span.data["http"]["header"]["X-Capture-This"] == "this" assert "X-Capture-That" in asgi_span.data["http"]["header"] - assert "that" == asgi_span.data["http"]["header"]["X-Capture-That"] + assert asgi_span.data["http"]["header"]["X-Capture-That"] == "that" def test_response_header_capture(self) -> None: path = "/response_headers" @@ -562,6 +562,6 @@ def test_response_header_capture(self) -> None: assert not asgi_span.data["http"]["params"] assert "X-Capture-This-Too" in asgi_span.data["http"]["header"] - assert "this too" == asgi_span.data["http"]["header"]["X-Capture-This-Too"] + assert asgi_span.data["http"]["header"]["X-Capture-This-Too"] == "this too" assert "X-Capture-That-Too" in asgi_span.data["http"]["header"] - assert "that too" == asgi_span.data["http"]["header"]["X-Capture-That-Too"] + assert asgi_span.data["http"]["header"]["X-Capture-That-Too"] == "that too" diff --git a/tests/frameworks/test_starlette.py b/tests/frameworks/test_starlette.py index 6da96a6c..283a6cdc 100644 --- a/tests/frameworks/test_starlette.py +++ b/tests/frameworks/test_starlette.py @@ -299,9 +299,9 @@ def test_request_header_capture(self) -> None: assert not asgi_span.data["http"]["params"] assert "X-Capture-This" in asgi_span.data["http"]["header"] - assert "this" == asgi_span.data["http"]["header"]["X-Capture-This"] + assert asgi_span.data["http"]["header"]["X-Capture-This"] == "this" assert "X-Capture-That" in asgi_span.data["http"]["header"] - assert "that" == asgi_span.data["http"]["header"]["X-Capture-That"] + assert asgi_span.data["http"]["header"]["X-Capture-That"] == "that" def test_response_header_capture(self) -> None: with self.tracer.start_as_current_span("test") as span: @@ -352,6 +352,6 @@ def test_response_header_capture(self) -> None: assert not asgi_span.data["http"]["params"] assert "X-Capture-This-Too" in asgi_span.data["http"]["header"] - assert "this too" == asgi_span.data["http"]["header"]["X-Capture-This-Too"] + assert asgi_span.data["http"]["header"]["X-Capture-This-Too"] == "this too" assert "X-Capture-That-Too" in asgi_span.data["http"]["header"] - assert "that too" == asgi_span.data["http"]["header"]["X-Capture-That-Too"] + assert asgi_span.data["http"]["header"]["X-Capture-That-Too"] == "that too" diff --git a/tests/frameworks/test_tornado_client.py b/tests/frameworks/test_tornado_client.py index 65166b7d..920607de 100644 --- a/tests/frameworks/test_tornado_client.py +++ b/tests/frameworks/test_tornado_client.py @@ -468,13 +468,13 @@ async def test(): assert server_span.n == "tornado-server" assert server_span.data["http"]["status"] == 200 assert testenv["tornado_server"] + "/" == server_span.data["http"]["url"] - assert "secret=" == server_span.data["http"]["params"] + assert server_span.data["http"]["params"] == "secret=" assert server_span.data["http"]["method"] == "GET" assert client_span.n == "tornado-client" assert client_span.data["http"]["status"] == 200 assert testenv["tornado_server"] + "/" == client_span.data["http"]["url"] - assert "secret=" == client_span.data["http"]["params"] + assert client_span.data["http"]["params"] == "secret=" assert client_span.data["http"]["method"] == "GET" assert client_span.stack assert type(client_span.stack) is list diff --git a/tests/frameworks/test_tornado_server.py b/tests/frameworks/test_tornado_server.py index f7e13388..ddba6bf9 100644 --- a/tests/frameworks/test_tornado_server.py +++ b/tests/frameworks/test_tornado_server.py @@ -388,7 +388,7 @@ async def test(): assert aiohttp_span.data["http"]["status"] == 500 assert testenv["tornado_server"] + "/500" == aiohttp_span.data["http"]["url"] assert aiohttp_span.data["http"]["method"] == "GET" - assert "Internal Server Error" == aiohttp_span.data["http"]["error"] + assert aiohttp_span.data["http"]["error"] == "Internal Server Error" assert aiohttp_span.stack assert isinstance(aiohttp_span.stack, list) assert len(aiohttp_span.stack) > 1 @@ -451,7 +451,7 @@ async def test(): assert aiohttp_span.data["http"]["status"] == 504 assert testenv["tornado_server"] + "/504" == aiohttp_span.data["http"]["url"] assert aiohttp_span.data["http"]["method"] == "GET" - assert "Gateway Timeout" == aiohttp_span.data["http"]["error"] + assert aiohttp_span.data["http"]["error"] == "Gateway Timeout" assert aiohttp_span.stack assert isinstance(aiohttp_span.stack, list) assert len(aiohttp_span.stack) > 1 diff --git a/tests/frameworks/test_wsgi.py b/tests/frameworks/test_wsgi.py index 056a4c01..ba562511 100644 --- a/tests/frameworks/test_wsgi.py +++ b/tests/frameworks/test_wsgi.py @@ -28,7 +28,7 @@ def test_vanilla_requests(self) -> None: response = self.http.request("GET", testenv["wsgi_server"] + "/") spans = self.recorder.queued_spans() - assert 1 == len(spans) + assert len(spans) == 1 assert get_current_span().is_recording() is False assert response.status == 200 @@ -38,7 +38,7 @@ def test_get_request(self) -> None: spans = self.recorder.queued_spans() - assert 3 == len(spans) + assert len(spans) == 3 assert get_current_span().is_recording() is False wsgi_span = spans[0] @@ -46,7 +46,7 @@ def test_get_request(self) -> None: test_span = spans[2] assert response - assert 200 == response.status + assert response.status == 200 assert "X-INSTANA-T" in response.headers assert int(response.headers["X-INSTANA-T"], 16) @@ -81,13 +81,13 @@ def test_get_request(self) -> None: assert wsgi_span.ec is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["wsgi_port"]) == wsgi_span.data["http"]["host"] ) - assert "/" == wsgi_span.data["http"]["path"] - assert "GET" == wsgi_span.data["http"]["method"] - assert "200" == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["path"] == "/" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == "200" assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None @@ -98,7 +98,7 @@ def test_synthetic_request(self) -> None: spans = self.recorder.queued_spans() - assert 3 == len(spans) + assert len(spans) == 3 assert get_current_span().is_recording() is False wsgi_span = spans[0] @@ -117,7 +117,7 @@ def test_secret_scrubbing(self) -> None: spans = self.recorder.queued_spans() - assert 3 == len(spans) + assert len(spans) == 3 assert get_current_span().is_recording() is False wsgi_span = spans[0] @@ -125,7 +125,7 @@ def test_secret_scrubbing(self) -> None: test_span = spans[2] assert response - assert 200 == response.status + assert response.status == 200 assert "X-INSTANA-T" in response.headers assert int(response.headers["X-INSTANA-T"], 16) @@ -156,14 +156,14 @@ def test_secret_scrubbing(self) -> None: assert wsgi_span.ec is None # wsgi - assert "wsgi" == wsgi_span.n + assert wsgi_span.n == "wsgi" assert ( "127.0.0.1:" + str(testenv["wsgi_port"]) == wsgi_span.data["http"]["host"] ) - assert "/" == wsgi_span.data["http"]["path"] - assert "secret=" == wsgi_span.data["http"]["params"] - assert "GET" == wsgi_span.data["http"]["method"] - assert "200" == wsgi_span.data["http"]["status"] + assert wsgi_span.data["http"]["path"] == "/" + assert wsgi_span.data["http"]["params"] == "secret=" + assert wsgi_span.data["http"]["method"] == "GET" + assert wsgi_span.data["http"]["status"] == "200" assert wsgi_span.data["http"]["error"] is None assert wsgi_span.stack is None @@ -177,10 +177,10 @@ def test_with_incoming_context(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 1 == len(spans) + assert len(spans) == 1 wsgi_span = spans[0] @@ -214,10 +214,10 @@ def test_with_incoming_mixed_case_context(self) -> None: ) assert response - assert 200 == response.status + assert response.status == 200 spans = self.recorder.queued_spans() - assert 1 == len(spans) + assert len(spans) == 1 wsgi_span = spans[0] diff --git a/tests/helpers.py b/tests/helpers.py index 07cd94e0..050e18a4 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -101,7 +101,7 @@ def fail_with_message_and_span_dump(msg, spans): @return: None """ span_count = len(spans) - span_dump = "\nDumping all collected spans (%d) -->\n" % span_count + span_dump = f"\nDumping all collected spans ({span_count}) -->\n" if span_count > 0: for span in spans: span.stack = "" diff --git a/tests/propagators/test_base_propagator.py b/tests/propagators/test_base_propagator.py index 5c50e901..ed299d1d 100644 --- a/tests/propagators/test_base_propagator.py +++ b/tests/propagators/test_base_propagator.py @@ -27,8 +27,8 @@ def test_extract_headers_dict(self) -> None: assert self.propagator.extract_headers_dict(wrong_carrier) is None def test_get_ctx_level(self) -> None: - assert 3 == self.propagator._get_ctx_level("3,4") - assert 1 == self.propagator._get_ctx_level("wrong_data") + assert self.propagator._get_ctx_level("3,4") == 3 + assert self.propagator._get_ctx_level("wrong_data") == 1 def test_get_correlation_properties(self) -> None: a, b = self.propagator._get_correlation_properties( @@ -36,8 +36,11 @@ def test_get_correlation_properties(self) -> None: ) assert a == "3" assert b == "5" - assert "3", None == self.propagator._get_correlation_properties( # noqa: E711 - ",correlationType=3;" + assert "3", ( + self.propagator._get_correlation_properties( # noqa: E711 + ",correlationType=3;" + ) + is None ) def test_get_participating_trace_context(self, span_context) -> None: diff --git a/tests/propagators/test_http_propagator.py b/tests/propagators/test_http_propagator.py index 76014345..dfb3ce5f 100644 --- a/tests/propagators/test_http_propagator.py +++ b/tests/propagators/test_http_propagator.py @@ -318,7 +318,7 @@ def test_w3c_off_x_instana_l_0( assert not span_ctx.correlation_id # Assert that the traceparent is propagated when it is enabled - if "traceparent" in carrier_header.keys(): + if "traceparent" in carrier_header: assert span_ctx.traceparent tp_trace_id = header_to_long_id(carrier_header["traceparent"].split("-")[1]) else: @@ -326,7 +326,7 @@ def test_w3c_off_x_instana_l_0( tp_trace_id = span_ctx.trace_id # Assert that the tracestate is propagated when it is enabled - if "tracestate" in carrier_header.keys(): + if "tracestate" in carrier_header: assert span_ctx.tracestate else: assert not span_ctx.tracestate @@ -352,7 +352,7 @@ def test_w3c_off_x_instana_l_0( ) # Assert that the tracestate is propagated when it is enabled - if "tracestate" in carrier_header.keys(): + if "tracestate" in carrier_header: assert "tracestate" in downstream_carrier assert carrier_header["tracestate"] == downstream_carrier["tracestate"] diff --git a/tests/recorder/test_stan_recorder.py b/tests/recorder/test_stan_recorder.py index c5b2eb91..d1ca77ef 100644 --- a/tests/recorder/test_stan_recorder.py +++ b/tests/recorder/test_stan_recorder.py @@ -1,3 +1,5 @@ +# (c) Copyright IBM Corp. 2026 + import sys from multiprocessing import Queue from unittest import TestCase diff --git a/tests/span/test_base_span.py b/tests/span/test_base_span.py index 0551a7d5..b10ec4fa 100644 --- a/tests/span/test_base_span.py +++ b/tests/span/test_base_span.py @@ -104,9 +104,9 @@ def test_populate_extra_span_attributes_with_values( # synthetic should be true only for entry spans assert not base_span.sy assert base_span.tp - assert "IDK" == base_span.ia + assert base_span.ia == "IDK" assert long_id == base_span.lt - assert "IDK" == base_span.crtp + assert base_span.crtp == "IDK" assert long_id == base_span.crid @@ -122,7 +122,7 @@ def test_validate_attributes( assert isinstance(filtered_attributes, dict) assert len(attributes) == len(filtered_attributes) for key, value in attributes.items(): - assert key in filtered_attributes.keys() + assert key in filtered_attributes assert value in filtered_attributes.values() diff --git a/tests/span/test_event.py b/tests/span/test_event.py index f80e7475..93233ae5 100644 --- a/tests/span/test_event.py +++ b/tests/span/test_event.py @@ -32,8 +32,8 @@ def test_span_event(): assert event.name == event_name assert event.attributes assert len(event.attributes) == 2 - assert "field1" in event.attributes.keys() - assert "two" == event.attributes.get("field2") + assert "field1" in event.attributes + assert event.attributes.get("field2") == "two" assert event.timestamp == timestamp diff --git a/tests/span/test_registered_span.py b/tests/span/test_registered_span.py index d54100a4..71006ee0 100644 --- a/tests/span/test_registered_span.py +++ b/tests/span/test_registered_span.py @@ -57,7 +57,7 @@ def test_registered_span( assert expected_result[0] == reg_span.n assert expected_result[1] == reg_span.k assert service_name == reg_span.data["service"] - assert expected_result[2] in reg_span.data.keys() + assert expected_result[2] in reg_span.data def test_collect_http_attributes_with_attributes( self, @@ -226,9 +226,9 @@ def test_populate_entry_span_data_AWSlambda( self.span.set_attributes(attributes) reg_span._populate_entry_span_data(self.span) - assert "python" == reg_span.data["lambda"]["runtime"] - assert "Unknown" == reg_span.data["lambda"]["functionName"] - assert "test" == reg_span.data["lambda"]["arn"] + assert reg_span.data["lambda"]["runtime"] == "python" + assert reg_span.data["lambda"]["functionName"] == "Unknown" + assert reg_span.data["lambda"]["arn"] == "test" assert expected_result["lambda.trigger"] == reg_span.data["lambda"]["trigger"] if expected_result["lambda.trigger"] == "aws:api.gateway": diff --git a/tests/span/test_span.py b/tests/span/test_span.py index 63afb5cd..c5c7f358 100644 --- a/tests/span/test_span.py +++ b/tests/span/test_span.py @@ -88,8 +88,8 @@ def test_span_set_attributes_default( assert self.span.attributes assert len(self.span.attributes) == 2 - assert "field1" in self.span.attributes.keys() - assert "two" == self.span.attributes.get("field2") + assert "field1" in self.span.attributes + assert self.span.attributes.get("field2") == "two" def test_span_set_attributes( self, @@ -107,8 +107,8 @@ def test_span_set_attributes( assert self.span.attributes assert len(self.span.attributes) == 2 - assert "field1" in self.span.attributes.keys() - assert "two" == self.span.attributes.get("field2") + assert "field1" in self.span.attributes + assert self.span.attributes.get("field2") == "two" attributes = { "field3": True, @@ -117,7 +117,7 @@ def test_span_set_attributes( self.span.set_attributes(attributes) assert len(self.span.attributes) == 4 - assert "field3" in self.span.attributes.keys() + assert "field3" in self.span.attributes assert "vier" in self.span.attributes.get("field4") def test_span_set_attribute_default( @@ -139,8 +139,8 @@ def test_span_set_attribute_default( assert self.span.attributes assert len(self.span.attributes) == 2 - assert "field1" in self.span.attributes.keys() - assert "two" == self.span.attributes.get("field2") + assert "field1" in self.span.attributes + assert self.span.attributes.get("field2") == "two" def test_span_set_attribute( self, @@ -158,8 +158,8 @@ def test_span_set_attribute( assert self.span.attributes assert len(self.span.attributes) == 2 - assert "field1" in self.span.attributes.keys() - assert "two" == self.span.attributes.get("field2") + assert "field1" in self.span.attributes + assert self.span.attributes.get("field2") == "two" attributes = { "field3": True, @@ -169,7 +169,7 @@ def test_span_set_attribute( self.span.set_attribute(key, value) assert len(self.span.attributes) == 4 - assert "field3" in self.span.attributes.keys() + assert "field3" in self.span.attributes assert "vier" in self.span.attributes.get("field4") def test_span_update_name( @@ -590,14 +590,14 @@ def test_span_record_exception_default( self.span.record_exception(exception) assert span_name == self.span.name - assert 1 == self.span.attributes.get("ec", 0) + assert self.span.attributes.get("ec", 0) == 1 if span_attribute: - assert span_attribute in self.span.attributes.keys() + assert span_attribute in self.span.attributes.keys() # noqa: SIM118 assert exception_msg == self.span.attributes.get(span_attribute, None) else: event = self.span.events[-1] # always get the latest event assert isinstance(event, Event) - assert "exception" == event.name + assert event.name == "exception" assert exception_msg == event.attributes.get("message", None) def test_span_record_exception_with_attribute( @@ -617,13 +617,13 @@ def test_span_record_exception_with_attribute( self.span.record_exception(exception, attributes) assert span_name == self.span.name - assert 1 == self.span.attributes.get("ec", 0) + assert self.span.attributes.get("ec", 0) == 1 event = self.span.events[-1] # always get the latest event assert isinstance(event, Event) - assert 2 == len(event.attributes) + assert len(event.attributes) == 2 assert exception_msg == event.attributes.get("message", None) - assert 0 == event.attributes.get("custom_attr", None) + assert event.attributes.get("custom_attr", None) == 0 def test_span_record_exception_with_Exception_msg( self, @@ -641,8 +641,8 @@ def test_span_record_exception_with_Exception_msg( self.span.record_exception(exception) assert span_name == self.span.name - assert 1 == self.span.attributes.get("ec", 0) - assert span_attribute in self.span.attributes.keys() + assert self.span.attributes.get("ec", 0) == 1 + assert span_attribute in self.span.attributes assert exception_msg == self.span.attributes.get(span_attribute, None) def test_span_record_exception_with_Exception_none_msg( @@ -660,9 +660,9 @@ def test_span_record_exception_with_Exception_none_msg( self.span.record_exception(exception) assert span_name == self.span.name - assert 1 == self.span.attributes.get("ec", 0) - assert span_attribute in self.span.attributes.keys() - assert "Exception()" == self.span.attributes.get(span_attribute, None) + assert self.span.attributes.get("ec", 0) == 1 + assert span_attribute in self.span.attributes + assert self.span.attributes.get(span_attribute, None) == "Exception()" def test_span_record_exception_with_Exception_raised( self, @@ -674,12 +674,14 @@ def test_span_record_exception_with_Exception_raised( exception = None self.span = InstanaSpan(span_name, span_context, span_processor) - with patch( - "instana.span.span.InstanaSpan.add_event", - side_effect=Exception("mocked error"), + with ( + patch( + "instana.span.span.InstanaSpan.add_event", + side_effect=Exception("mocked error"), + ), + pytest.raises(Exception), ): - with pytest.raises(Exception): - self.span.record_exception(exception) + self.span.record_exception(exception) def test_span_end_default( self, @@ -762,7 +764,7 @@ def test_span_mark_as_errored( assert self.span.attributes assert len(self.span.attributes) == 3 assert self.span.attributes.get("ec") == 1 - assert "field1" in self.span.attributes.keys() + assert "field1" in self.span.attributes assert self.span.attributes.get("field2") == "two" self.span.mark_as_errored() @@ -770,7 +772,7 @@ def test_span_mark_as_errored( assert self.span.attributes assert len(self.span.attributes) == 3 assert self.span.attributes.get("ec") == 2 - assert "field1" in self.span.attributes.keys() + assert "field1" in self.span.attributes assert self.span.attributes.get("field2") == "two" def test_span_mark_as_errored_exception( diff --git a/tests/span/test_span_sdk.py b/tests/span/test_span_sdk.py index c922d856..ed3a741e 100644 --- a/tests/span/test_span_sdk.py +++ b/tests/span/test_span_sdk.py @@ -28,7 +28,11 @@ def test_sdkspan( "return": "True", } self.span = InstanaSpan( - span_name, span_context, span_processor, attributes=attributes, kind=SpanKind.SERVER + span_name, + span_context, + span_processor, + attributes=attributes, + kind=SpanKind.SERVER, ) sdk_span = SDKSpan(self.span, None, service_name) @@ -98,4 +102,4 @@ def test_sdkspan_get_span_kind_default( ) -> None: self.span = SDKSpan(span, None, "test") kind = self.span.get_span_kind(span) - assert ("intermediate", 3) == kind + assert kind == ("intermediate", 3) diff --git a/tests/span/test_span_stack_trace.py b/tests/span/test_span_stack_trace.py index e31df2be..eb79fd66 100644 --- a/tests/span/test_span_stack_trace.py +++ b/tests/span/test_span_stack_trace.py @@ -30,15 +30,15 @@ def test_add_stack_hard_limit( """Test that stack trace is capped at 40 frames even with higher limit.""" span_name = "redis" # EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + # Manually set a high limit in options span_processor.agent.options.stack_trace_length = 50 - + # Call add_stack directly with is_errored=False stack = add_stack( level=span_processor.agent.options.stack_trace_level, limit=span_processor.agent.options.stack_trace_length, - is_errored=False + is_errored=False, ) # Check if default is set @@ -49,9 +49,9 @@ def test_add_stack_hard_limit( stack_0 = stack[0] assert len(stack_0) == 3 - assert "c" in stack_0.keys() - assert "n" in stack_0.keys() - assert "m" in stack_0.keys() + assert "c" in stack_0 + assert "n" in stack_0 + assert "m" in stack_0 def test_add_stack_level_all( self, @@ -61,16 +61,16 @@ def test_add_stack_level_all( """Test stack trace collection with level='all'.""" span_name = "http" # EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + span_processor.agent.options.stack_trace_level = "all" test_limit = 5 span_processor.agent.options.stack_trace_length = test_limit - + # Non-errored span should get stack trace stack = add_stack( level=span_processor.agent.options.stack_trace_level, limit=span_processor.agent.options.stack_trace_length, - is_errored=False + is_errored=False, ) assert stack @@ -84,15 +84,15 @@ def test_add_stack_level_error_not_errored( """Test that non-errored spans don't get stack trace with level='error'.""" span_name = "http" # EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + span_processor.agent.options.stack_trace_level = "error" span_processor.agent.options.stack_trace_length = 35 - + # Non-errored span should NOT get stack trace stack = add_stack( level=span_processor.agent.options.stack_trace_level, limit=span_processor.agent.options.stack_trace_length, - is_errored=False + is_errored=False, ) assert stack is None @@ -105,16 +105,16 @@ def test_add_stack_level_error_errored( """Test that errored spans get full stack trace with level='error'.""" span_name = "http" # EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + span_processor.agent.options.stack_trace_level = "error" test_limit = 10 span_processor.agent.options.stack_trace_length = test_limit - + # Errored span should get FULL stack trace (no limit) stack = add_stack( level=span_processor.agent.options.stack_trace_level, limit=span_processor.agent.options.stack_trace_length, - is_errored=True + is_errored=True, ) assert stack @@ -129,23 +129,23 @@ def test_add_stack_level_none( """Test that no stack trace is collected with level='none'.""" span_name = "http" # EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + span_processor.agent.options.stack_trace_level = "none" span_processor.agent.options.stack_trace_length = 20 - + # Should NOT get stack trace stack = add_stack( level=span_processor.agent.options.stack_trace_level, limit=span_processor.agent.options.stack_trace_length, - is_errored=False + is_errored=False, ) assert stack is None - + # Even errored spans should not get stack trace stack = add_stack( level=span_processor.agent.options.stack_trace_level, limit=span_processor.agent.options.stack_trace_length, - is_errored=True + is_errored=True, ) assert stack is None @@ -157,17 +157,17 @@ def test_add_stack_errored_span_full_stack( """Test that errored spans get full stack regardless of level setting.""" span_name = "mysql" # EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + # Set level to 'all' with a low limit span_processor.agent.options.stack_trace_level = "all" test_limit = 5 span_processor.agent.options.stack_trace_length = test_limit - + # Errored span should get FULL stack (not limited to 5) stack = add_stack( level=span_processor.agent.options.stack_trace_level, limit=span_processor.agent.options.stack_trace_length, - is_errored=True + is_errored=True, ) assert stack @@ -182,7 +182,7 @@ def test_add_stack_trace_if_needed_exit_span( """Test add_stack_trace_if_needed for EXIT spans.""" span_name = "redis" # EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + # Call the function that checks if it's an EXIT span add_stack_trace_if_needed(self.span) @@ -196,7 +196,7 @@ def test_add_stack_trace_if_needed_non_exit_span( """Test add_stack_trace_if_needed for non-EXIT spans.""" span_name = "wsgi" # Not an EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + # Call the function - should not add stack for non-EXIT spans add_stack_trace_if_needed(self.span) @@ -213,10 +213,10 @@ def test_add_stack_trace_if_needed_errored_span( self.span = InstanaSpan( span_name, span_context, span_processor, attributes=attributes ) - + test_limit = 5 span_processor.agent.options.stack_trace_length = test_limit - + # Call the function - should detect error and use full stack add_stack_trace_if_needed(self.span) @@ -232,9 +232,9 @@ def test_span_end_collects_stack_trace( """Test that span.end() triggers stack trace collection for EXIT spans.""" span_name = "urllib3" # EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + assert not self.span.stack - + # End the span - should trigger stack trace collection self.span.end() @@ -249,15 +249,15 @@ def test_stack_frame_format( """Test that stack frames have correct format.""" span_name = "postgres" # EXIT span self.span = InstanaSpan(span_name, span_context, span_processor) - + test_limit = 5 span_processor.agent.options.stack_trace_length = test_limit - + # Use add_stack directly stack = add_stack( level=span_processor.agent.options.stack_trace_level, limit=span_processor.agent.options.stack_trace_length, - is_errored=False + is_errored=False, ) assert stack diff --git a/tests/test_fsm_cmdline.py b/tests/test_fsm_cmdline.py index 5c9eed99..903a8eb5 100644 --- a/tests/test_fsm_cmdline.py +++ b/tests/test_fsm_cmdline.py @@ -121,13 +121,13 @@ def test_get_cmdline_linux_proc( def test_get_cmdline_linux_proc_file_not_found(self) -> None: """Test _get_cmdline_linux_proc when file doesn't exist.""" - with patch("builtins.open", side_effect=FileNotFoundError()): + with patch("builtins.open", side_effect=FileNotFoundError()): # noqa: SIM117 with pytest.raises(FileNotFoundError): self.machine._get_cmdline_linux_proc() def test_get_cmdline_linux_proc_permission_error(self) -> None: """Test _get_cmdline_linux_proc with permission error.""" - with patch("builtins.open", side_effect=PermissionError()): + with patch("builtins.open", side_effect=PermissionError()): # noqa: SIM117 with pytest.raises(PermissionError): self.machine._get_cmdline_linux_proc() @@ -187,11 +187,13 @@ def test_get_cmdline_unix_ps_empty_output(self) -> None: def test_get_cmdline_unix_ps_subprocess_error(self) -> None: """Test _get_cmdline_unix_ps when subprocess fails.""" - with patch( - "subprocess.Popen", side_effect=subprocess.SubprocessError("Test error") + with ( + patch( + "subprocess.Popen", side_effect=subprocess.SubprocessError("Test error") + ), + pytest.raises(subprocess.SubprocessError), ): - with pytest.raises(subprocess.SubprocessError): - self.machine._get_cmdline_unix_ps(1234) + self.machine._get_cmdline_unix_ps(1234) @pytest.mark.parametrize( "proc_exists,proc_content,expected_output", @@ -263,18 +265,28 @@ def test_get_cmdline_platform_detection( def test_get_cmdline_windows_exception_fallback(self) -> None: """Test _get_cmdline falls back to sys.argv on Windows exception.""" - with patch("instana.fsm.is_windows", return_value=True), patch.object( - self.machine, "_get_cmdline_windows", side_effect=Exception("Test error") - ), patch("instana.fsm.logger.debug") as mock_logger: + with ( + patch("instana.fsm.is_windows", return_value=True), + patch.object( + self.machine, + "_get_cmdline_windows", + side_effect=Exception("Test error"), + ), + patch("instana.fsm.logger.debug") as mock_logger, + ): result = self.machine._get_cmdline(1234) assert result == sys.argv mock_logger.assert_called_once() def test_get_cmdline_unix_exception_fallback(self) -> None: """Test _get_cmdline falls back to sys.argv on Unix exception.""" - with patch("instana.fsm.is_windows", return_value=False), patch.object( - self.machine, "_get_cmdline_unix", side_effect=Exception("Test error") - ), patch("instana.fsm.logger.debug") as mock_logger: + with ( + patch("instana.fsm.is_windows", return_value=False), + patch.object( + self.machine, "_get_cmdline_unix", side_effect=Exception("Test error") + ), + patch("instana.fsm.logger.debug") as mock_logger, + ): result = self.machine._get_cmdline(1234) assert result == sys.argv mock_logger.assert_called_once() @@ -298,8 +310,13 @@ def test_get_cmdline_unix_exception_fallback(self) -> None: ) def test_get_cmdline_various_exceptions(self, exception_type: type) -> None: """Test _get_cmdline handles various exception types gracefully.""" - with patch("instana.fsm.is_windows", return_value=False), patch.object( - self.machine, "_get_cmdline_unix", side_effect=exception_type("Test error") + with ( + patch("instana.fsm.is_windows", return_value=False), + patch.object( + self.machine, + "_get_cmdline_unix", + side_effect=exception_type("Test error"), + ), ): result = self.machine._get_cmdline(1234) assert result == sys.argv @@ -307,9 +324,12 @@ def test_get_cmdline_various_exceptions(self, exception_type: type) -> None: def test_get_cmdline_with_actual_pid(self) -> None: """Test _get_cmdline with actual process ID.""" current_pid = os.getpid() - with patch("instana.fsm.is_windows", return_value=False), patch.object( - self.machine, "_get_cmdline_unix", return_value=["test_cmd"] - ) as mock_method: + with ( + patch("instana.fsm.is_windows", return_value=False), + patch.object( + self.machine, "_get_cmdline_unix", return_value=["test_cmd"] + ) as mock_method, + ): result = self.machine._get_cmdline(current_pid) assert result == ["test_cmd"] mock_method.assert_called_once_with(current_pid) diff --git a/tests/test_options.py b/tests/test_options.py index e0a4d35f..7f40ca41 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -47,7 +47,7 @@ class TestBaseOptions: def _resource(self) -> Generator[None, None, None]: self.base_options = None yield - if "tracing" in config.keys(): + if "tracing" in config: del config["tracing"] def test_base_options(self) -> None: @@ -788,7 +788,7 @@ class TestStandardOptions: def _resource(self) -> Generator[None, None, None]: self.standart_options = None yield - if "tracing" in config.keys(): + if "tracing" in config: del config["tracing"] def test_standard_options(self) -> None: @@ -1143,7 +1143,7 @@ class TestStackTraceConfiguration: def _resource(self) -> Generator[None, None, None]: self.options = None yield - if "tracing" in config.keys(): + if "tracing" in config: del config["tracing"] def test_stack_trace_defaults(self) -> None: diff --git a/tests/util/test_gunicorn.py b/tests/util/test_gunicorn.py new file mode 100644 index 00000000..7b2370b3 --- /dev/null +++ b/tests/util/test_gunicorn.py @@ -0,0 +1,305 @@ +# (c) Copyright IBM Corp. 2026 + +import os +import sys +from unittest import mock + +import pytest + +from instana.log import running_in_gunicorn + + +class TestRunningInGunicorn: + """Test suite for running_in_gunicorn() function""" + + @pytest.mark.parametrize( + "argv,expected,description", + [ + # Positive cases - gunicorn should be detected + (["gunicorn", "app:application"], True, "gunicorn as first argument"), + (["python", "-m", "gunicorn", "app"], True, "gunicorn in middle"), + (["/usr/bin/gunicorn", "--workers=4"], True, "gunicorn with full path"), + (["/path/to/gunicorn.py"], True, "gunicorn in filename"), + (["gunicorn"], True, "gunicorn alone"), + ( + ["python", "gunicorn_wrapper.py", "--config=gunicorn.conf"], + True, + "multiple gunicorn occurrences", + ), + ( + ["/home/user/.local/bin/gunicorn", "myapp:app"], + True, + "gunicorn in user bin", + ), + # Negative cases - gunicorn should NOT be detected + (["python", "manage.py", "runserver"], False, "django runserver"), + (["uwsgi", "--http", ":8000"], False, "uwsgi server"), + (["unicorn", "app"], False, "similar name unicorn"), + (["python", "gun.py"], False, "partial match gun"), + ([], False, "empty argv"), + (["python", "app.py"], False, "regular python script"), + (["flask", "run"], False, "flask development server"), + (["GUNICORN", "app"], False, "uppercase GUNICORN"), + ], + ) + def test_detection_via_sys_argv(self, monkeypatch, argv, expected, description): + """Test gunicorn detection via sys.argv""" + monkeypatch.setattr(sys, "argv", argv) + result = running_in_gunicorn() + assert result == expected, f"Failed: {description}" + + @pytest.mark.parametrize( + "cmdline_content,expected,description", + [ + # Positive cases - gunicorn in cmdline + ( + "gunicorn\0app:application\0", + True, + "gunicorn as first command", + ), + ( + "/usr/bin/gunicorn\0--workers=4\0", + True, + "gunicorn with full path", + ), + ( + "python\0-m\0gunicorn\0app\0", + True, + "gunicorn via python -m", + ), + ( + "/home/user/.local/bin/gunicorn\0myapp:app\0", + True, + "gunicorn in user directory", + ), + ( + "gunicorn\0", + True, + "gunicorn alone with null byte", + ), + # Negative cases - no gunicorn in cmdline + ( + "python\0manage.py\0runserver\0", + False, + "django runserver", + ), + ( + "uwsgi\0--http\0:8000\0", + False, + "uwsgi server", + ), + ( + "unicorn\0app\0", + False, + "similar name unicorn", + ), + ( + "", + False, + "empty cmdline", + ), + ( + "python\0app.py\0", + False, + "regular python script", + ), + ], + ) + def test_detection_via_proc_cmdline( + self, monkeypatch, cmdline_content, expected, description + ): + """Test gunicorn detection via /proc/self/cmdline when sys.argv is not available""" + # Remove sys.argv to force fallback to /proc/self/cmdline + monkeypatch.delattr(sys, "argv", raising=False) + + # Mock os.path.isfile to return True for /proc/self/cmdline + monkeypatch.setattr(os.path, "isfile", lambda x: x == "/proc/self/cmdline") + + # Mock file open to return cmdline content + mock_open = mock.mock_open(read_data=cmdline_content) + monkeypatch.setattr("builtins.open", mock_open) + + result = running_in_gunicorn() + assert result == expected, f"Failed: {description}" + + # Verify file was opened if sys.argv was not available + if not hasattr(sys, "argv"): + mock_open.assert_called_once_with("/proc/self/cmdline") + + def test_fallback_to_proc_cmdline_when_no_sys_argv(self, monkeypatch): + """Test that function falls back to /proc/self/cmdline when sys.argv is not available""" + # Remove sys.argv attribute + monkeypatch.delattr(sys, "argv", raising=False) + + # Mock /proc/self/cmdline with gunicorn + monkeypatch.setattr(os.path, "isfile", lambda x: x == "/proc/self/cmdline") + mock_open = mock.mock_open(read_data="gunicorn\0app:application\0") + monkeypatch.setattr("builtins.open", mock_open) + + result = running_in_gunicorn() + + assert result is True + mock_open.assert_called_once_with("/proc/self/cmdline") + + def test_proc_cmdline_not_exists(self, monkeypatch): + """Test when /proc/self/cmdline does not exist""" + # Remove sys.argv to force fallback + monkeypatch.delattr(sys, "argv", raising=False) + + # Mock os.path.isfile to return False + monkeypatch.setattr(os.path, "isfile", lambda x: False) + + result = running_in_gunicorn() + assert result is False + + def test_sys_argv_with_none_values(self, monkeypatch): + """Test handling of None values in sys.argv""" + # This should not crash, but may not find gunicorn + monkeypatch.setattr(sys, "argv", ["python", None, "app.py"]) + + # Should handle gracefully and return False (or raise exception which is caught) + result = running_in_gunicorn() + assert result is False + + def test_sys_argv_with_non_string_values(self, monkeypatch): + """Test handling of non-string values in sys.argv""" + monkeypatch.setattr(sys, "argv", ["python", 123, "app.py"]) + + # Should handle gracefully + result = running_in_gunicorn() + assert result is False + + def test_empty_sys_argv(self, monkeypatch): + """Test with empty sys.argv list""" + monkeypatch.setattr(sys, "argv", []) + + result = running_in_gunicorn() + assert result is False + + @pytest.mark.parametrize( + "cmdline_content,expected,description", + [ + ("", False, "empty content"), + ("\0", False, "single null byte"), + ("python\0\0\0app.py\0", False, "multiple consecutive null bytes"), + ( + "python\0" + "\0".join(["arg"] * 1000) + "\0gunicorn\0app\0", + True, + "very long command line with gunicorn", + ), + ( + "python\0" + "\0".join(["arg"] * 1000) + "\0app\0", + False, + "very long command line without gunicorn", + ), + (" \0 \0", False, "whitespace with null bytes"), + ("\0\0\0", False, "only null bytes"), + ], + ) + def test_proc_cmdline_edge_cases( + self, monkeypatch, cmdline_content, expected, description + ): + """Test /proc/self/cmdline with various edge case contents""" + monkeypatch.delattr(sys, "argv", raising=False) + monkeypatch.setattr(os.path, "isfile", lambda x: x == "/proc/self/cmdline") + + mock_open = mock.mock_open(read_data=cmdline_content) + monkeypatch.setattr("builtins.open", mock_open) + + result = running_in_gunicorn() + assert result == expected, f"Failed: {description}" + + def test_case_sensitivity(self, monkeypatch): + """Test that detection is case-sensitive""" + # Test uppercase - should not match + monkeypatch.setattr(sys, "argv", ["GUNICORN", "app"]) + result = running_in_gunicorn() + assert result is False + + # Test mixed case - should not match + monkeypatch.setattr(sys, "argv", ["Gunicorn", "app"]) + result = running_in_gunicorn() + assert result is False + + # Test lowercase - should match + monkeypatch.setattr(sys, "argv", ["gunicorn", "app"]) + result = running_in_gunicorn() + assert result is True + + def test_partial_match_in_argv(self, monkeypatch): + """Test that partial matches work correctly""" + # These should match (gunicorn is substring) + test_cases_match = [ + ["/usr/local/bin/gunicorn"], + ["python", "/path/to/gunicorn.py"], + ["gunicorn_wrapper"], + ] + + for argv in test_cases_match: + monkeypatch.setattr(sys, "argv", argv) + result = running_in_gunicorn() + assert result is True, f"Should match for argv: {argv}" + + # These should NOT match (gunicorn is not substring) + test_cases_no_match = [ + ["unicorn"], + ["gun"], + ["gunicor"], + ] + + for argv in test_cases_no_match: + monkeypatch.setattr(sys, "argv", argv) + result = running_in_gunicorn() + assert result is False, f"Should not match for argv: {argv}" + + def test_real_world_gunicorn_command_lines(self, monkeypatch): + """Test with realistic gunicorn command line examples""" + real_world_cases = [ + # Standard gunicorn invocation + ["gunicorn", "myapp:app", "--bind", "0.0.0.0:8000"], + # With workers + ["gunicorn", "myapp:app", "-w", "4", "-b", "127.0.0.1:8000"], + # With config file + ["gunicorn", "-c", "gunicorn_config.py", "myapp:app"], + # Via python module + ["python", "-m", "gunicorn", "myapp:app"], + # With full path + ["/usr/local/bin/gunicorn", "myapp:app", "--daemon"], + # In virtual environment + ["/home/user/venv/bin/gunicorn", "myapp:app"], + ] + + for argv in real_world_cases: + monkeypatch.setattr(sys, "argv", argv) + result = running_in_gunicorn() + assert result is True, f"Should detect gunicorn in: {argv}" + + def test_no_side_effects(self, monkeypatch): + """Test that function doesn't modify global state""" + original_argv = ["gunicorn", "app"] + monkeypatch.setattr(sys, "argv", original_argv.copy()) + + running_in_gunicorn() + + # sys.argv should remain unchanged + assert sys.argv == original_argv + + def test_idempotency(self, monkeypatch): + """Test that multiple calls return the same result""" + monkeypatch.setattr(sys, "argv", ["gunicorn", "app"]) + + result1 = running_in_gunicorn() + result2 = running_in_gunicorn() + result3 = running_in_gunicorn() + + assert result1 == result2 == result3 is True + + monkeypatch.setattr(sys, "argv", ["python", "app.py"]) + + result4 = running_in_gunicorn() + result5 = running_in_gunicorn() + + assert result4 == result5 is False + + +# Made with Bob diff --git a/tests/w3c_trace_context/test_traceparent.py b/tests/w3c_trace_context/test_traceparent.py index beec0341..b46bfa59 100644 --- a/tests/w3c_trace_context/test_traceparent.py +++ b/tests/w3c_trace_context/test_traceparent.py @@ -5,6 +5,7 @@ import unittest from instana.util.ids import header_to_long_id, header_to_id + class TestTraceparent(unittest.TestCase): def setUp(self): self.tp = Traceparent() @@ -38,14 +39,18 @@ def test_validate_traceparent_None(self): def test_get_traceparent_fields(self): traceparent = f"00-{self.w3cTraceId}-00f067aa0ba902b7-01" - version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields(traceparent) + version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields( + traceparent + ) self.assertEqual(trace_id, header_to_long_id(self.w3cTraceId)) self.assertEqual(parent_id, 67667974448284343) self.assertTrue(sampled_flag) def test_get_traceparent_fields_unsampled(self): traceparent = f"00-{self.w3cTraceId}-00f067aa0ba902b7-00" - version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields(traceparent) + version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields( + traceparent + ) self.assertEqual(trace_id, header_to_long_id(self.w3cTraceId)) self.assertEqual(parent_id, 67667974448284343) self.assertFalse(sampled_flag) @@ -54,28 +59,36 @@ def test_get_traceparent_fields_newer_version(self): # Although the incoming traceparent header sports a newer version number, we should still be able to parse the # parts that we understand (and consider it valid). traceparent = f"fe-{self.w3cTraceId}-00f067aa0ba902b7-01-12345-abcd" - version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields(traceparent) + version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields( + traceparent + ) self.assertEqual(trace_id, header_to_long_id(self.w3cTraceId)) self.assertEqual(parent_id, 67667974448284343) self.assertTrue(sampled_flag) def test_get_traceparent_fields_unknown_flags(self): traceparent = f"00-{self.w3cTraceId}-00f067aa0ba902b7-ff" - version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields(traceparent) + version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields( + traceparent + ) self.assertEqual(trace_id, header_to_long_id(self.w3cTraceId)) self.assertEqual(parent_id, 67667974448284343) self.assertTrue(sampled_flag) def test_get_traceparent_fields_None_input(self): traceparent = None - version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields(traceparent) + version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields( + traceparent + ) self.assertIsNone(trace_id) self.assertIsNone(parent_id) self.assertFalse(sampled_flag) def test_get_traceparent_fields_string_input_no_dash(self): traceparent = "invalid" - version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields(traceparent) + version, trace_id, parent_id, sampled_flag = self.tp.get_traceparent_fields( + traceparent + ) self.assertIsNone(trace_id) self.assertIsNone(parent_id) self.assertFalse(sampled_flag) @@ -86,7 +99,12 @@ def test_update_traceparent(self): in_span_id = "1234567890abcdef" level = 1 expected_traceparent = "00-4bf92f3577b34da6a3ce929d0e0e4736-1234567890abcdef-01" - self.assertEqual(expected_traceparent, self.tp.update_traceparent(traceparent, in_trace_id, header_to_id(in_span_id), level)) + self.assertEqual( + expected_traceparent, + self.tp.update_traceparent( + traceparent, in_trace_id, header_to_id(in_span_id), level + ), + ) def test_update_traceparent_None(self): traceparent = None @@ -94,4 +112,9 @@ def test_update_traceparent_None(self): in_span_id = "7890abcdef" level = 0 expected_traceparent = "00-00000000000000001234d0e0e4736234-0000007890abcdef-00" - self.assertEqual(expected_traceparent, self.tp.update_traceparent(traceparent, in_trace_id, header_to_id(in_span_id), level)) + self.assertEqual( + expected_traceparent, + self.tp.update_traceparent( + traceparent, in_trace_id, header_to_id(in_span_id), level + ), + ) diff --git a/tests_autowrapt/test_autowrapt.py b/tests_autowrapt/test_autowrapt.py index 61496d1f..4cf45b2b 100644 --- a/tests_autowrapt/test_autowrapt.py +++ b/tests_autowrapt/test_autowrapt.py @@ -1,6 +1,7 @@ import os import sys + def test_autowrapt_bootstrap(): assert os.environ.get("AUTOWRAPT_BOOTSTRAP") == "instana" assert "instana" in sys.modules diff --git a/tests_aws/01_lambda/test_lambda.py b/tests_aws/01_lambda/test_lambda.py index de59d921..545881c4 100644 --- a/tests_aws/01_lambda/test_lambda.py +++ b/tests_aws/01_lambda/test_lambda.py @@ -24,6 +24,7 @@ if TYPE_CHECKING: from instana.span.span import InstanaSpan + # Mock Context object class MockContext(dict): def __init__(self, **kwargs: Dict[str, Any]) -> None: @@ -81,7 +82,7 @@ def _resource(self) -> Generator[None, None, None]: self.agent: AWSLambdaAgent = get_agent() yield # tearDown - # Reset collector config + # Reset collector config self.agent.collector.snapshot_data_sent = False # Reset all environment variables of consequence if "AWS_EXECUTION_ENV" in os.environ: @@ -139,28 +140,28 @@ def test_get_handler(self) -> None: os.environ["LAMBDA_HANDLER"] = "tests.lambda_handler" handler_module, handler_function = get_aws_lambda_handler() - assert "tests" == handler_module - assert "lambda_handler" == handler_function + assert handler_module == "tests" + assert handler_function == "lambda_handler" def test_get_handler_with_multi_subpackages(self) -> None: os.environ["LAMBDA_HANDLER"] = "tests.one.two.three.lambda_handler" handler_module, handler_function = get_aws_lambda_handler() - assert "tests.one.two.three" == handler_module - assert "lambda_handler" == handler_function + assert handler_module == "tests.one.two.three" + assert handler_function == "lambda_handler" def test_get_handler_with_space_in_it(self) -> None: os.environ["LAMBDA_HANDLER"] = " tests.another_module.lambda_handler" handler_module, handler_function = get_aws_lambda_handler() - assert "tests.another_module" == handler_module - assert "lambda_handler" == handler_function + assert handler_module == "tests.another_module" + assert handler_function == "lambda_handler" os.environ["LAMBDA_HANDLER"] = "tests.another_module.lambda_handler " handler_module, handler_function = get_aws_lambda_handler() - assert "tests.another_module" == handler_module - assert "lambda_handler" == handler_function + assert handler_module == "tests.another_module" + assert handler_function == "lambda_handler" def test_agent_extra_http_headers(self) -> None: os.environ["INSTANA_EXTRA_HTTP_HEADERS"] = ( @@ -184,7 +185,7 @@ def test_custom_service_name(self, trace_id: int, span_id: int) -> None: os.environ["INSTANA_AGENT_KEY"] = "Fake_Key" # We need reset the AWSLambdaOptions with new INSTANA_SERVICE_NAME self.agent.options = AWSLambdaOptions() - + with open( self.pwd + "/../data/lambda/api_gateway_event.json", "r" ) as json_file: @@ -779,7 +780,9 @@ def test_arn_parsing(self) -> None: def test_agent_default_log_level(self) -> None: assert self.agent.options.log_level == logging.WARNING - def __validate_result_and_payload_for_gateway_v2_trace(self, result: Dict[str, Any], payload: defaultdict) -> "InstanaSpan": + def __validate_result_and_payload_for_gateway_v2_trace( + self, result: Dict[str, Any], payload: defaultdict + ) -> "InstanaSpan": assert isinstance(result, dict) assert "headers" in result assert "Server-Timing" in result["headers"] @@ -835,4 +838,4 @@ def __validate_result_and_payload_for_gateway_v2_trace(self, result: Dict[str, A assert span.data["http"]["path_tpl"] == "/my/{resource}" assert span.data["http"]["params"] == "secret=key&q=term" - return span \ No newline at end of file + return span diff --git a/tests_aws/02_fargate/conftest.py b/tests_aws/02_fargate/conftest.py index d249421a..4edea235 100644 --- a/tests_aws/02_fargate/conftest.py +++ b/tests_aws/02_fargate/conftest.py @@ -5,6 +5,7 @@ from instana.collector.aws_fargate import AWSFargateCollector + # Mocking AWSFargateCollector.get_ecs_metadata() @pytest.fixture(autouse=True) def get_ecs_metadata(monkeypatch, request) -> None: @@ -16,6 +17,10 @@ def _always_true(_: object) -> bool: if "original" in request.keywords: # If using the `@pytest.mark.original` marker before the test function, # uses the original AWSFargateCollector.get_ecs_metadata() - monkeypatch.setattr(AWSFargateCollector, "get_ecs_metadata", AWSFargateCollector.get_ecs_metadata) + monkeypatch.setattr( + AWSFargateCollector, + "get_ecs_metadata", + AWSFargateCollector.get_ecs_metadata, + ) else: monkeypatch.setattr(AWSFargateCollector, "get_ecs_metadata", _always_true) diff --git a/tests_aws/02_fargate/test_fargate.py b/tests_aws/02_fargate/test_fargate.py index 551b0968..dce29859 100644 --- a/tests_aws/02_fargate/test_fargate.py +++ b/tests_aws/02_fargate/test_fargate.py @@ -9,7 +9,6 @@ from instana.agent.aws_fargate import AWSFargateAgent from instana.options import AWSFargateOptions -from instana.singletons import get_agent class TestFargate: diff --git a/tests_aws/02_fargate/test_fargate_collector.py b/tests_aws/02_fargate/test_fargate_collector.py index 673b7c78..e0e46a87 100644 --- a/tests_aws/02_fargate/test_fargate_collector.py +++ b/tests_aws/02_fargate/test_fargate_collector.py @@ -8,7 +8,6 @@ import pytest from instana.agent.aws_fargate import AWSFargateAgent -from instana.singletons import get_agent def get_docker_plugin(plugins): @@ -82,7 +81,7 @@ def _resource(self) -> Generator[None, None, None]: os.environ.pop("INSTANA_ZONE") if "INSTANA_TAGS" in os.environ: os.environ.pop("INSTANA_TAGS") - + self.agent.collector.snapshot_data_last_sent = 0 _unset_ecs_metadata(self.agent) diff --git a/tests_aws/03_eks/test_eksfargate.py b/tests_aws/03_eks/test_eksfargate.py index 6f7984d9..59b23cee 100644 --- a/tests_aws/03_eks/test_eksfargate.py +++ b/tests_aws/03_eks/test_eksfargate.py @@ -8,7 +8,6 @@ from instana.agent.aws_eks_fargate import EKSFargateAgent from instana.options import EKSFargateOptions -from instana.singletons import get_agent class TestEKSFargate: diff --git a/tests_aws/03_eks/test_eksfargate_collector.py b/tests_aws/03_eks/test_eksfargate_collector.py index 32f8f93e..0c1f6471 100644 --- a/tests_aws/03_eks/test_eksfargate_collector.py +++ b/tests_aws/03_eks/test_eksfargate_collector.py @@ -6,7 +6,6 @@ import pytest from instana.agent.aws_eks_fargate import EKSFargateAgent -from instana.singletons import get_agent class TestEKSFargateCollector: