vinted-prometheus-client-mmap 1.5.0-x86_64-linux
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +5 -0
- data/ext/fast_mmaped_file_rs/Cargo.toml +40 -0
- data/ext/fast_mmaped_file_rs/README.md +52 -0
- data/ext/fast_mmaped_file_rs/build.rs +7 -0
- data/ext/fast_mmaped_file_rs/extconf.rb +28 -0
- data/ext/fast_mmaped_file_rs/src/error.rs +174 -0
- data/ext/fast_mmaped_file_rs/src/exemplars.rs +25 -0
- data/ext/fast_mmaped_file_rs/src/file_entry.rs +1252 -0
- data/ext/fast_mmaped_file_rs/src/file_info.rs +240 -0
- data/ext/fast_mmaped_file_rs/src/lib.rs +89 -0
- data/ext/fast_mmaped_file_rs/src/macros.rs +14 -0
- data/ext/fast_mmaped_file_rs/src/map.rs +519 -0
- data/ext/fast_mmaped_file_rs/src/metrics.proto +153 -0
- data/ext/fast_mmaped_file_rs/src/mmap/inner.rs +775 -0
- data/ext/fast_mmaped_file_rs/src/mmap.rs +977 -0
- data/ext/fast_mmaped_file_rs/src/raw_entry.rs +547 -0
- data/ext/fast_mmaped_file_rs/src/testhelper.rs +222 -0
- data/ext/fast_mmaped_file_rs/src/util.rs +140 -0
- data/lib/.DS_Store +0 -0
- 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/3.3/fast_mmaped_file_rs.so +0 -0
- data/lib/prometheus/.DS_Store +0 -0
- data/lib/prometheus/client/configuration.rb +24 -0
- data/lib/prometheus/client/counter.rb +27 -0
- data/lib/prometheus/client/formats/protobuf.rb +93 -0
- data/lib/prometheus/client/formats/text.rb +85 -0
- data/lib/prometheus/client/gauge.rb +40 -0
- data/lib/prometheus/client/helper/entry_parser.rb +132 -0
- data/lib/prometheus/client/helper/file_locker.rb +50 -0
- data/lib/prometheus/client/helper/json_parser.rb +23 -0
- data/lib/prometheus/client/helper/metrics_processing.rb +45 -0
- data/lib/prometheus/client/helper/metrics_representation.rb +51 -0
- data/lib/prometheus/client/helper/mmaped_file.rb +64 -0
- data/lib/prometheus/client/helper/plain_file.rb +29 -0
- data/lib/prometheus/client/histogram.rb +80 -0
- data/lib/prometheus/client/label_set_validator.rb +85 -0
- data/lib/prometheus/client/metric.rb +80 -0
- data/lib/prometheus/client/mmaped_dict.rb +83 -0
- data/lib/prometheus/client/mmaped_value.rb +164 -0
- data/lib/prometheus/client/page_size.rb +17 -0
- data/lib/prometheus/client/push.rb +203 -0
- data/lib/prometheus/client/rack/collector.rb +88 -0
- data/lib/prometheus/client/rack/exporter.rb +102 -0
- data/lib/prometheus/client/registry.rb +65 -0
- data/lib/prometheus/client/simple_value.rb +31 -0
- data/lib/prometheus/client/summary.rb +69 -0
- data/lib/prometheus/client/support/puma.rb +44 -0
- data/lib/prometheus/client/support/unicorn.rb +35 -0
- data/lib/prometheus/client/uses_value_type.rb +20 -0
- data/lib/prometheus/client/version.rb +5 -0
- data/lib/prometheus/client.rb +58 -0
- data/lib/prometheus.rb +3 -0
- metadata +210 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e813eec5d2233337d34cd3f19c79e68a9b38b63e45607b3dd0929fbcf84e353f
|
4
|
+
data.tar.gz: 979ebaef61c83ecf0e6eeb85c85581e3869c269e7868d3194d6d6faab2c83bf4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1df8af4b3368826fde07874b89b14648a66f193a5c5a945bcda4fc6e9588500ddf800866ce2af04c573474b2c8aa5b1ee275674ba45dabc82539345b42f4ff10
|
7
|
+
data.tar.gz: 51c47ecccd1d1f0afb6c4543837c43657f203dc8b391b3ff4ed57a947499a6a7e98375be644eb5cd1033f2fc901f38cc4b663944ffb2a76c2ad8cbcd856bc27d
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
[package]
|
2
|
+
name = "fast_mmaped_file_rs"
|
3
|
+
version = "0.1.0"
|
4
|
+
edition = "2021"
|
5
|
+
|
6
|
+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
7
|
+
|
8
|
+
[dependencies]
|
9
|
+
prost = "0.12"
|
10
|
+
prost-types = "0.12"
|
11
|
+
hashbrown = "0.14"
|
12
|
+
varint-rs = "2.2.0"
|
13
|
+
itertools = "0.11.0"
|
14
|
+
libc = "0.2"
|
15
|
+
magnus = { version = "0.6", features = ["rb-sys"] }
|
16
|
+
memmap2 = "0.9"
|
17
|
+
# v0.26 cannot be built on CentOS 7 https://github.com/nix-rust/nix/issues/1972
|
18
|
+
nix = { version = "0.25", features = ["mman"] } # mman used for MsFlags
|
19
|
+
rb-sys = { version = "0.9", features = ["stable-api-compiled-fallback"] }
|
20
|
+
serde = { version = "1.0", features = ["derive"] }
|
21
|
+
serde_json = { version = "1.0", features = ["raw_value"] }
|
22
|
+
smallvec = { version = "1.10", features = ["serde"] }
|
23
|
+
thiserror = "1.0"
|
24
|
+
|
25
|
+
[dev-dependencies]
|
26
|
+
bstr = "1.9"
|
27
|
+
indoc = "2.0"
|
28
|
+
# We need the `embed` feature to run tests, but this triggers failures when building as a Gem.
|
29
|
+
magnus = { version = "0.6", features = ["rb-sys","embed"] }
|
30
|
+
rand = "0.8"
|
31
|
+
sha2 = "0.10"
|
32
|
+
tempfile = "3.9"
|
33
|
+
|
34
|
+
[build-dependencies]
|
35
|
+
rb-sys-env = "0.1"
|
36
|
+
prost-build = "0.12"
|
37
|
+
|
38
|
+
[lib]
|
39
|
+
# Integration tests won't work if crate is only `cdylib`.
|
40
|
+
crate-type = ["cdylib","lib"]
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Testing
|
2
|
+
|
3
|
+
## Running Tests
|
4
|
+
|
5
|
+
Use [cargo nextest](https://nexte.st/) to execute the Rust unit tests.
|
6
|
+
|
7
|
+
```sh
|
8
|
+
$ cargo nextest run
|
9
|
+
```
|
10
|
+
|
11
|
+
## Why not use 'cargo test'?
|
12
|
+
|
13
|
+
We need to embed Ruby into the test binary to access Ruby types. This requires
|
14
|
+
us to run `magnus::embed::init()` no more than once before calling Ruby.
|
15
|
+
See [the magnus docs](https://docs.rs/magnus/latest/magnus/embed/fn.init.html)
|
16
|
+
for more details.
|
17
|
+
|
18
|
+
If we try to create separate `#[test]` functions that call `init()` these will
|
19
|
+
conflict, as Cargo runs tests in parallel using a single process with separate
|
20
|
+
threads. Running `cargo test` will result in errors like:
|
21
|
+
|
22
|
+
```
|
23
|
+
---- file_info::test::with_ruby stdout ----
|
24
|
+
thread 'file_info::test::with_ruby' panicked at 'Ruby already initialized'
|
25
|
+
```
|
26
|
+
|
27
|
+
The simplest workaround for this is to avoid using `cargo test` to run unit
|
28
|
+
tests. [nextest](https://nexte.st/) is an alternate test harness that runs each
|
29
|
+
test as its own process, enabling each test to intitialize Ruby without
|
30
|
+
conflict.
|
31
|
+
|
32
|
+
## 'symbol not found' errors when running tests
|
33
|
+
|
34
|
+
If you see errors like the following when running tests:
|
35
|
+
|
36
|
+
```
|
37
|
+
Caused by:
|
38
|
+
for `fast_mmaped_file_rs`, command `/Users/myuser/prometheus-client-mmap/ext/fast_mmaped_file_rs/target/debug/deps/fast_mmaped_file_rs-c81ccc96a6484e04 --list --format terse` exited with signal 6 (SIGABRT)
|
39
|
+
--- stdout:
|
40
|
+
|
41
|
+
--- stderr:
|
42
|
+
dyld[17861]: symbol not found in flat namespace '_rb_cArray'
|
43
|
+
```
|
44
|
+
|
45
|
+
Clearing the build cache will resolve the problem.
|
46
|
+
|
47
|
+
```sh
|
48
|
+
$ cargo clean
|
49
|
+
```
|
50
|
+
|
51
|
+
This is probably due to separate features being used with `magnus` in
|
52
|
+
development builds.
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "mkmf"
|
2
|
+
require "rb_sys/mkmf"
|
3
|
+
|
4
|
+
if find_executable('rustc')
|
5
|
+
create_rust_makefile("fast_mmaped_file_rs") do |r|
|
6
|
+
r.auto_install_rust_toolchain = false
|
7
|
+
|
8
|
+
if enable_config('fail-on-warning')
|
9
|
+
r.extra_rustflags = ["-Dwarnings"]
|
10
|
+
end
|
11
|
+
|
12
|
+
if enable_config('debug')
|
13
|
+
r.profile = :dev
|
14
|
+
end
|
15
|
+
|
16
|
+
if enable_config('address-sanitizer')
|
17
|
+
r.extra_rustflags = ["-Zsanitizer=address"]
|
18
|
+
end
|
19
|
+
|
20
|
+
# `rb_sys/mkmf` passes all arguments after `--` directly to `cargo rustc`.
|
21
|
+
# We use this awful hack to keep compatibility with existing flags used by
|
22
|
+
# the C implementation.
|
23
|
+
trimmed_argv = ARGV.take_while { |arg| arg != "--" }
|
24
|
+
ARGV = trimmed_argv
|
25
|
+
end
|
26
|
+
else
|
27
|
+
raise 'rustc not found. prometheus-client-mmap now requires Rust.'
|
28
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
use magnus::{exception, Ruby};
|
2
|
+
use std::any;
|
3
|
+
use std::fmt::Display;
|
4
|
+
use std::io;
|
5
|
+
use std::path::Path;
|
6
|
+
use thiserror::Error;
|
7
|
+
|
8
|
+
use crate::util;
|
9
|
+
use crate::PROM_EPARSING_ERROR;
|
10
|
+
|
11
|
+
/// A lightweight representation of Ruby ExceptionClasses.
|
12
|
+
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
13
|
+
pub enum RubyError {
|
14
|
+
Arg,
|
15
|
+
Encoding,
|
16
|
+
Frozen,
|
17
|
+
Index,
|
18
|
+
Io,
|
19
|
+
NoMem,
|
20
|
+
PromParsing,
|
21
|
+
Runtime,
|
22
|
+
Type,
|
23
|
+
}
|
24
|
+
|
25
|
+
impl From<RubyError> for magnus::ExceptionClass {
|
26
|
+
fn from(err: RubyError) -> magnus::ExceptionClass {
|
27
|
+
match err {
|
28
|
+
RubyError::Arg => exception::arg_error(),
|
29
|
+
RubyError::Encoding => exception::encoding_error(),
|
30
|
+
RubyError::Frozen => exception::frozen_error(),
|
31
|
+
RubyError::Index => exception::index_error(),
|
32
|
+
RubyError::Io => exception::io_error(),
|
33
|
+
RubyError::NoMem => exception::no_mem_error(),
|
34
|
+
RubyError::Runtime => exception::runtime_error(),
|
35
|
+
RubyError::PromParsing => {
|
36
|
+
// UNWRAP: this will panic if called outside of a Ruby thread.
|
37
|
+
let ruby = Ruby::get().unwrap();
|
38
|
+
ruby.get_inner(&PROM_EPARSING_ERROR)
|
39
|
+
}
|
40
|
+
RubyError::Type => exception::type_error(),
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
/// Errors returned internally within the crate. Methods called directly by Ruby return
|
46
|
+
/// `magnus::error::Error` as do functions that interact heavily with Ruby. This can be
|
47
|
+
/// converted into a `magnus::error::Error` at the boundary between Rust and Ruby.
|
48
|
+
#[derive(PartialEq, Eq, Error, Debug)]
|
49
|
+
pub enum MmapError {
|
50
|
+
/// A read or write was made while another thread had mutable access to the mmap.
|
51
|
+
#[error("read/write operation attempted while mmap was being written to")]
|
52
|
+
ConcurrentAccess,
|
53
|
+
/// An error message used to exactly match the messages returned by the C
|
54
|
+
/// implementation.
|
55
|
+
#[error("{0}")]
|
56
|
+
Legacy(String, RubyError),
|
57
|
+
/// A String had invalid UTF-8 sequences.
|
58
|
+
#[error("{0}")]
|
59
|
+
Encoding(String),
|
60
|
+
/// A failed attempt to cast an integer from one type to another.
|
61
|
+
#[error("failed to cast {object_name} {value} from {from} to {to}")]
|
62
|
+
FailedCast {
|
63
|
+
from: &'static str,
|
64
|
+
to: &'static str,
|
65
|
+
value: String,
|
66
|
+
object_name: String,
|
67
|
+
},
|
68
|
+
/// The mmap was frozen when a mutable operation was attempted.
|
69
|
+
#[error("mmap")]
|
70
|
+
Frozen,
|
71
|
+
/// An io operation failed.
|
72
|
+
#[error("failed to {operation} path '{path}': {err}")]
|
73
|
+
Io {
|
74
|
+
operation: String,
|
75
|
+
path: String,
|
76
|
+
err: String,
|
77
|
+
},
|
78
|
+
#[error("string length gt {}", i32::MAX)]
|
79
|
+
KeyLength,
|
80
|
+
/// Failed to allocate memory.
|
81
|
+
#[error("Couldn't allocate for {0} memory")]
|
82
|
+
OutOfMemory(usize),
|
83
|
+
/// A memory operation fell outside of the containers bounds.
|
84
|
+
#[error("offset {index} out of bounds of len {len}")]
|
85
|
+
OutOfBounds { index: String, len: String },
|
86
|
+
/// A numeric operation overflowed.
|
87
|
+
#[error("overflow when {op} {value} and {added} of type {ty}")]
|
88
|
+
Overflow {
|
89
|
+
value: String,
|
90
|
+
added: String,
|
91
|
+
op: String,
|
92
|
+
ty: &'static str,
|
93
|
+
},
|
94
|
+
/// A miscellaneous error.
|
95
|
+
#[error("{0}")]
|
96
|
+
Other(String),
|
97
|
+
/// A failure when parsing a `.db` file containing Prometheus metrics.
|
98
|
+
#[error("{0}")]
|
99
|
+
PromParsing(String),
|
100
|
+
/// No mmap open.
|
101
|
+
#[error("unmapped file")]
|
102
|
+
UnmappedFile,
|
103
|
+
/// A custom error message with `strerror(3)` appended.
|
104
|
+
#[error("{0}")]
|
105
|
+
WithErrno(String),
|
106
|
+
}
|
107
|
+
|
108
|
+
impl MmapError {
|
109
|
+
pub fn legacy<T: Into<String>>(msg: T, ruby_err: RubyError) -> Self {
|
110
|
+
MmapError::Legacy(msg.into(), ruby_err)
|
111
|
+
}
|
112
|
+
|
113
|
+
pub fn failed_cast<T: Display, U>(value: T, object_name: &str) -> Self {
|
114
|
+
MmapError::FailedCast {
|
115
|
+
from: any::type_name::<T>(),
|
116
|
+
to: any::type_name::<U>(),
|
117
|
+
value: value.to_string(),
|
118
|
+
object_name: object_name.to_string(),
|
119
|
+
}
|
120
|
+
}
|
121
|
+
pub fn io(operation: &str, path: &Path, err: io::Error) -> Self {
|
122
|
+
MmapError::Io {
|
123
|
+
operation: operation.to_string(),
|
124
|
+
path: path.display().to_string(),
|
125
|
+
err: err.to_string(),
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
pub fn overflowed<T: Display>(value: T, added: T, op: &str) -> Self {
|
130
|
+
MmapError::Overflow {
|
131
|
+
value: value.to_string(),
|
132
|
+
added: added.to_string(),
|
133
|
+
op: op.to_string(),
|
134
|
+
ty: any::type_name::<T>(),
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
pub fn out_of_bounds<T: Display>(index: T, len: T) -> Self {
|
139
|
+
MmapError::OutOfBounds {
|
140
|
+
index: index.to_string(),
|
141
|
+
len: len.to_string(),
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
pub fn with_errno<T: Into<String>>(msg: T) -> Self {
|
146
|
+
let strerror = util::strerror(util::errno());
|
147
|
+
MmapError::WithErrno(format!("{}: ({strerror})", msg.into()))
|
148
|
+
}
|
149
|
+
|
150
|
+
pub fn ruby_err(&self) -> RubyError {
|
151
|
+
match self {
|
152
|
+
MmapError::ConcurrentAccess => RubyError::Arg,
|
153
|
+
MmapError::Legacy(_, e) => *e,
|
154
|
+
MmapError::Encoding(_) => RubyError::Encoding,
|
155
|
+
MmapError::Io { .. } => RubyError::Io,
|
156
|
+
MmapError::FailedCast { .. } => RubyError::Arg,
|
157
|
+
MmapError::Frozen => RubyError::Frozen,
|
158
|
+
MmapError::KeyLength => RubyError::Arg,
|
159
|
+
MmapError::Overflow { .. } => RubyError::Arg,
|
160
|
+
MmapError::OutOfBounds { .. } => RubyError::Index,
|
161
|
+
MmapError::OutOfMemory { .. } => RubyError::NoMem,
|
162
|
+
MmapError::Other(_) => RubyError::Arg,
|
163
|
+
MmapError::PromParsing(_) => RubyError::PromParsing,
|
164
|
+
MmapError::UnmappedFile => RubyError::Io,
|
165
|
+
MmapError::WithErrno(_) => RubyError::Io,
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
impl From<MmapError> for magnus::error::Error {
|
171
|
+
fn from(err: MmapError) -> magnus::error::Error {
|
172
|
+
magnus::error::Error::new(err.ruby_err().into(), err.to_string())
|
173
|
+
}
|
174
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#[derive(Clone, Debug, Serialize, Deserialize)]
|
2
|
+
pub struct Exemplar {
|
3
|
+
// Labels (set of label names/values). Only 1 for now.
|
4
|
+
// Value -> f64.
|
5
|
+
// Timestamp -> uint64.
|
6
|
+
// We have to cap the maximum size of strings.
|
7
|
+
// From the spec:
|
8
|
+
// The combined length of the label names and values of an Exemplar's LabelSet MUST NOT exceed 128 UTF-8 character code points.
|
9
|
+
// 4 bytes max per code point.
|
10
|
+
// So, we need to allocate 128*4 = 512 bytes for the label names and values.
|
11
|
+
pub label_name: String,
|
12
|
+
|
13
|
+
pub label_value: String,
|
14
|
+
pub value: f64,
|
15
|
+
pub timestamp: u128,
|
16
|
+
}
|
17
|
+
|
18
|
+
use serde::{Deserialize, Serialize};
|
19
|
+
|
20
|
+
use crate::size_of;
|
21
|
+
|
22
|
+
pub const EXEMPLAR_ENTRY_MAX_SIZE_BYTES:usize = 512 + size_of::<f64>() + size_of::<u64>();
|
23
|
+
|
24
|
+
// Key -> use the old one.
|
25
|
+
// Value -> allocate EXEMPLAR_ENTRY_MAX_SIZE_BYTES. If it exceeds this, we need to return an error. Use JSON.
|