prometheus-client-mmap 0.20.3-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +253 -0
  3. data/ext/fast_mmaped_file/extconf.rb +30 -0
  4. data/ext/fast_mmaped_file/fast_mmaped_file.c +122 -0
  5. data/ext/fast_mmaped_file/file_format.c +5 -0
  6. data/ext/fast_mmaped_file/file_format.h +11 -0
  7. data/ext/fast_mmaped_file/file_parsing.c +195 -0
  8. data/ext/fast_mmaped_file/file_parsing.h +27 -0
  9. data/ext/fast_mmaped_file/file_reading.c +102 -0
  10. data/ext/fast_mmaped_file/file_reading.h +30 -0
  11. data/ext/fast_mmaped_file/globals.h +14 -0
  12. data/ext/fast_mmaped_file/mmap.c +427 -0
  13. data/ext/fast_mmaped_file/mmap.h +61 -0
  14. data/ext/fast_mmaped_file/rendering.c +199 -0
  15. data/ext/fast_mmaped_file/rendering.h +8 -0
  16. data/ext/fast_mmaped_file/utils.c +56 -0
  17. data/ext/fast_mmaped_file/utils.h +22 -0
  18. data/ext/fast_mmaped_file/value_access.c +242 -0
  19. data/ext/fast_mmaped_file/value_access.h +15 -0
  20. data/ext/fast_mmaped_file_rs/.cargo/config.toml +23 -0
  21. data/ext/fast_mmaped_file_rs/Cargo.lock +790 -0
  22. data/ext/fast_mmaped_file_rs/Cargo.toml +30 -0
  23. data/ext/fast_mmaped_file_rs/README.md +52 -0
  24. data/ext/fast_mmaped_file_rs/extconf.rb +30 -0
  25. data/ext/fast_mmaped_file_rs/src/error.rs +174 -0
  26. data/ext/fast_mmaped_file_rs/src/file_entry.rs +579 -0
  27. data/ext/fast_mmaped_file_rs/src/file_info.rs +190 -0
  28. data/ext/fast_mmaped_file_rs/src/lib.rs +79 -0
  29. data/ext/fast_mmaped_file_rs/src/macros.rs +14 -0
  30. data/ext/fast_mmaped_file_rs/src/map.rs +492 -0
  31. data/ext/fast_mmaped_file_rs/src/mmap.rs +151 -0
  32. data/ext/fast_mmaped_file_rs/src/parser.rs +346 -0
  33. data/ext/fast_mmaped_file_rs/src/raw_entry.rs +473 -0
  34. data/ext/fast_mmaped_file_rs/src/testhelper.rs +222 -0
  35. data/ext/fast_mmaped_file_rs/src/util.rs +121 -0
  36. data/lib/2.7/fast_mmaped_file.so +0 -0
  37. data/lib/2.7/fast_mmaped_file_rs.so +0 -0
  38. data/lib/3.0/fast_mmaped_file.so +0 -0
  39. data/lib/3.0/fast_mmaped_file_rs.so +0 -0
  40. data/lib/3.1/fast_mmaped_file.so +0 -0
  41. data/lib/3.1/fast_mmaped_file_rs.so +0 -0
  42. data/lib/3.2/fast_mmaped_file.so +0 -0
  43. data/lib/3.2/fast_mmaped_file_rs.so +0 -0
  44. data/lib/prometheus/client/configuration.rb +23 -0
  45. data/lib/prometheus/client/counter.rb +27 -0
  46. data/lib/prometheus/client/formats/text.rb +118 -0
  47. data/lib/prometheus/client/gauge.rb +40 -0
  48. data/lib/prometheus/client/helper/entry_parser.rb +132 -0
  49. data/lib/prometheus/client/helper/file_locker.rb +50 -0
  50. data/lib/prometheus/client/helper/json_parser.rb +23 -0
  51. data/lib/prometheus/client/helper/metrics_processing.rb +45 -0
  52. data/lib/prometheus/client/helper/metrics_representation.rb +51 -0
  53. data/lib/prometheus/client/helper/mmaped_file.rb +64 -0
  54. data/lib/prometheus/client/helper/plain_file.rb +29 -0
  55. data/lib/prometheus/client/histogram.rb +80 -0
  56. data/lib/prometheus/client/label_set_validator.rb +86 -0
  57. data/lib/prometheus/client/metric.rb +80 -0
  58. data/lib/prometheus/client/mmaped_dict.rb +79 -0
  59. data/lib/prometheus/client/mmaped_value.rb +154 -0
  60. data/lib/prometheus/client/page_size.rb +17 -0
  61. data/lib/prometheus/client/push.rb +203 -0
  62. data/lib/prometheus/client/rack/collector.rb +88 -0
  63. data/lib/prometheus/client/rack/exporter.rb +96 -0
  64. data/lib/prometheus/client/registry.rb +65 -0
  65. data/lib/prometheus/client/simple_value.rb +31 -0
  66. data/lib/prometheus/client/summary.rb +69 -0
  67. data/lib/prometheus/client/support/unicorn.rb +35 -0
  68. data/lib/prometheus/client/uses_value_type.rb +20 -0
  69. data/lib/prometheus/client/version.rb +5 -0
  70. data/lib/prometheus/client.rb +58 -0
  71. data/lib/prometheus.rb +3 -0
  72. data/vendor/c/hashmap/.gitignore +52 -0
  73. data/vendor/c/hashmap/LICENSE +21 -0
  74. data/vendor/c/hashmap/README.md +90 -0
  75. data/vendor/c/hashmap/_config.yml +1 -0
  76. data/vendor/c/hashmap/src/hashmap.c +692 -0
  77. data/vendor/c/hashmap/src/hashmap.h +267 -0
  78. data/vendor/c/hashmap/test/Makefile +22 -0
  79. data/vendor/c/hashmap/test/hashmap_test.c +608 -0
  80. data/vendor/c/jsmn/.travis.yml +4 -0
  81. data/vendor/c/jsmn/LICENSE +20 -0
  82. data/vendor/c/jsmn/Makefile +41 -0
  83. data/vendor/c/jsmn/README.md +168 -0
  84. data/vendor/c/jsmn/example/jsondump.c +126 -0
  85. data/vendor/c/jsmn/example/simple.c +76 -0
  86. data/vendor/c/jsmn/jsmn.c +314 -0
  87. data/vendor/c/jsmn/jsmn.h +76 -0
  88. data/vendor/c/jsmn/library.json +16 -0
  89. data/vendor/c/jsmn/test/test.h +27 -0
  90. data/vendor/c/jsmn/test/tests.c +407 -0
  91. data/vendor/c/jsmn/test/testutil.h +94 -0
  92. metadata +243 -0
@@ -0,0 +1,346 @@
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, 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, 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, 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
+ }