Skip to content

feat(metrics): add default_dimensions to single_metric #1880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion aws_lambda_powertools/metrics/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,11 @@ def add_metric(self, name: str, unit: Union[MetricUnit, str], value: float) -> N

@contextmanager
def single_metric(
name: str, unit: MetricUnit, value: float, namespace: Optional[str] = None
name: str,
unit: MetricUnit,
value: float,
namespace: Optional[str] = None,
default_dimensions: Optional[Dict[str, str]] = None,
) -> Generator[SingleMetric, None, None]:
"""Context manager to simplify creation of a single metric

Expand Down Expand Up @@ -516,6 +520,11 @@ def single_metric(
try:
metric: SingleMetric = SingleMetric(namespace=namespace)
metric.add_metric(name=name, unit=unit, value=value)

if default_dimensions:
for dim_name, dim_value in default_dimensions.items():
metric.add_dimension(name=dim_name, value=dim_value)

yield metric
metric_set = metric.serialize_metric_set()
finally:
Expand Down
14 changes: 14 additions & 0 deletions docs/core/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,20 @@ CloudWatch EMF uses the same dimensions across all your metrics. Use `single_met
--8<-- "examples/metrics/src/single_metric_output.json"
```

By default it will skip all previously defined dimensions including default dimensions. Use `default_dimensions` keyword argument if you want to reuse default dimensions or specify custom dimensions from a dictionary.

=== "single_metric_default_dimensions_inherit.json"

```json hl_lines="10 15"
--8<-- "examples/metrics/src/single_metric_default_dimensions_inherit.py"
```

=== "single_metric_default_dimensions.py"

```python hl_lines="12"
--8<-- "examples/metrics/src/single_metric_default_dimensions.py"
```

### Flushing metrics manually

If you prefer not to use `log_metrics` because you might want to encapsulate additional logic when doing so, you can manually flush and clear metrics as follows:
Expand Down
14 changes: 14 additions & 0 deletions examples/metrics/src/single_metric_default_dimensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import os

from aws_lambda_powertools import single_metric
from aws_lambda_powertools.metrics import MetricUnit
from aws_lambda_powertools.utilities.typing import LambdaContext

STAGE = os.getenv("STAGE", "dev")


def lambda_handler(event: dict, context: LambdaContext):
with single_metric(
name="RecordsCount", unit=MetricUnit.Count, value=10, default_dimensions={"environment": STAGE}
) as metric:
metric.add_dimension(name="TableName", value="Users")
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import os

from aws_lambda_powertools import single_metric
from aws_lambda_powertools.metrics import Metrics, MetricUnit
from aws_lambda_powertools.utilities.typing import LambdaContext

STAGE = os.getenv("STAGE", "dev")

metrics = Metrics()
metrics.set_default_dimensions(environment=STAGE)


def lambda_handler(event: dict, context: LambdaContext):
with single_metric(
name="RecordsCount", unit=MetricUnit.Count, value=10, default_dimensions=metrics.default_dimensions
) as metric:
metric.add_dimension(name="TableName", value="Users")
32 changes: 32 additions & 0 deletions tests/functional/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,38 @@ def test_single_metric_logs_one_metric_only(capsys, metric, dimension, namespace
assert expected == output


def test_single_metric_default_dimensions(capsys, metric, dimension, namespace):
# GIVEN we provide default dimensions
# WHEN using single_metric context manager
default_dimensions = {dimension["name"]: dimension["value"]}
with single_metric(namespace=namespace, default_dimensions=default_dimensions, **metric) as my_metric:
my_metric.add_metric(name="second_metric", unit="Count", value=1)

output = capture_metrics_output(capsys)
expected = serialize_single_metric(metric=metric, dimension=dimension, namespace=namespace)

# THEN we should have default dimension added to the metric
remove_timestamp(metrics=[output, expected])
assert expected == output


def test_single_metric_default_dimensions_inherit(capsys, metric, dimension, namespace):
# GIVEN we provide Metrics default dimensions
# WHEN using single_metric context manager
metrics = Metrics()
default_dimensions = {dimension["name"]: dimension["value"]}
metrics.set_default_dimensions(**default_dimensions)
with single_metric(namespace=namespace, default_dimensions=metrics.default_dimensions, **metric) as my_metric:
my_metric.add_metric(name="second_metric", unit="Count", value=1)

output = capture_metrics_output(capsys)
expected = serialize_single_metric(metric=metric, dimension=dimension, namespace=namespace)

# THEN we should have default dimension added to the metric
remove_timestamp(metrics=[output, expected])
assert expected == output


def test_log_metrics(capsys, metrics, dimensions, namespace):
# GIVEN Metrics is initialized
my_metrics = Metrics(namespace=namespace)
Expand Down