diff --git a/aws_lambda_powertools/metrics/base.py b/aws_lambda_powertools/metrics/base.py index 05c1fcbdfe9..8abdcde2717 100644 --- a/aws_lambda_powertools/metrics/base.py +++ b/aws_lambda_powertools/metrics/base.py @@ -23,7 +23,11 @@ MetricValueError, SchemaValidationError, ) -from aws_lambda_powertools.metrics.functions import convert_timestamp_to_emf_format, validate_emf_timestamp +from aws_lambda_powertools.metrics.functions import ( + convert_timestamp_to_emf_format, + is_metrics_disabled, + validate_emf_timestamp, +) from aws_lambda_powertools.metrics.provider import cold_start from aws_lambda_powertools.metrics.provider.cloudwatch_emf.constants import ( MAX_DIMENSIONS, @@ -659,4 +663,5 @@ def single_metric( yield metric metric_set = metric.serialize_metric_set() finally: - print(json.dumps(metric_set, separators=(",", ":"))) + if metric_set is not None and not is_metrics_disabled(): + print(json.dumps(metric_set, separators=(",", ":"))) diff --git a/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py index f8675018a24..2b982f29ef8 100644 --- a/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py +++ b/aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py @@ -174,8 +174,9 @@ def add_metric( if len(self.metric_set) == MAX_METRICS or len(metric["Value"]) == MAX_METRICS: logger.debug(f"Exceeded maximum of {MAX_METRICS} metrics - Publishing existing metric set") - metrics = self.serialize_metric_set() - print(json.dumps(metrics)) + if not is_metrics_disabled(): + metrics = self.serialize_metric_set() + print(json.dumps(metrics)) # clear metric set only as opposed to metrics and dimensions set # since we could have more than 100 metrics diff --git a/aws_lambda_powertools/metrics/provider/datadog/datadog.py b/aws_lambda_powertools/metrics/provider/datadog/datadog.py index ca6fca8a69a..1f295cd5a8a 100644 --- a/aws_lambda_powertools/metrics/provider/datadog/datadog.py +++ b/aws_lambda_powertools/metrics/provider/datadog/datadog.py @@ -197,7 +197,7 @@ def flush_metrics(self, raise_on_empty_metrics: bool = False) -> None: logger.debug("Flushing existing metrics") metrics = self.serialize_metric_set() # submit through datadog extension - if lambda_metric and not self.flush_to_log: + if lambda_metric and not self.flush_to_log and not is_metrics_disabled(): # use lambda_metric function from datadog package, submit metrics to datadog for metric_item in metrics: # pragma: no cover lambda_metric( # pragma: no cover diff --git a/tests/functional/metrics/datadog/test_metrics_datadog.py b/tests/functional/metrics/datadog/test_metrics_datadog.py index b07af997e4e..4a83cf58491 100644 --- a/tests/functional/metrics/datadog/test_metrics_datadog.py +++ b/tests/functional/metrics/datadog/test_metrics_datadog.py @@ -418,6 +418,21 @@ def test_metrics_disabled_with_env_var(monkeypatch, capsys): assert not captured.out +def test_metrics_disabled_with_env_var_does_not_submit_through_datadog_extension(monkeypatch, mocker): + # GIVEN environment variable is set to disable metrics + monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true") + # AND the datadog_lambda package is available + lambda_metric = mocker.patch("aws_lambda_powertools.metrics.provider.datadog.datadog.lambda_metric") + + # WHEN metrics are flushed through the Datadog extension + metrics = DatadogMetrics(flush_to_log=False) + metrics.add_metric(name="test_metric", value=1) + metrics.flush_metrics() + + # THEN no metrics should have been submitted + lambda_metric.assert_not_called() + + def test_metrics_disabled_persists_after_flush(monkeypatch, capsys): # GIVEN environment variable is set to disable metrics monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true") diff --git a/tests/functional/metrics/required_dependencies/test_metrics_cloudwatch_emf.py b/tests/functional/metrics/required_dependencies/test_metrics_cloudwatch_emf.py index 9d6c2cc8ee5..f1ac09c76d6 100644 --- a/tests/functional/metrics/required_dependencies/test_metrics_cloudwatch_emf.py +++ b/tests/functional/metrics/required_dependencies/test_metrics_cloudwatch_emf.py @@ -26,6 +26,7 @@ from aws_lambda_powertools.metrics.provider.cloudwatch_emf.constants import ( MAX_DIMENSIONS, MAX_METRIC_NAME_LENGTH, + MAX_METRICS, MIN_METRIC_NAME_LENGTH, ) from aws_lambda_powertools.metrics.provider.cloudwatch_emf.exceptions import MetricNameError @@ -1568,6 +1569,74 @@ def test_metrics_disabled_with_namespace_and_service(monkeypatch, capsys): assert not captured.out +def test_single_metric_disabled_with_env_var(monkeypatch, capsys, namespace): + # GIVEN environment variable is set to disable metrics + monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true") + + # WHEN a single metric is created + with single_metric(name="test_metric", unit=MetricUnit.Count, value=1, namespace=namespace): + pass + + # THEN no metrics should have been recorded + assert not capsys.readouterr().out + + +def test_single_metric_disabled_with_powertools_dev(monkeypatch, capsys, namespace): + # GIVEN POWERTOOLS_DEV is enabled and POWERTOOLS_METRICS_DISABLED is not set + monkeypatch.setenv("POWERTOOLS_DEV", "true") + monkeypatch.delenv("POWERTOOLS_METRICS_DISABLED", raising=False) + + # WHEN a single metric is created + with single_metric(name="test_metric", unit=MetricUnit.Count, value=1, namespace=namespace): + pass + + # THEN no metrics should have been recorded + assert not capsys.readouterr().out + + +def test_cold_start_metric_disabled_with_env_var(monkeypatch, capsys, namespace, service): + # GIVEN environment variable is set to disable metrics + monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true") + my_metrics = Metrics(service=service, namespace=namespace) + + # WHEN log_metrics captures the cold start metric + @my_metrics.log_metrics(capture_cold_start_metric=True) + def lambda_handler(evt, context): + my_metrics.add_metric(name="test_metric", unit=MetricUnit.Count, value=1) + + LambdaContext = namedtuple("LambdaContext", "function_name") + lambda_handler({}, LambdaContext("example_fn")) + + # THEN neither the cold start metric nor the application metric should have been recorded + assert not capsys.readouterr().out + + +def test_metrics_disabled_with_env_var_on_max_metrics_flush(monkeypatch, capsys, namespace): + # GIVEN environment variable is set to disable metrics + monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "true") + my_metrics = Metrics(namespace=namespace) + + # WHEN enough metrics are added to trigger the automatic flush + for i in range(MAX_METRICS): + my_metrics.add_metric(name=f"metric_{i}", unit=MetricUnit.Count, value=1) + + # THEN no metrics should have been recorded + assert not capsys.readouterr().out + # AND the metric set is still cleared + assert not my_metrics.metric_set + + +def test_single_metric_does_not_print_when_block_raises(capsys, namespace): + # GIVEN a single metric block + # WHEN its body raises + with pytest.raises(RuntimeError): + with single_metric(name="test_metric", unit=MetricUnit.Count, value=1, namespace=namespace): + raise RuntimeError("failure") + + # THEN nothing should have been printed + assert not capsys.readouterr().out + + def test_metrics_enabled_with_env_var_false(monkeypatch, capsys): # GIVEN environment variable is set to enable metrics monkeypatch.setenv("POWERTOOLS_METRICS_DISABLED", "false")