diff --git a/aws_lambda_powertools/event_handler/api_gateway.py b/aws_lambda_powertools/event_handler/api_gateway.py index 734e66b2eca..769d702ddfe 100644 --- a/aws_lambda_powertools/event_handler/api_gateway.py +++ b/aws_lambda_powertools/event_handler/api_gateway.py @@ -15,7 +15,7 @@ from aws_lambda_powertools.event_handler import content_types from aws_lambda_powertools.event_handler.exceptions import NotFoundError, ServiceError from aws_lambda_powertools.shared import constants -from aws_lambda_powertools.shared.functions import resolve_truthy_env_var_choice +from aws_lambda_powertools.shared.functions import powertools_dev_is_set, strtobool from aws_lambda_powertools.shared.json_encoder import Encoder from aws_lambda_powertools.utilities.data_classes import ( ALBEvent, @@ -453,9 +453,7 @@ def __init__( self._cors = cors self._cors_enabled: bool = cors is not None self._cors_methods: Set[str] = {"OPTIONS"} - self._debug = resolve_truthy_env_var_choice( - env=os.getenv(constants.EVENT_HANDLER_DEBUG_ENV, "false"), choice=debug - ) + self._debug = self._has_debug(debug) self._strip_prefixes = strip_prefixes self.context: Dict = {} # early init as customers might add context before event resolution @@ -527,6 +525,22 @@ def resolve(self, event, context) -> Dict[str, Any]: def __call__(self, event, context) -> Any: return self.resolve(event, context) + @staticmethod + def _has_debug(debug: Optional[bool] = None) -> bool: + # It might have been explicitly switched off (debug=False) + if debug is not None: + return debug + + # Maintenance: deprecate EVENT_HANDLER_DEBUG later in V2. + env_debug = os.getenv(constants.EVENT_HANDLER_DEBUG_ENV) + if env_debug is not None: + warnings.warn( + "POWERTOOLS_EVENT_HANDLER_DEBUG is set and will be deprecated in V2. Please use POWERTOOLS_DEV instead." + ) + return strtobool(env_debug) or powertools_dev_is_set() + + return powertools_dev_is_set() + @staticmethod def _compile_regex(rule: str): """Precompile regex pattern diff --git a/aws_lambda_powertools/logging/formatter.py b/aws_lambda_powertools/logging/formatter.py index 51f60a87021..25f9c227c97 100644 --- a/aws_lambda_powertools/logging/formatter.py +++ b/aws_lambda_powertools/logging/formatter.py @@ -9,7 +9,7 @@ from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union from ..shared import constants -from ..shared.functions import strtobool +from ..shared.functions import powertools_dev_is_set RESERVED_LOG_ATTRS = ( "name", @@ -116,7 +116,7 @@ def __init__( self.json_deserializer = json_deserializer or json.loads self.json_default = json_default or str self.json_indent = ( - constants.PRETTY_INDENT if strtobool(os.getenv("POWERTOOLS_DEV", "0")) else constants.COMPACT_INDENT + constants.PRETTY_INDENT if powertools_dev_is_set() else constants.COMPACT_INDENT ) # indented json serialization when in AWS SAM Local self.json_serializer = json_serializer or partial( json.dumps, default=self.json_default, separators=(",", ":"), indent=self.json_indent diff --git a/aws_lambda_powertools/shared/constants.py b/aws_lambda_powertools/shared/constants.py index 09d9132af90..5db9ec08a56 100644 --- a/aws_lambda_powertools/shared/constants.py +++ b/aws_lambda_powertools/shared/constants.py @@ -36,3 +36,4 @@ # JSON indentation level PRETTY_INDENT: int = 4 COMPACT_INDENT = None +POWERTOOLS_DEV_ENV: str = "POWERTOOLS_DEV" diff --git a/aws_lambda_powertools/shared/functions.py b/aws_lambda_powertools/shared/functions.py index e9bc3521125..a25a3e7631e 100644 --- a/aws_lambda_powertools/shared/functions.py +++ b/aws_lambda_powertools/shared/functions.py @@ -1,8 +1,12 @@ import base64 import logging +import os +import warnings from binascii import Error as BinAsciiError from typing import Optional, Union +from aws_lambda_powertools.shared import constants + logger = logging.getLogger(__name__) @@ -78,3 +82,12 @@ def bytes_to_string(value: bytes) -> str: return value.decode("utf-8") except (BinAsciiError, TypeError): raise ValueError("base64 UTF-8 decode failed") + + +def powertools_dev_is_set() -> bool: + is_on = strtobool(os.getenv(constants.POWERTOOLS_DEV_ENV, "0")) + if is_on: + warnings.warn("POWERTOOLS_DEV environment variable is enabled. Increasing verbosity across utilities.") + return True + + return False diff --git a/docs/core/event_handler/api_gateway.md b/docs/core/event_handler/api_gateway.md index fe22bc1bc4f..9f7fe132876 100644 --- a/docs/core/event_handler/api_gateway.md +++ b/docs/core/event_handler/api_gateway.md @@ -388,7 +388,7 @@ Like `compress` feature, the client must send the `Accept` header with the corre ### Debug mode -You can enable debug mode via `debug` param, or via `POWERTOOLS_EVENT_HANDLER_DEBUG` [environment variable](../../index.md#environment-variables). +You can enable debug mode via `debug` param, or via `POWERTOOLS_DEV` [environment variable](../../index.md#environment-variables). This will enable full tracebacks errors in the response, print request and responses, and set CORS in development mode. diff --git a/tests/functional/event_handler/test_api_gateway.py b/tests/functional/event_handler/test_api_gateway.py index 04870adb619..ae2c3eee43e 100644 --- a/tests/functional/event_handler/test_api_gateway.py +++ b/tests/functional/event_handler/test_api_gateway.py @@ -686,6 +686,16 @@ def test_debug_mode_environment_variable(monkeypatch): assert app._debug +def test_powertools_dev_sets_debug_mode(monkeypatch): + # GIVEN a debug mode environment variable is set + monkeypatch.setenv(constants.POWERTOOLS_DEV_ENV, "true") + app = ApiGatewayResolver() + + # WHEN calling app._debug + # THEN the debug mode is enabled + assert app._debug + + def test_debug_json_formatting(json_dump): # GIVEN debug is True app = ApiGatewayResolver(debug=True)