Skip to content

Conversation

@hazel-shen
Copy link
Contributor

@hazel-shen hazel-shen commented Nov 14, 2025

Description

Fixes #1035

Child metrics created via labels() could rebuild their full names when using metric subclasses with default namespace/subsystem/unit, especially in multiprocess mode, producing double-prefixed names.

Problem

With a subclass like:

class CustomCounter(Counter):
    def __init__(self, name, documentation, labelnames=(),
                 namespace='mydefaultnamespace',
                 subsystem='mydefaultsubsystem',
                 unit='defaultunit',
                 **kwargs):
        super().__init__(name, documentation, labelnames=labelnames,
                         namespace=namespace, subsystem=subsystem,
                         unit=unit, **kwargs)

and an instance:

c = CustomCounter(
    name='m',
    documentation='help',
    labelnames=('status', 'method'),
    namespace='mynamespace',
    subsystem='mysubsystem',
    unit='seconds',
)

multiprocess mode could export child metrics with double-prefixed names like:

mydefaultnamespace_mydefaultsubsystem_mynamespace_mysubsystem_m_seconds_total

instead of the correct:

mynamespace_mysubsystem_m_seconds_total

This happened because the already-built full name was passed to the child metric constructor, which then applied namespace/subsystem/unit transformations a second time.

Solution

  • In MetricWrapperBase.__init__, store original constructor arguments:

    self._original_name = name
    self._namespace = namespace
    self._subsystem = subsystem
    self._unit = unit
  • In MetricWrapperBase.labels(), use stored values when creating child metrics:

    original_name = getattr(self, '_original_name', self._name)
    namespace = getattr(self, '_namespace', '')
    subsystem = getattr(self, '_subsystem', '')
    unit = getattr(self, '_unit', '')
    
    self._metrics[labelvalues] = self.__class__(
        original_name,
        namespace=namespace,
        subsystem=subsystem,
        unit=unit,
        ...
    )

This ensures the full name is built exactly once, making single-process and multiprocess exports consistent.

Testing

  • All existing tests pass
  • Verified correct name construction in multiprocess mode
  • Verified subclass compatibility (child metrics preserve parent context)
  • Backward compatible via getattr() fallbacks

Breaking Changes

None (internal-only change to MetricWrapperBase)

@hazel-shen hazel-shen force-pushed the fix/multiprocess-child-name-double-build-1035 branch from 7bef223 to 11f2793 Compare November 14, 2025 11:23
@hazel-shen hazel-shen force-pushed the fix/multiprocess-child-name-double-build-1035 branch 2 times, most recently from 2c01fe2 to e21061a Compare November 14, 2025 11:30
Signed-off-by: hazel-shen <mail@hazel.style>
@hazel-shen hazel-shen force-pushed the fix/multiprocess-child-name-double-build-1035 branch from e21061a to d0cf1fc Compare November 14, 2025 11:40
Copy link
Member

@csmarchbanks csmarchbanks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@csmarchbanks csmarchbanks merged commit e8f8bae into prometheus:master Nov 17, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants