A Go library for converting OpenTelemetry Protocol (OTLP) metric and attribute names to Prometheus-compliant formats. This is an internal library for both Prometheus and Open Telemetry, without any stability guarantees for external usage.
Part of the Prometheus ecosystem, following the OpenTelemetry to Prometheus compatibility specification.
- Metric Name and Label Translation: Convert OTLP metric names and attributes to Prometheus-compliant format
- Unit Handling: Translate OTLP units to Prometheus unit conventions, using spec-correct UCUM mappings by default with an opt-out (
LegacyUnitMapping) for callers pinned to pre-correction names - Type-Aware Suffixes: Optionally append
_total,_ratiobased on metric type - Namespace Support: Add configurable namespace prefixes
- UTF-8 Support: Choose between Prometheus legacy scheme compliant metric/label names (
[a-zA-Z0-9:_]) or untranslated metric/label names - Translation Strategy Configuration: Select a translation strategy with a standard set of strings.
go get github.com/prometheus/otlptranslatorpackage main
import (
"fmt"
"github.com/prometheus/otlptranslator"
)
func main() {
// Create a metric namer using traditional Prometheus name translation, with suffixes added and UTF-8 disallowed.
strategy := otlptranslator.UnderscoreEscapingWithSuffixes
namer := otlptranslator.NewMetricNamer("myapp", strategy)
// Translate OTLP metric to Prometheus format
metric := otlptranslator.Metric{
Name: "http.server.request.duration",
Unit: "s",
Type: otlptranslator.MetricTypeHistogram,
}
metricName, err := namer.Build(metric)
if err != nil {
panic(err)
}
fmt.Println(metricName) // Output: myapp_http_server_request_duration_seconds
// Translate label names
labelNamer := otlptranslator.LabelNamer{UTF8Allowed: false}
labelName, err := labelNamer.Build("http.method")
if err != nil {
panic(err)
}
fmt.Println(labelName) // Output: http_method
}namer := otlptranslator.MetricNamer{WithMetricSuffixes: true, UTF8Allowed: false}
// Counter gets _total suffix
counter := otlptranslator.Metric{
Name: "requests.count", Unit: "1", Type: otlptranslator.MetricTypeMonotonicCounter,
}
counterName, _ := namer.Build(counter)
fmt.Println(counterName) // requests_count_total
// Gauge with unit conversion
gauge := otlptranslator.Metric{
Name: "memory.usage", Unit: "By", Type: otlptranslator.MetricTypeGauge,
}
gaugeName, _ := namer.Build(gauge)
fmt.Println(gaugeName) // memory_usage_bytes
// Dimensionless gauge gets _ratio suffix
ratio := otlptranslator.Metric{
Name: "cpu.utilization", Unit: "1", Type: otlptranslator.MetricTypeGauge,
}
ratioName, _ := namer.Build(ratio)
fmt.Println(ratioName) // cpu_utilization_ratiolabelNamer := otlptranslator.LabelNamer{UTF8Allowed: false}
labelNamer.Build("http.method") // http_method, nil
labelNamer.Build("123invalid") // key_123invalid, nil
labelNamer.Build("_private") // _private, nil
labelNamer.Build("__reserved__") // __reserved__, nil
labelNamer.Build("label@with$symbols") // label_with_symbols, nilunitNamer := otlptranslator.UnitNamer{UTF8Allowed: false}
unitNamer.Build("s") // seconds
unitNamer.Build("By") // bytes
unitNamer.Build("requests/s") // requests_per_second
unitNamer.Build("1") // "" (dimensionless)This library now uses the spec-correct UCUM unit suffixes by default. Two mappings changed compared to earlier releases:
TiBy→tebibytes(previouslytibibytes—tebi-is the IEC binary prefix; the older spelling was a misspelling).kBy→kilobytesis newly recognised (previously not mapped).KBycontinues to map tokilobytesas before, for backwards compatibility.
Behavior change for existing consumers: dashboards, alerts, and recording rules that reference *_tibibytes will silently stop receiving new datapoints once your Prometheus / OTel Collector deployment picks up this library version.
To preserve the pre-correction names while you migrate, opt in to the legacy mapping (combine with UTF8Allowed: true if your callers use UTF-8 metric names):
namer := otlptranslator.MetricNamer{
WithMetricSuffixes: true,
LegacyUnitMapping: true,
}// Prometheus-compliant mode - supports [a-zA-Z0-9:_]
compliantNamer := otlptranslator.MetricNamer{UTF8Allowed: false, WithMetricSuffixes: true}
// Transparent pass-through mode, aka "NoTranslation"
utf8Namer := otlptranslator.MetricNamer{UTF8Allowed: true, WithMetricSuffixes: false}
utf8Namer = otlptranslator.NewMetricNamer("", otlptranslator.NoTranslation)
// With namespace and suffixes
productionNamer := otlptranslator.MetricNamer{
Namespace: "myservice",
WithMetricSuffixes: true,
UTF8Allowed: false,
}Licensed under the Apache License 2.0 - see the LICENSE file for details.