prometheus-client-mmap 0.24.3-x86_64-linux → 0.24.5-x86_64-linux
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_rs/Cargo.lock +42 -0
 - data/ext/fast_mmaped_file_rs/Cargo.toml +3 -1
 - data/ext/fast_mmaped_file_rs/src/file_entry.rs +217 -12
 - data/ext/fast_mmaped_file_rs/src/lib.rs +0 -1
 - data/lib/2.7/fast_mmaped_file_rs.so +0 -0
 - data/lib/3.0/fast_mmaped_file_rs.so +0 -0
 - data/lib/3.1/fast_mmaped_file_rs.so +0 -0
 - data/lib/3.2/fast_mmaped_file_rs.so +0 -0
 - data/lib/prometheus/client/version.rb +1 -1
 - metadata +2 -3
 - data/ext/fast_mmaped_file_rs/src/parser.rs +0 -346
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 1207aad86766a410bc9b90eee5b83ae1785f9c36fb34ac79a3bc56a44ce9d7ed
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: b1cc8b946f96ff5f26de048492159e162cb7831d11f3b724f01988aca1e1da94
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: ca3048cd9a5829d78a1a091554d33434188b6a49babe0b73ece6c508c0c7514cf54da7dc89c74bf26ecae9642fd54a89da9990be03877631942d99c81113306c
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 554ca7fa38267fa42e13d024e22f03cb96c34cc882f97d21a351b1248827cc6ab41104ad067ed2f33e3b03f4f507b344e94a9887a6d5bff737ef0878c6175d40
         
     | 
| 
         @@ -169,6 +169,8 @@ dependencies = [ 
     | 
|
| 
       169 
169 
     | 
    
         
             
             "nix",
         
     | 
| 
       170 
170 
     | 
    
         
             
             "rand",
         
     | 
| 
       171 
171 
     | 
    
         
             
             "rb-sys",
         
     | 
| 
      
 172 
     | 
    
         
            +
             "serde",
         
     | 
| 
      
 173 
     | 
    
         
            +
             "serde_json",
         
     | 
| 
       172 
174 
     | 
    
         
             
             "sha2",
         
     | 
| 
       173 
175 
     | 
    
         
             
             "smallvec",
         
     | 
| 
       174 
176 
     | 
    
         
             
             "tempfile",
         
     | 
| 
         @@ -252,6 +254,12 @@ dependencies = [ 
     | 
|
| 
       252 
254 
     | 
    
         
             
             "windows-sys 0.48.0",
         
     | 
| 
       253 
255 
     | 
    
         
             
            ]
         
     | 
| 
       254 
256 
     | 
    
         | 
| 
      
 257 
     | 
    
         
            +
            [[package]]
         
     | 
| 
      
 258 
     | 
    
         
            +
            name = "itoa"
         
     | 
| 
      
 259 
     | 
    
         
            +
            version = "1.0.6"
         
     | 
| 
      
 260 
     | 
    
         
            +
            source = "registry+https://github.com/rust-lang/crates.io-index"
         
     | 
| 
      
 261 
     | 
    
         
            +
            checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
         
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
       255 
263 
     | 
    
         
             
            [[package]]
         
     | 
| 
       256 
264 
     | 
    
         
             
            name = "lazy_static"
         
     | 
| 
       257 
265 
     | 
    
         
             
            version = "1.4.0"
         
     | 
| 
         @@ -515,6 +523,12 @@ dependencies = [ 
     | 
|
| 
       515 
523 
     | 
    
         
             
             "windows-sys 0.48.0",
         
     | 
| 
       516 
524 
     | 
    
         
             
            ]
         
     | 
| 
       517 
525 
     | 
    
         | 
| 
      
 526 
     | 
    
         
            +
            [[package]]
         
     | 
| 
      
 527 
     | 
    
         
            +
            name = "ryu"
         
     | 
| 
      
 528 
     | 
    
         
            +
            version = "1.0.13"
         
     | 
| 
      
 529 
     | 
    
         
            +
            source = "registry+https://github.com/rust-lang/crates.io-index"
         
     | 
| 
      
 530 
     | 
    
         
            +
            checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
         
     | 
| 
      
 531 
     | 
    
         
            +
             
     | 
| 
       518 
532 
     | 
    
         
             
            [[package]]
         
     | 
| 
       519 
533 
     | 
    
         
             
            name = "seq-macro"
         
     | 
| 
       520 
534 
     | 
    
         
             
            version = "0.3.3"
         
     | 
| 
         @@ -526,6 +540,31 @@ name = "serde" 
     | 
|
| 
       526 
540 
     | 
    
         
             
            version = "1.0.159"
         
     | 
| 
       527 
541 
     | 
    
         
             
            source = "registry+https://github.com/rust-lang/crates.io-index"
         
     | 
| 
       528 
542 
     | 
    
         
             
            checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
         
     | 
| 
      
 543 
     | 
    
         
            +
            dependencies = [
         
     | 
| 
      
 544 
     | 
    
         
            +
             "serde_derive",
         
     | 
| 
      
 545 
     | 
    
         
            +
            ]
         
     | 
| 
      
 546 
     | 
    
         
            +
             
     | 
| 
      
 547 
     | 
    
         
            +
            [[package]]
         
     | 
| 
      
 548 
     | 
    
         
            +
            name = "serde_derive"
         
     | 
| 
      
 549 
     | 
    
         
            +
            version = "1.0.159"
         
     | 
| 
      
 550 
     | 
    
         
            +
            source = "registry+https://github.com/rust-lang/crates.io-index"
         
     | 
| 
      
 551 
     | 
    
         
            +
            checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
         
     | 
| 
      
 552 
     | 
    
         
            +
            dependencies = [
         
     | 
| 
      
 553 
     | 
    
         
            +
             "proc-macro2",
         
     | 
| 
      
 554 
     | 
    
         
            +
             "quote",
         
     | 
| 
      
 555 
     | 
    
         
            +
             "syn 2.0.13",
         
     | 
| 
      
 556 
     | 
    
         
            +
            ]
         
     | 
| 
      
 557 
     | 
    
         
            +
             
     | 
| 
      
 558 
     | 
    
         
            +
            [[package]]
         
     | 
| 
      
 559 
     | 
    
         
            +
            name = "serde_json"
         
     | 
| 
      
 560 
     | 
    
         
            +
            version = "1.0.96"
         
     | 
| 
      
 561 
     | 
    
         
            +
            source = "registry+https://github.com/rust-lang/crates.io-index"
         
     | 
| 
      
 562 
     | 
    
         
            +
            checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
         
     | 
| 
      
 563 
     | 
    
         
            +
            dependencies = [
         
     | 
| 
      
 564 
     | 
    
         
            +
             "itoa",
         
     | 
| 
      
 565 
     | 
    
         
            +
             "ryu",
         
     | 
| 
      
 566 
     | 
    
         
            +
             "serde",
         
     | 
| 
      
 567 
     | 
    
         
            +
            ]
         
     | 
| 
       529 
568 
     | 
    
         | 
| 
       530 
569 
     | 
    
         
             
            [[package]]
         
     | 
| 
       531 
570 
     | 
    
         
             
            name = "sha2"
         
     | 
| 
         @@ -555,6 +594,9 @@ name = "smallvec" 
     | 
|
| 
       555 
594 
     | 
    
         
             
            version = "1.10.0"
         
     | 
| 
       556 
595 
     | 
    
         
             
            source = "registry+https://github.com/rust-lang/crates.io-index"
         
     | 
| 
       557 
596 
     | 
    
         
             
            checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
         
     | 
| 
      
 597 
     | 
    
         
            +
            dependencies = [
         
     | 
| 
      
 598 
     | 
    
         
            +
             "serde",
         
     | 
| 
      
 599 
     | 
    
         
            +
            ]
         
     | 
| 
       558 
600 
     | 
    
         | 
| 
       559 
601 
     | 
    
         
             
            [[package]]
         
     | 
| 
       560 
602 
     | 
    
         
             
            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]
         
     | 
