Compare commits

..

No commits in common. "master" and "v0.13.3" have entirely different histories.

34 changed files with 1715 additions and 2076 deletions

View File

@ -9,9 +9,7 @@ on:
env:
CARGO_TERM_COLOR: always
# Pinned toolchain for linting and benchmarks
ACTIONS_LINTS_TOOLCHAIN: 1.81.0
# Minimum supported Rust version (MSRV)
ACTION_MSRV_TOOLCHAIN: 1.81.0
ACTIONS_LINTS_TOOLCHAIN: 1.63.0
EXTRA_FEATURES: "protobuf push process"
jobs:
@ -20,15 +18,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Install toolchain
uses: dtolnay/rust-toolchain@stable
uses: actions-rs/toolchain@v1
with:
toolchain: "stable"
default: true
- name: cargo build
run: cargo build
- name: cargo test
run: cargo test
- name: cargo test (no default features)
run: cargo test --no-default-features
- name: cargo test (extra features)
run: cargo test --no-default-features --features="${{ env['EXTRA_FEATURES'] }}"
- name: cargo package
@ -44,11 +43,12 @@ jobs:
- "nightly"
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Install toolchain
uses: dtolnay/rust-toolchain@master
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.channel }}
default: true
- name: cargo build
run: cargo build
- name: cargo test
@ -57,51 +57,33 @@ jobs:
run: cargo build -p prometheus-static-metric --examples --no-default-features --features="${{ env['EXTRA_FEATURES'] }}"
- name: cargo test (static-metric)
run: cargo test -p prometheus-static-metric --no-default-features --features="${{ env['EXTRA_FEATURES'] }}"
build-msrv:
name: "Build, minimum toolchain"
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env['ACTION_MSRV_TOOLCHAIN'] }}
- run: cargo build
- run: cargo test --no-run
- run: cargo build --no-default-features
- run: cargo test --no-default-features --no-run
- run: cargo build --no-default-features --features="${{ env['EXTRA_FEATURES'] }}"
- run: cargo test --no-default-features --features="${{ env['EXTRA_FEATURES'] }}"
linting:
name: "Lints, pinned toolchain"
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Install toolchain
uses: dtolnay/rust-toolchain@master
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env['ACTIONS_LINTS_TOOLCHAIN'] }}
default: true
components: rustfmt, clippy
- name: cargo fmt (check)
run: cargo fmt --all -- --check -l
- name: cargo clippy
run: cargo clippy --all
- name: cargo clippy (no default features)
run: cargo clippy --all --no-default-features
- name: cargo clippy (extra features)
run: cargo clippy --all --no-default-features --features="${{ env['EXTRA_FEATURES'] }}"
criterion:
name: "Benchmarks (criterion)"
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Install toolchain
uses: dtolnay/rust-toolchain@master
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env['ACTIONS_LINTS_TOOLCHAIN'] }}
default: true
- name: cargo bench (prometheus)
run: cargo bench -p prometheus
- name: cargo bench (prometheus-static-metric)

View File

@ -1,43 +1,5 @@
# Changelog
## 0.14.0
- API change: Use `AsRef<str>` for owned label values (#537)
- Improvement: Hashing improvements (#532)
- Dependency upgrade: Update `hyper` to 1.6 (#524)
- Dependency upgrade: Update `procfs` to 0.17 (#543)
- Dependency upgrade: Update `protobuf` to 3.7.2 for RUSTSEC-2024-0437 (#541)
- Dependency upgrade: Update `thiserror` to 2.0 (#534)
- Internal change: Fix LSP and Clippy warnings (#540)
- Internal change: Bump MSRV to 1.81 (#539)
- Documentation: Fix `register_histogram_vec_with_registry` docstring (#528)
- Documentation: Fix typos in static-metric docstrings (#479)
- Documentation: Add missing `protobuf` feature to README list (#531)
## 0.13.4
- Improvement: Add PullingGauge (#405)
- Improvement: Let cargo know which example requires which features (#511)
- Bug fix: Prevent `clippy::ignored_unit_patterns` in macro expansions (#497)
- Internal change: Add CI job for minimum toolchain (MSRV) (#467)
- Internal change: Update CI to `actions/checkout@v4` (#499)
- Internal change: Update dependencies
## 0.13.3
- Bug fix: Prevent ProcessCollector underflow with CPU time counter (#465)

View File

@ -9,15 +9,17 @@ license = "Apache-2.0"
name = "prometheus"
readme = "README.md"
repository = "https://github.com/tikv/rust-prometheus"
rust-version = "1.81"
version = "0.14.0"
version = "0.13.3"
[badges]
travis-ci = { repository = "pingcap/rust-prometheus" }
[package.metadata.docs.rs]
features = ["nightly"]
[features]
default = ["protobuf"]
gen = ["protobuf-codegen"]
gen = ["protobuf-codegen-pure"]
nightly = ["libc"]
process = ["libc", "procfs"]
push = ["reqwest", "libc", "protobuf"]
@ -28,23 +30,22 @@ fnv = "^1.0"
lazy_static = "^1.4"
libc = { version = "^0.2", optional = true }
parking_lot = "^0.12"
protobuf = { version = "^3.7.2", optional = true }
protobuf = { version = "^2.0", optional = true }
memchr = "^2.3"
reqwest = { version = "^0.12", features = ["blocking"], optional = true }
thiserror = "^2.0"
reqwest = { version = "^0.11", features = ["blocking"], optional = true }
thiserror = "^1.0"
[target.'cfg(target_os = "linux")'.dependencies]
procfs = { version = "^0.17", optional = true, default-features = false }
procfs = { version = "^0.14", optional = true, default-features = false }
[dev-dependencies]
criterion = "0.5"
criterion = "0.4"
getopts = "^0.2"
hyper = { version = "^1.6", features = ["http1", "server"] }
hyper-util = { version = "^0.1", features = ["http1", "server", "tokio"] }
tokio = { version = "^1.0", features = ["macros", "net", "rt-multi-thread"] }
hyper = { version = "^0.14", features = ["server", "http1", "tcp"] }
tokio = { version = "^1.0", features = ["macros", "rt-multi-thread"] }
[build-dependencies]
protobuf-codegen = { version = "^3.7.2", optional = true }
protobuf-codegen-pure = { version = "^2.0", optional = true }
[workspace]
members = ["static-metric"]
@ -72,11 +73,3 @@ harness = false
[[bench]]
name = "text_encoder"
harness = false
[[example]]
name = "example_push"
required-features = ["push"]
[[example]]
name = "example_process_collector"
required-features = ["process"]

View File

@ -1,6 +1,6 @@
# Prometheus Rust client library
[![Build Status](https://github.com/tikv/rust-prometheus/actions/workflows/rust.yml/badge.svg)](https://github.com/tikv/rust-prometheus/actions/workflows/rust.yml)
[![Build Status](https://travis-ci.org/tikv/rust-prometheus.svg?branch=master)](https://travis-ci.org/pingcap/rust-prometheus)
[![docs.rs](https://docs.rs/prometheus/badge.svg)](https://docs.rs/prometheus)
[![crates.io](https://img.shields.io/crates/v/prometheus.svg)](https://crates.io/crates/prometheus)
@ -18,8 +18,6 @@ Find the latest documentation at <https://docs.rs/prometheus>.
This crate provides several optional components which can be enabled via [Cargo `[features]`](https://doc.rust-lang.org/cargo/reference/features.html):
- `protobuf`: Protobuf support, enabled by default.
- `gen`: To generate protobuf client with the latest protobuf version instead of
using the pre-generated client.

View File

@ -11,8 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use fnv::FnvBuildHasher;
use criterion::{criterion_group, criterion_main, Criterion};
use prometheus::{Counter, CounterVec, IntCounter, Opts};
use std::collections::HashMap;
use std::sync::{atomic, Arc};
@ -25,11 +24,7 @@ fn bench_counter_with_label_values(c: &mut Criterion) {
)
.unwrap();
c.bench_function("counter_with_label_values", |b| {
b.iter(|| {
counter
.with_label_values(&black_box(["eins", "zwei", "drei"]))
.inc()
})
b.iter(|| counter.with_label_values(&["eins", "zwei", "drei"]).inc())
});
}
@ -46,25 +41,7 @@ fn bench_counter_with_mapped_labels(c: &mut Criterion) {
labels.insert("two", "zwei");
labels.insert("one", "eins");
labels.insert("three", "drei");
counter.with(&black_box(labels)).inc();
})
});
}
fn bench_counter_with_mapped_labels_fnv(c: &mut Criterion) {
let counter = CounterVec::new(
Opts::new("benchmark_counter", "A counter to benchmark it."),
&["one", "two", "three"],
)
.unwrap();
c.bench_function("counter_with_mapped_labels_fnv", |b| {
b.iter(|| {
let mut labels = HashMap::with_capacity_and_hasher(3, FnvBuildHasher::default());
labels.insert("two", "zwei");
labels.insert("one", "eins");
labels.insert("three", "drei");
counter.with(&black_box(labels)).inc();
counter.with(&labels).inc();
})
});
}
@ -215,7 +192,6 @@ criterion_group!(
bench_counter_with_label_values,
bench_counter_with_label_values_concurrent_write,
bench_counter_with_mapped_labels,
bench_counter_with_mapped_labels_fnv,
bench_counter_with_prepared_mapped_labels,
bench_int_counter_no_labels,
bench_int_counter_no_labels_concurrent_write,

View File

@ -2,12 +2,13 @@
#[cfg(feature = "gen")]
fn generate_protobuf_binding_file() {
protobuf_codegen::Codegen::new()
.out_dir("proto")
.inputs(["proto/proto_model.proto"])
.includes(["proto"])
.run()
.expect("Protobuf codegen failed");
protobuf_codegen_pure::run(protobuf_codegen_pure::Args {
out_dir: "proto",
input: &["proto/proto_model.proto"],
includes: &["proto"],
..Default::default()
})
.unwrap();
}
#[cfg(not(feature = "gen"))]

View File

@ -1,20 +1,14 @@
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
use std::net::SocketAddr;
use hyper::{
header::CONTENT_TYPE,
service::{make_service_fn, service_fn},
Body, Request, Response, Server,
};
use prometheus::{Counter, Encoder, Gauge, HistogramVec, TextEncoder};
use hyper::body::Incoming;
use hyper::header::CONTENT_TYPE;
use hyper::server::conn::http1;
use hyper::service::service_fn;
use hyper::Request;
use hyper::Response;
use hyper_util::rt::TokioIo;
use lazy_static::lazy_static;
use prometheus::{labels, opts, register_counter, register_gauge, register_histogram_vec};
use prometheus::{Counter, Encoder, Gauge, HistogramVec, TextEncoder};
use tokio::net::TcpListener;
type BoxedErr = Box<dyn std::error::Error + Send + Sync + 'static>;
lazy_static! {
static ref HTTP_COUNTER: Counter = register_counter!(opts!(
@ -37,20 +31,22 @@ lazy_static! {
.unwrap();
}
async fn serve_req(_req: Request<Incoming>) -> Result<Response<String>, BoxedErr> {
async fn serve_req(_req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
let encoder = TextEncoder::new();
HTTP_COUNTER.inc();
let timer = HTTP_REQ_HISTOGRAM.with_label_values(&["all"]).start_timer();
let metric_families = prometheus::gather();
let body = encoder.encode_to_string(&metric_families)?;
HTTP_BODY_GAUGE.set(body.len() as f64);
let mut buffer = vec![];
encoder.encode(&metric_families, &mut buffer).unwrap();
HTTP_BODY_GAUGE.set(buffer.len() as f64);
let response = Response::builder()
.status(200)
.header(CONTENT_TYPE, encoder.format_type())
.body(body)?;
.body(Body::from(buffer))
.unwrap();
timer.observe_duration();
@ -58,18 +54,15 @@ async fn serve_req(_req: Request<Incoming>) -> Result<Response<String>, BoxedErr
}
#[tokio::main]
async fn main() -> Result<(), BoxedErr> {
let addr: SocketAddr = ([127, 0, 0, 1], 9898).into();
async fn main() {
let addr = ([127, 0, 0, 1], 9898).into();
println!("Listening on http://{}", addr);
let listener = TcpListener::bind(addr).await?;
loop {
let (stream, _) = listener.accept().await?;
let io = TokioIo::new(stream);
let serve_future = Server::bind(&addr).serve(make_service_fn(|_| async {
Ok::<_, hyper::Error>(service_fn(serve_req))
}));
let service = service_fn(serve_req);
if let Err(err) = http1::Builder::new().serve_connection(io, service).await {
eprintln!("server error: {:?}", err);
};
if let Err(err) = serve_future.await {
eprintln!("server error: {}", err);
}
}

View File

@ -1,5 +1,6 @@
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
#[cfg(all(feature = "process", target_os = "linux"))]
fn main() {
use std::thread;
use std::time::Duration;
@ -20,3 +21,11 @@ fn main() {
thread::sleep(Duration::from_secs(1));
}
}
#[cfg(any(not(feature = "process"), not(target_os = "linux")))]
fn main() {
println!(
r#"Please enable feature "process", try:
cargo run --features="process" --example example_process_collector"#
);
}

View File

@ -1,5 +1,7 @@
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
#![cfg_attr(not(feature = "push"), allow(unused_imports, dead_code))]
use std::env;
use std::thread;
use std::time;
@ -23,6 +25,7 @@ lazy_static! {
.unwrap();
}
#[cfg(feature = "push")]
fn main() {
let args: Vec<String> = env::args().collect();
let program = args[0].clone();
@ -65,3 +68,11 @@ fn main() {
println!("Okay, please check the Pushgateway.");
}
#[cfg(not(feature = "push"))]
fn main() {
println!(
r#"Please enable feature "push", try:
cargo run --features="push" --example example_push"#
);
}

View File

@ -1,3 +0,0 @@
// @generated
pub mod proto_model;

File diff suppressed because it is too large Load Diff

View File

@ -241,8 +241,8 @@ impl AtomicU64 {
#[cfg(test)]
mod test {
use std::f64;
use std::f64::consts::PI;
use std::f64::{self, EPSILON};
use super::*;
@ -251,7 +251,7 @@ mod test {
let table: Vec<f64> = vec![0.0, 1.0, PI, f64::MIN, f64::MAX];
for f in table {
assert!((f - AtomicF64::new(f).get()).abs() < f64::EPSILON);
assert!((f - AtomicF64::new(f).get()).abs() < EPSILON);
}
}

View File

@ -44,10 +44,10 @@ impl<P: Atomic> GenericCounter<P> {
/// Create a [`GenericCounter`] with the `opts` options.
pub fn with_opts(opts: Opts) -> Result<Self> {
Self::with_opts_and_label_values::<&str>(&opts, &[])
Self::with_opts_and_label_values(&opts, &[])
}
fn with_opts_and_label_values<V: AsRef<str>>(opts: &Opts, label_values: &[V]) -> Result<Self> {
fn with_opts_and_label_values(opts: &Opts, label_values: &[&str]) -> Result<Self> {
let v = Value::new(opts, ValueType::Counter, P::T::from_i64(0), label_values)?;
Ok(Self { v: Arc::new(v) })
}
@ -126,7 +126,7 @@ impl<P: Atomic> MetricVecBuilder for CounterVecBuilder<P> {
type M = GenericCounter<P>;
type P = Opts;
fn build<V: AsRef<str>>(&self, opts: &Opts, vals: &[V]) -> Result<Self::M> {
fn build(&self, opts: &Opts, vals: &[&str]) -> Result<Self::M> {
Self::M::with_opts_and_label_values(opts, vals)
}
}
@ -323,12 +323,10 @@ impl<P: Atomic> Clone for GenericLocalCounterVec<P> {
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use std::f64;
use std::f64::EPSILON;
use super::*;
use crate::metrics::{Collector, Opts};
#[cfg(feature = "protobuf")]
use crate::proto_ext::MessageFieldExt;
#[test]
fn test_counter() {
@ -345,7 +343,7 @@ mod tests {
assert_eq!(mfs.len(), 1);
let mf = mfs.pop().unwrap();
let m = mf.get_metric().first().unwrap();
let m = mf.get_metric().get(0).unwrap();
assert_eq!(m.get_label().len(), 2);
assert_eq!(m.get_counter().get_value() as u64, 43);
@ -365,12 +363,12 @@ mod tests {
assert_eq!(mfs.len(), 1);
let mf = mfs.pop().unwrap();
let m = mf.get_metric().first().unwrap();
let m = mf.get_metric().get(0).unwrap();
assert_eq!(m.get_label().len(), 0);
assert_eq!(m.get_counter().get_value() as u64, 12);
counter.reset();
assert_eq!(counter.get(), 0);
assert_eq!(counter.get() as u64, 0);
}
#[test]
@ -416,9 +414,9 @@ mod tests {
local_counter.reset();
counter.reset();
assert_eq!(counter.get(), 0);
assert_eq!(counter.get() as u64, 0);
local_counter.flush();
assert_eq!(counter.get(), 0);
assert_eq!(counter.get() as u64, 0);
}
#[test]
@ -452,40 +450,6 @@ mod tests {
assert!(vec.remove(&labels3).is_err());
}
#[test]
fn test_counter_vec_with_owned_labels() {
let vec = CounterVec::new(
Opts::new("test_couter_vec", "test counter vec help"),
&["l1", "l2"],
)
.unwrap();
let v1 = "v1".to_string();
let v2 = "v2".to_string();
let mut labels = HashMap::new();
labels.insert("l1", v1.clone());
labels.insert("l2", v2.clone());
assert!(vec.remove(&labels).is_err());
vec.with(&labels).inc();
assert!(vec.remove(&labels).is_ok());
assert!(vec.remove(&labels).is_err());
let mut labels2 = HashMap::new();
labels2.insert("l1", v2.clone());
labels2.insert("l2", v1.clone());
vec.with(&labels).inc();
assert!(vec.remove(&labels2).is_err());
vec.with(&labels).inc();
let mut labels3 = HashMap::new();
labels3.insert("l1", v1.clone());
assert!(vec.remove(&labels3).is_err());
}
#[test]
fn test_int_counter_vec() {
let vec = IntCounterVec::new(Opts::new("foo", "bar"), &["l1", "l2"]).unwrap();
@ -525,27 +489,6 @@ mod tests {
assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
}
#[test]
fn test_counter_vec_with_owned_label_values() {
let vec = CounterVec::new(
Opts::new("test_vec", "test counter vec help"),
&["l1", "l2"],
)
.unwrap();
let v1 = "v1".to_string();
let v2 = "v2".to_string();
let v3 = "v3".to_string();
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_err());
vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_ok());
vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
assert!(vec.remove_label_values(&[v1.clone()]).is_err());
assert!(vec.remove_label_values(&[v1.clone(), v3.clone()]).is_err());
}
#[test]
fn test_counter_vec_local() {
let vec = CounterVec::new(
@ -559,48 +502,48 @@ mod tests {
assert!(local_vec_1.remove_label_values(&["v1", "v2"]).is_err());
local_vec_1.with_label_values(&["v1", "v2"]).inc_by(23.0);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 23.0) <= f64::EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 23.0) <= EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
local_vec_1.flush();
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= f64::EPSILON);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= EPSILON);
local_vec_1.flush();
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= f64::EPSILON);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= EPSILON);
local_vec_1.with_label_values(&["v1", "v2"]).inc_by(11.0);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 11.0) <= f64::EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= f64::EPSILON);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 11.0) <= EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= EPSILON);
local_vec_1.flush();
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 34.0) <= f64::EPSILON);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 34.0) <= EPSILON);
// When calling `remove_label_values`, it is "flushed" immediately.
assert!(local_vec_1.remove_label_values(&["v1", "v2"]).is_ok());
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
local_vec_1.with_label_values(&["v1", "v2"]).inc();
assert!(local_vec_1.remove_label_values(&["v1"]).is_err());
assert!(local_vec_1.remove_label_values(&["v1", "v3"]).is_err());
local_vec_1.with_label_values(&["v1", "v2"]).inc_by(13.0);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 14.0) <= f64::EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 14.0) <= EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
local_vec_2.with_label_values(&["v1", "v2"]).inc_by(7.0);
assert!((local_vec_2.with_label_values(&["v1", "v2"]).get() - 7.0) <= f64::EPSILON);
assert!((local_vec_2.with_label_values(&["v1", "v2"]).get() - 7.0) <= EPSILON);
local_vec_1.flush();
local_vec_2.flush();
assert!((vec.with_label_values(&["v1", "v2"]).get() - 21.0) <= f64::EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 21.0) <= EPSILON);
local_vec_1.flush();
local_vec_2.flush();
assert!((vec.with_label_values(&["v1", "v2"]).get() - 21.0) <= f64::EPSILON);
assert!((vec.with_label_values(&["v1", "v2"]).get() - 21.0) <= EPSILON);
}
#[test]

View File

@ -253,7 +253,8 @@ mod tests {
vec![name.into()],
HashMap::new(),
)
.expect_err(format!("expected error for {}", name).as_ref());
.err()
.expect(format!("expected error for {}", name).as_ref());
match res {
Error::Msg(msg) => assert_eq!(msg, format!("'{}' is not a valid label name", name)),
other => panic!("{}", other),
@ -267,7 +268,8 @@ mod tests {
let mut labels = HashMap::new();
labels.insert(name.into(), "value".into());
let res = Desc::new("name".into(), "help".into(), vec![], labels)
.expect_err(format!("expected error for {}", name).as_ref());
.err()
.expect(format!("expected error for {}", name).as_ref());
match res {
Error::Msg(msg) => assert_eq!(msg, format!("'{}' is not a valid label name", name)),
other => panic!("{}", other),
@ -279,7 +281,8 @@ mod tests {
fn test_invalid_metric_name() {
for &name in &["-dash", "9gag", "has space"] {
let res = Desc::new(name.into(), "help".into(), vec![], HashMap::new())
.expect_err(format!("expected error for {}", name).as_ref());
.err()
.expect(format!("expected error for {}", name).as_ref());
match res {
Error::Msg(msg) => {
assert_eq!(msg, format!("'{}' is not a valid metric name", name))

View File

@ -30,7 +30,7 @@ fn check_metric_family(mf: &MetricFamily) -> Result<()> {
if mf.get_metric().is_empty() {
return Err(Error::Msg(format!("MetricFamily has no metrics: {:?}", mf)));
}
if mf.name().is_empty() {
if mf.get_name().is_empty() {
return Err(Error::Msg(format!("MetricFamily has no name: {:?}", mf)));
}
Ok(())

View File

@ -6,8 +6,6 @@ use std::io::{self, Write};
use crate::errors::Result;
use crate::histogram::BUCKET_LABEL;
use crate::proto::{self, MetricFamily, MetricType};
#[cfg(feature = "protobuf")]
use crate::proto_ext::MessageFieldExt;
use super::{check_metric_family, Encoder};
@ -57,8 +55,8 @@ impl TextEncoder {
check_metric_family(mf)?;
// Write `# HELP` header.
let name = mf.name();
let help = mf.help();
let name = mf.get_name();
let help = mf.get_help();
if !help.is_empty() {
writer.write_all("# HELP ")?;
writer.write_all(name)?;
@ -89,14 +87,14 @@ impl TextEncoder {
let mut inf_seen = false;
for b in h.get_bucket() {
let upper_bound = b.upper_bound();
let upper_bound = b.get_upper_bound();
write_sample(
writer,
name,
Some("_bucket"),
m,
Some((BUCKET_LABEL, &upper_bound.to_string())),
b.cumulative_count() as f64,
b.get_cumulative_count() as f64,
)?;
if upper_bound.is_sign_positive() && upper_bound.is_infinite() {
inf_seen = true;
@ -127,18 +125,18 @@ impl TextEncoder {
MetricType::SUMMARY => {
let s = m.get_summary();
for q in s.get_quantile().iter() {
for q in s.get_quantile() {
write_sample(
writer,
name,
None,
m,
Some((QUANTILE, &q.quantile().to_string())),
q.value(),
Some((QUANTILE, &q.get_quantile().to_string())),
q.get_value(),
)?;
}
write_sample(writer, name, Some("_sum"), m, None, s.sample_sum())?;
write_sample(writer, name, Some("_sum"), m, None, s.get_sample_sum())?;
write_sample(
writer,
@ -146,7 +144,7 @@ impl TextEncoder {
Some("_count"),
m,
None,
s.sample_count() as f64,
s.get_sample_count() as f64,
)?;
}
MetricType::UNTYPED => {
@ -193,7 +191,7 @@ fn write_sample(
writer.write_all(" ")?;
writer.write_all(&value.to_string())?;
let timestamp = mc.timestamp_ms();
let timestamp = mc.get_timestamp_ms();
if timestamp != 0 {
writer.write_all(" ")?;
writer.write_all(&timestamp.to_string())?;
@ -223,9 +221,9 @@ fn label_pairs_to_text(
let mut separator = "{";
for lp in pairs {
writer.write_all(separator)?;
writer.write_all(lp.name())?;
writer.write_all(lp.get_name())?;
writer.write_all("=\"")?;
writer.write_all(&escape_string(lp.value(), true))?;
writer.write_all(&escape_string(lp.get_value(), true))?;
writer.write_all("\"")?;
separator = ",";
@ -425,11 +423,11 @@ test_histogram_count{a="1"} 1
quantile2.set_quantile(100.0);
quantile2.set_value(5.0);
summary.set_quantile(vec![quantile1, quantile2]);
summary.set_quantile(from_vec!(vec!(quantile1, quantile2)));
let mut metric = Metric::default();
metric.set_summary(summary);
metric_family.set_metric(vec![metric]);
metric_family.set_metric(from_vec!(vec!(metric)));
let mut writer = Vec::<u8>::new();
let encoder = TextEncoder::new();

View File

@ -22,10 +22,10 @@ pub enum Error {
/// An error containing a [`std::io::Error`].
#[error("Io error: {0}")]
Io(#[from] std::io::Error),
/// An error containing a [`protobuf::Error`].
/// An error containing a [`protobuf::error::ProtobufError`].
#[cfg(feature = "protobuf")]
#[error("Protobuf error: {0}")]
Protobuf(#[from] protobuf::Error),
Protobuf(#[from] protobuf::error::ProtobufError),
}
/// A specialized Result type for prometheus.

View File

@ -43,10 +43,10 @@ impl<P: Atomic> GenericGauge<P> {
/// Create a [`GenericGauge`] with the `opts` options.
pub fn with_opts(opts: Opts) -> Result<Self> {
Self::with_opts_and_label_values::<&str>(&opts, &[])
Self::with_opts_and_label_values(&opts, &[])
}
fn with_opts_and_label_values<V: AsRef<str>>(opts: &Opts, label_values: &[V]) -> Result<Self> {
fn with_opts_and_label_values(opts: &Opts, label_values: &[&str]) -> Result<Self> {
let v = Value::new(opts, ValueType::Gauge, P::T::from_i64(0), label_values)?;
Ok(Self { v: Arc::new(v) })
}
@ -129,7 +129,7 @@ impl<P: Atomic> MetricVecBuilder for GaugeVecBuilder<P> {
type M = GenericGauge<P>;
type P = Opts;
fn build<V: AsRef<str>>(&self, opts: &Opts, vals: &[V]) -> Result<Self::M> {
fn build(&self, opts: &Opts, vals: &[&str]) -> Result<Self::M> {
Self::M::with_opts_and_label_values(opts, vals)
}
}
@ -166,8 +166,6 @@ mod tests {
use super::*;
use crate::metrics::{Collector, Opts};
#[cfg(feature = "protobuf")]
use crate::proto_ext::MessageFieldExt;
#[test]
fn test_gauge() {
@ -190,7 +188,7 @@ mod tests {
assert_eq!(mfs.len(), 1);
let mf = mfs.pop().unwrap();
let m = mf.get_metric().first().unwrap();
let m = mf.get_metric().get(0).unwrap();
assert_eq!(m.get_label().len(), 2);
assert_eq!(m.get_gauge().get_value() as u64, 42);
}
@ -218,29 +216,6 @@ mod tests {
assert!(vec.remove(&labels).is_err());
}
#[test]
fn test_gauge_vec_with_owned_labels() {
let vec = GaugeVec::new(
Opts::new("test_gauge_vec", "test gauge vec help"),
&["l1", "l2"],
)
.unwrap();
let mut labels = HashMap::new();
labels.insert("l1", "v1");
labels.insert("l2", "v2");
assert!(vec.remove(&labels).is_err());
vec.with(&labels).inc();
vec.with(&labels).dec();
vec.with(&labels).add(42.0);
vec.with(&labels).sub(42.0);
vec.with(&labels).set(42.0);
assert!(vec.remove(&labels).is_ok());
assert!(vec.remove(&labels).is_err());
}
#[test]
fn test_gauge_vec_with_label_values() {
let vec = GaugeVec::new(
@ -262,30 +237,4 @@ mod tests {
assert!(vec.remove_label_values(&["v1"]).is_err());
assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
}
#[test]
fn test_gauge_vec_with_owned_label_values() {
let vec = GaugeVec::new(
Opts::new("test_gauge_vec", "test gauge vec help"),
&["l1", "l2"],
)
.unwrap();
let v1 = "v1".to_string();
let v2 = "v2".to_string();
let v3 = "v3".to_string();
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_err());
vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_ok());
vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
vec.with_label_values(&[v1.clone(), v2.clone()]).dec();
vec.with_label_values(&[v1.clone(), v2.clone()]).add(42.0);
vec.with_label_values(&[v1.clone(), v2.clone()]).sub(42.0);
vec.with_label_values(&[v1.clone(), v2.clone()]).set(42.0);
assert!(vec.remove_label_values(&[v1.clone()]).is_err());
assert!(vec.remove_label_values(&[v1.clone(), v3.clone()]).is_err());
}
}

View File

@ -284,11 +284,11 @@ impl ShardAndCount {
/// A histogram supports two main execution paths:
///
/// 1. `observe` which increases the overall observation counter, updates the
/// observation sum and increases a single bucket counter.
/// observation sum and increases a single bucket counter.
///
/// 2. `proto` (aka. collecting the metric, from now on referred to as the
/// collect operation) which snapshots the state of the histogram and exposes
/// it as a Protobuf struct.
/// collect operation) which snapshots the state of the histogram and exposes it
/// as a Protobuf struct.
///
/// If an observe and a collect operation interleave, the latter could be
/// exposing a snapshot of the histogram that does not uphold all histogram
@ -327,14 +327,14 @@ pub struct HistogramCore {
}
impl HistogramCore {
pub fn new<V: AsRef<str>>(opts: &HistogramOpts, label_values: &[V]) -> Result<HistogramCore> {
pub fn new(opts: &HistogramOpts, label_values: &[&str]) -> Result<HistogramCore> {
let desc = opts.describe()?;
for name in &desc.variable_labels {
check_bucket_label(name)?;
}
for pair in &desc.const_label_pairs {
check_bucket_label(pair.name())?;
check_bucket_label(pair.get_name())?;
}
let label_pairs = make_label_pairs(&desc, label_values)?;
@ -453,7 +453,7 @@ impl HistogramCore {
b.set_upper_bound(*upper_bound);
buckets.push(b);
}
h.set_bucket(buckets);
h.set_bucket(from_vec!(buckets));
// Update the hot shard.
hot_shard.count.inc_by(overall_count);
@ -542,7 +542,7 @@ impl Instant {
#[inline]
pub fn elapsed_sec(&self) -> f64 {
self.elapsed().as_secs_f64()
duration_to_seconds(self.elapsed())
}
}
@ -674,12 +674,12 @@ pub struct Histogram {
impl Histogram {
/// `with_opts` creates a [`Histogram`] with the `opts` options.
pub fn with_opts(opts: HistogramOpts) -> Result<Histogram> {
Histogram::with_opts_and_label_values::<&str>(&opts, &[])
Histogram::with_opts_and_label_values(&opts, &[])
}
fn with_opts_and_label_values<V: AsRef<str>>(
fn with_opts_and_label_values(
opts: &HistogramOpts,
label_values: &[V],
label_values: &[&str],
) -> Result<Histogram> {
let core = HistogramCore::new(opts, label_values)?;
@ -750,7 +750,8 @@ impl Histogram {
impl Metric for Histogram {
fn metric(&self) -> proto::Metric {
let mut m = proto::Metric::from_label(self.core.label_pairs.clone());
let mut m = proto::Metric::default();
m.set_label(from_vec!(self.core.label_pairs.clone()));
let h = self.core.proto();
m.set_histogram(h);
@ -769,7 +770,7 @@ impl Collector for Histogram {
m.set_name(self.core.desc.fq_name.clone());
m.set_help(self.core.desc.help.clone());
m.set_field_type(proto::MetricType::HISTOGRAM);
m.set_metric(vec![self.metric()]);
m.set_metric(from_vec!(vec![self.metric()]));
vec![m]
}
@ -782,7 +783,7 @@ impl MetricVecBuilder for HistogramVecBuilder {
type M = Histogram;
type P = HistogramOpts;
fn build<V: AsRef<str>>(&self, opts: &HistogramOpts, vals: &[V]) -> Result<Histogram> {
fn build(&self, opts: &HistogramOpts, vals: &[&str]) -> Result<Histogram> {
Histogram::with_opts_and_label_values(opts, vals)
}
}
@ -881,6 +882,13 @@ pub fn exponential_buckets(start: f64, factor: f64, count: usize) -> Result<Vec<
Ok(buckets)
}
/// `duration_to_seconds` converts Duration to seconds.
#[inline]
pub fn duration_to_seconds(d: Duration) -> f64 {
let nanos = f64::from(d.subsec_nanos()) / 1e9;
d.as_secs() as f64 + nanos
}
#[derive(Clone, Debug)]
pub struct LocalHistogramCore {
histogram: Histogram,
@ -1199,7 +1207,7 @@ impl Clone for LocalHistogramVec {
#[cfg(test)]
mod tests {
use std::f64;
use std::f64::{EPSILON, INFINITY};
use std::thread;
use std::time::Duration;
@ -1229,7 +1237,7 @@ mod tests {
assert_eq!(mfs.len(), 1);
let mf = mfs.pop().unwrap();
let m = mf.get_metric().first().unwrap();
let m = mf.get_metric().get(0).unwrap();
assert_eq!(m.get_label().len(), 2);
let proto_histogram = m.get_histogram();
assert_eq!(proto_histogram.get_sample_count(), 3);
@ -1243,11 +1251,11 @@ mod tests {
assert_eq!(mfs.len(), 1);
let mf = mfs.pop().unwrap();
let m = mf.get_metric().first().unwrap();
let m = mf.get_metric().get(0).unwrap();
assert_eq!(m.get_label().len(), 0);
let proto_histogram = m.get_histogram();
assert_eq!(proto_histogram.get_sample_count(), 0);
assert!((proto_histogram.get_sample_sum() - 0.0) < f64::EPSILON);
assert!((proto_histogram.get_sample_sum() - 0.0) < EPSILON);
assert_eq!(proto_histogram.get_bucket().len(), buckets.len())
}
@ -1279,7 +1287,7 @@ mod tests {
let m = mf.get_metric().get(0).unwrap();
let proto_histogram = m.get_histogram();
assert_eq!(proto_histogram.get_sample_count(), 3);
assert!((proto_histogram.get_sample_sum() - 0.0) > f64::EPSILON);
assert!((proto_histogram.get_sample_sum() - 0.0) > EPSILON);
}
#[test]
@ -1303,11 +1311,7 @@ mod tests {
(vec![], true, DEFAULT_BUCKETS.len()),
(vec![-2.0, -1.0, -0.5, 0.0, 0.5, 1.0, 2.0], true, 7),
(vec![-2.0, -1.0, -0.5, 10.0, 0.5, 1.0, 2.0], false, 7),
(
vec![-2.0, -1.0, -0.5, 0.0, 0.5, 1.0, f64::INFINITY],
true,
6,
),
(vec![-2.0, -1.0, -0.5, 0.0, 0.5, 1.0, INFINITY], true, 6),
];
for (buckets, is_ok, length) in table {
@ -1356,6 +1360,16 @@ mod tests {
}
}
#[test]
fn test_duration_to_seconds() {
let tbls = vec![(1000, 1.0), (1100, 1.1), (100_111, 100.111)];
for (millis, seconds) in tbls {
let d = Duration::from_millis(millis);
let v = duration_to_seconds(d);
assert!((v - seconds).abs() < EPSILON);
}
}
#[test]
fn test_histogram_vec_with_label_values() {
let vec = HistogramVec::new(
@ -1372,27 +1386,6 @@ mod tests {
assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
}
#[test]
fn test_histogram_vec_with_owned_label_values() {
let vec = HistogramVec::new(
HistogramOpts::new("test_histogram_vec", "test histogram vec help"),
&["l1", "l2"],
)
.unwrap();
let v1 = "v1".to_string();
let v2 = "v2".to_string();
let v3 = "v3".to_string();
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_err());
vec.with_label_values(&[v1.clone(), v2.clone()])
.observe(1.0);
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_ok());
assert!(vec.remove_label_values(&[v1.clone()]).is_err());
assert!(vec.remove_label_values(&[v1.clone(), v3.clone()]).is_err());
}
#[test]
fn test_histogram_vec_with_opts_buckets() {
let labels = ["l1", "l2"];
@ -1412,7 +1405,7 @@ mod tests {
let proto_histogram = m.get_histogram();
assert_eq!(proto_histogram.get_sample_count(), 1);
assert!((proto_histogram.get_sample_sum() - 1.0) < f64::EPSILON);
assert!((proto_histogram.get_sample_sum() - 1.0) < EPSILON);
assert_eq!(proto_histogram.get_bucket().len(), buckets.len())
}
@ -1428,7 +1421,7 @@ mod tests {
let m = histogram.metric();
let proto_histogram = m.get_histogram();
assert_eq!(proto_histogram.get_sample_count(), count);
assert!((proto_histogram.get_sample_sum() - sum) < f64::EPSILON);
assert!((proto_histogram.get_sample_sum() - sum) < EPSILON);
};
local.observe(1.0);
@ -1463,7 +1456,7 @@ mod tests {
let ms = vec.collect()[0].take_metric();
let proto_histogram = ms[0].get_histogram();
assert_eq!(proto_histogram.get_sample_count(), count);
assert!((proto_histogram.get_sample_sum() - sum) < f64::EPSILON);
assert!((proto_histogram.get_sample_sum() - sum) < EPSILON);
};
{
@ -1523,7 +1516,7 @@ mod tests {
sample_count = proto.get_sample_count();
sample_sum = proto.get_sample_sum() as u64;
// There is only one bucket thus the `[0]`.
cumulative_count = proto.get_bucket()[0].cumulative_count();
cumulative_count = proto.get_bucket()[0].get_cumulative_count();
if sample_count != cumulative_count {
break;

View File

@ -129,12 +129,23 @@ This library supports four features:
#[path = "../proto/proto_model.rs"]
pub mod proto;
#[cfg(feature = "protobuf")]
macro_rules! from_vec {
($e: expr) => {
::protobuf::RepeatedField::from_vec($e)
};
}
#[cfg(not(feature = "protobuf"))]
#[path = "plain_model.rs"]
pub mod proto;
#[cfg(feature = "protobuf")]
mod proto_ext;
#[cfg(not(feature = "protobuf"))]
macro_rules! from_vec {
($e: expr) => {
$e
};
}
#[macro_use]
mod macros;
@ -147,8 +158,6 @@ mod errors;
mod gauge;
mod histogram;
mod metrics;
mod nohash;
mod pulling_gauge;
#[cfg(feature = "push")]
mod push;
mod registry;
@ -210,7 +219,6 @@ pub use self::histogram::DEFAULT_BUCKETS;
pub use self::histogram::{exponential_buckets, linear_buckets};
pub use self::histogram::{Histogram, HistogramOpts, HistogramTimer, HistogramVec};
pub use self::metrics::Opts;
pub use self::pulling_gauge::PullingGauge;
#[cfg(feature = "push")]
pub use self::push::{
hostname_grouping_key, push_add_collector, push_add_metrics, push_collector, push_metrics,

View File

@ -43,7 +43,7 @@ fn test_labels_without_trailing_comma() {
"foo" => "bar"
};
assert_eq!(labels.len(), 2);
assert!(labels.contains_key("test"));
assert!(labels.get("test").is_some());
assert_eq!(*(labels.get("test").unwrap()), "hello");
}
@ -84,7 +84,6 @@ macro_rules! opts {
let opts = $crate::Opts::new($NAME, $HELP);
let lbs = HashMap::<String, String>::new();
$(
#[allow(clippy::redundant_locals)]
let mut lbs = lbs;
lbs.extend($CONST_LABELS.iter().map(|(k, v)| ((*k).into(), (*v).into())));
)*
@ -105,7 +104,7 @@ fn test_opts_trailing_comma() {
let opts = opts!(name, help, labels! {"test" => "hello", "foo" => "bar",},);
assert_eq!(opts.const_labels.len(), 2);
assert!(opts.const_labels.contains_key("foo"));
assert!(opts.const_labels.get("foo").is_some());
assert_eq!(opts.const_labels.get("foo").unwrap(), "bar");
let opts = opts!(
@ -115,7 +114,7 @@ fn test_opts_trailing_comma() {
labels! {"ans" => "42",},
);
assert_eq!(opts.const_labels.len(), 3);
assert!(opts.const_labels.contains_key("ans"));
assert!(opts.const_labels.get("ans").is_some());
assert_eq!(opts.const_labels.get("ans").unwrap(), "42");
}
@ -192,7 +191,7 @@ fn test_histogram_opts_trailing_comma() {
assert_eq!(opts.common_opts.name, name);
assert_eq!(opts.common_opts.help, help);
assert_eq!(opts.buckets.len(), 2);
assert!(opts.common_opts.const_labels.contains_key("key"));
assert!(opts.common_opts.const_labels.get("key").is_some());
assert_eq!(opts.common_opts.const_labels.get("key").unwrap(), "value");
}
@ -215,7 +214,7 @@ fn test_histogram_opts_trailing_comma() {
macro_rules! register_counter {
(@of_type $TYPE:ident, $OPTS:expr) => {{
let counter = $crate::$TYPE::with_opts($OPTS).unwrap();
$crate::register(Box::new(counter.clone())).map(|()| counter)
$crate::register(Box::new(counter.clone())).map(|_| counter)
}};
($OPTS:expr $(,)?) => {{
@ -261,7 +260,7 @@ fn test_register_counter_trailing_comma() {
macro_rules! register_counter_with_registry {
(@of_type $TYPE: ident, $OPTS:expr, $REGISTRY:expr) => {{
let counter = $crate::$TYPE::with_opts($OPTS).unwrap();
$REGISTRY.register(Box::new(counter.clone())).map(|()| counter)
$REGISTRY.register(Box::new(counter.clone())).map(|_| counter)
}};
($OPTS:expr, $REGISTRY:expr $(,)?) => {{
@ -362,14 +361,14 @@ fn test_register_int_counter() {
macro_rules! __register_counter_vec {
($TYPE:ident, $OPTS:expr, $LABELS_NAMES:expr) => {{
let counter_vec = $crate::$TYPE::new($OPTS, $LABELS_NAMES).unwrap();
$crate::register(Box::new(counter_vec.clone())).map(|()| counter_vec)
$crate::register(Box::new(counter_vec.clone())).map(|_| counter_vec)
}};
($TYPE:ident, $OPTS:expr, $LABELS_NAMES:expr, $REGISTRY:expr) => {{
let counter_vec = $crate::$TYPE::new($OPTS, $LABELS_NAMES).unwrap();
$REGISTRY
.register(Box::new(counter_vec.clone()))
.map(|()| counter_vec)
.map(|_| counter_vec)
}};
}
@ -544,12 +543,12 @@ fn test_register_int_counter_vec() {
macro_rules! __register_gauge {
($TYPE:ident, $OPTS:expr) => {{
let gauge = $crate::$TYPE::with_opts($OPTS).unwrap();
$crate::register(Box::new(gauge.clone())).map(|()| gauge)
$crate::register(Box::new(gauge.clone())).map(|_| gauge)
}};
($TYPE:ident, $OPTS:expr, $REGISTRY:expr) => {{
let gauge = $crate::$TYPE::with_opts($OPTS).unwrap();
$REGISTRY.register(Box::new(gauge.clone())).map(|()| gauge)
$REGISTRY.register(Box::new(gauge.clone())).map(|_| gauge)
}};
}
@ -671,14 +670,14 @@ macro_rules! register_int_gauge_with_registry {
macro_rules! __register_gauge_vec {
($TYPE:ident, $OPTS:expr, $LABELS_NAMES:expr $(,)?) => {{
let gauge_vec = $crate::$TYPE::new($OPTS, $LABELS_NAMES).unwrap();
$crate::register(Box::new(gauge_vec.clone())).map(|()| gauge_vec)
$crate::register(Box::new(gauge_vec.clone())).map(|_| gauge_vec)
}};
($TYPE:ident, $OPTS:expr, $LABELS_NAMES:expr, $REGISTRY:expr $(,)?) => {{
let gauge_vec = $crate::$TYPE::new($OPTS, $LABELS_NAMES).unwrap();
$REGISTRY
.register(Box::new(gauge_vec.clone()))
.map(|()| gauge_vec)
.map(|_| gauge_vec)
}};
}
@ -918,7 +917,7 @@ macro_rules! register_histogram {
($HOPTS:expr $(,)?) => {{
let histogram = $crate::Histogram::with_opts($HOPTS).unwrap();
$crate::register(Box::new(histogram.clone())).map(|()| histogram)
$crate::register(Box::new(histogram.clone())).map(|_| histogram)
}};
}
@ -975,7 +974,7 @@ macro_rules! register_histogram_with_registry {
let histogram = $crate::Histogram::with_opts($HOPTS).unwrap();
$REGISTRY
.register(Box::new(histogram.clone()))
.map(|()| histogram)
.map(|_| histogram)
}};
}
@ -1031,7 +1030,7 @@ fn test_register_histogram_with_registry_trailing_comma() {
macro_rules! register_histogram_vec {
($HOPTS:expr, $LABELS_NAMES:expr $(,)?) => {{
let histogram_vec = $crate::HistogramVec::new($HOPTS, $LABELS_NAMES).unwrap();
$crate::register(Box::new(histogram_vec.clone())).map(|()| histogram_vec)
$crate::register(Box::new(histogram_vec.clone())).map(|_| histogram_vec)
}};
($NAME:expr, $HELP:expr, $LABELS_NAMES:expr $(,)?) => {{
@ -1061,7 +1060,7 @@ fn test_register_histogram_vec_trailing_comma() {
assert!(histogram_vec.is_ok());
}
/// Create a [`HistogramVec`][crate::HistogramVec] and registers to a custom registry.
/// Create a [`HistogramVec`][crate::HistogramVec] and registers to default registry.
///
/// # Examples
///
@ -1095,7 +1094,7 @@ macro_rules! register_histogram_vec_with_registry {
let histogram_vec = $crate::HistogramVec::new($HOPTS, $LABELS_NAMES).unwrap();
$REGISTRY
.register(Box::new(histogram_vec.clone()))
.map(|()| histogram_vec)
.map(|_| histogram_vec)
}};
($NAME:expr, $HELP:expr, $LABELS_NAMES:expr, $REGISTRY:expr $(,)?) => {{

View File

@ -177,7 +177,7 @@ impl Describer for Opts {
impl Ord for LabelPair {
fn cmp(&self, other: &LabelPair) -> Ordering {
self.name().cmp(other.name())
self.get_name().cmp(other.get_name())
}
}

View File

@ -1,23 +0,0 @@
use std::hash::{BuildHasherDefault, Hasher};
/// Inspired by nohash-hasher, but we avoid the crate dependency because it's in public archive.
#[derive(Copy, Clone, Debug, Default)]
pub(crate) struct NoHashHasher(u64);
pub(crate) type BuildNoHashHasher = BuildHasherDefault<NoHashHasher>;
impl Hasher for NoHashHasher {
#[inline]
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, _bytes: &[u8]) {
panic!("Invalid use of NoHashHasher");
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.0 = i;
}
}

View File

@ -29,13 +29,7 @@ impl LabelPair {
self.name = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.name()` instead")]
pub fn get_name(&self) -> &str {
self.name()
}
/// Returns the name of this label pair.
pub fn name(&self) -> &str {
&self.name
}
@ -43,13 +37,7 @@ impl LabelPair {
self.value = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.value()` instead")]
pub fn get_value(&self) -> &str {
self.value()
}
/// Returns the value of this label pair.
pub fn value(&self) -> &str {
&self.value
}
}
@ -111,13 +99,7 @@ impl Quantile {
self.quantile = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.quantile()` instead")]
pub fn get_quantile(&self) -> f64 {
self.quantile()
}
/// Returns the quantile of this quantile.
pub fn quantile(&self) -> f64 {
self.quantile
}
@ -125,13 +107,7 @@ impl Quantile {
self.value = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.value()` instead")]
pub fn get_value(&self) -> f64 {
self.value()
}
/// Returns the value of this quantile.
pub fn value(&self) -> f64 {
self.value
}
}
@ -153,27 +129,15 @@ impl Summary {
self.sample_count = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.sample_count()` instead")]
pub fn get_sample_count(&self) -> u64 {
self.sample_count
}
/// Returns the sample count of this summary.
pub fn sample_count(&self) -> u64 {
self.sample_count
}
pub fn set_sample_sum(&mut self, v: f64) {
self.sample_sum = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.sample_sum()` instead")]
pub fn get_sample_sum(&self) -> f64 {
self.sample_sum()
}
/// Returns the sample sum of this summary.
pub fn sample_sum(&self) -> f64 {
self.sample_sum
}
@ -268,13 +232,7 @@ impl Bucket {
self.cumulative_count = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.cumulative_count()` instead")]
pub fn get_cumulative_count(&self) -> u64 {
self.cumulative_count()
}
/// Returns the cumulative count of this bucket.
pub fn cumulative_count(&self) -> u64 {
self.cumulative_count
}
@ -282,13 +240,7 @@ impl Bucket {
self.upper_bound = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.upper_bound()` instead")]
pub fn get_upper_bound(&self) -> f64 {
self.upper_bound()
}
/// Returns the upper bound of this bucket.
pub fn upper_bound(&self) -> f64 {
self.upper_bound
}
}
@ -311,22 +263,6 @@ impl Metric {
Default::default()
}
/// Creates a new metric with the specified label pairs.
pub fn from_label(label: Vec<LabelPair>) -> Self {
Metric {
label,
..Default::default()
}
}
/// Creates a new metric with the specified gauge value.
pub fn from_gauge(gauge: Gauge) -> Self {
Metric {
gauge: gauge.into(),
..Default::default()
}
}
pub fn set_label(&mut self, v: Vec<LabelPair>) {
self.label = v;
}
@ -395,13 +331,7 @@ impl Metric {
self.timestamp_ms = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.timestamp_ms()` instead")]
pub fn get_timestamp_ms(&self) -> i64 {
self.timestamp_ms()
}
/// Returns the timestamp of this metric.
pub fn timestamp_ms(&self) -> i64 {
self.timestamp_ms
}
}
@ -443,13 +373,7 @@ impl MetricFamily {
self.name = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.name()` instead")]
pub fn get_name(&self) -> &str {
self.name()
}
/// Returns the name of this metric family.
pub fn name(&self) -> &str {
&self.name
}
@ -457,13 +381,7 @@ impl MetricFamily {
self.help = v;
}
#[deprecated(since = "0.14.0", note = "Please use `.help()` instead")]
pub fn get_help(&self) -> &str {
self.help()
}
/// Returns the help text of this metric family.
pub fn help(&self) -> &str {
&self.help
}

View File

@ -1,265 +0,0 @@
use protobuf::{EnumOrUnknown, MessageField};
use crate::proto::{
Bucket, Counter, Gauge, Histogram, LabelPair, Metric, MetricFamily, MetricType, Quantile,
Summary,
};
impl Metric {
/// Creates a new metric with the specified label pairs.
pub fn from_label(label: Vec<LabelPair>) -> Self {
Metric {
label,
..Default::default()
}
}
/// Creates a new metric with the specified gauge value.
pub fn from_gauge(gauge: Gauge) -> Self {
Metric {
gauge: gauge.into(),
..Default::default()
}
}
#[deprecated(since = "0.14.0", note = "Please use `.timestamp_ms()` instead")]
/// Returns the timestamp of this metric.
pub fn get_timestamp_ms(&self) -> i64 {
self.timestamp_ms()
}
/// Returns the summary of this metric.
pub fn get_summary(&self) -> &MessageField<Summary> {
&self.summary
}
/// Sets the summary of this metric to the specified summary.
pub fn set_summary(&mut self, summary: Summary) {
self.summary = summary.into();
}
/// Returns the value of the counter for this metric.
pub fn get_counter(&self) -> &MessageField<Counter> {
&self.counter
}
/// Sets the counter of this metric to the specified counter.
pub fn set_counter(&mut self, counter: Counter) {
self.counter = counter.into();
}
/// Returns all label pairs associated with this metric.
pub fn get_label(&self) -> &[LabelPair] {
&self.label
}
/// Sets the label pairs associated with this metric.
pub fn set_label(&mut self, label: Vec<LabelPair>) {
self.label = label;
}
/// Returns all label pairs associated with ownership.
pub fn take_label(&mut self) -> Vec<LabelPair> {
std::mem::take(&mut self.label)
}
/// Returns the gauge of this metric.
pub fn get_gauge(&self) -> &MessageField<Gauge> {
&self.gauge
}
/// Sets the gauge of this metric to the specified gauge.
pub fn set_gauge(&mut self, gauge: Gauge) {
self.gauge = gauge.into();
}
/// Returns the histogram of this metric.
pub fn get_histogram(&self) -> &MessageField<Histogram> {
&self.histogram
}
/// Sets the histogram of this metric to the specified histogram.
pub fn set_histogram(&mut self, histogram: Histogram) {
self.histogram = histogram.into();
}
}
impl MetricFamily {
#[deprecated(since = "0.14.0", note = "Please use `.name()` instead")]
/// Returns the name of this metric family.
pub fn get_name(&self) -> &str {
self.name()
}
#[deprecated(since = "0.14.0", note = "Please use `.help()` instead")]
/// Returns the help text of this metric family.
pub fn get_help(&self) -> &str {
self.help()
}
/// Sets the metric for this metric family (replaces any existing metrics).
pub fn set_metric(&mut self, metric: Vec<Metric>) {
self.metric = metric;
}
/// Returns the type of this metric family.
pub fn get_field_type(&self) -> MetricType {
self.type_()
}
/// Sets the type of this metric family.
pub fn set_field_type(&mut self, t: MetricType) {
self.type_ = t.into();
}
/// Returns all metrics in this metric family.
pub fn get_metric(&self) -> &[Metric] {
&self.metric
}
/// Returns all metrics in this metric family mutably.
pub fn mut_metric(&mut self) -> &mut Vec<Metric> {
&mut self.metric
}
/// Returns all metrics in this metric family with taking ownership.
pub fn take_metric(&mut self) -> Vec<Metric> {
std::mem::take(&mut self.metric)
}
}
impl Summary {
/// Sets the quantiles for this summary.
pub fn set_quantile(&mut self, quantiles: Vec<Quantile>) {
self.quantile = quantiles;
}
/// Returns the quantiles of this summary.
pub fn get_quantile(&self) -> &[Quantile] {
&self.quantile
}
#[deprecated(since = "0.14.0", note = "Please use `.sample_count()` instead")]
/// Returns the sample count of this summary.
pub fn get_sample_count(&self) -> u64 {
self.sample_count()
}
#[deprecated(since = "0.14.0", note = "Please use `.sample_sum()` instead")]
/// Returns the sample sum of this summary.
pub fn get_sample_sum(&self) -> f64 {
self.sample_sum()
}
}
impl Quantile {
#[deprecated(since = "0.14.0", note = "Please use `.quantile()` instead")]
/// Returns the quantile of this quantile.
pub fn get_quantile(&self) -> f64 {
self.quantile()
}
#[deprecated(since = "0.14.0", note = "Please use `.value()` instead")]
/// Returns the value of this quantile.
pub fn get_value(&self) -> f64 {
self.value()
}
}
pub trait MessageFieldExt {
/// Returns the value of the wrapped gauge.
#[allow(dead_code)]
fn get_value(&self) -> f64;
}
impl MessageFieldExt for MessageField<Gauge> {
fn get_value(&self) -> f64 {
self.value()
}
}
impl MessageFieldExt for MessageField<Counter> {
fn get_value(&self) -> f64 {
self.value()
}
}
impl Histogram {
/// Returns the sample count of this histogram.
pub fn get_sample_count(&self) -> u64 {
self.sample_count.unwrap_or_default()
}
/// Returns the sample sum of this histogram.
pub fn get_sample_sum(&self) -> f64 {
self.sample_sum.unwrap_or_default()
}
/// Returns all buckets in this histogram.
pub fn get_bucket(&self) -> &[Bucket] {
&self.bucket
}
/// Sets the buckets of this histogram.
pub fn set_bucket(&mut self, bucket: Vec<Bucket>) {
self.bucket = bucket;
}
}
impl Bucket {
#[deprecated(since = "0.14.0", note = "Please use `.cumulative_count()` instead")]
/// Returns the cumulative count of this bucket.
pub fn get_cumulative_count(&self) -> u64 {
self.cumulative_count()
}
#[deprecated(since = "0.14.0", note = "Please use `.upper_bound()` instead")]
/// Returns the upper bound of this bucket.
pub fn get_upper_bound(&self) -> f64 {
self.upper_bound()
}
}
impl LabelPair {
#[deprecated(since = "0.14.0", note = "Please use `.value()` instead")]
/// Returns the value of this label pair.
pub fn get_value(&self) -> &str {
self.value()
}
#[deprecated(since = "0.14.0", note = "Please use `.name()` instead")]
/// Returns the name of this label pair.
pub fn get_name(&self) -> &str {
self.name()
}
}
impl From<Counter> for MessageField<Counter> {
fn from(value: Counter) -> Self {
MessageField::some(value)
}
}
impl From<Gauge> for MessageField<Gauge> {
fn from(value: Gauge) -> Self {
MessageField::some(value)
}
}
impl From<Histogram> for MessageField<Histogram> {
fn from(value: Histogram) -> Self {
MessageField::some(value)
}
}
impl From<Summary> for MessageField<Summary> {
fn from(value: Summary) -> Self {
MessageField::some(value)
}
}
impl From<MetricType> for Option<EnumOrUnknown<MetricType>> {
fn from(value: MetricType) -> Self {
Some(EnumOrUnknown::from(value))
}
}

View File

@ -1,99 +0,0 @@
use std::{collections::HashMap, fmt, sync::Arc};
use crate::{
core::Collector,
proto::{Gauge, Metric, MetricFamily, MetricType},
};
/// A [Gauge] that returns the value from a provided function on every collect run.
///
/// This metric is the equivalant of Go's
/// <https://pkg.go.dev/github.com/prometheus/client_golang@v1.11.0/prometheus#GaugeFunc>
///
/// # Examples
/// ```
/// # use prometheus::{Registry, PullingGauge};
/// # // We are stubbing out std::thread::available_parallelism since it's not available in the
/// # // oldest Rust version that we support.
/// # fn available_parallelism() -> f64 { 0.0 }
///
/// let registry = Registry::new();
/// let gauge = PullingGauge::new(
/// "available_parallelism",
/// "The available parallelism, usually the numbers of logical cores.",
/// Box::new(|| available_parallelism())
/// ).unwrap();
/// registry.register(Box::new(gauge));
/// ```
#[derive(Clone)]
pub struct PullingGauge {
desc: crate::core::Desc,
value: Arc<Box<dyn Fn() -> f64 + Send + Sync>>,
}
impl fmt::Debug for PullingGauge {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PullingGauge")
.field("desc", &self.desc)
.field("value", &"<opaque>")
.finish()
}
}
impl PullingGauge {
/// Create a new [`PullingGauge`].
pub fn new<S1: Into<String>, S2: Into<String>>(
name: S1,
help: S2,
value: Box<dyn Fn() -> f64 + Send + Sync>,
) -> crate::Result<Self> {
Ok(PullingGauge {
value: Arc::new(value),
desc: crate::core::Desc::new(name.into(), help.into(), Vec::new(), HashMap::new())?,
})
}
fn metric(&self) -> Metric {
let mut gauge = Gauge::default();
let getter = &self.value;
gauge.set_value(getter());
Metric::from_gauge(gauge)
}
}
impl Collector for PullingGauge {
fn desc(&self) -> Vec<&crate::core::Desc> {
vec![&self.desc]
}
fn collect(&self) -> Vec<crate::proto::MetricFamily> {
let mut m = MetricFamily::default();
m.set_name(self.desc.fq_name.clone());
m.set_help(self.desc.help.clone());
m.set_field_type(MetricType::GAUGE);
m.set_metric(vec![self.metric()]);
vec![m]
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::metrics::Collector;
#[cfg(feature = "protobuf")]
use crate::proto_ext::MessageFieldExt;
#[test]
fn test_pulling_gauge() {
const VALUE: f64 = 10.0;
let gauge =
PullingGauge::new("test_gauge", "Purely for testing", Box::new(|| VALUE)).unwrap();
let metrics = gauge.collect();
assert_eq!(metrics.len(), 1);
assert_eq!(VALUE, metrics[0].get_metric()[0].get_gauge().get_value());
}
}

View File

@ -277,9 +277,9 @@ mod tests {
let mut l = proto::LabelPair::new();
l.set_name(case.0.to_owned());
let mut m = proto::Metric::new();
m.set_label(vec![l]);
m.set_label(from_vec!(vec![l]));
let mut mf = proto::MetricFamily::new();
mf.set_metric(vec![m]);
mf.set_metric(from_vec!(vec![m]));
let res = push_metrics("test", hostname_grouping_key(), "mockurl", vec![mf], None);
assert!(format!("{}", res.unwrap_err()).contains(case.1));
}

View File

@ -94,7 +94,7 @@ impl RegistryCore {
let mut id_set = Vec::new();
let mut collector_id: u64 = 0;
for desc in c.desc() {
if !id_set.contains(&desc.id) {
if !id_set.iter().any(|id| *id == desc.id) {
id_set.push(desc.id);
collector_id = collector_id.wrapping_add(desc.id);
}
@ -127,7 +127,7 @@ impl RegistryCore {
continue;
}
let name = mf.name().to_owned();
let name = mf.get_name().to_owned();
match mf_by_name.entry(name) {
BEntry::Vacant(entry) => {
entry.insert(mf);
@ -166,8 +166,8 @@ impl RegistryCore {
}
for (lp1, lp2) in lps1.iter().zip(lps2.iter()) {
if lp1.value() != lp2.value() {
return lp1.value().cmp(lp2.value());
if lp1.get_value() != lp2.get_value() {
return lp1.get_value().cmp(lp2.get_value());
}
}
@ -177,17 +177,17 @@ impl RegistryCore {
// here, even for inconsistent metrics. So sort equal metrics
// by their timestamp, with missing timestamps (implying "now")
// coming last.
m1.timestamp_ms().cmp(&m2.timestamp_ms())
m1.get_timestamp_ms().cmp(&m2.get_timestamp_ms())
});
}
// Write out MetricFamilies sorted by their name.
mf_by_name
.into_values()
.map(|mut m| {
.into_iter()
.map(|(_, mut m)| {
// Add registry namespace prefix, if any.
if let Some(ref namespace) = self.prefix {
let prefixed = format!("{}_{}", namespace, m.name());
let prefixed = format!("{}_{}", namespace, m.get_name());
m.set_name(prefixed);
}
@ -204,9 +204,9 @@ impl RegistryCore {
.collect();
for metric in m.mut_metric().iter_mut() {
let mut labels: Vec<_> = metric.take_label();
let mut labels: Vec<_> = metric.take_label().into();
labels.append(&mut pairs.clone());
metric.set_label(labels);
metric.set_label(labels.into());
}
}
m
@ -341,10 +341,7 @@ mod tests {
use crate::counter::{Counter, CounterVec};
use crate::desc::Desc;
use crate::metrics::{Collector, Opts};
#[cfg(feature = "protobuf")]
use crate::proto;
#[cfg(feature = "protobuf")]
use crate::proto_ext::MessageFieldExt;
#[test]
fn test_registry() {
@ -404,9 +401,9 @@ mod tests {
let mfs = r.gather();
assert_eq!(mfs.len(), 3);
assert_eq!(mfs[0].name(), "test_2_counter");
assert_eq!(mfs[1].name(), "test_a_counter");
assert_eq!(mfs[2].name(), "test_b_counter");
assert_eq!(mfs[0].get_name(), "test_2_counter");
assert_eq!(mfs[1].get_name(), "test_a_counter");
assert_eq!(mfs[2].get_name(), "test_b_counter");
let r = Registry::new();
let opts = Opts::new("test", "test help")
@ -476,7 +473,7 @@ mod tests {
let mfs = r.gather();
assert_eq!(mfs.len(), 1);
assert_eq!(mfs[0].name(), "common_prefix_test_a_counter");
assert_eq!(mfs[0].get_name(), "common_prefix_test_a_counter");
}
#[test]
@ -496,8 +493,8 @@ mod tests {
let mfs = r.gather();
assert_eq!(mfs.len(), 2);
assert_eq!(mfs[0].name(), "test_a_counter");
assert_eq!(mfs[1].name(), "test_vec");
assert_eq!(mfs[0].get_name(), "test_a_counter");
assert_eq!(mfs[1].get_name(), "test_vec");
let mut needle = proto::LabelPair::default();
needle.set_name("tkey".to_string());

View File

@ -37,11 +37,11 @@ pub struct Value<P: Atomic> {
}
impl<P: Atomic> Value<P> {
pub fn new<D: Describer, V: AsRef<str>>(
pub fn new<D: Describer>(
describer: &D,
val_type: ValueType,
val: P::T,
label_values: &[V],
label_values: &[&str],
) -> Result<Self> {
let desc = describer.describe()?;
let label_pairs = make_label_pairs(&desc, label_values)?;
@ -85,7 +85,8 @@ impl<P: Atomic> Value<P> {
}
pub fn metric(&self) -> Metric {
let mut m = Metric::from_label(self.label_pairs.clone());
let mut m = Metric::default();
m.set_label(from_vec!(self.label_pairs.clone()));
let val = self.get();
match self.val_type {
@ -109,12 +110,12 @@ impl<P: Atomic> Value<P> {
m.set_name(self.desc.fq_name.clone());
m.set_help(self.desc.help.clone());
m.set_field_type(self.val_type.metric_type());
m.set_metric(vec![self.metric()]);
m.set_metric(from_vec!(vec![self.metric()]));
m
}
}
pub fn make_label_pairs<V: AsRef<str>>(desc: &Desc, label_values: &[V]) -> Result<Vec<LabelPair>> {
pub fn make_label_pairs(desc: &Desc, label_values: &[&str]) -> Result<Vec<LabelPair>> {
if desc.variable_labels.len() != label_values.len() {
return Err(Error::InconsistentCardinality {
expect: desc.variable_labels.len(),
@ -135,7 +136,7 @@ pub fn make_label_pairs<V: AsRef<str>>(desc: &Desc, label_values: &[V]) -> Resul
for (i, n) in desc.variable_labels.iter().enumerate() {
let mut label_pair = LabelPair::default();
label_pair.set_name(n.clone());
label_pair.set_value(label_values[i].as_ref().to_owned());
label_pair.set_value(label_values[i].to_owned());
label_pairs.push(label_pair);
}

View File

@ -2,7 +2,7 @@
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
use std::collections::HashMap;
use std::hash::{BuildHasher, Hasher};
use std::hash::Hasher;
use std::sync::Arc;
use fnv::FnvHasher;
@ -11,7 +11,6 @@ use parking_lot::RwLock;
use crate::desc::{Desc, Describer};
use crate::errors::{Error, Result};
use crate::metrics::{Collector, Metric};
use crate::nohash::BuildNoHashHasher;
use crate::proto::{MetricFamily, MetricType};
/// An interface for building a metric vector.
@ -22,13 +21,12 @@ pub trait MetricVecBuilder: Send + Sync + Clone {
type P: Describer + Sync + Send + Clone;
/// `build` builds a [`Metric`] with option and corresponding label names.
fn build<V: AsRef<str>>(&self, _: &Self::P, _: &[V]) -> Result<Self::M>;
fn build(&self, _: &Self::P, _: &[&str]) -> Result<Self::M>;
}
#[derive(Debug)]
pub(crate) struct MetricVecCore<T: MetricVecBuilder> {
// the key is pre-hashed, and so we use a no-hash hasher to avoid hashing again.
pub children: RwLock<HashMap<u64, T::M, BuildNoHashHasher>>,
pub children: RwLock<HashMap<u64, T::M>>,
pub desc: Desc,
pub metric_type: MetricType,
pub new_metric: T,
@ -47,14 +45,11 @@ impl<T: MetricVecBuilder> MetricVecCore<T> {
for child in children.values() {
metrics.push(child.metric());
}
m.set_metric(metrics);
m.set_metric(from_vec!(metrics));
m
}
pub fn get_metric_with_label_values<V>(&self, vals: &[V]) -> Result<T::M>
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn get_metric_with_label_values(&self, vals: &[&str]) -> Result<T::M> {
let h = self.hash_label_values(vals)?;
if let Some(metric) = self.children.read().get(&h).cloned() {
@ -64,10 +59,7 @@ impl<T: MetricVecBuilder> MetricVecCore<T> {
self.get_or_create_metric(h, vals)
}
pub fn get_metric_with<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<T::M>
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn get_metric_with(&self, labels: &HashMap<&str, &str>) -> Result<T::M> {
let h = self.hash_labels(labels)?;
if let Some(metric) = self.children.read().get(&h).cloned() {
@ -78,10 +70,7 @@ impl<T: MetricVecBuilder> MetricVecCore<T> {
self.get_or_create_metric(h, &vals)
}
pub fn delete_label_values<V>(&self, vals: &[V]) -> Result<()>
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn delete_label_values(&self, vals: &[&str]) -> Result<()> {
let h = self.hash_label_values(vals)?;
let mut children = self.children.write();
@ -92,10 +81,7 @@ impl<T: MetricVecBuilder> MetricVecCore<T> {
Ok(())
}
pub fn delete<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<()>
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn delete(&self, labels: &HashMap<&str, &str>) -> Result<()> {
let h = self.hash_labels(labels)?;
let mut children = self.children.write();
@ -111,10 +97,7 @@ impl<T: MetricVecBuilder> MetricVecCore<T> {
self.children.write().clear();
}
pub(crate) fn hash_label_values<V>(&self, vals: &[V]) -> Result<u64>
where
V: AsRef<str> + std::fmt::Debug,
{
pub(crate) fn hash_label_values(&self, vals: &[&str]) -> Result<u64> {
if vals.len() != self.desc.variable_labels.len() {
return Err(Error::InconsistentCardinality {
expect: self.desc.variable_labels.len(),
@ -124,16 +107,13 @@ impl<T: MetricVecBuilder> MetricVecCore<T> {
let mut h = FnvHasher::default();
for val in vals {
h.write(val.as_ref().as_bytes());
h.write(val.as_bytes());
}
Ok(h.finish())
}
fn hash_labels<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<u64>
where
V: AsRef<str> + std::fmt::Debug,
{
fn hash_labels(&self, labels: &HashMap<&str, &str>) -> Result<u64> {
if labels.len() != self.desc.variable_labels.len() {
return Err(Error::InconsistentCardinality {
expect: self.desc.variable_labels.len(),
@ -144,7 +124,7 @@ impl<T: MetricVecBuilder> MetricVecCore<T> {
let mut h = FnvHasher::default();
for name in &self.desc.variable_labels {
match labels.get(&name.as_ref()) {
Some(val) => h.write(val.as_ref().as_bytes()),
Some(val) => h.write(val.as_bytes()),
None => {
return Err(Error::Msg(format!(
"label name {} missing in label map",
@ -157,17 +137,11 @@ impl<T: MetricVecBuilder> MetricVecCore<T> {
Ok(h.finish())
}
fn get_label_values<'a, V, S: BuildHasher>(
&'a self,
labels: &'a HashMap<&str, V, S>,
) -> Result<Vec<&'a str>>
where
V: AsRef<str> + std::fmt::Debug,
{
fn get_label_values<'a>(&self, labels: &'a HashMap<&str, &str>) -> Result<Vec<&'a str>> {
let mut values = Vec::new();
for name in &self.desc.variable_labels {
match labels.get(&name.as_ref()) {
Some(val) => values.push(val.as_ref()),
Some(val) => values.push(*val),
None => {
return Err(Error::Msg(format!(
"label name {} missing in label map",
@ -179,10 +153,7 @@ impl<T: MetricVecBuilder> MetricVecCore<T> {
Ok(values)
}
fn get_or_create_metric<V>(&self, hash: u64, label_values: &[V]) -> Result<T::M>
where
V: AsRef<str> + std::fmt::Debug,
{
fn get_or_create_metric(&self, hash: u64, label_values: &[&str]) -> Result<T::M> {
let mut children = self.children.write();
// Check exist first.
if let Some(metric) = children.get(&hash).cloned() {
@ -217,7 +188,7 @@ impl<T: MetricVecBuilder> MetricVec<T> {
pub fn create(metric_type: MetricType, new_metric: T, opts: T::P) -> Result<MetricVec<T>> {
let desc = opts.describe()?;
let v = MetricVecCore {
children: RwLock::new(HashMap::default()),
children: RwLock::new(HashMap::new()),
desc,
metric_type,
new_metric,
@ -250,10 +221,7 @@ impl<T: MetricVecBuilder> MetricVec<T> {
/// an alternative to avoid that type of mistake. For higher label numbers, the
/// latter has a much more readable (albeit more verbose) syntax, but it comes
/// with a performance overhead (for creating and processing the Labels map).
pub fn get_metric_with_label_values<V>(&self, vals: &[V]) -> Result<T::M>
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn get_metric_with_label_values(&self, vals: &[&str]) -> Result<T::M> {
self.v.get_metric_with_label_values(vals)
}
@ -269,10 +237,7 @@ impl<T: MetricVecBuilder> MetricVec<T> {
/// This method is used for the same purpose as
/// `get_metric_with_label_values`. See there for pros and cons of the two
/// methods.
pub fn get_metric_with<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<T::M>
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn get_metric_with(&self, labels: &HashMap<&str, &str>) -> Result<T::M> {
self.v.get_metric_with(labels)
}
@ -289,20 +254,14 @@ impl<T: MetricVecBuilder> MetricVec<T> {
/// ).unwrap();
/// vec.with_label_values(&["404", "POST"]).inc()
/// ```
pub fn with_label_values<V>(&self, vals: &[V]) -> T::M
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn with_label_values(&self, vals: &[&str]) -> T::M {
self.get_metric_with_label_values(vals).unwrap()
}
/// `with` works as `get_metric_with`, but panics if an error occurs. The method allows
/// neat syntax like:
/// httpReqs.with(Labels{"status":"404", "method":"POST"}).inc()
pub fn with<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> T::M
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn with(&self, labels: &HashMap<&str, &str>) -> T::M {
self.get_metric_with(labels).unwrap()
}
@ -318,10 +277,7 @@ impl<T: MetricVecBuilder> MetricVec<T> {
/// alternative to avoid that type of mistake. For higher label numbers, the
/// latter has a much more readable (albeit more verbose) syntax, but it comes
/// with a performance overhead (for creating and processing the Labels map).
pub fn remove_label_values<V>(&self, vals: &[V]) -> Result<()>
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn remove_label_values(&self, vals: &[&str]) -> Result<()> {
self.v.delete_label_values(vals)
}
@ -333,10 +289,7 @@ impl<T: MetricVecBuilder> MetricVec<T> {
///
/// This method is used for the same purpose as `delete_label_values`. See
/// there for pros and cons of the two methods.
pub fn remove<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<()>
where
V: AsRef<str> + std::fmt::Debug,
{
pub fn remove(&self, labels: &HashMap<&str, &str>) -> Result<()> {
self.v.delete(labels)
}
@ -395,40 +348,6 @@ mod tests {
assert!(vec.remove(&labels3).is_err());
}
#[test]
fn test_counter_vec_with_owned_labels() {
let vec = CounterVec::new(
Opts::new("test_couter_vec", "test counter vec help"),
&["l1", "l2"],
)
.unwrap();
let v1 = "v1".to_string();
let v2 = "v2".to_string();
let mut labels = HashMap::new();
labels.insert("l1", v1.clone());
labels.insert("l2", v2.clone());
assert!(vec.remove(&labels).is_err());
vec.with(&labels).inc();
assert!(vec.remove(&labels).is_ok());
assert!(vec.remove(&labels).is_err());
let mut labels2 = HashMap::new();
labels2.insert("l1", v2.clone());
labels2.insert("l2", v1.clone());
vec.with(&labels).inc();
assert!(vec.remove(&labels2).is_err());
vec.with(&labels).inc();
let mut labels3 = HashMap::new();
labels3.insert("l1", v1.clone());
assert!(vec.remove(&labels3).is_err());
}
#[test]
fn test_counter_vec_with_label_values() {
let vec = CounterVec::new(
@ -446,27 +365,6 @@ mod tests {
assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
}
#[test]
fn test_counter_vec_with_owned_label_values() {
let vec = CounterVec::new(
Opts::new("test_vec", "test counter vec help"),
&["l1", "l2"],
)
.unwrap();
let v1 = "v1".to_string();
let v2 = "v2".to_string();
let v3 = "v3".to_string();
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_err());
vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_ok());
vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
assert!(vec.remove_label_values(&[v1.clone()]).is_err());
assert!(vec.remove_label_values(&[v1.clone(), v3.clone()]).is_err());
}
#[test]
fn test_gauge_vec_with_labels() {
let vec = GaugeVec::new(
@ -490,32 +388,6 @@ mod tests {
assert!(vec.remove(&labels).is_err());
}
#[test]
fn test_gauge_vec_with_owned_labels() {
let vec = GaugeVec::new(
Opts::new("test_gauge_vec", "test gauge vec help"),
&["l1", "l2"],
)
.unwrap();
let v1 = "v1".to_string();
let v2 = "v2".to_string();
let mut labels = HashMap::new();
labels.insert("l1", v1.clone());
labels.insert("l2", v2.clone());
assert!(vec.remove(&labels).is_err());
vec.with(&labels).inc();
vec.with(&labels).dec();
vec.with(&labels).add(42.0);
vec.with(&labels).sub(42.0);
vec.with(&labels).set(42.0);
assert!(vec.remove(&labels).is_ok());
assert!(vec.remove(&labels).is_err());
}
#[test]
fn test_gauge_vec_with_label_values() {
let vec = GaugeVec::new(
@ -538,32 +410,6 @@ mod tests {
assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
}
#[test]
fn test_gauge_vec_with_owned_label_values() {
let vec = GaugeVec::new(
Opts::new("test_gauge_vec", "test gauge vec help"),
&["l1", "l2"],
)
.unwrap();
let v1 = "v1".to_string();
let v2 = "v2".to_string();
let v3 = "v3".to_string();
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_err());
vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_ok());
vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
vec.with_label_values(&[v1.clone(), v2.clone()]).dec();
vec.with_label_values(&[v1.clone(), v2.clone()]).add(42.0);
vec.with_label_values(&[v1.clone(), v2.clone()]).sub(42.0);
vec.with_label_values(&[v1.clone(), v2.clone()]).set(42.0);
assert!(vec.remove_label_values(&[v1.clone()]).is_err());
assert!(vec.remove_label_values(&[v1.clone(), v3.clone()]).is_err());
}
#[test]
fn test_vec_get_metric_with() {
let vec = CounterVec::new(
@ -582,7 +428,7 @@ mod tests {
let label_pairs = m.get_label();
assert_eq!(label_pairs.len(), labels.len());
for lp in label_pairs.iter() {
assert_eq!(lp.value(), labels[lp.name()]);
assert_eq!(lp.get_value(), labels[lp.get_name()]);
}
}
}

View File

@ -13,13 +13,13 @@ edition = "2018"
proc-macro = true
[dependencies]
syn = { version = "2.0", features = ["full", "extra-traits"] }
syn = { version = "1.0", features = ["full", "extra-traits"] }
proc-macro2 = "1.0"
quote = "1.0"
lazy_static = "1.4"
[dev-dependencies]
criterion = "0.5"
criterion = "0.4"
prometheus = { path = "../" }
[features]

View File

@ -714,6 +714,7 @@ impl<'a> MetricBuilderContext<'a> {
})#local_suffix_call,
}
} else {
let prev_labels_ident = prev_labels_ident;
quote! {
#name: #member_type::from(
#(

View File

@ -300,6 +300,7 @@ impl<'a> MetricBuilderContext<'a> {
})#local_suffix_call,
}
} else {
let prev_labels_ident = prev_labels_ident;
quote! {
#name: #member_type::from(
#(

View File

@ -44,7 +44,7 @@ pub fn make_static_metric(input: TokenStream) -> TokenStream {
TokensBuilder::build(body).into()
}
/// Build auto flushable static metrics.
/// Build auto flush able static metrics.
/// refer to https://github.com/tikv/rust-prometheus/tree/master/static-metric for more info.
#[proc_macro]
pub fn make_auto_flush_static_metric(input: TokenStream) -> TokenStream {
@ -52,7 +52,7 @@ pub fn make_auto_flush_static_metric(input: TokenStream) -> TokenStream {
AutoFlushTokensBuilder::build(body).into()
}
/// Instantiate an auto flushable static metric struct from a HistogramVec or CounterVec.
/// Instantiate a auto flush able static metric struct from a HistogramVec or CounterVec.
#[proc_macro]
pub fn auto_flush_from(input: TokenStream) -> TokenStream {
let def: AutoFlushFromDef = syn::parse(input).unwrap();