Skip to content

Commit dee0fdc

Browse files
feat(metrics): allow change ColdStart function_name dimension (#6315)
* Adding function name for ColdStart metric * Adding function name for ColdStart metric * Fix datadog metrics
1 parent 5afa4ee commit dee0fdc

File tree

11 files changed

+205
-24
lines changed

11 files changed

+205
-24
lines changed

aws_lambda_powertools/metrics/functions.py

+38
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import os
44
from datetime import datetime
5+
from typing import TYPE_CHECKING
56

67
from aws_lambda_powertools.metrics.provider.cloudwatch_emf.exceptions import (
78
MetricResolutionError,
@@ -11,6 +12,9 @@
1112
from aws_lambda_powertools.shared import constants
1213
from aws_lambda_powertools.shared.functions import strtobool
1314

15+
if TYPE_CHECKING:
16+
from aws_lambda_powertools.utilities.typing.lambda_context import LambdaContext
17+
1418

1519
def extract_cloudwatch_metric_resolution_value(metric_resolutions: list, resolution: int | MetricResolution) -> int:
1620
"""Return metric value from CloudWatch metric unit whether that's str or MetricResolution enum
@@ -161,3 +165,37 @@ def is_metrics_disabled() -> bool:
161165
]
162166

163167
return any(disable_conditions)
168+
169+
170+
def resolve_cold_start_function_name(function_name: str | None, context: LambdaContext) -> str:
171+
"""
172+
Resolve the function name for ColdStart metrics with a prioritized approach.
173+
174+
Parameters
175+
----------
176+
function_name : str, optional
177+
Explicitly provided function name (highest priority).
178+
context : LambdaContext
179+
AWS Lambda context object.
180+
181+
Returns
182+
-------
183+
str
184+
Resolved function name.
185+
186+
Notes
187+
-----
188+
Function name resolution follows this priority:
189+
1. Explicitly provided function_name
190+
2. Environment variable POWERTOOLS_METRICS_FUNCTION_NAME
191+
3. Lambda context function name
192+
"""
193+
194+
if function_name:
195+
return function_name
196+
197+
metrics_function_name_env = os.getenv(constants.METRICS_FUNCTION_NAME_ENV)
198+
if metrics_function_name_env:
199+
return metrics_function_name_env
200+
201+
return context.function_name

aws_lambda_powertools/metrics/metrics.py

+2
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def __init__(
8686
service: str | None = None,
8787
namespace: str | None = None,
8888
provider: AmazonCloudWatchEMFProvider | None = None,
89+
function_name: str | None = None,
8990
):
9091
self.metric_set = self._metrics
9192
self.metadata_set = self._metadata
@@ -102,6 +103,7 @@ def __init__(
102103
dimension_set=self.dimension_set,
103104
metadata_set=self.metadata_set,
104105
default_dimensions=self._default_dimensions,
106+
function_name=function_name,
105107
)
106108
else:
107109
self.provider = provider

aws_lambda_powertools/metrics/provider/cloudwatch_emf/cloudwatch.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
extract_cloudwatch_metric_resolution_value,
1717
extract_cloudwatch_metric_unit_value,
1818
is_metrics_disabled,
19+
resolve_cold_start_function_name,
1920
validate_emf_timestamp,
2021
)
2122
from aws_lambda_powertools.metrics.provider.base import BaseProvider
@@ -51,6 +52,10 @@ class AmazonCloudWatchEMFProvider(BaseProvider):
5152
metric namespace to be set for all metrics
5253
POWERTOOLS_SERVICE_NAME : str
5354
service name used for default dimension
55+
POWERTOOLS_METRICS_FUNCTION_NAME: str
56+
function name used as dimension for the ColdStart metric
57+
POWERTOOLS_METRICS_DISABLED: bool
58+
disables all metrics emitted by Powertools
5459
5560
Raises
5661
------
@@ -72,12 +77,14 @@ def __init__(
7277
metadata_set: dict[str, Any] | None = None,
7378
service: str | None = None,
7479
default_dimensions: dict[str, Any] | None = None,
80+
function_name: str | None = None,
7581
):
7682
self.metric_set = metric_set if metric_set is not None else {}
7783
self.dimension_set = dimension_set if dimension_set is not None else {}
7884
self.default_dimensions = default_dimensions or {}
7985
self.namespace = resolve_env_var_choice(choice=namespace, env=os.getenv(constants.METRICS_NAMESPACE_ENV))
8086
self.service = resolve_env_var_choice(choice=service, env=os.getenv(constants.SERVICE_NAME_ENV))
87+
self.function_name = function_name
8188

8289
self.metadata_set = metadata_set if metadata_set is not None else {}
8390
self.timestamp: int | None = None
@@ -445,9 +452,11 @@ def add_cold_start_metric(self, context: LambdaContext) -> None:
445452
context : Any
446453
Lambda context
447454
"""
455+
456+
cold_start_function_name = resolve_cold_start_function_name(function_name=self.function_name, context=context)
448457
logger.debug("Adding cold start metric and function_name dimension")
449458
with single_metric(name="ColdStart", unit=MetricUnit.Count, value=1, namespace=self.namespace) as metric:
450-
metric.add_dimension(name="function_name", value=context.function_name)
459+
metric.add_dimension(name="function_name", value=cold_start_function_name)
451460
if self.service:
452461
metric.add_dimension(name="service", value=str(self.service))
453462

aws_lambda_powertools/metrics/provider/datadog/datadog.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from typing import TYPE_CHECKING, Any
1111

1212
from aws_lambda_powertools.metrics.exceptions import MetricValueError, SchemaValidationError
13-
from aws_lambda_powertools.metrics.functions import is_metrics_disabled
13+
from aws_lambda_powertools.metrics.functions import is_metrics_disabled, resolve_cold_start_function_name
1414
from aws_lambda_powertools.metrics.provider import BaseProvider
1515
from aws_lambda_powertools.metrics.provider.datadog.warnings import DatadogDataValidationWarning
1616
from aws_lambda_powertools.shared import constants
@@ -58,8 +58,10 @@ def __init__(
5858
namespace: str | None = None,
5959
flush_to_log: bool | None = None,
6060
default_tags: dict[str, Any] | None = None,
61+
function_name: str | None = None,
6162
):
6263
self.metric_set = metric_set if metric_set is not None else []
64+
self.function_name = function_name
6365
self.namespace = (
6466
resolve_env_var_choice(choice=namespace, env=os.getenv(constants.METRICS_NAMESPACE_ENV))
6567
or DEFAULT_NAMESPACE
@@ -224,8 +226,11 @@ def add_cold_start_metric(self, context: LambdaContext) -> None:
224226
context : Any
225227
Lambda context
226228
"""
229+
230+
cold_start_function_name = resolve_cold_start_function_name(function_name=self.function_name, context=context)
231+
227232
logger.debug("Adding cold start metric and function_name tagging")
228-
self.add_metric(name="ColdStart", value=1, function_name=context.function_name)
233+
self.add_metric(name="ColdStart", value=1, function_name=cold_start_function_name)
229234

230235
def log_metrics(
231236
self,

aws_lambda_powertools/shared/constants.py

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
DATADOG_FLUSH_TO_LOG: str = "DD_FLUSH_TO_LOG"
4242
SERVICE_NAME_ENV: str = "POWERTOOLS_SERVICE_NAME"
4343
METRICS_DISABLED_ENV: str = "POWERTOOLS_METRICS_DISABLED"
44+
METRICS_FUNCTION_NAME_ENV: str = "POWERTOOLS_METRICS_FUNCTION_NAME"
4445
# If the timestamp of log event is more than 2 hours in future, the log event is skipped.
4546
# If the timestamp of log event is more than 14 days in past, the log event is skipped.
4647
# See https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AgentReference.html

docs/core/metrics.md

+24-6
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,20 @@ If you're new to Amazon CloudWatch, there are five terminologies you must be awa
3434
???+ tip
3535
All examples shared in this documentation are available within the [project repository](https://github.com/aws-powertools/powertools-lambda-python/tree/develop/examples){target="_blank"}.
3636

37-
Metric has three global settings that will be used across all metrics emitted:
37+
Metric has two global settings that will be used across all metrics emitted:
3838

3939
| Setting | Description | Environment variable | Constructor parameter |
4040
| ------------------------------- | ------------------------------------------------------------------------------- | ------------------------------ | --------------------- |
4141
| **Metric namespace** | Logical container where all metrics will be placed e.g. `ServerlessAirline` | `POWERTOOLS_METRICS_NAMESPACE` | `namespace` |
4242
| **Service** | Optionally, sets **service** metric dimension across all metrics e.g. `payment` | `POWERTOOLS_SERVICE_NAME` | `service` |
43-
| **Disable Powertools Metrics** | Optionally, disables all Powertools metrics. | `POWERTOOLS_METRICS_DISABLED` | N/A |
4443

4544
???+ info
4645
`POWERTOOLS_METRICS_DISABLED` will not disable default metrics created by AWS services.
4746

4847
???+ tip
4948
Use your application or main service as the metric namespace to easily group all metrics.
5049

51-
```yaml hl_lines="13" title="AWS Serverless Application Model (SAM) example"
50+
```yaml hl_lines="12-14" title="AWS Serverless Application Model (SAM) example"
5251
--8<-- "examples/metrics/sam/template.yaml"
5352
```
5453

@@ -214,13 +213,32 @@ This has the advantage of keeping cold start metric separate from your applicati
214213
???+ info
215214
We do not emit 0 as a value for ColdStart metric for cost reasons. [Let us know](https://github.com/aws-powertools/powertools-lambda-python/issues/new?assignees=&labels=feature-request%2C+triage&template=feature_request.md&title=){target="_blank"} if you'd prefer a flag to override it.
216215

216+
#### Customizing function name for cold start metrics
217+
218+
When emitting cold start metrics, the `function_name` dimension defaults to `context.function_name`. If you want to change the value you can set the `function_name` parameter in the metrics constructor, or define the environment variable `POWERTOOLS_METRICS_FUNCTION_NAME`.
219+
220+
The priority of the `function_name` dimension value is defined as:
221+
222+
1. `function_name` constructor option
223+
2. `POWERTOOLS_METRICS_FUNCTION_NAME` environment variable
224+
3. `context.function_name` property
225+
226+
=== "working_with_custom_cold_start_function_name.py"
227+
228+
```python hl_lines="4"
229+
--8<-- "examples/metrics/src/working_with_custom_cold_start_function_name.py"
230+
```
231+
217232
### Environment variables
218233

219234
The following environment variable is available to configure Metrics at a global scope:
220235

221-
| Setting | Description | Environment variable | Default |
222-
| ------------------ | -------------------------------- | ------------------------------ | ------- |
223-
| **Namespace Name** | Sets namespace used for metrics. | `POWERTOOLS_METRICS_NAMESPACE` | `None` |
236+
| Setting | Description | Environment variable | Default |
237+
| ------------------ | ------------------------------------------------------------ | ---------------------------------- | ------- |
238+
| **Namespace Name** | Sets **namespace** used for metrics. | `POWERTOOLS_METRICS_NAMESPACE` | `None` |
239+
| **Service** | Sets **service** metric dimension across all metrics e.g. `payment` | `POWERTOOLS_SERVICE_NAME` | `None` |
240+
| **Function Name** | Function name used as dimension for the **ColdStart** metric. | `POWERTOOLS_METRICS_FUNCTION_NAME` | `None` |
241+
| **Disable Powertools Metrics** | **Disables** all metrics emitted by Powertools. | `POWERTOOLS_METRICS_DISABLED` | `None` |
224242

225243
`POWERTOOLS_METRICS_NAMESPACE` is also available on a per-instance basis with the `namespace` parameter, which will consequently override the environment variable value.
226244

docs/index.md

+15-13
Original file line numberDiff line numberDiff line change
@@ -405,19 +405,21 @@ Core utilities such as Tracing, Logging, Metrics, and Event Handler will be avai
405405

406406
| Environment variable | Description | Utility | Default |
407407
| ----------------------------------------- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | --------------------- |
408-
| __POWERTOOLS_SERVICE_NAME__ | Sets service name used for tracing namespace, metrics dimension and structured logging | All | `"service_undefined"` |
409-
| __POWERTOOLS_METRICS_NAMESPACE__ | Sets namespace used for metrics | [Metrics](./core/metrics.md){target="_blank"} | `None` |
410-
| __POWERTOOLS_TRACE_DISABLED__ | Explicitly disables tracing | [Tracing](./core/tracer.md){target="_blank"} | `false` |
411-
| __POWERTOOLS_TRACER_CAPTURE_RESPONSE__ | Captures Lambda or method return as metadata. | [Tracing](./core/tracer.md){target="_blank"} | `true` |
412-
| __POWERTOOLS_TRACER_CAPTURE_ERROR__ | Captures Lambda or method exception as metadata. | [Tracing](./core/tracer.md){target="_blank"} | `true` |
413-
| __POWERTOOLS_TRACE_MIDDLEWARES__ | Creates sub-segment for each custom middleware | [Middleware factory](./utilities/middleware_factory.md){target="_blank"} | `false` |
414-
| __POWERTOOLS_LOGGER_LOG_EVENT__ | Logs incoming event | [Logging](./core/logger.md){target="_blank"} | `false` |
415-
| __POWERTOOLS_LOGGER_SAMPLE_RATE__ | Debug log sampling | [Logging](./core/logger.md){target="_blank"} | `0` |
416-
| __POWERTOOLS_LOG_DEDUPLICATION_DISABLED__ | Disables log deduplication filter protection to use Pytest Live Log feature | [Logging](./core/logger.md){target="_blank"} | `false` |
417-
| __POWERTOOLS_PARAMETERS_MAX_AGE__ | Adjust how long values are kept in cache (in seconds) | [Parameters](./utilities/parameters.md#adjusting-cache-ttl){target="_blank"} | `5` |
418-
| __POWERTOOLS_PARAMETERS_SSM_DECRYPT__ | Sets whether to decrypt or not values retrieved from AWS SSM Parameters Store | [Parameters](./utilities/parameters.md#ssmprovider){target="_blank"} | `false` |
419-
| __POWERTOOLS_DEV__ | Increases verbosity across utilities | Multiple; see [POWERTOOLS_DEV effect below](#optimizing-for-non-production-environments) | `false` |
420-
| __POWERTOOLS_LOG_LEVEL__ | Sets logging level | [Logging](./core/logger.md){target="_blank"} | `INFO` |
408+
| **POWERTOOLS_SERVICE_NAME** | Sets service name used for tracing namespace, metrics dimension and structured logging | All | `"service_undefined"` |
409+
| **POWERTOOLS_METRICS_NAMESPACE** | Sets namespace used for metrics | [Metrics](./core/metrics.md){target="_blank"} | `None` |
410+
| **POWERTOOLS_METRICS_FUNCTION_NAME** | Function name used as dimension for the **ColdStart** metric metrics | [Metrics](./core/metrics.md){target="_blank"} | `None` |
411+
| **POWERTOOLS_METRICS_DISABLED** | **Disables** all metrics emitted by Powertools metrics | [Metrics](./core/metrics.md){target="_blank"} | `None` |
412+
| **POWERTOOLS_TRACE_DISABLED** | Explicitly disables tracing | [Tracing](./core/tracer.md){target="_blank"} | `false` |
413+
| **POWERTOOLS_TRACER_CAPTURE_RESPONSE** | Captures Lambda or method return as metadata. | [Tracing](./core/tracer.md){target="_blank"} | `true` |
414+
| **POWERTOOLS_TRACER_CAPTURE_ERROR** | Captures Lambda or method exception as metadata. | [Tracing](./core/tracer.md){target="_blank"} | `true` |
415+
| **POWERTOOLS_TRACE_MIDDLEWARES** | Creates sub-segment for each custom middleware | [Middleware factory](./utilities/middleware_factory.md){target="_blank"} | `false` |
416+
| **POWERTOOLS_LOGGER_LOG_EVENT** | Logs incoming event | [Logging](./core/logger.md){target="_blank"} | `false` |
417+
| **POWERTOOLS_LOGGER_SAMPLE_RATE** | Debug log sampling | [Logging](./core/logger.md){target="_blank"} | `0` |
418+
| **POWERTOOLS_LOG_DEDUPLICATION_DISABLED** | Disables log deduplication filter protection to use Pytest Live Log feature | [Logging](./core/logger.md){target="_blank"} | `false` |
419+
| **POWERTOOLS_PARAMETERS_MAX_AGE** | Adjust how long values are kept in cache (in seconds) | [Parameters](./utilities/parameters.md#adjusting-cache-ttl){target="_blank"} | `5` |
420+
| **POWERTOOLS_PARAMETERS_SSM_DECRYPT** | Sets whether to decrypt or not values retrieved from AWS SSM Parameters Store | [Parameters](./utilities/parameters.md#ssmprovider){target="_blank"} | `false` |
421+
| **POWERTOOLS_DEV** | Increases verbosity across utilities | Multiple; see [POWERTOOLS_DEV effect below](#optimizing-for-non-production-environments) | `false` |
422+
| **POWERTOOLS_LOG_LEVEL** | Sets logging level | [Logging](./core/logger.md){target="_blank"} | `INFO` |
421423

422424
### Optimizing for non-production environments
423425

examples/metrics/sam/template.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Globals:
1111
Variables:
1212
POWERTOOLS_SERVICE_NAME: booking
1313
POWERTOOLS_METRICS_NAMESPACE: ServerlessAirline
14+
POWERTOOLS_METRICS_FUNCTION_NAME: my-function-name
1415

1516
Layers:
1617
# Find the latest Layer version in the official documentation
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from aws_lambda_powertools import Metrics
2+
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
4+
metrics = Metrics(function_name="my-function-name")
5+
6+
7+
@metrics.log_metrics(capture_cold_start_metric=True)
8+
def lambda_handler(event: dict, context: LambdaContext): ...

0 commit comments

Comments
 (0)