From d38190f6520ff66c9f3a475aa85f3f9852d53399 Mon Sep 17 00:00:00 2001 From: Paulo Vital Date: Fri, 11 Jul 2025 10:21:15 +0200 Subject: [PATCH] feat(config): add support for multiple boolean formats in environment variables. Add `is_truthy()` function to accept `True`, `true`, and `1` as boolean `True` values when reading environment variables. This makes configuration more flexible and user-friendly. - Add new `is_truthy()` utility function in config.py - Update environment variable checks in options.py to use the new function - Add parametrized tests to verify functionality with various input values Signed-off-by: Paulo Vital --- src/instana/options.py | 25 ++++++++++--------------- src/instana/util/config.py | 31 +++++++++++++++++++++++++++++++ tests/util/test_config.py | 34 +++++++++++++++++++++++++++------- 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/src/instana/options.py b/src/instana/options.py index da124020..356ea961 100644 --- a/src/instana/options.py +++ b/src/instana/options.py @@ -14,17 +14,15 @@ - GCROptions - Options class for Google cloud Run. Holds settings specific to GCR. """ -import os import logging +import os from typing import Any, Dict +from instana.configurator import config from instana.log import logger -from instana.util.config import ( - parse_ignored_endpoints, - parse_ignored_endpoints_from_yaml, -) +from instana.util.config import (is_truthy, parse_ignored_endpoints, + parse_ignored_endpoints_from_yaml) from instana.util.runtime import determine_service_name -from instana.configurator import config class BaseOptions(object): @@ -76,10 +74,9 @@ def set_trace_configurations(self) -> None: str(os.environ["INSTANA_EXTRA_HTTP_HEADERS"]).lower().split(";") ) - if "1" in [ - os.environ.get("INSTANA_ALLOW_EXIT_AS_ROOT", None), # deprecated - os.environ.get("INSTANA_ALLOW_ROOT_EXIT_SPAN", None), - ]: + # Check if either of the environment variables is truthy + if is_truthy(os.environ.get("INSTANA_ALLOW_EXIT_AS_ROOT", None)) or \ + is_truthy(os.environ.get("INSTANA_ALLOW_ROOT_EXIT_SPAN", None)): self.allow_exit_as_root = True # The priority is as follows: @@ -102,9 +99,7 @@ def set_trace_configurations(self) -> None: ) if "INSTANA_KAFKA_TRACE_CORRELATION" in os.environ: - self.kafka_trace_correlation = ( - os.environ["INSTANA_KAFKA_TRACE_CORRELATION"].lower() == "true" - ) + self.kafka_trace_correlation = is_truthy(os.environ["INSTANA_KAFKA_TRACE_CORRELATION"]) elif isinstance(config.get("tracing"), dict) and "kafka" in config["tracing"]: self.kafka_trace_correlation = config["tracing"]["kafka"].get( "trace_correlation", True @@ -167,8 +162,8 @@ def set_tracing(self, tracing: Dict[str, Any]) -> None: ) and "trace-correlation" in tracing["kafka"] ): - self.kafka_trace_correlation = ( - str(tracing["kafka"].get("trace-correlation", True)) == "true" + self.kafka_trace_correlation = is_truthy( + tracing["kafka"].get("trace-correlation", True) ) if ( diff --git a/src/instana/util/config.py b/src/instana/util/config.py index 93c6e7c2..887c2292 100644 --- a/src/instana/util/config.py +++ b/src/instana/util/config.py @@ -146,3 +146,34 @@ def parse_ignored_endpoints_from_yaml(file_path: str) -> List[str]: return ignored_endpoints else: return [] + + +def is_truthy(value: Any) -> bool: + """ + Check if a value is truthy, accepting various formats. + + @param value: The value to check + @return: True if the value is considered truthy, False otherwise + + Accepts the following as True: + - True (Python boolean) + - "True", "true" (case-insensitive string) + - "1" (string) + - 1 (integer) + """ + if value is None: + return False + + if isinstance(value, bool): + return value + + if isinstance(value, int): + return value == 1 + + if isinstance(value, str): + value_lower = value.lower() + return value_lower == "true" or value == "1" + + return False + +# Made with Bob diff --git a/tests/util/test_config.py b/tests/util/test_config.py index 83b3a796..741d5658 100644 --- a/tests/util/test_config.py +++ b/tests/util/test_config.py @@ -1,12 +1,11 @@ # (c) Copyright IBM Corp. 2025 -from instana.util.config import ( - parse_endpoints_of_service, - parse_ignored_endpoints, - parse_ignored_endpoints_dict, - parse_kafka_methods, - parse_service_pair, -) +import pytest + +from instana.util.config import (is_truthy, parse_endpoints_of_service, + parse_ignored_endpoints, + parse_ignored_endpoints_dict, + parse_kafka_methods, parse_service_pair) class TestConfig: @@ -168,3 +167,24 @@ def test_parse_kafka_methods_as_str(self) -> None: test_rule_as_str = ["send"] parsed_rule = parse_kafka_methods(test_rule_as_str) assert parsed_rule == ["kafka.send.*"] + + @pytest.mark.parametrize("value, expected", [ + (True, True), + (False, False), + ("True", True), + ("true", True), + ("1", True), + (1, True), + ("False", False), + ("false", False), + ("0", False), + (0, False), + (None, False), + ("TRUE", True), + ("FALSE", False), + ("yes", False), # Only "true" and "1" are considered truthy + ("no", False), + ]) + def test_is_truthy(self, value, expected) -> None: + """Test the is_truthy function with various input values.""" + assert is_truthy(value) == expected