| 
         @@ -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 {
         
     | 
| 
         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.24. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.24.5
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: x86_64-linux
         
     | 
| 
       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-13 00:00:00.000000000 Z
         
     | 
| 
       15 
15 
     | 
    
         
             
            dependencies:
         
     | 
| 
       16 
16 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       17 
17 
     | 
    
         
             
              name: rb_sys
         
     | 
| 
         @@ -159,7 +159,6 @@ files: 
     | 
|
| 
       159 
159 
     | 
    
         
             
            - ext/fast_mmaped_file_rs/src/map.rs
         
     | 
| 
       160 
160 
     | 
    
         
             
            - ext/fast_mmaped_file_rs/src/mmap.rs
         
     | 
| 
       161 
161 
     | 
    
         
             
            - ext/fast_mmaped_file_rs/src/mmap/inner.rs
         
     | 
| 
       162 
     | 
    
         
            -
            - ext/fast_mmaped_file_rs/src/parser.rs
         
     | 
| 
       163 
162 
     | 
    
         
             
            - ext/fast_mmaped_file_rs/src/raw_entry.rs
         
     | 
| 
       164 
163 
     | 
    
         
             
            - ext/fast_mmaped_file_rs/src/testhelper.rs
         
     | 
| 
       165 
164 
     | 
    
         
             
            - ext/fast_mmaped_file_rs/src/util.rs
         
     | 
| 
         @@ -1,346 +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 
     | 
    
         
            -
                // Now: family_name","metric_name",[...
         
     | 
| 
       67 
     | 
    
         
            -
                let remainder = json.get(2..)?;
         
     | 
| 
       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)?;
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
                // Split on commas into:
         
     | 
| 
       78 
     | 
    
         
            -
                // family_name","metric_name",
         
     | 
| 
       79 
     | 
    
         
            -
                // ^^^^one^^^^^ ^^^^^two^^^^^
         
     | 
| 
       80 
     | 
    
         
            -
                let mut token_iter = remainder.split(',');
         
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                // Captured: family_name","metric_name",
         
     | 
| 
       83 
     | 
    
         
            -
                //           ^^^^^^^^^^^
         
     | 
| 
       84 
     | 
    
         
            -
                let family_name = token_iter.next()?.trim_end_matches('"');
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
                // Captured: "family_name","metric_name",
         
     | 
| 
       87 
     | 
    
         
            -
                //                          ^^^^^^^^^^^
         
     | 
| 
       88 
     | 
    
         
            -
                let metric_name = token_iter.next()?.trim_matches('"');
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
                // Confirm the final entry of the iter is empty, the the trailing ','.
         
     | 
| 
       91 
     | 
    
         
            -
                if !token_iter.next()?.is_empty() {
         
     | 
| 
       92 
     | 
    
         
            -
                    return None;
         
     | 
| 
       93 
     | 
    
         
            -
                }
         
     | 
| 
       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('[') && json.ends_with("]]")) {
         
     | 
| 
       105 
     | 
    
         
            -
                    return None;
         
     | 
| 
       106 
     | 
    
         
            -
                }
         
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
                // Validate we either have the start of a label string or an
         
     | 
| 
       109 
     | 
    
         
            -
                // empty array, e.g. `["` or `[]`.
         
     | 
| 
       110 
     | 
    
         
            -
                if !matches!(json.as_bytes().get(1)?, b'"' | b']') {
         
     | 
| 
       111 
     | 
    
         
            -
                    return None;
         
     | 
| 
       112 
     | 
    
         
            -
                }
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                // Now: "label_a","label_b"
         
     | 
| 
       115 
     | 
    
         
            -
                let labels_end = json.find(']')?;
         
     | 
