Skip to content

Feature request: Reuse namespace in Metrics.flushSingleMetric and other limitations #2153

Closed

Description

@humanzz

Use case

As a user of Powertools v1, and considering moving to v2, I found the withMetricsLogger now replaced with flushSingleMetric. I see 2 issues

  1. The current overloads, requires setting namespace, even though previously I've been relying on the namespace being whatever was already set (e.g. via powertools environment variables). I find this a degradation in UX if - which I think is a typical use case - I wanna use the same namespace
  2. I also had use cases for withMetricsLogger where I add multiple metrics, which share an overriden dimensionset. Now this needs to be replaced with multiple calls to flushSingleMetric

I think the refactor/abstractions led to some degradations when it comes to withMetricsLogger. Moreover, LambdaMetricsAspect do set a few other properties/metadata that no longer seem to be available in instances emitted by flushSingleMetric such as trace and function id.

Solution/User Experience

For 1, one solution would be to add flushSingleMetric overloads that don't take a namespace, and to update EmfMetricsLogger to treat the namespace parameter as nullable and a potential override to its this.namespace

For 2, maybe Metrics should get a new method flushMetrics with takes a Consumer<Metrics>, then one is more free about using default dimensions/namespace, or overriding them and adding multiple metrics.

Alternative solutions

N/A

Acknowledgment

Future readers

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

