prometheus-client-mmap 0.24.4-x86_64-darwin → 0.25.0-x86_64-darwin
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/fast_mmaped_file/mmap.c +13 -2
- data/ext/fast_mmaped_file_rs/Cargo.lock +52 -8
- data/ext/fast_mmaped_file_rs/Cargo.toml +6 -1
- data/ext/fast_mmaped_file_rs/build.rs +5 -0
- data/ext/fast_mmaped_file_rs/src/file_entry.rs +217 -12
- data/ext/fast_mmaped_file_rs/src/lib.rs +0 -1
- data/ext/fast_mmaped_file_rs/src/mmap.rs +15 -6
- data/lib/2.7/fast_mmaped_file.bundle +0 -0
- data/lib/2.7/fast_mmaped_file_rs.bundle +0 -0
- data/lib/3.0/fast_mmaped_file.bundle +0 -0
- data/lib/3.0/fast_mmaped_file_rs.bundle +0 -0
- data/lib/3.1/fast_mmaped_file.bundle +0 -0
- data/lib/3.1/fast_mmaped_file_rs.bundle +0 -0
- data/lib/3.2/fast_mmaped_file.bundle +0 -0
- data/lib/3.2/fast_mmaped_file_rs.bundle +0 -0
- data/lib/prometheus/client/version.rb +1 -1
- metadata +3 -3
- data/ext/fast_mmaped_file_rs/src/parser.rs +0 -448
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74773c45b9ddb83dfa6b24c8ebbc0cef9b5c42e25130739abe1a9c5e31303606
|
4
|
+
data.tar.gz: c0ecad5a2f9cc1208929857d044fdf15e5dfe4b7ead267098ce294beb96f9fa3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c24415dcfceadf7b6c569afd67ec520a965ed220cc8e5a1e5d884cf8e23d948fccaaf57fd2fb74a20a294179a0d76ff15059a0b72d270aa351d08b7aadbe91b
|
7
|
+
data.tar.gz: b972c38fad8aacc72692a4a12292955d1be095510c701f4ccfc1121aeeb57a8a20102cf004230b53ce237068cba0a89bff5cd63845ea36d498061f22c0675dad
|
data/ext/fast_mmaped_file/mmap.c
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
#include <errno.h>
|
4
4
|
#include <fcntl.h>
|
5
5
|
#include <ruby/util.h>
|
6
|
+
#include <ruby/version.h>
|
6
7
|
#include <sys/mman.h>
|
7
8
|
|
8
9
|
#include "file_format.h"
|
@@ -27,6 +28,16 @@
|
|
27
28
|
*/
|
28
29
|
static VALUE weak_obj_tracker_get_key(VALUE val) { return val; }
|
29
30
|
|
31
|
+
static void update_rstring_len(VALUE val, size_t len) {
|
32
|
+
#if defined(RUBY_API_VERSION_MAJOR) && defined(RUBY_API_VERSION_MINOR) && (RUBY_API_VERSION_MAJOR == 3) && \
|
33
|
+
(RUBY_API_VERSION_MINOR >= 3)
|
34
|
+
|
35
|
+
RSTRING(val)->len = len;
|
36
|
+
#else
|
37
|
+
RSTRING(val)->as.heap.len = len;
|
38
|
+
#endif
|
39
|
+
}
|
40
|
+
|
30
41
|
/**
|
31
42
|
* Adds a T_STRING type to the WeakMap. The WeakMap should be stored
|
32
43
|
* as an instance variable.
|
@@ -52,7 +63,7 @@ VALUE mm_update_obj_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, self)) {
|
|
52
63
|
GET_MMAP(self, i_mm, MM_MODIFY);
|
53
64
|
|
54
65
|
RSTRING(i)->as.heap.ptr = i_mm->t->addr;
|
55
|
-
|
66
|
+
update_rstring_len(i, i_mm->t->real);
|
56
67
|
|
57
68
|
return Qtrue;
|
58
69
|
}
|
@@ -98,7 +109,7 @@ static VALUE mm_str(VALUE obj, int modify) {
|
|
98
109
|
ret = rb_obj_alloc(rb_cString);
|
99
110
|
RSTRING(ret)->as.heap.ptr = i_mm->t->addr;
|
100
111
|
RSTRING(ret)->as.heap.aux.capa = i_mm->t->len;
|
101
|
-
|
112
|
+
update_rstring_len(ret, i_mm->t->real);
|
102
113
|
|
103
114
|
weak_obj_tracker_add(obj, ret);
|
104
115
|
|
@@ -30,9 +30,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|
30
30
|
|
31
31
|
[[package]]
|
32
32
|
name = "bindgen"
|
33
|
-
version = "0.
|
33
|
+
version = "0.62.0"
|
34
34
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
35
|
-
checksum = "
|
35
|
+
checksum = "c6720a8b7b2d39dd533285ed438d458f65b31b5c257e6ac7bb3d7e82844dd722"
|
36
36
|
dependencies = [
|
37
37
|
"bitflags",
|
38
38
|
"cexpr",
|
@@ -45,6 +45,7 @@ dependencies = [
|
|
45
45
|
"regex",
|
46
46
|
"rustc-hash",
|
47
47
|
"shlex",
|
48
|
+
"syn 1.0.109",
|
48
49
|
]
|
49
50
|
|
50
51
|
[[package]]
|
@@ -169,6 +170,9 @@ dependencies = [
|
|
169
170
|
"nix",
|
170
171
|
"rand",
|
171
172
|
"rb-sys",
|
173
|
+
"rb-sys-env",
|
174
|
+
"serde",
|
175
|
+
"serde_json",
|
172
176
|
"sha2",
|
173
177
|
"smallvec",
|
174
178
|
"tempfile",
|
@@ -252,6 +256,12 @@ dependencies = [
|
|
252
256
|
"windows-sys 0.48.0",
|
253
257
|
]
|
254
258
|
|
259
|
+
[[package]]
|
260
|
+
name = "itoa"
|
261
|
+
version = "1.0.6"
|
262
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
263
|
+
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
264
|
+
|
255
265
|
[[package]]
|
256
266
|
name = "lazy_static"
|
257
267
|
version = "1.4.0"
|
@@ -289,7 +299,7 @@ checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
|
|
289
299
|
[[package]]
|
290
300
|
name = "magnus"
|
291
301
|
version = "0.5.0"
|
292
|
-
source = "git+https://github.com/matsadler/magnus?branch=main#
|
302
|
+
source = "git+https://github.com/matsadler/magnus?branch=main#50cab2380103c39c14765a10bdc4b38a74082285"
|
293
303
|
dependencies = [
|
294
304
|
"magnus-macros",
|
295
305
|
"rb-sys",
|
@@ -300,7 +310,7 @@ dependencies = [
|
|
300
310
|
[[package]]
|
301
311
|
name = "magnus-macros"
|
302
312
|
version = "0.4.0"
|
303
|
-
source = "git+https://github.com/matsadler/magnus?branch=main#
|
313
|
+
source = "git+https://github.com/matsadler/magnus?branch=main#50cab2380103c39c14765a10bdc4b38a74082285"
|
304
314
|
dependencies = [
|
305
315
|
"proc-macro2",
|
306
316
|
"quote",
|
@@ -435,18 +445,18 @@ dependencies = [
|
|
435
445
|
|
436
446
|
[[package]]
|
437
447
|
name = "rb-sys"
|
438
|
-
version = "0.9.
|
448
|
+
version = "0.9.79"
|
439
449
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
440
|
-
checksum = "
|
450
|
+
checksum = "939fb78db3e4f26665c1d4c7b91ca66d3578335a19aba552d4a6445811d07072"
|
441
451
|
dependencies = [
|
442
452
|
"rb-sys-build",
|
443
453
|
]
|
444
454
|
|
445
455
|
[[package]]
|
446
456
|
name = "rb-sys-build"
|
447
|
-
version = "0.9.
|
457
|
+
version = "0.9.79"
|
448
458
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
449
|
-
checksum = "
|
459
|
+
checksum = "335a95eb0420d52fa94ef12019df3c2c250c6b19cbb3c60bd05cb7e9c362072c"
|
450
460
|
dependencies = [
|
451
461
|
"bindgen",
|
452
462
|
"lazy_static",
|
@@ -515,6 +525,12 @@ dependencies = [
|
|
515
525
|
"windows-sys 0.48.0",
|
516
526
|
]
|
517
527
|
|
528
|
+
[[package]]
|
529
|
+
name = "ryu"
|
530
|
+
version = "1.0.13"
|
531
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
532
|
+
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
533
|
+
|
518
534
|
[[package]]
|
519
535
|
name = "seq-macro"
|
520
536
|
version = "0.3.3"
|
@@ -526,6 +542,31 @@ name = "serde"
|
|
526
542
|
version = "1.0.159"
|
527
543
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
528
544
|
checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
|
545
|
+
dependencies = [
|
546
|
+
"serde_derive",
|
547
|
+
]
|
548
|
+
|
549
|
+
[[package]]
|
550
|
+
name = "serde_derive"
|
551
|
+
version = "1.0.159"
|
552
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
553
|
+
checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
|
554
|
+
dependencies = [
|
555
|
+
"proc-macro2",
|
556
|
+
"quote",
|
557
|
+
"syn 2.0.13",
|
558
|
+
]
|
559
|
+
|
560
|
+
[[package]]
|
561
|
+
name = "serde_json"
|
562
|
+
version = "1.0.96"
|
563
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
564
|
+
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
|
565
|
+
dependencies = [
|
566
|
+
"itoa",
|
567
|
+
"ryu",
|
568
|
+
"serde",
|
569
|
+
]
|
529
570
|
|
530
571
|
[[package]]
|
531
572
|
name = "sha2"
|
@@ -555,6 +596,9 @@ name = "smallvec"
|
|
555
596
|
version = "1.10.0"
|
556
597
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
557
598
|
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
599
|
+
dependencies = [
|
600
|
+
"serde",
|
601
|
+
]
|
558
602
|
|
559
603
|
[[package]]
|
560
604
|
name = "syn"
|
@@ -13,7 +13,9 @@ memmap2 = "0.5"
|
|
13
13
|
# v0.26 cannot be built on CentOS 7 https://github.com/nix-rust/nix/issues/1972
|
14
14
|
nix = { version = "0.25", features = ["mman"] } # mman used for MsFlags
|
15
15
|
rb-sys = "0.9"
|
16
|
-
|
16
|
+
serde = { version = "1.0", features = ["derive"] }
|
17
|
+
serde_json = { version = "1.0", features = ["raw_value"] }
|
18
|
+
smallvec = { version = "1.10", features = ["serde"] }
|
17
19
|
thiserror = "1.0"
|
18
20
|
|
19
21
|
[dev-dependencies]
|
@@ -25,6 +27,9 @@ rand = "0.8"
|
|
25
27
|
sha2 = "0.10"
|
26
28
|
tempfile = "3.5"
|
27
29
|
|
30
|
+
[build-dependencies]
|
31
|
+
rb-sys-env = "0.1"
|
32
|
+
|
28
33
|
[lib]
|
29
34
|
# Integration tests won't work if crate is only `cdylib`.
|
30
35
|
crate-type = ["cdylib","lib"]
|
@@ -1,10 +1,12 @@
|
|
1
1
|
use magnus::Symbol;
|
2
|
+
use serde::Deserialize;
|
3
|
+
use serde_json::value::RawValue;
|
4
|
+
use smallvec::SmallVec;
|
2
5
|
use std::fmt::Write;
|
3
6
|
use std::str;
|
4
7
|
|
5
8
|
use crate::error::{MmapError, RubyError};
|
6
9
|
use crate::file_info::FileInfo;
|
7
|
-
use crate::parser::{self, MetricText};
|
8
10
|
use crate::raw_entry::RawEntry;
|
9
11
|
use crate::Result;
|
10
12
|
use crate::{SYM_GAUGE, SYM_LIVESUM, SYM_MAX, SYM_MIN};
|
@@ -16,6 +18,16 @@ pub struct FileEntry {
|
|
16
18
|
pub meta: EntryMetadata,
|
17
19
|
}
|
18
20
|
|
21
|
+
/// String slices pointing to the fields of a borrowed `Entry`'s JSON data.
|
22
|
+
#[derive(Deserialize, Debug)]
|
23
|
+
pub struct MetricText<'a> {
|
24
|
+
pub family_name: &'a str,
|
25
|
+
pub metric_name: &'a str,
|
26
|
+
pub labels: SmallVec<[&'a str; 4]>,
|
27
|
+
#[serde(borrow)]
|
28
|
+
pub values: SmallVec<[&'a RawValue; 4]>,
|
29
|
+
}
|
30
|
+
|
19
31
|
/// The primary data payload for a `FileEntry`, the JSON string and the
|
20
32
|
/// associated pid, if significant. Used as the key for `EntryMap`.
|
21
33
|
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
|
@@ -134,11 +146,16 @@ impl FileEntry {
|
|
134
146
|
let mut processed_count = 0;
|
135
147
|
|
136
148
|
for entry in entries {
|
137
|
-
let metrics_data = match
|
138
|
-
|
149
|
+
let metrics_data = match serde_json::from_str::<MetricText>(&entry.data.json) {
|
150
|
+
Ok(m) => {
|
151
|
+
if m.labels.len() != m.values.len() {
|
152
|
+
continue;
|
153
|
+
}
|
154
|
+
m
|
155
|
+
}
|
139
156
|
// We don't exit the function here so the total number of invalid
|
140
157
|
// entries can be calculated below.
|
141
|
-
|
158
|
+
Err(_) => continue,
|
142
159
|
};
|
143
160
|
|
144
161
|
match prev_name.as_ref() {
|
@@ -197,16 +214,20 @@ impl FileEntry {
|
|
197
214
|
|
198
215
|
let it = json_data.labels.iter().zip(json_data.values.iter());
|
199
216
|
|
200
|
-
for (i, (&key,
|
217
|
+
for (i, (&key, val)) in it.enumerate() {
|
201
218
|
out.push_str(key);
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
219
|
+
out.push('=');
|
220
|
+
|
221
|
+
match val.get() {
|
222
|
+
"null" => out.push_str("\"\""),
|
223
|
+
s if s.starts_with('"') => out.push_str(s),
|
224
|
+
s => {
|
225
|
+
// Quote numeric values.
|
226
|
+
out.push('"');
|
227
|
+
out.push_str(s);
|
228
|
+
out.push('"');
|
229
|
+
}
|
208
230
|
}
|
209
|
-
out.push('"');
|
210
231
|
|
211
232
|
if i < json_data.labels.len() - 1 {
|
212
233
|
out.push(',');
|
@@ -276,6 +297,20 @@ mod test {
|
|
276
297
|
"##}),
|
277
298
|
expected_err: None,
|
278
299
|
},
|
300
|
+
TestCase {
|
301
|
+
name: "many labels",
|
302
|
+
multiprocess_mode: "min",
|
303
|
+
json: &[
|
304
|
+
r#"["family","name",["label_a","label_b","label_c","label_d","label_e"],["value_a","value_b","value_c","value_d","value_e"]]"#,
|
305
|
+
],
|
306
|
+
values: &[1.0],
|
307
|
+
pids: &["worker-1"],
|
308
|
+
expected_out: Some(indoc! {r##"# HELP family Multiprocess metric
|
309
|
+
# TYPE family gauge
|
310
|
+
name{label_a="value_a",label_b="value_b",label_c="value_c",label_d="value_d",label_e="value_e"} 1
|
311
|
+
"##}),
|
312
|
+
expected_err: None,
|
313
|
+
},
|
279
314
|
TestCase {
|
280
315
|
name: "floating point shown",
|
281
316
|
multiprocess_mode: "min",
|
@@ -288,6 +323,44 @@ mod test {
|
|
288
323
|
"##}),
|
289
324
|
expected_err: None,
|
290
325
|
},
|
326
|
+
TestCase {
|
327
|
+
name: "numeric value",
|
328
|
+
multiprocess_mode: "min",
|
329
|
+
json: &[
|
330
|
+
r#"["family","name",["label_a","label_b","label_c"],["value_a",403,-0.2E5]]"#,
|
331
|
+
],
|
332
|
+
values: &[1.5],
|
333
|
+
pids: &["worker-1"],
|
334
|
+
expected_out: Some(indoc! {r##"# HELP family Multiprocess metric
|
335
|
+
# TYPE family gauge
|
336
|
+
name{label_a="value_a",label_b="403",label_c="-0.2E5"} 1.5
|
337
|
+
"##}),
|
338
|
+
expected_err: None,
|
339
|
+
},
|
340
|
+
TestCase {
|
341
|
+
name: "null value",
|
342
|
+
multiprocess_mode: "min",
|
343
|
+
json: &[r#"["family","name",["label_a","label_b"],["value_a",null]]"#],
|
344
|
+
values: &[1.5],
|
345
|
+
pids: &["worker-1"],
|
346
|
+
expected_out: Some(indoc! {r##"# HELP family Multiprocess metric
|
347
|
+
# TYPE family gauge
|
348
|
+
name{label_a="value_a",label_b=""} 1.5
|
349
|
+
"##}),
|
350
|
+
expected_err: None,
|
351
|
+
},
|
352
|
+
TestCase {
|
353
|
+
name: "comma in value",
|
354
|
+
multiprocess_mode: "min",
|
355
|
+
json: &[r#"["family","name",["label_a","label_b"],["value_a","value,_b"]]"#],
|
356
|
+
values: &[1.5],
|
357
|
+
pids: &["worker-1"],
|
358
|
+
expected_out: Some(indoc! {r##"# HELP family Multiprocess metric
|
359
|
+
# TYPE family gauge
|
360
|
+
name{label_a="value_a",label_b="value,_b"} 1.5
|
361
|
+
"##}),
|
362
|
+
expected_err: None,
|
363
|
+
},
|
291
364
|
TestCase {
|
292
365
|
name: "no labels, pid significant",
|
293
366
|
multiprocess_mode: "all",
|
@@ -413,6 +486,138 @@ mod test {
|
|
413
486
|
RubyError::Runtime,
|
414
487
|
)),
|
415
488
|
},
|
489
|
+
TestCase {
|
490
|
+
name: "too many values",
|
491
|
+
multiprocess_mode: "min",
|
492
|
+
json: &[r#"["family","name",["label_a"],["value_a","value,_b"]]"#],
|
493
|
+
values: &[1.5],
|
494
|
+
pids: &["worker-1"],
|
495
|
+
expected_out: None,
|
496
|
+
expected_err: Some(MmapError::legacy(
|
497
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
498
|
+
RubyError::Runtime,
|
499
|
+
)),
|
500
|
+
},
|
501
|
+
TestCase {
|
502
|
+
name: "no values",
|
503
|
+
multiprocess_mode: "min",
|
504
|
+
json: &[r#"["family","name",["label_a"]]"#],
|
505
|
+
values: &[1.5],
|
506
|
+
pids: &["worker-1"],
|
507
|
+
expected_out: None,
|
508
|
+
expected_err: Some(MmapError::legacy(
|
509
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
510
|
+
RubyError::Runtime,
|
511
|
+
)),
|
512
|
+
},
|
513
|
+
TestCase {
|
514
|
+
name: "no labels or values",
|
515
|
+
multiprocess_mode: "min",
|
516
|
+
json: &[r#"["family","name","foo"]"#],
|
517
|
+
values: &[1.5],
|
518
|
+
pids: &["worker-1"],
|
519
|
+
expected_out: None,
|
520
|
+
expected_err: Some(MmapError::legacy(
|
521
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
522
|
+
RubyError::Runtime,
|
523
|
+
)),
|
524
|
+
},
|
525
|
+
TestCase {
|
526
|
+
name: "too many leading brackets",
|
527
|
+
multiprocess_mode: "min",
|
528
|
+
json: &[r#"[["family","name",["label_a","label_b"],["value_a","value_b"]]"#],
|
529
|
+
values: &[1.5],
|
530
|
+
pids: &["worker-1"],
|
531
|
+
expected_out: None,
|
532
|
+
expected_err: Some(MmapError::legacy(
|
533
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
534
|
+
RubyError::Runtime,
|
535
|
+
)),
|
536
|
+
},
|
537
|
+
TestCase {
|
538
|
+
name: "too many trailing brackets",
|
539
|
+
multiprocess_mode: "min",
|
540
|
+
json: &[r#"["family","name",["label_a","label_b"],["value_a","value_b"]]]"#],
|
541
|
+
values: &[1.5],
|
542
|
+
pids: &["worker-1"],
|
543
|
+
expected_out: None,
|
544
|
+
expected_err: Some(MmapError::legacy(
|
545
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
546
|
+
RubyError::Runtime,
|
547
|
+
)),
|
548
|
+
},
|
549
|
+
TestCase {
|
550
|
+
name: "too many leading label brackets",
|
551
|
+
multiprocess_mode: "min",
|
552
|
+
json: &[r#"["family","name",[["label_a","label_b"],["value_a","value_b"]]"#],
|
553
|
+
values: &[1.5],
|
554
|
+
pids: &["worker-1"],
|
555
|
+
expected_out: None,
|
556
|
+
expected_err: Some(MmapError::legacy(
|
557
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
558
|
+
RubyError::Runtime,
|
559
|
+
)),
|
560
|
+
},
|
561
|
+
TestCase {
|
562
|
+
name: "too many leading label brackets",
|
563
|
+
multiprocess_mode: "min",
|
564
|
+
json: &[r#"["family","name",[["label_a","label_b"],["value_a","value_b"]]"#],
|
565
|
+
values: &[1.5],
|
566
|
+
pids: &["worker-1"],
|
567
|
+
expected_out: None,
|
568
|
+
expected_err: Some(MmapError::legacy(
|
569
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
570
|
+
RubyError::Runtime,
|
571
|
+
)),
|
572
|
+
},
|
573
|
+
TestCase {
|
574
|
+
name: "too many leading value brackets",
|
575
|
+
multiprocess_mode: "min",
|
576
|
+
json: &[r#"["family","name",["label_a","label_b"],[["value_a","value_b"]]"#],
|
577
|
+
values: &[1.5],
|
578
|
+
pids: &["worker-1"],
|
579
|
+
expected_out: None,
|
580
|
+
expected_err: Some(MmapError::legacy(
|
581
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
582
|
+
RubyError::Runtime,
|
583
|
+
)),
|
584
|
+
},
|
585
|
+
TestCase {
|
586
|
+
name: "misplaced bracket",
|
587
|
+
multiprocess_mode: "min",
|
588
|
+
json: &[r#"["family","name",["label_a","label_b"],]["value_a","value_b"]]"#],
|
589
|
+
values: &[1.5],
|
590
|
+
pids: &["worker-1"],
|
591
|
+
expected_out: None,
|
592
|
+
expected_err: Some(MmapError::legacy(
|
593
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
594
|
+
RubyError::Runtime,
|
595
|
+
)),
|
596
|
+
},
|
597
|
+
TestCase {
|
598
|
+
name: "comma in numeric",
|
599
|
+
multiprocess_mode: "min",
|
600
|
+
json: &[r#"["family","name",["label_a","label_b"],["value_a",403,0]]"#],
|
601
|
+
values: &[1.5],
|
602
|
+
pids: &["worker-1"],
|
603
|
+
expected_out: None,
|
604
|
+
expected_err: Some(MmapError::legacy(
|
605
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
606
|
+
RubyError::Runtime,
|
607
|
+
)),
|
608
|
+
},
|
609
|
+
TestCase {
|
610
|
+
name: "non-e letter in numeric",
|
611
|
+
multiprocess_mode: "min",
|
612
|
+
json: &[r#"["family","name",["label_a","label_b"],["value_a",-2.0c5]]"#],
|
613
|
+
values: &[1.5],
|
614
|
+
pids: &["worker-1"],
|
615
|
+
expected_out: None,
|
616
|
+
expected_err: Some(MmapError::legacy(
|
617
|
+
"Processed entries 0 != map entries 1".to_owned(),
|
618
|
+
RubyError::Runtime,
|
619
|
+
)),
|
620
|
+
},
|
416
621
|
];
|
417
622
|
|
418
623
|
for case in tc {
|
@@ -418,10 +418,10 @@ impl MmapedFile {
|
|
418
418
|
|
419
419
|
raw_str.as_mut().as_.heap.ptr = self.as_mut_ptr().offset(offset);
|
420
420
|
|
421
|
-
let current_len =
|
421
|
+
let current_len = str.len() as c_long;
|
422
422
|
let new_shared_len = old_cap + current_len;
|
423
423
|
|
424
|
-
|
424
|
+
self.update_rstring_len(raw_str, new_shared_len);
|
425
425
|
continue;
|
426
426
|
}
|
427
427
|
|
@@ -436,7 +436,7 @@ impl MmapedFile {
|
|
436
436
|
//
|
437
437
|
// See https://gitlab.com/gitlab-org/ruby/gems/prometheus-client-mmap/-/issues/45
|
438
438
|
raw_str.as_mut().as_.heap.ptr = self.as_mut_ptr();
|
439
|
-
|
439
|
+
self.update_rstring_len(raw_str, new_len);
|
440
440
|
}
|
441
441
|
}
|
442
442
|
|
@@ -632,6 +632,16 @@ impl MmapedFile {
|
|
632
632
|
unsafe fn rb_string_internal(rb_str: RString) -> NonNull<rb_sys::RString> {
|
633
633
|
mem::transmute::<RString, NonNull<rb_sys::RString>>(rb_str)
|
634
634
|
}
|
635
|
+
|
636
|
+
#[cfg(ruby_lte_3_2)]
|
637
|
+
unsafe fn update_rstring_len(&self, mut raw_str: NonNull<rb_sys::RString>, new_len: c_long) {
|
638
|
+
raw_str.as_mut().as_.heap.len = new_len;
|
639
|
+
}
|
640
|
+
|
641
|
+
#[cfg(ruby_gte_3_3)]
|
642
|
+
unsafe fn update_rstring_len(&self, mut raw_str: NonNull<rb_sys::RString>, new_len: c_long) {
|
643
|
+
raw_str.as_mut().len = new_len;
|
644
|
+
}
|
635
645
|
}
|
636
646
|
|
637
647
|
#[cfg(test)]
|
@@ -772,8 +782,7 @@ mod test {
|
|
772
782
|
if str.as_raw() == child_id {
|
773
783
|
assert_eq!(parent_id, raw_str.as_ref().as_.heap.aux.shared);
|
774
784
|
|
775
|
-
let child_offset =
|
776
|
-
mmap_len as isize - raw_str.as_ref().as_.heap.len as isize;
|
785
|
+
let child_offset = mmap_len as isize - str.len() as isize;
|
777
786
|
assert_eq!(mmap_ptr.offset(child_offset), raw_str.as_ref().as_.heap.ptr);
|
778
787
|
|
779
788
|
child_checked = true;
|
@@ -781,7 +790,7 @@ mod test {
|
|
781
790
|
assert_eq!(parent_id, str.as_raw());
|
782
791
|
|
783
792
|
assert_eq!(mmap_ptr, raw_str.as_ref().as_.heap.ptr);
|
784
|
-
assert_eq!(mmap_len as c_long,
|
793
|
+
assert_eq!(mmap_len as c_long, str.len() as c_long);
|
785
794
|
assert!(raw_str.as_ref().basic.flags & (STR_SHARED | STR_NOEMBED) > 0);
|
786
795
|
assert!(str.is_frozen());
|
787
796
|
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
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.
|
4
|
+
version: 0.25.0
|
5
5
|
platform: x86_64-darwin
|
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-06-
|
14
|
+
date: 2023-06-15 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rb_sys
|
@@ -150,6 +150,7 @@ files:
|
|
150
150
|
- ext/fast_mmaped_file_rs/Cargo.lock
|
151
151
|
- ext/fast_mmaped_file_rs/Cargo.toml
|
152
152
|
- ext/fast_mmaped_file_rs/README.md
|
153
|
+
- ext/fast_mmaped_file_rs/build.rs
|
153
154
|
- ext/fast_mmaped_file_rs/extconf.rb
|
154
155
|
- ext/fast_mmaped_file_rs/src/error.rs
|
155
156
|
- ext/fast_mmaped_file_rs/src/file_entry.rs
|
@@ -159,7 +160,6 @@ files:
|
|
159
160
|
- ext/fast_mmaped_file_rs/src/map.rs
|
160
161
|
- ext/fast_mmaped_file_rs/src/mmap.rs
|
161
162
|
- ext/fast_mmaped_file_rs/src/mmap/inner.rs
|
162
|
-
- ext/fast_mmaped_file_rs/src/parser.rs
|
163
163
|
- ext/fast_mmaped_file_rs/src/raw_entry.rs
|
164
164
|
- ext/fast_mmaped_file_rs/src/testhelper.rs
|
165
165
|
- ext/fast_mmaped_file_rs/src/util.rs
|
@@ -1,448 +0,0 @@
|
|
1
|
-
use smallvec::SmallVec;
|
2
|
-
use std::str;
|
3
|
-
|
4
|
-
/// String slices pointing to the fields of a borrowed `Entry`'s JSON data.
|
5
|
-
#[derive(PartialEq, Eq, Debug)]
|
6
|
-
pub struct MetricText<'a> {
|
7
|
-
pub family_name: &'a str,
|
8
|
-
pub metric_name: &'a str,
|
9
|
-
pub labels: SmallVec<[&'a str; 4]>,
|
10
|
-
pub values: SmallVec<[&'a str; 4]>,
|
11
|
-
}
|
12
|
-
|
13
|
-
#[derive(PartialEq, Eq, Debug)]
|
14
|
-
struct MetricNames<'a> {
|
15
|
-
label_json: &'a str,
|
16
|
-
family_name: &'a str,
|
17
|
-
metric_name: &'a str,
|
18
|
-
}
|
19
|
-
|
20
|
-
#[derive(PartialEq, Eq, Debug)]
|
21
|
-
struct MetricLabelVals<'a> {
|
22
|
-
labels: SmallVec<[&'a str; 4]>,
|
23
|
-
values: SmallVec<[&'a str; 4]>,
|
24
|
-
}
|
25
|
-
|
26
|
-
/// Parse Prometheus metric data stored in the following format:
|
27
|
-
///
|
28
|
-
/// ["metric","name",["label_a","label_b"],["value_a","value_b"]]
|
29
|
-
///
|
30
|
-
/// There will be 1-8 trailing spaces to ensure at least a one-byte
|
31
|
-
/// gap between the json and value, and to pad to an 8-byte alignment.
|
32
|
-
/// We strip the surrounding double quotes from all items. Values may
|
33
|
-
/// or may not have surrounding double quotes, depending on their type.
|
34
|
-
pub fn parse_metrics(json: &str) -> Option<MetricText> {
|
35
|
-
// It would be preferable to use `serde_json` here, but the values
|
36
|
-
// may be strings, numbers, or null, and so don't parse easily to a
|
37
|
-
// defined struct. Using `serde_json::Value` is an option, but since
|
38
|
-
// we're just copying the literal values into a buffer this will be
|
39
|
-
// inefficient and verbose.
|
40
|
-
|
41
|
-
// Trim trailing spaces from string before processing. We use
|
42
|
-
// `trim_end_matches()` instead of `trim_end()` because we know the
|
43
|
-
// trailing bytes are always ASCII 0x20 bytes. `trim_end()` will also
|
44
|
-
// check for unicode spaces and consume a few more CPU cycles.
|
45
|
-
let trimmed = json.trim_end_matches(' ');
|
46
|
-
|
47
|
-
let names = parse_names(trimmed)?;
|
48
|
-
let label_json = names.label_json;
|
49
|
-
|
50
|
-
let label_vals = parse_label_values(label_json)?;
|
51
|
-
|
52
|
-
Some(MetricText {
|
53
|
-
family_name: names.family_name,
|
54
|
-
metric_name: names.metric_name,
|
55
|
-
labels: label_vals.labels,
|
56
|
-
values: label_vals.values,
|
57
|
-
})
|
58
|
-
}
|
59
|
-
|
60
|
-
fn parse_names(json: &str) -> Option<MetricNames> {
|
61
|
-
// Starting with: ["family_name","metric_name",[...
|
62
|
-
if !json.starts_with("[\"") {
|
63
|
-
return None;
|
64
|
-
}
|
65
|
-
|
66
|
-
// Captured: "family_name","metric_name",
|
67
|
-
// ^^^^^^^^^^^
|
68
|
-
let (family_name, remainder) = scan_str(json.get(1..)?)?;
|
69
|
-
|
70
|
-
// Validate comma separated names
|
71
|
-
// ["family_name","metric_name",[...
|
72
|
-
// ^
|
73
|
-
if !remainder.starts_with("\",") {
|
74
|
-
return None;
|
75
|
-
}
|
76
|
-
|
77
|
-
// Now: "metric_name",[...
|
78
|
-
let remainder = remainder.get(2..)?;
|
79
|
-
|
80
|
-
// Captured: "family_name","metric_name",
|
81
|
-
// ^^^^^^^^^^^
|
82
|
-
let (metric_name, remainder) = scan_str(remainder)?;
|
83
|
-
|
84
|
-
// Validate comma separated names
|
85
|
-
// ["family_name","metric_name",[...
|
86
|
-
// ^^
|
87
|
-
if !remainder.starts_with("\",") {
|
88
|
-
return None;
|
89
|
-
}
|
90
|
-
|
91
|
-
// Save the rest of the slice to parse for labels later.
|
92
|
-
// Now: [...
|
93
|
-
let label_json = remainder.get(2..)?;
|
94
|
-
|
95
|
-
Some(MetricNames {
|
96
|
-
label_json,
|
97
|
-
family_name,
|
98
|
-
metric_name,
|
99
|
-
})
|
100
|
-
}
|
101
|
-
|
102
|
-
fn parse_label_values(json: &str) -> Option<MetricLabelVals> {
|
103
|
-
// Starting with: ["label_a","label_b"],["value_a", "value_b"]]
|
104
|
-
if !json.starts_with('[') {
|
105
|
-
return None;
|
106
|
-
}
|
107
|
-
|
108
|
-
// Now: "label_a","label_b"],["value_a", "value_b"]]
|
109
|
-
let mut remainder = json.get(1..)?;
|
110
|
-
|
111
|
-
// Validate we either have the start of a label string or an
|
112
|
-
// empty array, e.g. `["` or `[]`.
|
113
|
-
if !matches!(json.as_bytes().get(1)?, b'"' | b']') {
|
114
|
-
return None;
|
115
|
-
}
|
116
|
-
|
117
|
-
let mut labels = SmallVec::new();
|
118
|
-
|
119
|
-
// Split on commas into:
|
120
|
-
// "label_a","label_b"
|
121
|
-
// ^^^one^^^ ^^^two^^^
|
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..)?;
|
139
|
-
}
|
140
|
-
|
141
|
-
if !remainder.starts_with("],[") {
|
142
|
-
return None;
|
143
|
-
}
|
144
|
-
// Now: "value_a", "value_b"]]
|
145
|
-
remainder = remainder.get(3..)?;
|
146
|
-
|
147
|
-
// Validate we don't have extra brackets.
|
148
|
-
if remainder.starts_with('[') {
|
149
|
-
return None;
|
150
|
-
}
|
151
|
-
|
152
|
-
let mut values = SmallVec::new();
|
153
|
-
// Split on commas into:
|
154
|
-
// "value_a","value_b"
|
155
|
-
// ^^^one^^^ ^^^two^^^
|
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..];
|
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..)?;
|
185
|
-
}
|
186
|
-
|
187
|
-
if values.len() != labels.len() {
|
188
|
-
return None;
|
189
|
-
}
|
190
|
-
|
191
|
-
// Now: ]]
|
192
|
-
if remainder != "]]" {
|
193
|
-
return None;
|
194
|
-
}
|
195
|
-
|
196
|
-
Some(MetricLabelVals { labels, values })
|
197
|
-
}
|
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
|
-
|
241
|
-
#[cfg(test)]
|
242
|
-
mod test {
|
243
|
-
use smallvec::smallvec;
|
244
|
-
|
245
|
-
use super::*;
|
246
|
-
|
247
|
-
struct TestCase {
|
248
|
-
name: &'static str,
|
249
|
-
input: &'static str,
|
250
|
-
expected: Option<MetricText<'static>>,
|
251
|
-
}
|
252
|
-
|
253
|
-
#[test]
|
254
|
-
fn valid_json() {
|
255
|
-
let tc = vec![
|
256
|
-
TestCase {
|
257
|
-
name: "basic",
|
258
|
-
input: r#"["metric","name",["label_a","label_b"],["value_a","value_b"]]"#,
|
259
|
-
expected: Some(MetricText {
|
260
|
-
family_name: "metric",
|
261
|
-
metric_name: "name",
|
262
|
-
labels: smallvec!["label_a", "label_b"],
|
263
|
-
values: smallvec!["value_a", "value_b"],
|
264
|
-
}),
|
265
|
-
},
|
266
|
-
TestCase {
|
267
|
-
name: "many labels",
|
268
|
-
input: r#"["metric","name",["label_a","label_b","label_c","label_d","label_e"],["value_a","value_b","value_c","value_d","value_e"]]"#,
|
269
|
-
|
270
|
-
expected: Some(MetricText {
|
271
|
-
family_name: "metric",
|
272
|
-
metric_name: "name",
|
273
|
-
labels: smallvec!["label_a", "label_b", "label_c", "label_d", "label_e"],
|
274
|
-
values: smallvec!["value_a", "value_b", "value_c", "value_d", "value_e"],
|
275
|
-
}),
|
276
|
-
},
|
277
|
-
TestCase {
|
278
|
-
name: "numeric value",
|
279
|
-
input: r#"["metric","name",["label_a","label_b"],["value_a",403]]"#,
|
280
|
-
expected: Some(MetricText {
|
281
|
-
family_name: "metric",
|
282
|
-
metric_name: "name",
|
283
|
-
labels: smallvec!["label_a", "label_b"],
|
284
|
-
values: smallvec!["value_a", "403"],
|
285
|
-
}),
|
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
|
-
},
|
297
|
-
TestCase {
|
298
|
-
name: "null value",
|
299
|
-
input: r#"["metric","name",["label_a","label_b"],[null,"value_b"]]"#,
|
300
|
-
expected: Some(MetricText {
|
301
|
-
family_name: "metric",
|
302
|
-
metric_name: "name",
|
303
|
-
labels: smallvec!["label_a", "label_b"],
|
304
|
-
values: smallvec!["null", "value_b"],
|
305
|
-
}),
|
306
|
-
},
|
307
|
-
TestCase {
|
308
|
-
name: "no labels",
|
309
|
-
input: r#"["metric","name",[],[]]"#,
|
310
|
-
expected: Some(MetricText {
|
311
|
-
family_name: "metric",
|
312
|
-
metric_name: "name",
|
313
|
-
labels: smallvec![],
|
314
|
-
values: smallvec![],
|
315
|
-
}),
|
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
|
-
},
|
347
|
-
];
|
348
|
-
|
349
|
-
for case in tc {
|
350
|
-
assert_eq!(
|
351
|
-
parse_metrics(case.input),
|
352
|
-
case.expected,
|
353
|
-
"test case: {}",
|
354
|
-
case.name,
|
355
|
-
);
|
356
|
-
}
|
357
|
-
}
|
358
|
-
|
359
|
-
#[test]
|
360
|
-
fn invalid_json() {
|
361
|
-
let tc = vec![
|
362
|
-
TestCase {
|
363
|
-
name: "not json",
|
364
|
-
input: "hello, world",
|
365
|
-
expected: None,
|
366
|
-
},
|
367
|
-
TestCase {
|
368
|
-
name: "no names",
|
369
|
-
input: r#"[["label_a","label_b"],["value_a","value_b"]]"#,
|
370
|
-
expected: None,
|
371
|
-
},
|
372
|
-
TestCase {
|
373
|
-
name: "too many names",
|
374
|
-
input: r#"["metric","name","unexpected_name",["label_a","label_b"],["value_a","value_b"]]"#,
|
375
|
-
expected: None,
|
376
|
-
},
|
377
|
-
TestCase {
|
378
|
-
name: "too many labels",
|
379
|
-
input: r#"["metric","name","unexpected_name",["label_a","label_b","label_c"],["value_a","value_b"]]"#,
|
380
|
-
expected: None,
|
381
|
-
},
|
382
|
-
TestCase {
|
383
|
-
name: "too many values",
|
384
|
-
input: r#"["metric","name",["label_a","label_b"],["value_a","value_b",null]]"#,
|
385
|
-
expected: None,
|
386
|
-
},
|
387
|
-
TestCase {
|
388
|
-
name: "no values",
|
389
|
-
input: r#"["metric","name",["label_a","label_b"]"#,
|
390
|
-
expected: None,
|
391
|
-
},
|
392
|
-
TestCase {
|
393
|
-
name: "no arrays",
|
394
|
-
input: r#"["metric","name","label_a","value_a"]"#,
|
395
|
-
expected: None,
|
396
|
-
},
|
397
|
-
TestCase {
|
398
|
-
name: "too many leading brackets",
|
399
|
-
input: r#"[["metric","name",["label_a","label_b"],["value_a","value_b"]]"#,
|
400
|
-
expected: None,
|
401
|
-
},
|
402
|
-
TestCase {
|
403
|
-
name: "too many trailing brackets",
|
404
|
-
input: r#"["metric","name",["label_a","label_b"],["value_a","value_b"]]]"#,
|
405
|
-
expected: None,
|
406
|
-
},
|
407
|
-
TestCase {
|
408
|
-
name: "too many leading label brackets",
|
409
|
-
input: r#"["metric","name",[["label_a","label_b"],["value_a","value_b"]]"#,
|
410
|
-
expected: None,
|
411
|
-
},
|
412
|
-
TestCase {
|
413
|
-
name: "too many trailing label brackets",
|
414
|
-
input: r#"["metric","name",["label_a","label_b"]],["value_a","value_b"]]"#,
|
415
|
-
expected: None,
|
416
|
-
},
|
417
|
-
TestCase {
|
418
|
-
name: "too many leading value brackets",
|
419
|
-
input: r#"["metric","name",["label_a","label_b"],[["value_a","value_b"]]"#,
|
420
|
-
expected: None,
|
421
|
-
},
|
422
|
-
TestCase {
|
423
|
-
name: "misplaced bracket",
|
424
|
-
input: r#"["metric","name",["label_a","label_b"],]["value_a","value_b"]]"#,
|
425
|
-
expected: None,
|
426
|
-
},
|
427
|
-
TestCase {
|
428
|
-
name: "comma in numeric value",
|
429
|
-
input: r#"["metric","name",["label_a","label_b"],[400,0,"value_b"]]"#,
|
430
|
-
expected: None,
|
431
|
-
},
|
432
|
-
TestCase {
|
433
|
-
name: "non-e letter in numeric value",
|
434
|
-
input: r#"["metric","name",["label_a","label_b"],[400x0,"value_b"]]"#,
|
435
|
-
expected: None,
|
436
|
-
},
|
437
|
-
];
|
438
|
-
|
439
|
-
for case in tc {
|
440
|
-
assert_eq!(
|
441
|
-
case.expected,
|
442
|
-
parse_metrics(case.input),
|
443
|
-
"test case: {}",
|
444
|
-
case.name,
|
445
|
-
);
|
446
|
-
}
|
447
|
-
}
|
448
|
-
}
|