Rust监控指标库prometheus-static-metric的使用:静态Prometheus指标生成与高性能采集
Rust监控指标库prometheus-static-metric的使用:静态Prometheus指标生成与高性能采集
为什么需要这个库?
MetricVec
(如CounterVec
、GaugeVec
或HistogramVec
)性能较低。但如果知道标签的所有可能值,可以将MetricVec
中的每个指标缓存起来以避免运行时开销。
例如,以下代码在多次调用时可能很慢:
some_counter_vec.with_label_values(&["label_1_foo", "label_2_bar"]).inc();
这是因为每次都要根据值检索特定的Counter
,并且为了确保线程安全,内部有一个锁,这使情况更糟。
示例代码
基础用法示例
use prometheus_static_metric::make_static_metric;
make_static_metric! {
pub struct MyStaticCounterVec: Counter {
"method" => {
post,
get,
put,
delete,
},
"product" => {
foo,
bar,
},
}
}
fn main() {
let vec = CounterVec::new(Opts::new("foo", "bar"), &["method", "product"]).unwrap();
let static_counter_vec = MyStaticCounterVec::from(&vec);
static_counter_vec.post.foo.inc();
static_counter_vec.delete.bar.inc_by(4.0);
assert_eq!(static_counter_vec.post.bar.get(), 0.0);
assert_eq!(vec.with_label_values(&["post", "foo"]).get(), 1.0);
assert_eq!(vec.with_label_values(&["delete", "bar"]).get(), 4.0);
}
自动刷新的本地线程指标
对于更重的场景,共享的静态指标可能不够高效,可以使用make_auto_flush_static metric!
宏,它将数据存储在本地线程存储中,并以自定义速率刷新到全局MetricVec
。
#[macro_use]
extern crate lazy_static;
extern crate prometheus;
extern crate prometheus_static_metric;
use prometheus::*;
use prometheus_static_metric::auto_flush_from;
use prometheus_static_metric::make_auto_flush_static_metric;
make_auto_flush_static_metric! {
pub label_enum FooBar {
foo,
bar,
}
pub label_enum Methods {
post,
get,
put,
delete,
}
pub struct Lhrs: LocalIntCounter {
"product" => FooBar,
"method" => Methods,
"version" => {
http1: "HTTP/1",
http2: "HTTP/2",
},
}
}
lazy_static! {
pub static ref HTTP_COUNTER_VEC: IntCounterVec =
register_int_counter_vec!(
"http_requests_total",
"Number of HTTP requests.",
&["product", "method", "version"] // label顺序不重要
).unwrap();
}
lazy_static! {
// 也可以使用默认的1秒刷新间隔
// pub static ref TLS_HTTP_COUNTER: Lhrs = auto_flush_from!(HTTP_COUNTER_VEC, Lhrs);
pub static ref TLS_HTTP_COUNTER: Lhrs = auto_flush_from!(HTTP_COUNTER_VEC, Lhrs, std::time::Duration::from_secs(1));
}
fn main() {
TLS_HTTP_COUNTER.foo.post.http1.inc();
TLS_HTTP_COUNTER.foo.post.http1.inc();
assert_eq!(
HTTP_COUNTER_VEC
.with_label_values(&["foo", "post", "HTTP/1"])
.get(),
0
);
::std::thread::sleep(::std::time::Duration::from_secs(2));
TLS_HTTP_COUNTER.foo.post.http1.inc();
assert_eq!(
HTTP_COUNTER_VEC
.with_label_values(&["foo", "post", "HTTP/1"])
.get(),
3
);
}
完整示例Demo
静态指标完整示例
use prometheus::{Opts, CounterVec};
use prometheus_static_metric::make_static_metric;
// 定义静态指标结构
make_static_metric! {
pub struct HttpRequestMetrics: Counter {
"method" => {
get,
post,
put,
delete,
},
"status" => {
success: "200",
client_error: "400",
server_error: "500",
},
}
}
fn main() {
// 创建原始的CounterVec
let http_requests = CounterVec::new(
Opts::new("http_requests_total", "Total HTTP requests"),
&["method", "status"]
).unwrap();
// 转换为静态指标
let static_metrics = HttpRequestMetrics::from(&http_requests);
// 使用静态指标
static_metrics.get.success.inc();
static_metrics.post.client_error.inc_by极速3.0;
// 验证指标值
assert_eq!(http_requests.with_label_values(&["get", "200"]).get(), 1.0);
assert_eq!(http_requests.with_label_values(&["post", "400"]).get(), 3.0);
}
自动刷新指标完整示例
#[macro_use]
extern crate lazy_static;
use prometheus::{IntCounterVec, register_int_counter_vec};
use prometheus_static_metric::{make_auto_flush_static_metric, auto_flush_from};
use std::time::Duration;
// 定义自动刷新指标
make_auto_flush_static_metric! {
pub label_enum ApiName {
user_api,
order_api,
payment_api,
}
pub label_enum Env {
production,
staging,
development,
}
pub struct ApiMetrics: LocalIntCounter {
"api" => ApiName,
"env" => Env,
}
}
lazy_static! {
static ref GLOBAL_API_METRICS: IntCounterVec = register_int_counter_vec!(
"api_calls_total",
"Total API calls",
&["api", "env"]
).unwrap();
static ref TLS_API_METRICS: ApiMetrics = auto_flush_from!(
GLOBAL_API_METRICS,
ApiMetrics,
Duration::from_secs(2) // 每2秒刷新一次
);
}
fn main() {
// 线程局部指标会自动累加
TLS_API_METRICS.user_api.production.inc();
TLS_API_METRICS.order_api.staging.inc_by(5);
// 初始时全局指标还未更新
assert_eq!(GLOBAL_API_METRICS.with_label_values(&["user_api", "production"]).get(), 0);
// 等待刷新间隔
std::thread::sleep(Duration::from_secs(3));
// 现在全局指标已更新
assert_eq!(GLOBAL_API_METRICS.with_label_values(&["user_api", "production"]).get(), 1);
assert_eq!(GLOBAL_API_METRICS.with_label_values(&["order_api", "staging"]).get(), 5);
}
安装
在项目的Cargo.toml中添加依赖:
[dependencies]
prometheus-static-metric = "0.5.1"
或者在项目目录中运行:
cargo add prometheus-static-metric
1 回复
以下是基于您提供的内容整理的完整示例demo,包含HTTP请求监控和温度监控两个完整示例:
HTTP请求监控示例
use prometheus::Registry;
use prometheus_static_metric::{make_static_metric, StaticMetric};
// 1. 定义静态HTTP请求指标
make_static_metric! {
pub struct HttpRequestStatistics: Counter {
"method" => {
get,
post,
put,
delete,
},
"status" => {
ok: "200",
bad_request: "400",
not_found: "404",
server_error: "500",
},
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 2. 创建指标实例
let http_requests = HttpRequestStatistics::default();
// 3. 注册到Prometheus
let registry = Registry::new();
registry.register(Box::new(http_requests.clone()))?;
// 4. 模拟记录HTTP请求
// GET /api/users 200 OK
http_requests.get.ok.inc();
// POST /api/orders 400 Bad Request
http_requests.post.bad_request.inc();
// DELETE /api/products 404 Not Found
http_requests.delete.not_found.inc();
// PUT /api/items 500 Server Error
http_requests.put.server_error.inc_by(3.0);
// 5. 采集并打印指标
let metric_families = registry.gather();
for mf in metric_families {
println!("{}", mf);
}
Ok(())
}
温度监控示例
use prometheus::Registry;
use prometheus_static_metric::{make_static_metric, StaticMetric};
// 1. 定义静态温度指标
make_static_metric! {
pub struct TemperatureMetrics: Gauge {
"location" => {
kitchen,
living_room,
bedroom,
outdoor,
},
"unit" => {
celsius,
fahrenheit,
},
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 2. 创建指标实例
let temperatures = TemperatureMetrics::default();
// 3. 注册到Prometheus
let registry = Registry::new();
registry.register(Box::new(temperatures.clone()))?;
// 4. 设置温度值
temperatures.kitchen.celsius.set(22.5);
temperatures.living_room.celsius.set(20.0);
temperatures.bedroom.fahrenheit.set(68.0);
temperatures.outdoor.celsius.set(15.3);
// 5. 修改温度值(模拟温度变化)
temperatures.kitchen.celsius.inc(); // 温度+1
temperatures.living_room.celsius.dec(); // 温度-1
// 6. 采集并打印指标
let metric_families = registry.gather();
for mf in metric_families {
println!("{}", mf);
}
Ok(())
}
数据库操作监控示例
use prometheus::Registry;
use prometheus_static_metric::{make_static_metric, StaticMetric};
// 1. 定义数据库操作指标
make_static_metric! {
pub struct DatabaseMetrics: Counter {
"operation" => {
select,
insert,
update,
delete,
},
"table" => {
users,
products,
orders,
},
"result" => {
success,
failure,
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 2. 创建指标实例
let db_metrics = DatabaseMetrics::default();
// 3. 注册到Prometheus
let registry = Registry::new();
registry.register(Box::new(db_metrics.clone()))?;
// 4. 模拟数据库操作
// SELECT * FROM users 成功
db_metrics.select.users.success.inc();
// INSERT INTO products 失败
db_metrics.insert.products.failure.inc();
// UPDATE orders 成功
db_metrics.update.orders.success.inc_by(5.0);
// DELETE FROM users 失败
db_metrics.delete.users.failure.inc();
// 5. 采集并打印指标
let metric_families = registry.gather();
for mf in metric_families {
println!("{}", mf);
}
Ok(())
}
这些示例展示了如何:
- 使用
make_static_metric!
宏定义静态指标 - 初始化指标实例并注册到Prometheus
- 记录各种指标值
- 采集并输出指标数据
每个示例都包含了完整的错误处理和指标操作,可以直接运行测试。