Activity

  1. leandrodamascena commented on Sep 29, 2025

    @leandrodamascena
    Contributor

    Hey @humanzz thanks for opening this issue and explaining more about the Developer Experience you expect from Powertools.

    Use case

    As a user of Powertools v1, and considering moving to v2, I found the withMetricsLogger now replaced with flushSingleMetric. I see 2 issues

    1. The current overloads, requires setting namespace, even though previously I've been relying on the namespace being whatever was already set (e.g. via powertools environment variables). I find this a degradation in UX if - which I think is a typical use case - I wanna use the same namespace

    Actually I think Java V2 aligns with the API for SingleMetrics in other runtimes, like Python and TypeScript. The mental model for a single metric is to have everything specific to that metric, like dimensions, values, and namespace. I'm open to discussing this and seeing if we can adapt this behavior or if we need to improve our documentation. Can you explain a bit more about using SingleMetrics with the same namespace? Shouldn't this be a use case for regular metric instances?

    1. I also had use cases for withMetricsLogger where I add multiple metrics, which share an overriden dimensionset. Now this needs to be replaced with multiple calls to flushSingleMetric>
      I think the refactor/abstractions led to some degradations when it comes to withMetricsLogger. Moreover, LambdaMetricsAspect do set a few other properties/metadata that no longer seem to be available in instances emitted by flushSingleMetric such as trace and function id.

    Can you give us your opinion here, @phipag?

    Solution/User Experience

    For 1, one solution would be to add flushSingleMetric overloads that don't take a namespace, and to update EmfMetricsLogger to treat the namespace parameter as nullable and a potential override to its this.namespace

    For 2, maybe Metrics should get a new method flushMetrics with takes a Consumer<Metrics>, then one is more free about using default dimensions/namespace, or overriding them and adding multiple metrics.

    Thanks for suggesting a better experience, but I think we have something to discuss before we decide which way to go.

  2. moved this from Triage to Pending review in Powertools for AWS Lambda (Java)on Sep 29, 2025
  3. moved this from Pending review to Working on it in Powertools for AWS Lambda (Java)on Sep 29, 2025
  4. phipag commented on Sep 29, 2025

    @phipag
    Contributor

    Can you explain a bit more about using SingleMetrics with the same namespace? Shouldn't this be a use case for regular metric instances?

    I would love to learn about such a use-case and how you solve it in v1 at the moment.

    I also had use cases for withMetricsLogger where I add multiple metrics, which share an overriden dimensionset. Now this needs to be replaced with multiple calls to flushSingleMetric

    This is a good call and indeed not possible anymore in v2. I see Python has

    with single_metric(name="MySingleMetric", unit=MetricUnit.Count, value=1) as metric:
            metric.add_dimension(name="environment", value=STAGE)

    When I implementing flushSingleMetric I was following the fact that emission of such single metrics should be single indeed – but I recognize there is a use-case for flushing multiple metrics with a different configuration in one go instead of calling flush every single time (e.g. in a for-loop). Inline with Java v2 naming conventions using the flush* syntax, I can image to introduce a new method such as this to support the use-case of flushing multiple custom metrics with a single call to flush:

        /**
         * Execute custom metrics collection with a fresh metrics instance.
         * The provided function receives a new Metrics instance that can be configured
         * independently (namespace, dimensions, etc.) and used to collect multiple metrics.
         * All metrics are automatically flushed after the function execution.
         *
         * @param metricsFunction function that receives a fresh Metrics instance for custom metric collection
         */
        void flushCustomMetrics(java.util.function.Consumer<Metrics> metricsFunction);

    The user-experience will look similar to this where metrics is the regular Metrics Singleton returned from the MetricsFactory:

    metrics.flushCustomMetrics(customMetrics -> {
        customMetrics.setNamespace("MyCustomNamespace");
        customMetrics.addDimension("Environment", "Production");
        customMetrics.addMetric("CustomMetric1", 42.0, MetricUnit.COUNT);
        customMetrics.addMetric("CustomMetric2", 3.14, MetricUnit.SECONDS);
        // No need to call flush() - it's done automatically
    });

    set a few other properties/metadata that no longer seem to be available in instances emitted by flushSingleMetric such as trace and function id

    Was this available in Java v1 (@humanzz?). How do you solve this in Python (@leandrodamascena?).

  5. leandrodamascena commented on Sep 29, 2025

    @leandrodamascena
    Contributor

    In Python, we don't define anything related to Tracerid, FunctionID, or any other Lambda function metadata when using metrics. In Metrics, we only add namespace, name, value, and dimensions that customer explicitly set it. I think PT Java v1 at some point had metrics published with function metadata, but I could be wrong.

  6. phipag commented on Sep 29, 2025

    @phipag
    Contributor

    Yes, I believe it was published with function metadata in v1 due to exposing the interface of the Java EMF library directly. However, we still set the trace id for example in LambdaMetricsAspect for all regular metrics and the function name for the cold start metric.

  7. assigned and unassigned on Sep 29, 2025
  8. moved this from Working on it to Backlog in Powertools for AWS Lambda (Java)on Sep 29, 2025
  9. 1 remaining item

  10. phipag commented on Sep 30, 2025

    @phipag
    Contributor

    Thanks for sending this PR @humanzz, I left some feedback there. I think we should add the flushMetrics function that you suggested and also incorporating the metrics metadata again (trace id) like you suggested.

    The key decision that we need to make in this issue before finalizing the implementation is:

    • Do we want to inherit the namespace, default dimensions, metadata from the existing metrics logger if flushMetrics() or flushSingleMetric is used?

    In v1 of the metrics utility we indeed copied over the existing metrics logger's configuration (see this code).

    @aws-powertools/lambda-dotnet-core, @aws-powertools/lambda-python-core, @aws-powertools/lambda-typescript-core Any opinions? I think Java was a special case here in v1.

  11. humanzz commented on Sep 30, 2025

    @humanzz
    ContributorAuthor

    So, over time, in many of lambda function handlers I work on, I came into the pattern of (as a user of v1 powertools)

    • in the handler, set some properties/metadata into both logging context/metrics metadata to ensure these are present across all log lines/metrics
    • in non-handler code, when emitting custom metrics, using MetricsUtils.withMetricsLogger, it's always intended to be within the same namespace - that I set via the environment variable - but the main difference that tends to happen is that I want to emit those metrics under different dimensions
    • This way, I'm emitting all metrics within the same namespace, and using the same metadata (already configured in the handler), and my business logic does not need to concern itself with figuring out namespace/metadata
    • The utility of shared metadata, is that like function request id, trace id, these metadata help with correlating different metrics/log lines if I want to inspect metrics/log lines for similar metadata
  12. dreamorosi commented on Sep 30, 2025

    @dreamorosi
    Contributor

    From a product standpoint, we should prioritize feature parity & have similar behaviors across runtimes, except for when there's a language specific or more idiomatic pattern that warrants diverging from it.

    With that said, if we think a certain pattern we had in v1 of this version is prevalent enough and valid, then we should consider adding it to all runtimes.

  13. phipag commented on Sep 30, 2025

    @phipag
    Contributor

    Personally, I like the proposal by @humanzz and this is how it was in v1 of Java Metrics as well. In our documentation we advertise the usage of single metrics as a way of emitting metrics with different dimensions:

    Use single_metric if you have a metric that should have different dimensions

    (Python)

    Use singleMetric if you have a metric that should have different dimensions.

    (TypeScript)

    Therefore, I think we should copy all configuration from the existing metrics logger to the single metrics logger except for the dimensions. If the user wants to change more than just dimensions they can still do so by using the set methods on the metrics logger.

    Right now, I see some inconsistent implementation and interface across the runtimes. This means, no matter what we decide, a breaking change is needed in at least one runtime to be consistent with the others.

    TypeScript

      const singleMetric = metrics.singleMetric();
      singleMetric.addDimension('metricType', 'business');
      singleMetric.addMetadata('orderId', event.orderId); 
    
    
      singleMetric.addMetric('successfulBooking', MetricUnit.Count, 1); 

    Python

        with single_metric(name="MySingleMetric", unit=MetricUnit.Count, value=1) as metric:
            metric.add_dimension(name="environment", value=STAGE)
    
        with single_metric(
            name="RecordsCount",
            unit=MetricUnit.Count,
            value=10,
            default_dimensions=metrics.default_dimensions,
        ) as metric:
            metric.add_dimension(name="TableName", value="Users")
    • Namespace copied
    • Default dimensions not copied
    • Regular dimensions not copied
    • Metadata not copied

    Suggestion for Java

            // This overload still needs to be added
            metrics.flushSingleMetric(
                "CustomMetric",
                1,
                MetricUnit.COUNT,
            );
    
            metrics.flushSingleMetric(
                "CustomMetric",
                1,
                MetricUnit.COUNT,
                "CustomNamespace"  // Overwrite namespace
            );
    
            metrics.flushSingleMetric(
                "CustomMetric",
                1,
                MetricUnit.COUNT,
                "CustomNamespace",
                DimensionSet.of("CustomDimension", "value")  // Overwrite default dimensions
            );
    
            // Equivalent to first flushSingleMetric call
            metrics.flushMetrics(metrics -> {
                // Namespace copied, default dimensions copied, regular dimensions not copied, metadata copied
                metrics.addMetric(name, value, unit);
            });
    • Namespace copied if not overwritten
    • Default dimensions copied if not overwritten
    • Regular dimensions not copied
    • Metadata copied
  14. moved this from Backlog to Pending review in Powertools for AWS Lambda (Java)on Oct 1, 2025
  15. linked a pull request that will close this issuefeat(metrics): introduce Metrics.flushMetrics #2154on Oct 1, 2025
  16. dreamorosi commented on Oct 1, 2025

    @dreamorosi
    Contributor

    Ok, if you think it makes sense no objections from my side.

  17. phipag commented on Oct 2, 2025

    @phipag
    Contributor

    Merged PR #2154

  18. moved this from Pending review to Shipped in Powertools for AWS Lambda (Java)on Oct 2, 2025
  19. moved this from Shipped to Coming soon in Powertools for AWS Lambda (Java)on Oct 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions