Skip to content

Maintenance: improve runtime validations in Metrics utility #4135

Open
@dreamorosi

Description

@dreamorosi

Summary

After comparing the Python and TypeScript implementations of AWS Lambda Powertools Metrics, I found a number of runtime validations that are present in the Python version but missing in the TypeScript version. These missing validations could lead to potential issues in production if not addressed.

Overall TypeScript version relies heavily on compile-time type safety without adequate runtime safeguards, and in certain cases, it allows invalid data to be passed at runtime.

Why is this needed?

The TypeScript implementation is missing several critical runtime validations that are present in the Python version:

  1. Metric Value Validation: No runtime check for numeric values
  2. Metric Unit Validation: No runtime validation against valid CloudWatch units
  3. Metric Resolution Validation: No runtime validation for resolution values (1 or 60)
  4. Dimension Name Validation: Only validates dimension values, not names, and allows whitespace-only strings

These missing validations could lead to:

  • Invalid metrics being sent to CloudWatch
  • Runtime errors when invalid data is passed
  • Silent failures where metrics are dropped by CloudWatch
  • Inconsistent behavior between Python and TypeScript implementations

Which area does this relate to?

Metrics

Solution

1. Runtime Metric Value Type Validation

The Python implementation includes a runtime check to ensure that metric values are valid numbers. If a non-numeric value is passed, it raises a MetricValueError.

Python code:

if not isinstance(value, numbers.Number):
    raise MetricValueError(f"{value} is not a valid number")

Python Source

The TypeScript implementation has no runtime validation if types are bypassed or incorrect values passed.

TypeScript Source - addMetric method

2. Runtime Metric Unit Validation

The Python implementation validates that the metric unit is one of the valid CloudWatch units at runtime. If an invalid unit is passed, it raises a MetricUnitError.

Python code:

def _extract_metric_unit_value(self, unit: str | MetricUnit) -> str:
    if isinstance(unit, str):
        if unit in self._metric_unit_valid_options:
            unit = MetricUnit[unit].value
        if unit not in self._metric_units:
            raise MetricUnitError(
                f"Invalid metric unit '{unit}', expected either option: {self._metric_unit_valid_options}",
            )

Python Source

The TypeScript implementation relies solely on TypeScript enum types and does not perform any runtime validation against valid CloudWatch units.

TypeScript Source - MetricUnit constants

3. Runtime Metric Resolution Validation

The Python implementation includes a runtime check to ensure that metric resolution values are valid integers (1 or 60). If an invalid resolution is passed, it raises a MetricResolutionError.

Python code:

def _extract_metric_resolution_value(self, resolution: int | MetricResolution) -> int:
    if isinstance(resolution, int) and resolution in self._metric_resolutions:
        return resolution
    raise MetricResolutionError(
        f"Invalid metric resolution '{resolution}', expected either option: {self._metric_resolutions}",
    )

Python Source

The TypeScript implementation does not perform any runtime validation for resolution values.

TypeScript Source - MetricResolution constants

4. Dimension Name Validation

The Python implementation includes validation for dimension names and values, ensuring they are non-empty strings and not just whitespace. If a dimension name or value is invalid, it raises a PowertoolsUserWarning.

Python code:

if not name.strip() or not value.strip():
    warnings.warn(
        f"The dimension {name} doesn't meet the requirements and won't be added. "
        "Ensure the dimension name and value are non-empty strings",
        category=PowertoolsUserWarning,
        stacklevel=2,
    )
    return

Python Source

The TypeScript implementation only checks if the value is truthy, which means it does not validate dimension names at all and allows whitespace-only strings.

TypeScript code:

// Only validates value, NOT name
if (!value) {
    this.#logger.warn(
        `The dimension ${name} doesn't meet the requirements and won't be added. Ensure the dimension name and value are non empty strings`
    );
    return;
}

TypeScript Source

Acknowledgment

Future readers

Please react with 👍 and your use case to help us understand customer demand.

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmedThe scope is clear, ready for implementationhelp-wantedWe would really appreciate some support from community for this onemetricsThis item relates to the Metrics Utility

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions