prometheus-client-mmap 0.24.3 → 0.24.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/fast_mmaped_file_rs/src/parser.rs +166 -64
- data/lib/prometheus/client/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6db16be87c209d7fa1ff15a76494ea04d1329a91de10aa1d5d53c6436bdcf557
|
4
|
+
data.tar.gz: cedd91b3c15aeb475e1be62e1514374a0c59cea2a502ab465dba5492a4b69b2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dddcc6094038212397c89061b2bacb51830f59e67832d45d0b96ff949f5b3725be91f18c507150b8237ff4a5fca498d7f7ee62a8b55addf2cc4888e62ec114b3
|
7
|
+
data.tar.gz: ba8d5ccb8e34a32c57f71321618450287ac9c2ab0c6a3b49efe819049ce7e37b059c3db54e04875d444cd85a42714fab293b4ba57914c1dfdaf4c29255159057
|
@@ -63,35 +63,35 @@ fn parse_names(json: &str) -> Option<MetricNames> {
|
|
63
63
|
return None;
|
64
64
|
}
|
65
65
|
|
66
|
-
//
|
67
|
-
|
68
|
-
|
69
|
-
let names_end = remainder.find('[')?;
|
70
|
-
|
71
|
-
// Save the rest of the slice to parse for labels later.
|
72
|
-
let label_json = remainder.get(names_end..)?;
|
73
|
-
|
74
|
-
// Now: family_name","metric_name",
|
75
|
-
let remainder = remainder.get(..names_end)?;
|
66
|
+
// Captured: "family_name","metric_name",
|
67
|
+
// ^^^^^^^^^^^
|
68
|
+
let (family_name, remainder) = scan_str(json.get(1..)?)?;
|
76
69
|
|
77
|
-
//
|
78
|
-
// family_name","metric_name",
|
79
|
-
//
|
80
|
-
|
70
|
+
// Validate comma separated names
|
71
|
+
// ["family_name","metric_name",[...
|
72
|
+
// ^
|
73
|
+
if !remainder.starts_with("\",") {
|
74
|
+
return None;
|
75
|
+
}
|
81
76
|
|
82
|
-
//
|
83
|
-
|
84
|
-
let family_name = token_iter.next()?.trim_end_matches('"');
|
77
|
+
// Now: "metric_name",[...
|
78
|
+
let remainder = remainder.get(2..)?;
|
85
79
|
|
86
80
|
// Captured: "family_name","metric_name",
|
87
81
|
// ^^^^^^^^^^^
|
88
|
-
let metric_name =
|
82
|
+
let (metric_name, remainder) = scan_str(remainder)?;
|
89
83
|
|
90
|
-
//
|
91
|
-
|
84
|
+
// Validate comma separated names
|
85
|
+
// ["family_name","metric_name",[...
|
86
|
+
// ^^
|
87
|
+
if !remainder.starts_with("\",") {
|
92
88
|
return None;
|
93
89
|
}
|
94
90
|
|
91
|
+
// Save the rest of the slice to parse for labels later.
|
92
|
+
// Now: [...
|
93
|
+
let label_json = remainder.get(2..)?;
|
94
|
+
|
95
95
|
Some(MetricNames {
|
96
96
|
label_json,
|
97
97
|
family_name,
|
@@ -101,76 +101,143 @@ fn parse_names(json: &str) -> Option<MetricNames> {
|
|
101
101
|
|
102
102
|
fn parse_label_values(json: &str) -> Option<MetricLabelVals> {
|
103
103
|
// Starting with: ["label_a","label_b"],["value_a", "value_b"]]
|
104
|
-
if !
|
104
|
+
if !json.starts_with('[') {
|
105
105
|
return None;
|
106
106
|
}
|
107
107
|
|
108
|
+
// Now: "label_a","label_b"],["value_a", "value_b"]]
|
109
|
+
let mut remainder = json.get(1..)?;
|
110
|
+
|
108
111
|
// Validate we either have the start of a label string or an
|
109
112
|
// empty array, e.g. `["` or `[]`.
|
110
113
|
if !matches!(json.as_bytes().get(1)?, b'"' | b']') {
|
111
114
|
return None;
|
112
115
|
}
|
113
116
|
|
114
|
-
// Now: "label_a","label_b"
|
115
|
-
let labels_end = json.find(']')?;
|
116
|
-
let label_range = json.get(1..labels_end)?;
|
117
|
-
|
118
117
|
let mut labels = SmallVec::new();
|
119
118
|
|
120
119
|
// Split on commas into:
|
121
120
|
// "label_a","label_b"
|
122
121
|
// ^^^one^^^ ^^^two^^^
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
122
|
+
loop {
|
123
|
+
let Some((label, label_rem)) = scan_str(remainder) else {
|
124
|
+
// No further keys.
|
125
|
+
break;
|
126
|
+
};
|
127
|
+
labels.push(label);
|
128
|
+
|
129
|
+
// Advance past trailing quote.
|
130
|
+
remainder = label_rem.get(1..)?;
|
131
|
+
match remainder.as_bytes().first() {
|
132
|
+
Some(b']') => break, // No further labels.
|
133
|
+
Some(b',') => {} // More labels expected.
|
134
|
+
_ => return None, // Invalid.
|
135
|
+
};
|
136
|
+
|
137
|
+
// Advance past comma.
|
138
|
+
remainder = remainder.get(1..)?;
|
130
139
|
}
|
131
140
|
|
132
|
-
|
133
|
-
let mut values_range = json.get(labels_end..)?;
|
134
|
-
|
135
|
-
// Validate we have a separating comma with one and only one leading bracket.
|
136
|
-
if !(values_range.starts_with("],[") && values_range.as_bytes().get(3)? != &b'[') {
|
141
|
+
if !remainder.starts_with("],[") {
|
137
142
|
return None;
|
138
143
|
}
|
139
|
-
|
140
144
|
// Now: "value_a", "value_b"]]
|
141
|
-
|
142
|
-
|
143
|
-
let values_end = values_range.find(']')?;
|
145
|
+
remainder = remainder.get(3..)?;
|
144
146
|
|
145
|
-
// Validate we have
|
146
|
-
if
|
147
|
+
// Validate we don't have extra brackets.
|
148
|
+
if remainder.starts_with('[') {
|
147
149
|
return None;
|
148
150
|
}
|
149
151
|
|
150
|
-
// Now: "value_a", "value_b"
|
151
|
-
values_range = values_range.get(..values_end)?;
|
152
|
-
|
153
152
|
let mut values = SmallVec::new();
|
154
|
-
|
155
153
|
// Split on commas into:
|
156
154
|
// "value_a","value_b"
|
157
155
|
// ^^^one^^^ ^^^two^^^
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
156
|
+
loop {
|
157
|
+
if remainder.starts_with('"') {
|
158
|
+
let (value, value_rem) = scan_str(remainder)?;
|
159
|
+
values.push(value);
|
160
|
+
|
161
|
+
// Advance past trailing quote.
|
162
|
+
remainder = value_rem.get(1..)?;
|
163
|
+
} else {
|
164
|
+
// An unquoted value, such as `true` or `404`.
|
165
|
+
let i = remainder.find(|c| c == ',' || c == ']')?;
|
166
|
+
let value = &remainder[..i];
|
167
|
+
|
168
|
+
match (value.is_empty(), is_valid_json_literal(value)) {
|
169
|
+
(true, _) => {} // Empty string, do nothing.
|
170
|
+
(false, true) => values.push(value), // Valid literal.
|
171
|
+
(false, false) => return None, // Invalid literal, fail.
|
172
|
+
}
|
173
|
+
|
174
|
+
remainder = &remainder[i..];
|
164
175
|
}
|
176
|
+
|
177
|
+
match remainder.as_bytes().first() {
|
178
|
+
Some(b']') => break, // End of values.
|
179
|
+
Some(b',') => {} // More values expected.
|
180
|
+
_ => return None, // Invalid.
|
181
|
+
};
|
182
|
+
|
183
|
+
// Advance past comma.
|
184
|
+
remainder = remainder.get(1..)?;
|
165
185
|
}
|
166
186
|
|
167
187
|
if values.len() != labels.len() {
|
168
188
|
return None;
|
169
189
|
}
|
170
190
|
|
191
|
+
// Now: ]]
|
192
|
+
if remainder != "]]" {
|
193
|
+
return None;
|
194
|
+
}
|
195
|
+
|
171
196
|
Some(MetricLabelVals { labels, values })
|
172
197
|
}
|
173
198
|
|
199
|
+
// Read a JSON-encoded str that includes starting and ending double quotes.
|
200
|
+
// Returns the validated str with the double quotes trimmed and the remainder
|
201
|
+
// of the input str.
|
202
|
+
fn scan_str(json: &str) -> Option<(&str, &str)> {
|
203
|
+
let mut escaping = false;
|
204
|
+
|
205
|
+
if !json.starts_with('"') {
|
206
|
+
return None;
|
207
|
+
}
|
208
|
+
|
209
|
+
// Trim leading double quote.
|
210
|
+
let json = json.get(1..)?;
|
211
|
+
|
212
|
+
for (i, &c) in json.as_bytes().iter().enumerate() {
|
213
|
+
if c == b'\\' {
|
214
|
+
escaping = true;
|
215
|
+
continue;
|
216
|
+
}
|
217
|
+
|
218
|
+
if c == b'"' && !escaping {
|
219
|
+
return Some((json.get(..i)?, json.get(i..)?));
|
220
|
+
}
|
221
|
+
|
222
|
+
escaping = false;
|
223
|
+
}
|
224
|
+
|
225
|
+
None
|
226
|
+
}
|
227
|
+
|
228
|
+
// Confirm an unquoted JSON literal is a boolean, null, or has a passing
|
229
|
+
// resemblance to a number. We do not confirm numeric formatting, only
|
230
|
+
// that all characters are valid. See https://www.json.org/json-en.html
|
231
|
+
// for details.
|
232
|
+
fn is_valid_json_literal(s: &str) -> bool {
|
233
|
+
match s {
|
234
|
+
"true" | "false" | "null" => true,
|
235
|
+
_ => s.chars().all(|c| {
|
236
|
+
c.is_ascii_digit() || c == '.' || c == '+' || c == '-' || c == 'e' || c == 'E'
|
237
|
+
}),
|
238
|
+
}
|
239
|
+
}
|
240
|
+
|
174
241
|
#[cfg(test)]
|
175
242
|
mod test {
|
176
243
|
use smallvec::smallvec;
|
@@ -217,6 +284,16 @@ mod test {
|
|
217
284
|
values: smallvec!["value_a", "403"],
|
218
285
|
}),
|
219
286
|
},
|
287
|
+
TestCase {
|
288
|
+
name: "scientific notation literal",
|
289
|
+
input: r#"["metric","name",["label_a"],[-2.0e-5]]"#,
|
290
|
+
expected: Some(MetricText {
|
291
|
+
family_name: "metric",
|
292
|
+
metric_name: "name",
|
293
|
+
labels: smallvec!["label_a"],
|
294
|
+
values: smallvec!["-2.0e-5"],
|
295
|
+
}),
|
296
|
+
},
|
220
297
|
TestCase {
|
221
298
|
name: "null value",
|
222
299
|
input: r#"["metric","name",["label_a","label_b"],[null,"value_b"]]"#,
|
@@ -237,6 +314,36 @@ mod test {
|
|
237
314
|
values: smallvec![],
|
238
315
|
}),
|
239
316
|
},
|
317
|
+
TestCase {
|
318
|
+
name: "comma in items",
|
319
|
+
input: r#"["met,ric","na,me",["label,_a","label_b"],["value,_a","value_b"]]"#,
|
320
|
+
expected: Some(MetricText {
|
321
|
+
family_name: "met,ric",
|
322
|
+
metric_name: "na,me",
|
323
|
+
labels: smallvec!["label,_a", "label_b"],
|
324
|
+
values: smallvec!["value,_a", "value_b"],
|
325
|
+
}),
|
326
|
+
},
|
327
|
+
TestCase {
|
328
|
+
name: "bracket in value",
|
329
|
+
input: r#"["met[r]ic","na[m]e",["label[_]a","label_b"],["value_a","val[ue]_b"]]"#,
|
330
|
+
expected: Some(MetricText {
|
331
|
+
family_name: "met[r]ic",
|
332
|
+
metric_name: "na[m]e",
|
333
|
+
labels: smallvec!["label[_]a", "label_b"],
|
334
|
+
values: smallvec!["value_a", "val[ue]_b"],
|
335
|
+
}),
|
336
|
+
},
|
337
|
+
TestCase {
|
338
|
+
name: "escaped quotes",
|
339
|
+
input: r#"["met\"ric","na\"me",["label\"_a","label_b"],["value\"_a","value_b"]]"#,
|
340
|
+
expected: Some(MetricText {
|
341
|
+
family_name: r#"met\"ric"#,
|
342
|
+
metric_name: r#"na\"me"#,
|
343
|
+
labels: smallvec![r#"label\"_a"#, "label_b"],
|
344
|
+
values: smallvec![r#"value\"_a"#, "value_b"],
|
345
|
+
}),
|
346
|
+
},
|
240
347
|
];
|
241
348
|
|
242
349
|
for case in tc {
|
@@ -313,23 +420,18 @@ mod test {
|
|
313
420
|
expected: None,
|
314
421
|
},
|
315
422
|
TestCase {
|
316
|
-
name: "
|
317
|
-
input: r#"["
|
318
|
-
expected: None,
|
319
|
-
},
|
320
|
-
TestCase {
|
321
|
-
name: "comma in metric name",
|
322
|
-
input: r#"["metric","na,me",["label_a","label_b"],["value_a","value_b"]]"#,
|
423
|
+
name: "misplaced bracket",
|
424
|
+
input: r#"["metric","name",["label_a","label_b"],]["value_a","value_b"]]"#,
|
323
425
|
expected: None,
|
324
426
|
},
|
325
427
|
TestCase {
|
326
|
-
name: "comma in value",
|
327
|
-
input: r#"["metric","
|
428
|
+
name: "comma in numeric value",
|
429
|
+
input: r#"["metric","name",["label_a","label_b"],[400,0,"value_b"]]"#,
|
328
430
|
expected: None,
|
329
431
|
},
|
330
432
|
TestCase {
|
331
|
-
name: "
|
332
|
-
input: r#"["metric","name",["label_a","label_b"],[
|
433
|
+
name: "non-e letter in numeric value",
|
434
|
+
input: r#"["metric","name",["label_a","label_b"],[400x0,"value_b"]]"#,
|
333
435
|
expected: None,
|
334
436
|
},
|
335
437
|
];
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prometheus-client-mmap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.24.
|
4
|
+
version: 0.24.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Schmidt
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2023-
|
14
|
+
date: 2023-06-12 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rb_sys
|