@@ -29,13 +29,15 @@ pub fn key_to_parts(
29
29
/// Writes a help (description) line in the Prometheus [exposition format].
30
30
///
31
31
/// [exposition format]: https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-format-details
32
- pub fn write_help_line ( buffer : & mut String , name : & str , unit : Option < Unit > , desc : & str ) {
32
+ pub fn write_help_line (
33
+ buffer : & mut String ,
34
+ name : & str ,
35
+ unit : Option < Unit > ,
36
+ suffix : Option < & ' static str > ,
37
+ desc : & str ,
38
+ ) {
33
39
buffer. push_str ( "# HELP " ) ;
34
- buffer. push_str ( name) ;
35
- if let Some ( unit) = unit {
36
- buffer. push ( '_' ) ;
37
- buffer. push_str ( unit. as_str ( ) ) ;
38
- }
40
+ add_metric_name ( buffer, name, unit, suffix) ;
39
41
buffer. push ( ' ' ) ;
40
42
let desc = sanitize_description ( desc) ;
41
43
buffer. push_str ( & desc) ;
@@ -45,13 +47,15 @@ pub fn write_help_line(buffer: &mut String, name: &str, unit: Option<Unit>, desc
45
47
/// Writes a metric type line in the Prometheus [exposition format].
46
48
///
47
49
/// [exposition format]: https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-format-details
48
- pub fn write_type_line ( buffer : & mut String , name : & str , unit : Option < Unit > , metric_type : & str ) {
50
+ pub fn write_type_line (
51
+ buffer : & mut String ,
52
+ name : & str ,
53
+ unit : Option < Unit > ,
54
+ suffix : Option < & ' static str > ,
55
+ metric_type : & str ,
56
+ ) {
49
57
buffer. push_str ( "# TYPE " ) ;
50
- buffer. push_str ( name) ;
51
- if let Some ( unit) = unit {
52
- buffer. push ( '_' ) ;
53
- buffer. push_str ( unit. as_str ( ) ) ;
54
- }
58
+ add_metric_name ( buffer, name, unit, suffix) ;
55
59
buffer. push ( ' ' ) ;
56
60
buffer. push_str ( metric_type) ;
57
61
buffer. push ( '\n' ) ;
@@ -77,18 +81,7 @@ pub fn write_metric_line<T, T2>(
77
81
T : std:: fmt:: Display ,
78
82
T2 : std:: fmt:: Display ,
79
83
{
80
- buffer. push_str ( name) ;
81
-
82
- match unit {
83
- Some ( Unit :: Count ) | None => { }
84
- Some ( Unit :: Percent ) => add_unit ( buffer, "ratio" ) ,
85
- Some ( unit) => add_unit ( buffer, unit. as_str ( ) ) ,
86
- }
87
-
88
- if let Some ( suffix) = suffix {
89
- buffer. push ( '_' ) ;
90
- buffer. push_str ( suffix) ;
91
- }
84
+ add_metric_name ( buffer, name, unit, suffix) ;
92
85
93
86
if !labels. is_empty ( ) || additional_label. is_some ( ) {
94
87
buffer. push ( '{' ) ;
@@ -121,24 +114,58 @@ pub fn write_metric_line<T, T2>(
121
114
buffer. push ( '\n' ) ;
122
115
}
123
116
124
- fn add_unit ( buffer : & mut String , unit : & str ) {
125
- const SUM_SUFFIX : & str = "_sum" ;
126
- const COUNT_SUFFIX : & str = "_count" ;
127
- const BUCKET_SUFFIX : & str = "_bucket" ;
128
-
129
- if buffer. ends_with ( SUM_SUFFIX ) {
130
- let suffix_pos = buffer. len ( ) - SUM_SUFFIX . len ( ) ;
131
- buffer. insert ( suffix_pos, '_' ) ;
132
- buffer. insert_str ( suffix_pos + 1 , unit) ;
133
- } else if buffer. ends_with ( COUNT_SUFFIX ) {
134
- let suffix_pos = buffer. len ( ) - COUNT_SUFFIX . len ( ) ;
135
- buffer. insert ( suffix_pos, '_' ) ;
136
- buffer. insert_str ( suffix_pos + 1 , unit) ;
137
- } else if buffer. ends_with ( BUCKET_SUFFIX ) {
138
- let suffix_pos = buffer. len ( ) - BUCKET_SUFFIX . len ( ) ;
139
- buffer. insert ( suffix_pos, '_' ) ;
140
- buffer. insert_str ( suffix_pos + 1 , unit) ;
141
- } else {
117
+ fn add_metric_name (
118
+ buffer : & mut String ,
119
+ name : & str ,
120
+ unit : Option < Unit > ,
121
+ suffix : Option < & ' static str > ,
122
+ ) {
123
+ buffer. push_str ( name) ;
124
+ if let Some ( unit) = unit {
125
+ add_unit_if_missing ( buffer, unit) ;
126
+ }
127
+ if let Some ( suffix) = suffix {
128
+ add_suffix_if_missing ( buffer, suffix) ;
129
+ }
130
+ }
131
+
132
+ /// Adds a suffix to the metric name if it is not already in the name.
133
+ fn add_suffix_if_missing ( buffer : & mut String , suffix : & str ) {
134
+ if !buffer. ends_with ( suffix) {
135
+ buffer. push ( '_' ) ;
136
+ buffer. push_str ( suffix) ;
137
+ }
138
+ }
139
+
140
+ /// Adds a unit to the metric name if it is not already in the name.
141
+ /// If the metric ends with a known suffix, we try to insert the unit before the suffix.
142
+ /// Otherwise, we append the unit to the end of the metric name.
143
+ fn add_unit_if_missing ( buffer : & mut String , unit : Unit ) {
144
+ const KNOWN_SUFFIXES : [ & str ; 4 ] = [ "_sum" , "_count" , "_bucket" , "_total" ] ;
145
+
146
+ let unit = match unit {
147
+ Unit :: Count => {
148
+ // For count, we don't suffix the unit.
149
+ return ;
150
+ }
151
+ Unit :: Percent => "ratio" ,
152
+ unit => unit. as_str ( ) ,
153
+ } ;
154
+
155
+ let mut handled = false ;
156
+ for suffix in KNOWN_SUFFIXES {
157
+ if buffer. ends_with ( suffix) {
158
+ let suffix_pos = buffer. len ( ) - suffix. len ( ) ;
159
+ // Check if name before suffix already has the unit
160
+ if !& buffer[ ..suffix_pos] . ends_with ( unit) {
161
+ buffer. insert ( suffix_pos, '_' ) ;
162
+ buffer. insert_str ( suffix_pos + 1 , unit) ;
163
+ }
164
+ handled = true ;
165
+ break ;
166
+ }
167
+ }
168
+ if !handled && !buffer. ends_with ( unit) {
142
169
buffer. push ( '_' ) ;
143
170
buffer. push_str ( unit) ;
144
171
}
0 commit comments