mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-28 18:42:25 -05:00
- codeberg.org/gruf/go-ffmpreg: v0.6.9 -> v0.6.10
- github.com/ncruces/go-sqlite3: v0.27.1 -> v0.28.0
- github.com/stretchr/testify: v1.10.0 -> v1.11.1
- github.com/tdewolff/minify/v2 v2.23.11 -> v2.24.2
- go.opentelemetry.io/otel{,/*}: v1.37.0 -> v1.38.0
- go.opentelemetry.io/contrib/*: v0.62.0 -> v0.63.0
Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4406
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
130 lines
4.3 KiB
Go
130 lines
4.3 KiB
Go
// Copyright 2025 The Prometheus Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
|
|
package otlptranslator
|
|
|
|
import "strings"
|
|
|
|
// UnitNamer is a helper for building compliant unit names.
|
|
// It processes OpenTelemetry Protocol (OTLP) unit strings and converts them
|
|
// to Prometheus-compliant unit names.
|
|
//
|
|
// Example usage:
|
|
//
|
|
// namer := UnitNamer{UTF8Allowed: false}
|
|
// result := namer.Build("s") // "seconds"
|
|
// result = namer.Build("By/s") // "bytes_per_second"
|
|
type UnitNamer struct {
|
|
UTF8Allowed bool
|
|
}
|
|
|
|
// Build builds a unit name for the specified unit string.
|
|
// It processes the unit by splitting it into main and per components,
|
|
// applying unit mappings, and cleaning up invalid characters when UTF8Allowed is false.
|
|
//
|
|
// Unit mappings include:
|
|
// - Time: s→seconds, ms→milliseconds, h→hours
|
|
// - Bytes: By→bytes, KBy→kilobytes, MBy→megabytes
|
|
// - SI: m→meters, V→volts, W→watts
|
|
// - Special: 1→"" (empty), %→percent
|
|
//
|
|
// Examples:
|
|
//
|
|
// namer := UnitNamer{UTF8Allowed: false}
|
|
// namer.Build("s") // "seconds"
|
|
// namer.Build("requests/s") // "requests_per_second"
|
|
// namer.Build("1") // "" (dimensionless)
|
|
func (un *UnitNamer) Build(unit string) string {
|
|
mainUnit, perUnit := buildUnitSuffixes(unit)
|
|
if !un.UTF8Allowed {
|
|
mainUnit, perUnit = cleanUpUnit(mainUnit), cleanUpUnit(perUnit)
|
|
}
|
|
|
|
var u string
|
|
switch {
|
|
case mainUnit != "" && perUnit != "":
|
|
u = mainUnit + "_" + perUnit
|
|
case mainUnit != "":
|
|
u = mainUnit
|
|
default:
|
|
u = perUnit
|
|
}
|
|
|
|
// Clean up leading and trailing underscores
|
|
if len(u) > 0 && u[0:1] == "_" {
|
|
u = u[1:]
|
|
}
|
|
if len(u) > 0 && u[len(u)-1:] == "_" {
|
|
u = u[:len(u)-1]
|
|
}
|
|
|
|
return u
|
|
}
|
|
|
|
// Retrieve the Prometheus "basic" unit corresponding to the specified "basic" unit.
|
|
// Returns the specified unit if not found in unitMap.
|
|
func unitMapGetOrDefault(unit string) string {
|
|
if promUnit, ok := unitMap[unit]; ok {
|
|
return promUnit
|
|
}
|
|
return unit
|
|
}
|
|
|
|
// Retrieve the Prometheus "per" unit corresponding to the specified "per" unit.
|
|
// Returns the specified unit if not found in perUnitMap.
|
|
func perUnitMapGetOrDefault(perUnit string) string {
|
|
if promPerUnit, ok := perUnitMap[perUnit]; ok {
|
|
return promPerUnit
|
|
}
|
|
return perUnit
|
|
}
|
|
|
|
// buildUnitSuffixes builds the main and per unit suffixes for the specified unit
|
|
// but doesn't do any special character transformation to accommodate Prometheus naming conventions.
|
|
// Removing trailing underscores or appending suffixes is done in the caller.
|
|
func buildUnitSuffixes(unit string) (mainUnitSuffix, perUnitSuffix string) {
|
|
// Split unit at the '/' if any
|
|
unitTokens := strings.SplitN(unit, "/", 2)
|
|
|
|
if len(unitTokens) > 0 {
|
|
// Main unit
|
|
// Update if not blank and doesn't contain '{}'
|
|
mainUnitOTel := strings.TrimSpace(unitTokens[0])
|
|
if mainUnitOTel != "" && !strings.ContainsAny(mainUnitOTel, "{}") {
|
|
mainUnitSuffix = unitMapGetOrDefault(mainUnitOTel)
|
|
}
|
|
|
|
// Per unit
|
|
// Update if not blank and doesn't contain '{}'
|
|
if len(unitTokens) > 1 && unitTokens[1] != "" {
|
|
perUnitOTel := strings.TrimSpace(unitTokens[1])
|
|
if perUnitOTel != "" && !strings.ContainsAny(perUnitOTel, "{}") {
|
|
perUnitSuffix = perUnitMapGetOrDefault(perUnitOTel)
|
|
}
|
|
if perUnitSuffix != "" {
|
|
perUnitSuffix = "per_" + perUnitSuffix
|
|
}
|
|
}
|
|
}
|
|
|
|
return mainUnitSuffix, perUnitSuffix
|
|
}
|
|
|
|
// cleanUpUnit cleans up unit so it matches model.LabelNameRE.
|
|
func cleanUpUnit(unit string) string {
|
|
// Multiple consecutive underscores are replaced with a single underscore.
|
|
// This is part of the OTel to Prometheus specification: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.38.0/specification/compatibility/prometheus_and_openmetrics.md#otlp-metric-points-to-prometheus.
|
|
return strings.TrimPrefix(multipleUnderscoresRE.ReplaceAllString(
|
|
strings.Map(replaceInvalidMetricChar, unit),
|
|
"_",
|
|
), "_")
|
|
}
|