@@ -96,7 +96,7 @@ type collector struct {
96
96
97
97
// prometheus counters MUST have a _total suffix by default:
98
98
// https://github.com/open-telemetry/opentelemetry-specification/blob/v1.20.0/specification/compatibility/prometheus_and_openmetrics.md
99
- const counterSuffix = "_total "
99
+ const counterSuffix = "total "
100
100
101
101
// New returns a Prometheus Exporter.
102
102
func New (opts ... Option ) (* Exporter , error ) {
@@ -368,38 +368,38 @@ func createScopeInfoMetric(scope instrumentation.Scope) (prometheus.Metric, erro
368
368
369
369
var unitSuffixes = map [string ]string {
370
370
// Time
371
- "d" : "_days " ,
372
- "h" : "_hours " ,
373
- "min" : "_minutes " ,
374
- "s" : "_seconds " ,
375
- "ms" : "_milliseconds " ,
376
- "us" : "_microseconds " ,
377
- "ns" : "_nanoseconds " ,
371
+ "d" : "days " ,
372
+ "h" : "hours " ,
373
+ "min" : "minutes " ,
374
+ "s" : "seconds " ,
375
+ "ms" : "milliseconds " ,
376
+ "us" : "microseconds " ,
377
+ "ns" : "nanoseconds " ,
378
378
379
379
// Bytes
380
- "By" : "_bytes " ,
381
- "KiBy" : "_kibibytes " ,
382
- "MiBy" : "_mebibytes " ,
383
- "GiBy" : "_gibibytes " ,
384
- "TiBy" : "_tibibytes " ,
385
- "KBy" : "_kilobytes " ,
386
- "MBy" : "_megabytes " ,
387
- "GBy" : "_gigabytes " ,
388
- "TBy" : "_terabytes " ,
380
+ "By" : "bytes " ,
381
+ "KiBy" : "kibibytes " ,
382
+ "MiBy" : "mebibytes " ,
383
+ "GiBy" : "gibibytes " ,
384
+ "TiBy" : "tibibytes " ,
385
+ "KBy" : "kilobytes " ,
386
+ "MBy" : "megabytes " ,
387
+ "GBy" : "gigabytes " ,
388
+ "TBy" : "terabytes " ,
389
389
390
390
// SI
391
- "m" : "_meters " ,
392
- "V" : "_volts " ,
393
- "A" : "_amperes " ,
394
- "J" : "_joules " ,
395
- "W" : "_watts " ,
396
- "g" : "_grams " ,
391
+ "m" : "meters " ,
392
+ "V" : "volts " ,
393
+ "A" : "amperes " ,
394
+ "J" : "joules " ,
395
+ "W" : "watts " ,
396
+ "g" : "grams " ,
397
397
398
398
// Misc
399
- "Cel" : "_celsius " ,
400
- "Hz" : "_hertz " ,
401
- "1" : "_ratio " ,
402
- "%" : "_percent " ,
399
+ "Cel" : "celsius " ,
400
+ "Hz" : "hertz " ,
401
+ "1" : "ratio " ,
402
+ "%" : "percent " ,
403
403
}
404
404
405
405
// getName returns the sanitized name, prefixed with the namespace and suffixed with unit.
@@ -414,19 +414,31 @@ func (c *collector) getName(m metricdata.Metrics, typ *dto.MetricType) string {
414
414
// Remove the _total suffix here, as we will re-add the total suffix
415
415
// later, and it needs to come after the unit suffix.
416
416
name = strings .TrimSuffix (name , counterSuffix )
417
+ // If the last character is an underscore, or would be converted to an underscore, trim it from the name.
418
+ // an underscore will be added back in later.
419
+ if convertsToUnderscore (rune (name [len (name )- 1 ])) {
420
+ name = name [:len (name )- 1 ]
421
+ }
417
422
}
418
423
if c .namespace != "" {
419
424
name = c .namespace + name
420
425
}
421
426
if suffix , ok := unitSuffixes [m .Unit ]; ok && ! c .withoutUnits && ! strings .HasSuffix (name , suffix ) {
422
- name += suffix
427
+ name += "_" + suffix
423
428
}
424
429
if addCounterSuffix {
425
- name += counterSuffix
430
+ name += "_" + counterSuffix
426
431
}
427
432
return name
428
433
}
429
434
435
+ // convertsToUnderscore returns true if the character would be converted to an
436
+ // underscore when the escaping scheme is underscore escaping. This is meant to
437
+ // capture any character that should be considered a "delimiter".
438
+ func convertsToUnderscore (b rune ) bool {
439
+ return b < 'a' && b > 'z' && b < 'A' && b > 'Z' && b != ':' && b < '0' && b > '9'
440
+ }
441
+
430
442
func (c * collector ) metricType (m metricdata.Metrics ) * dto.MetricType {
431
443
switch v := m .Data .(type ) {
432
444
case metricdata.Histogram [int64 ], metricdata.Histogram [float64 ]:
0 commit comments