| 
       116 
     | 
    
         
            -
                let label_range = json.get(1..labels_end)?;
         
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
                let mut labels = SmallVec::new();
         
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
                // Split on commas into:
         
     | 
| 
       121 
     | 
    
         
            -
                // "label_a","label_b"
         
     | 
| 
       122 
     | 
    
         
            -
                // ^^^one^^^ ^^^two^^^
         
     | 
| 
       123 
     | 
    
         
            -
                for label in label_range.split(',') {
         
     | 
| 
       124 
     | 
    
         
            -
                    // Captured: "label_a","label_b"
         
     | 
| 
       125 
     | 
    
         
            -
                    //            ^^^^^^^
         
     | 
| 
       126 
     | 
    
         
            -
                    // If there are no labels, e.g. `[][]`, then don't capture anything.
         
     | 
| 
       127 
     | 
    
         
            -
                    if !label.is_empty() {
         
     | 
| 
       128 
     | 
    
         
            -
                        labels.push(label.trim_matches('"'));
         
     | 
| 
       129 
     | 
    
         
            -
                    }
         
     | 
| 
       130 
     | 
    
         
            -
                }
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
                // Now: ],["value_a", "value_b"]]
         
     | 
| 
       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'[') {
         
     | 
| 
       137 
     | 
    
         
            -
                    return None;
         
     | 
| 
       138 
     | 
    
         
            -
                }
         
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
       140 
     | 
    
         
            -
                // Now: "value_a", "value_b"]]
         
     | 
| 
       141 
     | 
    
         
            -
                values_range = values_range.get(3..)?;
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
                let values_end = values_range.find(']')?;
         
     | 
| 
       144 
     | 
    
         
            -
             
     | 
| 
       145 
     | 
    
         
            -
                // Validate we have only two trailing brackets.
         
     | 
| 
       146 
     | 
    
         
            -
                if values_range.get(values_end..)?.len() > 2 {
         
     | 
| 
       147 
     | 
    
         
            -
                    return None;
         
     | 
| 
       148 
     | 
    
         
            -
                }
         
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
                // Now: "value_a", "value_b"
         
     | 
| 
       151 
     | 
    
         
            -
                values_range = values_range.get(..values_end)?;
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                let mut values = SmallVec::new();
         
     | 
| 
       154 
     | 
    
         
            -
             
     | 
| 
       155 
     | 
    
         
            -
                // Split on commas into:
         
     | 
| 
       156 
     | 
    
         
            -
                // "value_a","value_b"
         
     | 
| 
       157 
     | 
    
         
            -
                // ^^^one^^^ ^^^two^^^
         
     | 
| 
       158 
     | 
    
         
            -
                for value in values_range.split(',') {
         
     | 
| 
       159 
     | 
    
         
            -
                    // Captured: "value_a","value_b"
         
     | 
| 
       160 
     | 
    
         
            -
                    //           ^^^^^^^^^
         
     | 
| 
       161 
     | 
    
         
            -
                    // If there are no values, e.g. `[][]`, then don't capture anything.
         
     | 
| 
       162 
     | 
    
         
            -
                    if !value.is_empty() {
         
     | 
| 
       163 
     | 
    
         
            -
                        values.push(value.trim_matches('"'));
         
     | 
| 
       164 
     | 
    
         
            -
                    }
         
     | 
| 
       165 
     | 
    
         
            -
                }
         
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
                if values.len() != labels.len() {
         
     | 
| 
       168 
     | 
    
         
            -
                    return None;
         
     | 
| 
       169 
     | 
    
         
            -
                }
         
     | 
| 
       170 
     | 
    
         
            -
             
     | 
| 
       171 
     | 
    
         
            -
                Some(MetricLabelVals { labels, values })
         
     | 
| 
       172 
     | 
    
         
            -
            }
         
     | 
| 
       173 
     | 
    
         
            -
             
     | 
| 
       174 
     | 
    
         
            -
            #[cfg(test)]
         
     | 
| 
       175 
     | 
    
         
            -
            mod test {
         
     | 
| 
       176 
     | 
    
         
            -
                use smallvec::smallvec;
         
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
                use super::*;
         
     | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
       180 
     | 
    
         
            -
                struct TestCase {
         
     | 
| 
       181 
     | 
    
         
            -
                    name: &'static str,
         
     | 
| 
       182 
     | 
    
         
            -
                    input: &'static str,
         
     | 
| 
       183 
     | 
    
         
            -
                    expected: Option<MetricText<'static>>,
         
     | 
| 
       184 
     | 
    
         
            -
                }
         
     | 
| 
       185 
     | 
    
         
            -
             
     | 
| 
       186 
     | 
    
         
            -
                #[test]
         
     | 
| 
       187 
     | 
    
         
            -
                fn valid_json() {
         
     | 
| 
       188 
     | 
    
         
            -
                    let tc = vec![
         
     | 
| 
       189 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       190 
     | 
    
         
            -
                            name: "basic",
         
     | 
| 
       191 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b"],["value_a","value_b"]]"#,
         
     | 
| 
       192 
     | 
    
         
            -
                            expected: Some(MetricText {
         
     | 
| 
       193 
     | 
    
         
            -
                                family_name: "metric",
         
     | 
| 
       194 
     | 
    
         
            -
                                metric_name: "name",
         
     | 
| 
       195 
     | 
    
         
            -
                                labels: smallvec!["label_a", "label_b"],
         
     | 
| 
       196 
     | 
    
         
            -
                                values: smallvec!["value_a", "value_b"],
         
     | 
| 
       197 
     | 
    
         
            -
                            }),
         
     | 
| 
       198 
     | 
    
         
            -
                        },
         
     | 
| 
       199 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       200 
     | 
    
         
            -
                            name: "many labels",
         
     | 
| 
       201 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b","label_c","label_d","label_e"],["value_a","value_b","value_c","value_d","value_e"]]"#,
         
     | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
       203 
     | 
    
         
            -
                            expected: Some(MetricText {
         
     | 
| 
       204 
     | 
    
         
            -
                                family_name: "metric",
         
     | 
| 
       205 
     | 
    
         
            -
                                metric_name: "name",
         
     | 
| 
       206 
     | 
    
         
            -
                                labels: smallvec!["label_a", "label_b", "label_c", "label_d", "label_e"],
         
     | 
| 
       207 
     | 
    
         
            -
                                values: smallvec!["value_a", "value_b", "value_c", "value_d", "value_e"],
         
     | 
| 
       208 
     | 
    
         
            -
                            }),
         
     | 
| 
       209 
     | 
    
         
            -
                        },
         
     | 
| 
       210 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       211 
     | 
    
         
            -
                            name: "numeric value",
         
     | 
| 
       212 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b"],["value_a",403]]"#,
         
     | 
| 
       213 
     | 
    
         
            -
                            expected: Some(MetricText {
         
     | 
| 
       214 
     | 
    
         
            -
                                family_name: "metric",
         
     | 
| 
       215 
     | 
    
         
            -
                                metric_name: "name",
         
     | 
| 
       216 
     | 
    
         
            -
                                labels: smallvec!["label_a", "label_b"],
         
     | 
| 
       217 
     | 
    
         
            -
                                values: smallvec!["value_a", "403"],
         
     | 
| 
       218 
     | 
    
         
            -
                            }),
         
     | 
| 
       219 
     | 
    
         
            -
                        },
         
     | 
| 
       220 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       221 
     | 
    
         
            -
                            name: "null value",
         
     | 
| 
       222 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b"],[null,"value_b"]]"#,
         
     | 
| 
       223 
     | 
    
         
            -
                            expected: Some(MetricText {
         
     | 
| 
       224 
     | 
    
         
            -
                                family_name: "metric",
         
     | 
| 
       225 
     | 
    
         
            -
                                metric_name: "name",
         
     | 
| 
       226 
     | 
    
         
            -
                                labels: smallvec!["label_a", "label_b"],
         
     | 
| 
       227 
     | 
    
         
            -
                                values: smallvec!["null", "value_b"],
         
     | 
| 
       228 
     | 
    
         
            -
                            }),
         
     | 
| 
       229 
     | 
    
         
            -
                        },
         
     | 
| 
       230 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       231 
     | 
    
         
            -
                            name: "no labels",
         
     | 
| 
       232 
     | 
    
         
            -
                            input: r#"["metric","name",[],[]]"#,
         
     | 
| 
       233 
     | 
    
         
            -
                            expected: Some(MetricText {
         
     | 
| 
       234 
     | 
    
         
            -
                                family_name: "metric",
         
     | 
| 
       235 
     | 
    
         
            -
                                metric_name: "name",
         
     | 
| 
       236 
     | 
    
         
            -
                                labels: smallvec![],
         
     | 
| 
       237 
     | 
    
         
            -
                                values: smallvec![],
         
     | 
| 
       238 
     | 
    
         
            -
                            }),
         
     | 
| 
       239 
     | 
    
         
            -
                        },
         
     | 
| 
       240 
     | 
    
         
            -
                    ];
         
     | 
| 
       241 
     | 
    
         
            -
             
     | 
| 
       242 
     | 
    
         
            -
                    for case in tc {
         
     | 
| 
       243 
     | 
    
         
            -
                        assert_eq!(
         
     | 
| 
       244 
     | 
    
         
            -
                            parse_metrics(case.input),
         
     | 
| 
       245 
     | 
    
         
            -
                            case.expected,
         
     | 
| 
       246 
     | 
    
         
            -
                            "test case: {}",
         
     | 
| 
       247 
     | 
    
         
            -
                            case.name,
         
     | 
| 
       248 
     | 
    
         
            -
                        );
         
     | 
| 
       249 
     | 
    
         
            -
                    }
         
     | 
| 
       250 
     | 
    
         
            -
                }
         
     | 
| 
       251 
     | 
    
         
            -
             
     | 
| 
       252 
     | 
    
         
            -
                #[test]
         
     | 
| 
       253 
     | 
    
         
            -
                fn invalid_json() {
         
     | 
| 
       254 
     | 
    
         
            -
                    let tc = vec![
         
     | 
| 
       255 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       256 
     | 
    
         
            -
                            name: "not json",
         
     | 
| 
       257 
     | 
    
         
            -
                            input: "hello, world",
         
     | 
| 
       258 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       259 
     | 
    
         
            -
                        },
         
     | 
| 
       260 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       261 
     | 
    
         
            -
                            name: "no names",
         
     | 
| 
       262 
     | 
    
         
            -
                            input: r#"[["label_a","label_b"],["value_a","value_b"]]"#,
         
     | 
| 
       263 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       264 
     | 
    
         
            -
                        },
         
     | 
| 
       265 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       266 
     | 
    
         
            -
                            name: "too many names",
         
     | 
| 
       267 
     | 
    
         
            -
                            input: r#"["metric","name","unexpected_name",["label_a","label_b"],["value_a","value_b"]]"#,
         
     | 
| 
       268 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       269 
     | 
    
         
            -
                        },
         
     | 
| 
       270 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       271 
     | 
    
         
            -
                            name: "too many labels",
         
     | 
| 
       272 
     | 
    
         
            -
                            input: r#"["metric","name","unexpected_name",["label_a","label_b","label_c"],["value_a","value_b"]]"#,
         
     | 
| 
       273 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       274 
     | 
    
         
            -
                        },
         
     | 
| 
       275 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       276 
     | 
    
         
            -
                            name: "too many values",
         
     | 
| 
       277 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b"],["value_a","value_b",null]]"#,
         
     | 
| 
       278 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       279 
     | 
    
         
            -
                        },
         
     | 
| 
       280 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       281 
     | 
    
         
            -
                            name: "no values",
         
     | 
| 
       282 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b"]"#,
         
     | 
| 
       283 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       284 
     | 
    
         
            -
                        },
         
     | 
| 
       285 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       286 
     | 
    
         
            -
                            name: "no arrays",
         
     | 
| 
       287 
     | 
    
         
            -
                            input: r#"["metric","name","label_a","value_a"]"#,
         
     | 
| 
       288 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       289 
     | 
    
         
            -
                        },
         
     | 
| 
       290 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       291 
     | 
    
         
            -
                            name: "too many leading brackets",
         
     | 
| 
       292 
     | 
    
         
            -
                            input: r#"[["metric","name",["label_a","label_b"],["value_a","value_b"]]"#,
         
     | 
| 
       293 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       294 
     | 
    
         
            -
                        },
         
     | 
| 
       295 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       296 
     | 
    
         
            -
                            name: "too many trailing brackets",
         
     | 
| 
       297 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b"],["value_a","value_b"]]]"#,
         
     | 
| 
       298 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       299 
     | 
    
         
            -
                        },
         
     | 
| 
       300 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       301 
     | 
    
         
            -
                            name: "too many leading label brackets",
         
     | 
| 
       302 
     | 
    
         
            -
                            input: r#"["metric","name",[["label_a","label_b"],["value_a","value_b"]]"#,
         
     | 
| 
       303 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       304 
     | 
    
         
            -
                        },
         
     | 
| 
       305 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       306 
     | 
    
         
            -
                            name: "too many trailing label brackets",
         
     | 
| 
       307 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b"]],["value_a","value_b"]]"#,
         
     | 
| 
       308 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       309 
     | 
    
         
            -
                        },
         
     | 
| 
       310 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       311 
     | 
    
         
            -
                            name: "too many leading value brackets",
         
     | 
| 
       312 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b"],[["value_a","value_b"]]"#,
         
     | 
| 
       313 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       314 
     | 
    
         
            -
                        },
         
     | 
| 
       315 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       316 
     | 
    
         
            -
                            name: "comma in family name",
         
     | 
| 
       317 
     | 
    
         
            -
                            input: r#"["met,ric","name",["label_a","label_b"],["value_a","value_b"]]"#,
         
     | 
| 
       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"]]"#,
         
     | 
| 
       323 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       324 
     | 
    
         
            -
                        },
         
     | 
| 
       325 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       326 
     | 
    
         
            -
                            name: "comma in value",
         
     | 
| 
       327 
     | 
    
         
            -
                            input: r#"["metric","na,me",["label_a","label_b"],["val,ue_a","value_b"]]"#,
         
     | 
| 
       328 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       329 
     | 
    
         
            -
                        },
         
     | 
| 
       330 
     | 
    
         
            -
                        TestCase {
         
     | 
| 
       331 
     | 
    
         
            -
                            name: "comma in numeric value",
         
     | 
| 
       332 
     | 
    
         
            -
                            input: r#"["metric","name",["label_a","label_b"],[400,0,"value_b"]]"#,
         
     | 
| 
       333 
     | 
    
         
            -
                            expected: None,
         
     | 
| 
       334 
     | 
    
         
            -
                        },
         
     | 
| 
       335 
     | 
    
         
            -
                    ];
         
     | 
| 
       336 
     | 
    
         
            -
             
     | 
| 
       337 
     | 
    
         
            -
                    for case in tc {
         
     | 
| 
       338 
     | 
    
         
            -
                        assert_eq!(
         
     | 
| 
       339 
     | 
    
         
            -
                            case.expected,
         
     | 
| 
       340 
     | 
    
         
            -
                            parse_metrics(case.input),
         
     | 
| 
       341 
     | 
    
         
            -
                            "test case: {}",
         
     | 
| 
       342 
     | 
    
         
            -
                            case.name,
         
     | 
| 
       343 
     | 
    
         
            -
                        );
         
     | 
| 
       344 
     | 
    
         
            -
                    }
         
     | 
| 
       345 
     | 
    
         
            -
                }
         
     | 
| 
       346 
     | 
    
         
            -
            }
         
     |