From ceb130914e95cd86aad163ca7796a5a8d4819bda Mon Sep 17 00:00:00 2001 From: Harel Moshe Date: Mon, 23 Sep 2024 08:44:07 +0300 Subject: [PATCH] feat(tracing) - allow opting-out from tracing (#891) --- src/lumigo_opentelemetry/__init__.py | 26 +++++++++++++------ .../instrumentations/__init__.py | 21 ++++++++++++--- .../instrumentations/boto/__init__.py | 2 +- .../instrumentations/botocore/__init__.py | 2 +- .../instrumentations/django/__init__.py | 2 +- .../instrumentations/fastapi/__init__.py | 2 +- .../instrumentations/flask/__init__.py | 2 +- .../instrumentations/grpcio/__init__.py | 2 +- .../instrumentations/instrumentations.py | 10 +++---- .../instrumentations/kafka_python/__init__.py | 2 +- .../instrumentations/pika/__init__.py | 2 +- .../instrumentations/psycopg/__init__.py | 2 +- .../instrumentations/psycopg2/__init__.py | 2 +- .../instrumentations/pymongo/__init__.py | 2 +- .../instrumentations/pymysql/__init__.py | 2 +- .../instrumentations/redis/__init__.py | 2 +- .../instrumentations/requests/__init__.py | 2 +- .../integration/motor/requirements_others.txt | 1 + 18 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/lumigo_opentelemetry/__init__.py b/src/lumigo_opentelemetry/__init__.py index d49d48f0..8dfce10c 100644 --- a/src/lumigo_opentelemetry/__init__.py +++ b/src/lumigo_opentelemetry/__init__.py @@ -135,7 +135,8 @@ def init() -> Dict[str, Any]: lumigo_report_dependencies = ( os.getenv("LUMIGO_REPORT_DEPENDENCIES", "true").lower() == "true" ) - logging_enabled = os.getenv("LUMIGO_ENABLE_LOGS", "").lower() == "true" + logging_enabled = os.getenv("LUMIGO_ENABLE_LOGS", "false").lower() == "true" + tracing_enabled = os.getenv("LUMIGO_ENABLE_TRACES", "true").lower() == "true" spandump_file = os.getenv("LUMIGO_DEBUG_SPANDUMP") logdump_file = os.getenv("LUMIGO_DEBUG_LOGDUMP") @@ -167,14 +168,19 @@ def init() -> Dict[str, Any]: logger_provider.add_log_record_processor(LumigoLogRecordProcessor()) if lumigo_token: - tracer_provider.add_span_processor( - LumigoSpanProcessor( - OTLPSpanExporter( - endpoint=lumigo_traces_endpoint, - headers={"Authorization": f"LumigoToken {lumigo_token}"}, - ), + if tracing_enabled: + tracer_provider.add_span_processor( + LumigoSpanProcessor( + OTLPSpanExporter( + endpoint=lumigo_traces_endpoint, + headers={"Authorization": f"LumigoToken {lumigo_token}"}, + ), + ) + ) + else: + logger.info( + 'Tracing is disabled (the "LUMIGO_ENABLE_TRACES" environment variable is not set to "true"): no traces will be sent to Lumigo.' ) - ) if logging_enabled: logger_provider.add_log_record_processor( @@ -185,6 +191,10 @@ def init() -> Dict[str, Any]: ) ) ) + else: + logger.info( + 'Logging is disabled (the "LUMIGO_ENABLE_LOGS" environment variable is not set to "true"): no logs will be sent to Lumigo.' + ) if lumigo_report_dependencies: from lumigo_opentelemetry.dependencies import report diff --git a/src/lumigo_opentelemetry/instrumentations/__init__.py b/src/lumigo_opentelemetry/instrumentations/__init__.py index c373878f..3f173d08 100644 --- a/src/lumigo_opentelemetry/instrumentations/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/__init__.py @@ -1,4 +1,5 @@ from abc import abstractmethod, ABC +import os class AbstractInstrumentor(ABC): @@ -12,10 +13,24 @@ class AbstractInstrumentor(ABC): def __init__(self, instrumentation_id: str): self._instrumentation_id = instrumentation_id + def is_applicable(self) -> bool: + tracing_enabled = ( + os.environ.get("LUMIGO_ENABLE_TRACES", "true").lower() == "true" + ) + if not tracing_enabled: + return False + + try: + self.assert_instrumented_package_importable() + return True + except ImportError: + return False + @abstractmethod - def check_if_applicable(self) -> None: - # TODO Implement version lookup per instrumented package, and check that the version is supported - raise Exception("'check_if_applicable' method not implemented!") + def assert_instrumented_package_importable(self) -> None: + raise Exception( + "'assert_instrumented_package_importable' method not implemented!" + ) @abstractmethod def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/boto/__init__.py b/src/lumigo_opentelemetry/instrumentations/boto/__init__.py index 6a52214b..cac6a1b7 100644 --- a/src/lumigo_opentelemetry/instrumentations/boto/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/boto/__init__.py @@ -5,7 +5,7 @@ class BotoInstrumentorWrapper(AbstractInstrumentor): def __init__(self) -> None: super().__init__("boto") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import boto # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/botocore/__init__.py b/src/lumigo_opentelemetry/instrumentations/botocore/__init__.py index 4030386d..17e50c2a 100644 --- a/src/lumigo_opentelemetry/instrumentations/botocore/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/botocore/__init__.py @@ -14,7 +14,7 @@ class BotoCoreInstrumentorWrapper(AbstractInstrumentor): def __init__(self) -> None: super().__init__("botocore") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: from botocore.client import BaseClient # noqa from botocore.endpoint import Endpoint # noqa from botocore.exceptions import ClientError # noqa diff --git a/src/lumigo_opentelemetry/instrumentations/django/__init__.py b/src/lumigo_opentelemetry/instrumentations/django/__init__.py index 0d98723d..a1185802 100644 --- a/src/lumigo_opentelemetry/instrumentations/django/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/django/__init__.py @@ -12,7 +12,7 @@ class DjangoInstrumentorWrapper(AbstractInstrumentor): def __init__(self) -> None: super().__init__("django") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import django # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/fastapi/__init__.py b/src/lumigo_opentelemetry/instrumentations/fastapi/__init__.py index 5a29e1bd..3f9a6751 100644 --- a/src/lumigo_opentelemetry/instrumentations/fastapi/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/fastapi/__init__.py @@ -6,7 +6,7 @@ class FastApiInstrumentorWrapper(AbstractInstrumentor): def __init__(self) -> None: super().__init__("fast-api") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import fastapi # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/flask/__init__.py b/src/lumigo_opentelemetry/instrumentations/flask/__init__.py index be9a705e..d5ed3b53 100644 --- a/src/lumigo_opentelemetry/instrumentations/flask/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/flask/__init__.py @@ -11,7 +11,7 @@ class FlaskInstrumentorWrapper(AbstractInstrumentor): def __init__(self) -> None: super().__init__("flask") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import flask # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/grpcio/__init__.py b/src/lumigo_opentelemetry/instrumentations/grpcio/__init__.py index b67cf74f..7c58516a 100644 --- a/src/lumigo_opentelemetry/instrumentations/grpcio/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/grpcio/__init__.py @@ -6,7 +6,7 @@ class GRPCInstrumentor(AbstractInstrumentor): def __init__(self) -> None: super().__init__("grpc") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import grpc # noqa @staticmethod diff --git a/src/lumigo_opentelemetry/instrumentations/instrumentations.py b/src/lumigo_opentelemetry/instrumentations/instrumentations.py index 9a992e97..b09a6635 100644 --- a/src/lumigo_opentelemetry/instrumentations/instrumentations.py +++ b/src/lumigo_opentelemetry/instrumentations/instrumentations.py @@ -37,12 +37,8 @@ redis_instrumentor, requests_instrumentor, ] -for instrumentor in instrumentors: - try: - instrumentor.check_if_applicable() - except ImportError: - continue - +applicable_instumentors = [inst for inst in instrumentors if inst.is_applicable()] +for instrumentor in applicable_instumentors: try: instrumentor.install_instrumentation() installed_instrumentations.append(instrumentor.instrumentation_id) @@ -56,7 +52,7 @@ ) logger.debug( - "Installed instrumentations: %s", ", ".join(list(installed_instrumentations)) + "Installed instrumentations: [%s]", ", ".join(list(installed_instrumentations)) ) frameworks = list( diff --git a/src/lumigo_opentelemetry/instrumentations/kafka_python/__init__.py b/src/lumigo_opentelemetry/instrumentations/kafka_python/__init__.py index 0fe8d03c..082f49dd 100644 --- a/src/lumigo_opentelemetry/instrumentations/kafka_python/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/kafka_python/__init__.py @@ -13,7 +13,7 @@ class KafkaPythonInstrumentor(AbstractInstrumentor): def __init__(self) -> None: super().__init__("kafka_python") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import kafka # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/pika/__init__.py b/src/lumigo_opentelemetry/instrumentations/pika/__init__.py index 60d7cf51..6c8be64e 100644 --- a/src/lumigo_opentelemetry/instrumentations/pika/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/pika/__init__.py @@ -10,7 +10,7 @@ class PikaInstrumentor(AbstractInstrumentor): def __init__(self) -> None: super().__init__("pika") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import pika # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/psycopg/__init__.py b/src/lumigo_opentelemetry/instrumentations/psycopg/__init__.py index 5534ff7a..6b005bb5 100644 --- a/src/lumigo_opentelemetry/instrumentations/psycopg/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/psycopg/__init__.py @@ -8,7 +8,7 @@ class PsycopgInstrumentor(AbstractInstrumentor): def __init__(self) -> None: super().__init__("psycopg") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import psycopg # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/psycopg2/__init__.py b/src/lumigo_opentelemetry/instrumentations/psycopg2/__init__.py index 197066f9..0a80ae3f 100644 --- a/src/lumigo_opentelemetry/instrumentations/psycopg2/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/psycopg2/__init__.py @@ -8,7 +8,7 @@ class Psycopg2Instrumentor(AbstractInstrumentor): def __init__(self) -> None: super().__init__("psycopg2") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import psycopg2 # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/pymongo/__init__.py b/src/lumigo_opentelemetry/instrumentations/pymongo/__init__.py index b4e2950c..fa933a96 100644 --- a/src/lumigo_opentelemetry/instrumentations/pymongo/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/pymongo/__init__.py @@ -12,7 +12,7 @@ class PymongoInstrumentor(AbstractInstrumentor): def __init__(self) -> None: super().__init__("pymongo") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import pymongo # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/pymysql/__init__.py b/src/lumigo_opentelemetry/instrumentations/pymysql/__init__.py index 995087f5..4e92cf0f 100644 --- a/src/lumigo_opentelemetry/instrumentations/pymysql/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/pymysql/__init__.py @@ -5,7 +5,7 @@ class PyMySqlInstrumentor(AbstractInstrumentor): def __init__(self) -> None: super().__init__("pymysql") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import pymysql # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/redis/__init__.py b/src/lumigo_opentelemetry/instrumentations/redis/__init__.py index c95c542d..1ebfb827 100644 --- a/src/lumigo_opentelemetry/instrumentations/redis/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/redis/__init__.py @@ -13,7 +13,7 @@ class RedisInstrumentor(AbstractInstrumentor): def __init__(self) -> None: super().__init__("redis") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: import redis # noqa def install_instrumentation(self) -> None: diff --git a/src/lumigo_opentelemetry/instrumentations/requests/__init__.py b/src/lumigo_opentelemetry/instrumentations/requests/__init__.py index ad356888..0a9124cd 100644 --- a/src/lumigo_opentelemetry/instrumentations/requests/__init__.py +++ b/src/lumigo_opentelemetry/instrumentations/requests/__init__.py @@ -11,7 +11,7 @@ class RequestsInstrumentor(AbstractInstrumentor): def __init__(self) -> None: super().__init__("requests") - def check_if_applicable(self) -> None: + def assert_instrumented_package_importable(self) -> None: from requests.models import Response # noqa from requests.sessions import Session # noqa from requests.structures import CaseInsensitiveDict # noqa diff --git a/src/test/integration/motor/requirements_others.txt b/src/test/integration/motor/requirements_others.txt index 321a0e0c..f3d4db9e 100644 --- a/src/test/integration/motor/requirements_others.txt +++ b/src/test/integration/motor/requirements_others.txt @@ -1,3 +1,4 @@ pytest==7.1.1 psutil==5.9.1 testcontainers==3.7.0 +pymongo==4.4.0 # make sure the version used in the test is compatible with motor \ No newline at end of file