Skip to content

Instantly share code, notes, and snippets.

@andir
Last active October 21, 2025 10:19
Show Gist options
  • Select an option

  • Save andir/2825171a65a0ba089c61e5be08542739 to your computer and use it in GitHub Desktop.

Select an option

Save andir/2825171a65a0ba089c61e5be08542739 to your computer and use it in GitHub Desktop.
use proc_macro::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields, Lit, Meta, MetaNameValue, parse_macro_input};
#[proc_macro_derive(SimplePrometheus, attributes(prefix))]
pub fn simple_prometheus_derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let fields = match &ast.data {
Data::Struct(s) => s.fields.clone(),
_ => unimplemented!(),
};
let prefix = get_prefix(&ast.attrs)
.map(|prefix| {
if !prefix.starts_with("_") {
format!("{}_", prefix)
} else {
prefix
}
})
.unwrap_or("".to_string());
let name = &ast.ident;
let field_names = match fields {
Fields::Named(field_named) => field_named.named.into_iter().map(|f| f.ident.unwrap()),
_ => unimplemented!(),
};
let write_statements = field_names.map(|field_name| {
let prefix = format!("{}{}", prefix, field_name);
let format_label = format!("{}{} {}", prefix, "{{server={}}}", "{}");
let format = format!("{} {}", prefix, "{}");
quote! {
if let Some(ref server) = server {
writeln!(out, #format_label, server, self.#field_name)?;
} else {
writeln!(out, #format, self.#field_name)?;
}
}
});
let code = quote! {
impl simple_prometheus::SimplePrometheus for #name {
fn to_prometheus_metrics(&self, server: Option<String>) -> Result<String, core::fmt::Error> {
use std::fmt::Write;
let mut out = String::new();
#( #write_statements )*
Ok(out)
}
}
};
//println!("{}", code.to_string());
code.into()
}
fn get_prefix(attrs: &[syn::Attribute]) -> Option<String> {
attrs
.iter()
.filter(|attr| attr.path().is_ident("simple_prometheus"))
.filter_map(|attr| {
if let Meta::NameValue(MetaNameValue {
path,
value: syn::Expr::Lit(expr_lit),
..
}) = attr.meta.clone()
{
Some((path, expr_lit))
} else {
None
}
})
.filter_map(|(path, attr)| {
if path.is_ident("prefix") {
if let Lit::Str(lit_str) = &attr.lit {
Some(lit_str.value())
} else {
None
}
} else {
None
}
})
.next()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple() {}
}
[2025-10-21T10:19:43Z INFO statsbot] prometheus metrics: users{server=lechuck.hackint.dn42} 10218
users_memory{server=lechuck.hackint.dn42} 1226160
users_invited{server=lechuck.hackint.dn42} 0
users_invited_memory{server=lechuck.hackint.dn42} 0
user_channels{server=lechuck.hackint.dn42} 30523
user_channels_memory{server=lechuck.hackint.dn42} 732552
users_away{server=lechuck.hackint.dn42} 496
users_away_memory{server=lechuck.hackint.dn42} 14377
local_client_conf_count{server=lechuck.hackint.dn42} 24
local_client_conf_memory{server=lechuck.hackint.dn42} 576
conf_count{server=lechuck.hackint.dn42} 0
conf_memory{server=lechuck.hackint.dn42} 0
classes_count{server=lechuck.hackint.dn42} 12
classes_memory{server=lechuck.hackint.dn42} 960
channels_count{server=lechuck.hackint.dn42} 1980
channels_memory{server=lechuck.hackint.dn42} 813460
channel_ban_count{server=lechuck.hackint.dn42} 826
channel_ban_memory{server=lechuck.hackint.dn42} 66080
channel_exceptions_count{server=lechuck.hackint.dn42} 31
channel_exceptions_memory{server=lechuck.hackint.dn42} 2480
channel_invex_count{server=lechuck.hackint.dn42} 553
channel_invex_memory{server=lechuck.hackint.dn42} 44240
channel_quiets_count{server=lechuck.hackint.dn42} 131
channel_quiets_memory{server=lechuck.hackint.dn42} 10480
channel_members{server=lechuck.hackint.dn42} 30523
channel_members_memory{server=lechuck.hackint.dn42} 732552
channel_invites_count{server=lechuck.hackint.dn42} 0
channel_invites_memory{server=lechuck.hackint.dn42} 0
whowas_count{server=lechuck.hackint.dn42} 15000
whowas_memory{server=lechuck.hackint.dn42} 5756896
hash_client_count{server=lechuck.hackint.dn42} 131072
hash_client_memory{server=lechuck.hackint.dn42} 3145728
hash_channel_count{server=lechuck.hackint.dn42} 65536
hash_channel_memory{server=lechuck.hackint.dn42} 1572864
linebuf_count{server=lechuck.hackint.dn42} 0
linebuf_memory{server=lechuck.hackint.dn42} 0
servers_cached_number{server=lechuck.hackint.dn42} 8
servers_cached_memory{server=lechuck.hackint.dn42} 1152
hostname_count{server=lechuck.hackint.dn42} 131072
hostname_memory{server=lechuck.hackint.dn42} 3145728
total_channel_memory{server=lechuck.hackint.dn42} 1612092
local_client_count{server=lechuck.hackint.dn42} 0
local_client_memory{server=lechuck.hackint.dn42} 0
remote_client_count{server=lechuck.hackint.dn42} 0
remote_client_memory{server=lechuck.hackint.dn42} 0
total{server=lechuck.hackint.dn42} 7371100
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment