Skip to content

feat: expose registered metrics#1931

Draft
ivankatliarchuk wants to merge 3 commits into
prometheus:mainfrom
gofogo:feat-1801
Draft

feat: expose registered metrics#1931
ivankatliarchuk wants to merge 3 commits into
prometheus:mainfrom
gofogo:feat-1801

Conversation

@ivankatliarchuk
Copy link
Copy Markdown

@ivankatliarchuk ivankatliarchuk commented Dec 25, 2025

What This PR Does

Adds programmatic access to registered metric descriptors, eliminating the need for unsafe reflection to introspect metrics.

New APIs:

  1. Desc getter methods:

    • Name() string - Returns metric name
    • Help() string - Returns help text
    • ConstLabels() Labels - Returns constant labels
    • VariableLabels() []string - Returns variable label names
  2. Registry introspection:

    • Descriptors() []*Desc - Returns all registered metric descriptors

Benefits

  • Generate documentation from running services
  • Validate metric configurations programmatically
  • Build metric discovery and debugging tools
  • Replace unsafe reflection hacks (external-dns currently needs ~500 lines of workarounds)

Testing

  • Runnable example in examples/introspection/

Fixes #1801

Here's a practical example of how this simplifies real-world code.

  **Before (external-dns approach):**
  ```go
  // UNSAFE: Uses reflection to access private registry fields
  func extractMetrics(reg *prometheus.Registry) (map[string]MetricInfo, error) {
      // Get private dimHashesByName field using unsafe pointer manipulation
      registryValue := reflect.ValueOf(reg).Elem()
      dimHashesField := registryValue.FieldByName("dimHashesByName")
      dimHashesField = reflect.NewAt(
          dimHashesField.Type(),
          unsafe.Pointer(dimHashesField.UnsafeAddr()),
      ).Elem()

      // Extract and process descriptors (50+ more lines)
      // ...
  }

  After (with this PR):
  func extractMetrics(reg *prometheus.Registry) []MetricInfo {
      descs := reg.Descriptors()
      metrics := make([]MetricInfo, len(descs))

      for i, desc := range descs {
          metrics[i] = MetricInfo{
              Name:           desc.Name(),
              Help:           desc.Help(),
              ConstLabels:    desc.ConstLabels(),
              VariableLabels: desc.VariableLabels(),
          }
      }

      return metrics
  }

Clean, safe, and maintainable

Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>
Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>
Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>
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.

For Registerer interface expose all registered Metrics

1 participant