#prometheus #prometheus-metrics #format #exposition #label #text-based #name

serde_prometheus

基于serde的Prometheus文本展示格式的序列化器

13个版本

0.2.5 2024年5月11日
0.2.4 2023年9月8日
0.2.3 2023年6月22日
0.2.2 2023年3月20日
0.1.4 2020年7月16日

#310编码

Download history 11641/week @ 2024-04-20 12192/week @ 2024-04-27 12777/week @ 2024-05-04 11756/week @ 2024-05-11 12802/week @ 2024-05-18 12634/week @ 2024-05-25 11509/week @ 2024-06-01 11515/week @ 2024-06-08 12678/week @ 2024-06-15 10415/week @ 2024-06-22 9965/week @ 2024-06-29 11042/week @ 2024-07-06 10479/week @ 2024-07-13 11715/week @ 2024-07-20 13933/week @ 2024-07-27 13977/week @ 2024-08-03

51,820 每月下载量
用于 2 crates

WTFPL OR 0BSD

78KB
2K SLoC

Serde Prometheus Crate API

一个用于Prometheus文本展示格式的serde实现。


lib.rs:

一个用于Prometheus文本展示格式的serde实现。

目前这个库只支持将指标序列化为Prometheus格式,但以后可能会扩展到反序列化。

serde_prometheus将与大多数度量库的struct结构无缝工作,但是可能需要对它们进行一些处理才能达到Prometheus期望的格式。

格式中暴露的度量名称是从包含它的struct或map中的值的名称派生出来的。

基本用法

#[derive(Serialize)]
struct HitCount(u64);

#[derive(Serialize)]
struct MetricRegistry {
    my_struct: MyStructMetrics
}

#[derive(Serialize)]
struct MyStructMetrics {
    hit_count: HitCount
}

let metrics = MetricRegistry {
    my_struct: MyStructMetrics {
        hit_count: HitCount(30)
    }
};

assert_eq!(
   serde_prometheus::to_string(&metrics, None, HashMap::new())?,
   "hit_count{path = \"my_struct\"} 30\n"
);

全局标签

可以使用HashMap(或任何可以解析为IntoIterator<Borrow<(&str, &str)>>)将全局标签添加到serde_prometheus导出的所有指标中,例如通过传递到serde_prometheus::to_string

#
#
#
let mut labels = HashMap::new();
labels.insert("my_key", "my_value");

let serialised = serde_prometheus::to_string(&metrics, None, &[("my_key", "my_value")])?;
assert_eq!(serialised, "hit_count{my_key = \"my_value\", path = \"my_struct\"} 30\n");

全局前缀

还可以添加全局前缀到所有指标

#
#
#
assert_eq!(
   serde_prometheus::to_string(&metrics, Some("my_prefix"), HashMap::new())?,
   "my_prefix_hit_count{path = \"my_struct\"} 30\n"
);

元数据和键操作

serde_prometheus通过使用Serde的newtype实现来添加元数据到序列化字段,而不会破坏与serde_json等的向后兼容性。

例如,serde_prometheus已添加到metered-rs的直方图中,同时仍然保持相同的JSON模式,它是通过在一个struct的Serialize trait impl中调用serialize_newtype_struct来实现的,类型名称的格式如下

keymodifiers|key=value,key2=value2

也可以在标签中使用修饰符,例如这样使用==

|key3==modifiers

对于每个标签值,都会重置path堆栈,然而在写入path标签本身时,应用了键修饰符后,它会保留。

可以使用的修饰符有

修饰符 描述
< path堆栈中弹出一个值并将其附加到名称上
! path堆栈中弹出的最后一个值并将其丢弃
- 将堆栈光标向后移动一个位置,当从堆栈中弹出一个值时,位置会重置回堆栈顶部
. serde_prometheus 0.1的默认行为是将收集到的堆栈附加到path中的下一个值(就像在修饰符中添加了一个额外的<),要防止这种情况,请使用此修饰符。在标签中此操作无效果。

这些修饰符可以组合使用,并且从左到右读取,例如

#
#
#
struct HitCount(u64);
impl Serialize for HitCount {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        // metric name: include our key (hit_count), ignore the second (my_method), and include the third (my_struct)
        // metric meta: for the method_name, ignore our key (hit_count), include the second (my_method)
        serializer.serialize_newtype_struct("<!<|my_key=my_value,method_name==!<", &self.0)
    }
}

let metrics = MetricRegistry {
    my_struct: MyStructMetrics {
        my_method: MyMethodMetrics {
            hit_count: HitCount(30)
        }
    }
};

let serialised = serde_prometheus::to_string(&metrics, None, HashMap::new())?;
assert_eq!(
   serialised,
   // would be `hit_count{path = "my_struct/my_method"}` without the Serialize impl
   "my_struct_hit_count{my_key = \"my_value\", method_name = \"my_method\"} 30\n"
);

内部覆盖

serialize_newtype_struct支持一个额外的部分,允许覆盖内部操作,如下所示

keymodifiers|key=value,key2=value2|:internal=abc

内部覆盖始终以:开头,以使其明显不是标签,以下是可以使用的内部覆盖列表

覆盖 描述
:namespace 用新的值覆盖该结构及其下任何叶子的全局命名空间

标签连接

默认情况下,通过serialize_newtype_struct调用添加的新标签,将覆盖堆栈上更高位置的先前设置的标签。可以通过在标签名称中附加[::]来覆盖“更深”的值,这将使用::连接先前设置的标签和新的标签。::可以是Prometheus标签值中的任何有效值,但不能是=

fn add_my_cool_key<S: serde::Serializer, T: serde::Serialize>(
    value: &T,
    serializer: S,
) -> Result<S::Ok, S::Error> {
    serializer.serialize_newtype_struct("!|my_cool_key[::]==<", value)
}

#[derive(Serialize)]
struct MetricRegistry {
    #[serde(serialize_with = "add_my_cool_key")]
    my_struct: MyStructMetrics
}

#[derive(Serialize)]
struct MyStructMetrics {
    #[serde(serialize_with = "add_my_cool_key")]
    my_method: MyMethodMetrics
}

#[derive(Serialize)]
struct MyMethodMetrics {
    hit_count: HitCount
}
#

let metrics = MetricRegistry {
    my_struct: MyStructMetrics {
        my_method: MyMethodMetrics {
            hit_count: HitCount(30)
        }
    }
};

let serialised = serde_prometheus::to_string(&metrics, None, HashMap::new())?;
assert_eq!(
   serialised,
   "hit_count{my_cool_key = \"my_struct::my_method\"} 30\n"
);

依赖

~2.1–3MB
~62K SLoC