Skip to content

wip: refactor: uniquely identify metric time series by name and label sets #131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

incertum
Copy link
Contributor

@incertum incertum commented Aug 5, 2025

Previously, metrics were identified by their name. This change allows a shared metric name per metric type, with each unique set of labels defining a distinct time series.

Additionally, the internal data structure for a stored metric has been refactored, providing a more robust and programmatic representation.

CC @FranzBusch, @ktoso, @blindspotbounty

Let me know how you'd prefer to proceed. We have two main options:

  1. I can split this work into a few smaller, more focused PRs.
  2. We can finalize the overall approach in this PR, and I can push the remaining changes here next week.

Fixes #125 opened by @blindspotbounty

Previously, counters could only be identified by their name. This change allows multiple counters to share the same name, with each unique set of labels defining a distinct time series.

Additionally, the internal data structure for a stored metric has been refactored, providing a more robust and programmatic representation.

Signed-off-by: Melissa Kilby <[email protected]>
}

private enum MetricType {
case counterMetrics(String, MetricContainer<Counter>)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In general not sure yet about naming, ideas?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also I would love to benefit from your Swift expertise re below ... it's probably the Type? It should be typed out for each metric type?

 note: consider making enum 'MetricType' conform to the 'Sendable' protocol
    private enum MetricType {

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah Type isn't right, this isn't a type, it's a container. Something feels off with the names here, this is a container but why do we need MetricContainer if it's a single field?

By what is this supposed to be keyed, MetricsByLabel or some MetricGroup maybe?


If you're seeing a note there's an associated warning (or error) that is the actual problem somewhere. Sendable is about concurrency safety, and yeah this may want to be Sendable if able to?

Copy link
Collaborator

@ktoso ktoso left a comment

Choose a reason for hiding this comment

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

Overall ok, but the names are really confusing. Perhaps: keep Metric a type, drop MetricContainer, doesn't seem to have anything specific it's adding -- just a single field, and then rename "MetricType" to be the Container type?

private enum Metric {
case counter(Counter, help: String)
case counterWithLabels([String], [LabelsKey: Counter], help: String)
private typealias Metric<T> = (metric: T, help: String)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd avoid tuples when a thing seems more like a normal data type, make it a real type I think

}

private enum MetricType {
case counterMetrics(String, MetricContainer<Counter>)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah Type isn't right, this isn't a type, it's a container. Something feels off with the names here, this is a container but why do we need MetricContainer if it's a single field?

By what is this supposed to be keyed, MetricsByLabel or some MetricGroup maybe?


If you're seeing a note there's an associated warning (or error) that is the actual problem somewhere. Sendable is about concurrency safety, and yeah this may want to be Sendable if able to?

guard let _ = MetricContainer.metrics.first?.value else {
continue
}
for Metric in MetricContainer.metrics.values {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
for Metric in MetricContainer.metrics.values {
for metric in MetricContainer.metrics.values {

buffer.addLine(prefix: prefixType, name: label, value: "counter")
for counter in counters.values {
counter.emit(into: &buffer)
case .counterMetrics(_, let MetricContainer):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure why the uppercase names?

Suggested change
case .counterMetrics(_, let MetricContainer):
case .counterMetrics(_, let metricContainer):

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.

Crash if tags and not the same (allow different tags for the same metric name)
2 participants