Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions Sources/Prometheus/MetricDescriptor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftPrometheus open source project
//
// Copyright (c) 2018-2025 SwiftPrometheus project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftPrometheus project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

/// A descriptor that defines the components of a fully qualified Prometheus metric name.
///
/// The final, underscore-separated metric name is generated by the ``name`` computed property. The ``helpText``
/// is used to generate the corresponding `# HELP` line in the Prometheus exposition format.
/// - Warning: This initializer will trigger a `preconditionFailure` if ``metricName`` is an empty string.
public struct MetricNameDescriptor {
/// An optional top-level namespace for the metric.
public let namespace: String?

/// An optional subsystem to group related metrics.
public let subsystem: String?

/// The required, descriptive base name of the metric.
public let metricName: String

/// An optional suffix describing the metric's unit (e.g., `total`).
public let unitName: String?

/// Optional descriptive text for the metric.
public let helpText: String?

/// Creates a new ``MetricNameDescriptor`` that defines the components of a fully qualified Prometheus metric name.
///
/// - Parameter namespace: An optional top-level namespace for the metric.
/// - Parameter subsystem: An optional subsystem to group related metrics within a namespace.
/// - Parameter metricName: The required, descriptive base name of the metric.
/// - Parameter unitName: An optional suffix describing the metric's unit (e.g., `total`).
/// - Parameter helpText: Optional descriptive text for the metric.
public init(
namespace: String? = nil,
subsystem: String? = nil,
metricName: String,
unitName: String? = nil,
helpText: String? = nil
) {
precondition(!metricName.isEmpty, "metricName must not be empty")
self.namespace = namespace
self.subsystem = subsystem
self.metricName = metricName
self.unitName = unitName
self.helpText = helpText
}

/// The fully qualified metric name, joining non-empty components with underscores.
public var name: String {
[namespace, subsystem, metricName, unitName]
.compactMap { $0?.isEmpty == false ? $0 : nil }
.joined(separator: "_")
}
}
118 changes: 118 additions & 0 deletions Sources/Prometheus/PrometheusCollectorRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,18 @@ public final class PrometheusCollectorRegistry: Sendable {
}
}

/// Creates a new ``Counter`` collector or returns the already existing one with the same name,
/// based on the provided descriptor.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
/// created ``Counter`` will be part of the export.
///
/// - Parameter descriptor: An ``MetricNameDescriptor`` that provides the fully qualified name for the metric.
/// - Returns: A ``Counter`` that is registered with this ``PrometheusCollectorRegistry``
public func makeCounter(descriptor: MetricNameDescriptor) -> Counter {
return self.makeCounter(name: descriptor.name)
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 a follow up PR will adjust this to enable printing the HELP line if applicable for all cases.

}

/// Creates a new ``Counter`` collector or returns the already existing one with the same name.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
Expand Down Expand Up @@ -150,6 +162,20 @@ public final class PrometheusCollectorRegistry: Sendable {
}
}

/// Creates a new ``Counter`` collector or returns the already existing one with the same name,
/// based on the provided descriptor.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
/// created ``Counter`` will be part of the export.
///
/// - Parameter descriptor: An ``MetricNameDescriptor`` that provides the fully qualified name for the metric.
/// - Parameter labels: Labels are sets of key-value pairs that allow us to characterize and organize
/// what’s actually being measured in a Prometheus metric.
/// - Returns: A ``Counter`` that is registered with this ``PrometheusCollectorRegistry``
public func makeCounter(descriptor: MetricNameDescriptor, labels: [(String, String)]) -> Counter {
return self.makeCounter(name: descriptor.name, labels: labels)
}

/// Creates a new ``Gauge`` collector or returns the already existing one with the same name.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
Expand Down Expand Up @@ -178,6 +204,18 @@ public final class PrometheusCollectorRegistry: Sendable {
}
}

/// Creates a new ``Gauge`` collector or returns the already existing one with the same name,
/// based on the provided descriptor.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
/// created ``Gauge`` will be part of the export.
///
/// - Parameter descriptor: An ``MetricNameDescriptor`` that provides the fully qualified name for the metric.
/// - Returns: A ``Gauge`` that is registered with this ``PrometheusCollectorRegistry``
public func makeGauge(descriptor: MetricNameDescriptor) -> Gauge {
return self.makeGauge(name: descriptor.name)
}

/// Creates a new ``Gauge`` collector or returns the already existing one with the same name.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
Expand Down Expand Up @@ -235,6 +273,20 @@ public final class PrometheusCollectorRegistry: Sendable {
}
}

/// Creates a new ``Gauge`` collector or returns the already existing one with the same name and labels,
/// based on the provided descriptor.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
/// created ``Gauge`` will be part of the export.
///
/// - Parameter descriptor: An ``MetricNameDescriptor`` that provides the fully qualified name for the metric.
/// - Parameter labels: Labels are sets of key-value pairs that allow us to characterize and organize
/// what’s actually being measured in a Prometheus metric.
/// - Returns: A ``Gauge`` that is registered with this ``PrometheusCollectorRegistry``
public func makeGauge(descriptor: MetricNameDescriptor, labels: [(String, String)]) -> Gauge {
return self.makeGauge(name: descriptor.name, labels: labels)
}

/// Creates a new ``DurationHistogram`` collector or returns the already existing one with the same name.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
Expand Down Expand Up @@ -264,6 +316,19 @@ public final class PrometheusCollectorRegistry: Sendable {
}
}

/// Creates a new ``DurationHistogram`` collector or returns the already existing one with the same name,
/// based on the provided descriptor.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
/// created ``DurationHistogram`` will be part of the export.
///
/// - Parameter descriptor: An ``MetricNameDescriptor`` that provides the fully qualified name for the metric.
/// - Parameter buckets: Define the buckets that shall be used within the ``DurationHistogram``
/// - Returns: A ``DurationHistogram`` that is registered with this ``PrometheusCollectorRegistry``
public func makeDurationHistogram(descriptor: MetricNameDescriptor, buckets: [Duration]) -> DurationHistogram {
return self.makeDurationHistogram(name: descriptor.name, buckets: buckets)
}

/// Creates a new ``DurationHistogram`` collector or returns the already existing one with the same name.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
Expand Down Expand Up @@ -338,6 +403,25 @@ public final class PrometheusCollectorRegistry: Sendable {
}
}

/// Creates a new ``DurationHistogram`` collector or returns the already existing one with the same name and labels,
/// based on the provided descriptor.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
/// created ``DurationHistogram`` will be part of the export.
///
/// - Parameter descriptor: An ``MetricNameDescriptor`` that provides the fully qualified name for the metric.
/// - Parameter labels: Labels are sets of key-value pairs that allow us to characterize and organize
/// what’s actually being measured in a Prometheus metric.
/// - Parameter buckets: Define the buckets that shall be used within the ``DurationHistogram``
/// - Returns: A ``DurationHistogram`` that is registered with this ``PrometheusCollectorRegistry``
public func makeDurationHistogram(
descriptor: MetricNameDescriptor,
labels: [(String, String)],
buckets: [Duration]
) -> DurationHistogram {
return self.makeDurationHistogram(name: descriptor.name, labels: labels, buckets: buckets)
}

/// Creates a new ``ValueHistogram`` collector or returns the already existing one with the same name.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
Expand All @@ -362,6 +446,19 @@ public final class PrometheusCollectorRegistry: Sendable {
}
}

/// Creates a new ``ValueHistogram`` collector or returns the already existing one with the same name,
/// based on the provided descriptor.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
/// created ``ValueHistogram`` will be part of the export.
///
/// - Parameter descriptor: An ``MetricNameDescriptor`` that provides the fully qualified name for the metric.
/// - Parameter buckets: Define the buckets that shall be used within the ``ValueHistogram``
/// - Returns: A ``ValueHistogram`` that is registered with this ``PrometheusCollectorRegistry``
public func makeValueHistogram(descriptor: MetricNameDescriptor, buckets: [Double]) -> ValueHistogram {
return self.makeValueHistogram(name: descriptor.name, buckets: buckets)
}

/// Creates a new ``ValueHistogram`` collector or returns the already existing one with the same name.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
Expand Down Expand Up @@ -408,6 +505,27 @@ public final class PrometheusCollectorRegistry: Sendable {
}
}

/// Creates a new ``ValueHistogram`` collector or returns the already existing one with the same name and labels,
/// based on the provided descriptor.
///
/// When the ``PrometheusCollectorRegistry/emit(into:)`` is called, metrics from the
/// created ``ValueHistogram`` will be part of the export.
///
/// - Parameter descriptor: An ``MetricNameDescriptor`` that provides the fully qualified name for the metric.
/// - Parameter labels: Labels are sets of key-value pairs that allow us to characterize and organize
/// what’s actually being measured in a Prometheus metric.
/// - Parameter buckets: Define the buckets that shall be used within the ``ValueHistogram``
/// - Returns: A ``ValueHistogram`` that is registered with this ``PrometheusCollectorRegistry``
public func makeValueHistogram(
descriptor: MetricNameDescriptor,
labels: [(String, String)],
buckets: [Double]
) -> ValueHistogram {
return self.makeValueHistogram(name: descriptor.name, labels: labels, buckets: buckets)
}

// MARK: - Histogram

// MARK: Destroying Metrics

/// Unregisters a ``Counter`` from the ``PrometheusCollectorRegistry``. This means that the provided ``Counter``
Expand Down
Loading