Skip to content
Merged
Prev Previous commit
Next Next commit
Remove ratio special case, combine _total in names
  • Loading branch information
robertcoltheart committed May 24, 2024
commit 2f1eef7aaff6ba303958ac487429950226fc1604
Original file line number Diff line number Diff line change
Expand Up @@ -36,40 +36,19 @@ public PrometheusMetric(string name, string unit, PrometheusType type, bool disa

// The resulting unit SHOULD be added to the metric as
// [OpenMetrics UNIT metadata](https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#metricfamily)
// and as a suffix to the metric name unless the metric name already contains the
// unit, or the unit MUST be omitted. The unit suffix comes before any
// type-specific suffixes.
// https://github.com/open-telemetry/opentelemetry-specification/blob/b2f923fb1650dde1f061507908b834035506a796/specification/compatibility/prometheus_and_openmetrics.md#L242-L246
if (!sanitizedName.Contains(sanitizedUnit))
// and as a suffix to the metric name. The unit suffix comes before any type-specific suffixes.
// https://github.com/open-telemetry/opentelemetry-specification/blob/3dfb383fe583e3b74a2365c5a1d90256b273ee76/specification/compatibility/prometheus_and_openmetrics.md#metric-metadata-1
if (!sanitizedName.EndsWith(sanitizedUnit))
{
sanitizedName += $"_{sanitizedUnit}";
}

// OpenMetrics name MUST be suffixed with '_{unit}', regardless of whether the unit name appears within the text.
// Note that this may change in the future, however for the moment Prometheus will fail to read the metric using
// OpenMetrics format unless the suffix matches the unit.
// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#unit
if (!openMetricsName.EndsWith(sanitizedUnit))
{
openMetricsName += $"_{sanitizedUnit}";
}
}

// Special case: Converting "1" to "ratio".
// https://github.com/open-telemetry/opentelemetry-specification/blob/b2f923fb1650dde1f061507908b834035506a796/specification/compatibility/prometheus_and_openmetrics.md#L239
if (type == PrometheusType.Gauge && unit == "1" && !sanitizedName.Contains("ratio"))
{
sanitizedName += "_ratio";
openMetricsName += "_ratio";
}

// For TYPE, HELP and UNIT declarations for counters, the suffix '_total' is omitted in OpenMetrics format.
// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#counter-1
this.OpenMetricsMetadataName = openMetricsName;

// If the metric name for monotonic Sum metric points does not end in a suffix of `_total` a suffix of `_total` MUST be added by default, otherwise the name MUST remain unchanged.
// Exporters SHOULD provide a configuration option to disable the addition of `_total` suffixes.
// https://github.com/open-telemetry/opentelemetry-specification/blob/b2f923fb1650dde1f061507908b834035506a796/specification/compatibility/prometheus_and_openmetrics.md#L286
// Note that we no longer append '_ratio' for units that are '1', see: https://github.com/open-telemetry/opentelemetry-specification/issues/4058
if (type == PrometheusType.Counter && !sanitizedName.EndsWith("_total") && !disableTotalNameSuffixForCounters)
{
sanitizedName += "_total";
Expand All @@ -82,8 +61,15 @@ public PrometheusMetric(string name, string unit, PrometheusType type, bool disa
openMetricsName += "_total";
}

// In OpenMetrics format, the UNIT, TYPE and HELP metadata must be suffixed with the unit (handled above), and not the '_total' suffix, as in the case for counters.
// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#unit
var openMetricsMetadataName = type == PrometheusType.Counter
? SanitizeOpenMetricsName(openMetricsName)
: sanitizedName;

this.Name = sanitizedName;
this.OpenMetricsName = openMetricsName;
this.OpenMetricsMetadataName = openMetricsMetadataName;
this.Unit = sanitizedUnit;
this.Type = type;
}
Expand Down Expand Up @@ -142,6 +128,16 @@ internal static string SanitizeMetricName(string metricName)
static StringBuilder CreateStringBuilder(string name) => new StringBuilder(name.Length);
}

private static string SanitizeOpenMetricsName(string metricName)
{
if (metricName.EndsWith("_total"))
{
return metricName.Substring(0, metricName.Length - 6);
}

return metricName;
}

internal static string RemoveAnnotations(string unit)
{
// UCUM standard says the curly braces shouldn't be nested:
Expand Down Expand Up @@ -186,16 +182,6 @@ internal static string RemoveAnnotations(string unit)
return sb.ToString();
}

private static string SanitizeOpenMetricsName(string metricName)
{
if (metricName.EndsWith("_total"))
{
return metricName.Substring(0, metricName.Length - 6);
}

return metricName;
}

private static string GetUnit(string unit)
{
// Dropping the portions of the Unit within brackets (e.g. {packet}). Brackets MUST NOT be included in the resulting unit. A "count of foo" is considered unitless in Prometheus.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,6 @@ public void Unit_AnnotationMismatch_Close()
Assert.Equal(string.Empty, PrometheusMetric.RemoveAnnotations("{{one}"));
}

[Fact]
public void Name_SpecialCaseGauge_AppendRatio()
{
AssertName("sample", "1", PrometheusType.Gauge, false, "sample_ratio");
}

[Fact]
public void Name_GaugeWithUnit_NoAppendRatio()
{
Expand Down Expand Up @@ -241,12 +235,6 @@ public void OpenMetricsName_CounterSuffixedWithTotal_DisableSuffixTotal_AppendTo
AssertOpenMetricsName("db_bytes_written_total", "By", PrometheusType.Counter, false, "db_bytes_written_bytes_total");
}

[Fact]
public void OpenMetricsName_SpecialCaseGauge_AppendRatio()
{
AssertOpenMetricsName("sample", "1", PrometheusType.Gauge, false, "sample_ratio");
}

[Fact]
public void OpenMetricsMetadataName_Counter_NotAppendTotal()
{
Expand All @@ -259,12 +247,6 @@ public void OpenMetricsMetadataName_Counter_DisableSuffixTotal_NotAppendTotal()
AssertOpenMetricsMetadataName("db_bytes_written", "By", PrometheusType.Counter, true, "db_bytes_written_bytes");
}

[Fact]
public void OpenMetricsMetadataName_SpecialCaseGauge_AppendRatio()
{
AssertOpenMetricsMetadataName("sample", "1", PrometheusType.Gauge, false, "sample_ratio");
}

private static void AssertName(
string name, string unit, PrometheusType type, bool disableTotalNameSuffixForCounters, string expected)
{
Expand Down