Skip to content

Commit 8e115bb

Browse files
committed
chore: log debug custom validators
Signed-off-by: heitorlessa <[email protected]>
1 parent 2828fe6 commit 8e115bb

File tree

2 files changed

+37
-24
lines changed

2 files changed

+37
-24
lines changed

aws_lambda_powertools/utilities/feature_flags/schema.py

+35-20
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
TIME_RANGE_PATTERN = re.compile(r"2[0-3]:[0-5]\d|[0-1]\d:[0-5]\d") # 24 hour clock
2626
HOUR_MIN_SEPARATOR = ":"
2727

28+
LOGGER: logging.Logger | Logger = logging.getLogger(__name__)
29+
2830

2931
class RuleAction(str, Enum):
3032
EQUALS = "EQUALS"
@@ -196,7 +198,12 @@ class SchemaValidator(BaseValidator):
196198

197199
def __init__(self, schema: Dict[str, Any], logger: Optional[Union[logging.Logger, Logger]] = None):
198200
self.schema = schema
199-
self.logger = logger or logging.getLogger(__name__)
201+
self.logger = logger or LOGGER
202+
203+
# Validators are designed for modular testing
204+
# therefore we link the custom logger with global LOGGER
205+
# so custom validators can use them when necessary
206+
SchemaValidator._link_global_logger(self.logger)
200207

201208
def validate(self) -> None:
202209
self.logger.debug("Validating schema")
@@ -206,13 +213,18 @@ def validate(self) -> None:
206213
features = FeaturesValidator(schema=self.schema, logger=self.logger)
207214
features.validate()
208215

216+
@staticmethod
217+
def _link_global_logger(logger: logging.Logger | Logger):
218+
global LOGGER
219+
LOGGER = logger
220+
209221

210222
class FeaturesValidator(BaseValidator):
211223
"""Validates each feature and calls RulesValidator to validate its rules"""
212224

213225
def __init__(self, schema: Dict, logger: Optional[Union[logging.Logger, Logger]] = None):
214226
self.schema = schema
215-
self.logger = logger or logging.getLogger(__name__)
227+
self.logger = logger or LOGGER
216228

217229
def validate(self):
218230
for name, feature in self.schema.items():
@@ -250,7 +262,7 @@ def __init__(
250262
self.feature = feature
251263
self.feature_name = next(iter(self.feature))
252264
self.rules: Optional[Dict] = self.feature.get(RULES_KEY)
253-
self.logger = logger or logging.getLogger(__name__)
265+
self.logger = logger or LOGGER
254266
self.boolean_feature = boolean_feature
255267

256268
def validate(self):
@@ -297,7 +309,7 @@ class ConditionsValidator(BaseValidator):
297309
def __init__(self, rule: Dict[str, Any], rule_name: str, logger: Optional[Union[logging.Logger, Logger]] = None):
298310
self.conditions: List[Dict[str, Any]] = rule.get(CONDITIONS_KEY, {})
299311
self.rule_name = rule_name
300-
self.logger = logger or logging.getLogger(__name__)
312+
self.logger = logger or LOGGER
301313

302314
def validate(self):
303315
if not self.conditions or not isinstance(self.conditions, list):
@@ -341,14 +353,17 @@ def validate_condition_key(condition: Dict[str, Any], rule_name: str):
341353
# SCHEDULE_BETWEEN_DAYS_OF_WEEK_KEY
342354
# - extra validation: `_validate_schedule_between_days_of_week_key`
343355
#
344-
# maintenance: we can split to separate file and classes for better organization later, e.g., visitor pattern.
356+
# maintenance: we should split to separate file/classes for better organization, e.g., visitor pattern.
357+
358+
custom_validator = getattr(ConditionsValidator, f"_validate_{action.lower()}_key")
345359

346-
custom_validator = getattr(
347-
ConditionsValidator,
348-
f"_validate_{action.lower()}_key",
349-
ConditionsValidator._validate_noop_value,
350-
)
360+
# ~90% of actions available don't require a custom validator
361+
# logging a debug statement for no-match will increase CPU cycles for most customers
362+
# for that reason only, we invert and log only when extra validation is found.
363+
if custom_validator is None:
364+
return
351365

366+
LOGGER.debug(f"{action} requires key validation. Running '{custom_validator}' validator.")
352367
custom_validator(key, rule_name)
353368

354369
@staticmethod
@@ -364,19 +379,19 @@ def validate_condition_value(condition: Dict[str, Any], rule_name: str):
364379
# SCHEDULE_BETWEEN_DAYS_OF_WEEK_KEY
365380
# - extra validation: `_validate_schedule_between_days_of_week_value`
366381
#
367-
# maintenance: we can split to separate file and classes for better organization later, e.g., visitor pattern.
382+
# maintenance: we should split to separate file/classes for better organization, e.g., visitor pattern.
368383

369-
custom_validator = getattr(
370-
ConditionsValidator,
371-
f"_validate_{action.lower()}_value",
372-
ConditionsValidator._validate_noop_value,
373-
)
384+
custom_validator = getattr(ConditionsValidator, f"_validate_{action.lower()}_value")
374385

375-
custom_validator(value, rule_name)
386+
# ~90% of actions available don't require a custom validator
387+
# logging a debug statement for no-match will increase CPU cycles for most customers
388+
# for that reason only, we invert and log only when extra validation is found.
389+
if custom_validator is None:
390+
return
376391

377-
@staticmethod
378-
def _validate_noop_value(*args, **kwargs):
379-
return True
392+
LOGGER.debug(f"{action} requires value validation. Running '{custom_validator}' validator.")
393+
394+
custom_validator(value, rule_name)
380395

381396
@staticmethod
382397
def _validate_schedule_between_days_of_week_key(key: str, rule_name: str):

tests/functional/feature_flags/test_schema_validation.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import logging
21
import re
32

4-
import pytest # noqa: F401
3+
import pytest
54

5+
from aws_lambda_powertools.logging.logger import Logger # noqa: F401
66
from aws_lambda_powertools.utilities.feature_flags.exceptions import (
77
SchemaValidationError,
88
)
@@ -24,8 +24,6 @@
2424
TimeValues,
2525
)
2626

27-
logger = logging.getLogger(__name__)
28-
2927
EMPTY_SCHEMA = {"": ""}
3028

3129

0 commit comments

Comments
 (0)