@@ -110,35 +110,37 @@ pub fn write_metric_line<T, T2>(
110
110
/// [data model]: https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
111
111
pub fn sanitize_metric_name ( name : & str ) -> String {
112
112
// The first character must be [a-zA-Z_:], and all subsequent characters must be [a-zA-Z0-9_:].
113
- let mut out = String :: with_capacity ( name. len ( ) ) ;
114
- let mut is_invalid: fn ( char ) -> bool = invalid_metric_name_start_character;
115
- for c in name. chars ( ) {
116
- if is_invalid ( c) {
117
- out. push ( '_' ) ;
118
- } else {
119
- out. push ( c) ;
120
- }
121
- is_invalid = invalid_metric_name_character;
122
- }
123
- out
113
+ name. chars ( )
114
+ . enumerate ( )
115
+ . map ( |( i, c) | {
116
+ if i == 0 && valid_metric_name_start_character ( c)
117
+ || i != 0 && valid_metric_name_character ( c)
118
+ {
119
+ c
120
+ } else {
121
+ '_'
122
+ }
123
+ } )
124
+ . collect ( )
124
125
}
125
126
126
127
/// Sanitizes a label key to be valid under the Prometheus [data model].
127
128
///
128
129
/// [data model]: https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
129
130
pub fn sanitize_label_key ( key : & str ) -> String {
130
131
// The first character must be [a-zA-Z_], and all subsequent characters must be [a-zA-Z0-9_].
131
- let mut out = String :: with_capacity ( key. len ( ) ) ;
132
- let mut is_invalid: fn ( char ) -> bool = invalid_label_key_start_character;
133
- for c in key. chars ( ) {
134
- if is_invalid ( c) {
135
- out. push ( '_' ) ;
136
- } else {
137
- out. push ( c) ;
138
- }
139
- is_invalid = invalid_label_key_character;
140
- }
141
- out
132
+ key. chars ( )
133
+ . enumerate ( )
134
+ . map ( |( i, c) | {
135
+ if i == 0 && valid_label_key_start_character ( c)
136
+ || i != 0 && valid_label_key_character ( c)
137
+ {
138
+ c
139
+ } else {
140
+ '_'
141
+ }
142
+ } )
143
+ . collect ( )
142
144
}
143
145
144
146
/// Sanitizes a label value to be valid under the Prometheus [data model].
@@ -209,35 +211,35 @@ fn sanitize_label_value_or_description(value: &str, is_desc: bool) -> String {
209
211
}
210
212
211
213
#[ inline]
212
- fn invalid_metric_name_start_character ( c : char ) -> bool {
214
+ fn valid_metric_name_start_character ( c : char ) -> bool {
213
215
// Essentially, needs to match the regex pattern of [a-zA-Z_:].
214
- ! ( c. is_ascii_alphabetic ( ) || c == '_' || c == ':' )
216
+ c. is_ascii_alphabetic ( ) || c == '_' || c == ':'
215
217
}
216
218
217
219
#[ inline]
218
- fn invalid_metric_name_character ( c : char ) -> bool {
220
+ fn valid_metric_name_character ( c : char ) -> bool {
219
221
// Essentially, needs to match the regex pattern of [a-zA-Z0-9_:].
220
- ! ( c. is_ascii_alphanumeric ( ) || c == '_' || c == ':' )
222
+ c. is_ascii_alphanumeric ( ) || c == '_' || c == ':'
221
223
}
222
224
223
225
#[ inline]
224
- fn invalid_label_key_start_character ( c : char ) -> bool {
226
+ fn valid_label_key_start_character ( c : char ) -> bool {
225
227
// Essentially, needs to match the regex pattern of [a-zA-Z_].
226
- ! ( c. is_ascii_alphabetic ( ) || c == '_' )
228
+ c. is_ascii_alphabetic ( ) || c == '_'
227
229
}
228
230
229
231
#[ inline]
230
- fn invalid_label_key_character ( c : char ) -> bool {
232
+ fn valid_label_key_character ( c : char ) -> bool {
231
233
// Essentially, needs to match the regex pattern of [a-zA-Z0-9_].
232
- ! ( c. is_ascii_alphanumeric ( ) || c == '_' )
234
+ c. is_ascii_alphanumeric ( ) || c == '_'
233
235
}
234
236
235
237
#[ cfg( test) ]
236
238
mod tests {
237
239
use crate :: formatting:: {
238
- invalid_label_key_character , invalid_label_key_start_character ,
239
- invalid_metric_name_character , invalid_metric_name_start_character , sanitize_description ,
240
- sanitize_label_key , sanitize_label_value , sanitize_metric_name ,
240
+ sanitize_description , sanitize_label_key , sanitize_label_value , sanitize_metric_name ,
241
+ valid_label_key_character , valid_label_key_start_character , valid_metric_name_character ,
242
+ valid_metric_name_start_character ,
241
243
} ;
242
244
use proptest:: prelude:: * ;
243
245
@@ -321,11 +323,11 @@ mod tests {
321
323
let as_chars = result. chars( ) . collect:: <Vec <_>>( ) ;
322
324
323
325
if let Some ( c) = as_chars. first( ) {
324
- assert_eq! ( false , invalid_metric_name_start_character ( * c) ,
326
+ assert! ( valid_metric_name_start_character ( * c) ,
325
327
"first character of metric name was not valid" ) ;
326
328
}
327
329
328
- assert!( ! as_chars. iter( ) . any ( |c| invalid_metric_name_character ( * c) ) ,
330
+ assert!( as_chars. iter( ) . all ( |c| valid_metric_name_character ( * c) ) ,
329
331
"invalid character in metric name" ) ;
330
332
}
331
333
@@ -335,7 +337,7 @@ mod tests {
335
337
let as_chars = result. chars( ) . collect:: <Vec <_>>( ) ;
336
338
337
339
if let Some ( c) = as_chars. first( ) {
338
- assert_eq! ( false , invalid_label_key_start_character ( * c) ,
340
+ assert! ( valid_label_key_start_character ( * c) ,
339
341
"first character of label key was not valid" ) ;
340
342
}
341
343
@@ -353,7 +355,7 @@ mod tests {
353
355
}
354
356
}*/
355
357
356
- assert!( ! as_chars. iter( ) . any ( |c| invalid_label_key_character ( * c) ) ,
358
+ assert!( as_chars. iter( ) . all ( |c| valid_label_key_character ( * c) ) ,
357
359
"invalid character in label key" ) ;
358
360
}
359
361
@@ -369,7 +371,7 @@ mod tests {
369
371
let as_chars = delayered_backslashes. chars( ) . collect:: <Vec <_>>( ) ;
370
372
371
373
// If the first character is a double quote, then we messed up.
372
- assert!( as_chars. first( ) . map ( |c| * c != '"' ) . unwrap_or ( true ) ,
374
+ assert!( as_chars. first( ) . map_or ( true , |c| * c != '"' ) ,
373
375
"first character cannot be a double quote: {}" , result) ;
374
376
375
377
// Now look for unescaped characters in the rest of the string, in a windowed fashion.
0 commit comments