-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Export gossip with macro #73
base: prometheus
Are you sure you want to change the base?
Changes from all commits
5e080e1
15ded10
8b20faf
b0f40a1
a728409
5332470
906f67c
3a958c3
ba68332
d734527
f528d3e
253ac1c
ecd70c1
2d09704
bfc1328
ad78d65
aedcbe4
ddf4cdf
78fe0c8
2a861d9
390a8c5
399e9e1
2aebf10
b7e4d96
9d97a4e
f25093e
e224e52
ad69c55
f9727f3
11a6f7f
3a1fad8
c5421d1
0888bc4
d7045e7
da01458
e432aae
b711766
e45bbac
ac132cf
980fb16
d46b45a
0af8d74
eb9f025
db9b7f7
dccf07d
3109cbf
8f54039
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "solana-prometheus" | ||
version = "1.10.28" | ||
description = "Solana Prometheus" | ||
authors = ["ChorusOne <[email protected]>"] | ||
repository = "https://github.com/ChorusOne/solana" | ||
license = "Apache-2.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
jsonrpc-http-server = "18.0.0" | ||
solana-gossip = { path = "../gossip" } | ||
solana-runtime = { path = "../runtime" } | ||
solana-sdk = { path = "../sdk" } | ||
solana-vote-program = { path = "../programs/vote" } | ||
solana-prometheus-utils = { path = "utils" } | ||
|
||
[lib] | ||
crate-type = ["lib"] | ||
name = "solana_prometheus" | ||
|
||
[package.metadata.docs.rs] | ||
targets = ["x86_64-unknown-linux-gnu"] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "solana-prometheus-macro" | ||
version = "1.0.0" | ||
description = "Solana Prometheus" | ||
authors = ["ChorusOne <[email protected]>"] | ||
repository = "https://github.com/ChorusOne/solana" | ||
license = "Apache-2.0" | ||
edition = "2021" | ||
|
||
|
||
[lib] | ||
proc-macro = true | ||
|
||
[dependencies] | ||
bs58 = "0.4.0" | ||
proc-macro2 = "1.0.19" | ||
quote = "1.0" | ||
syn = { version = "1.0", features = ["full", "extra-traits"] } | ||
rustversion = "1.0.3" | ||
solana-prometheus-utils = { path = "../utils" } | ||
|
||
[package.metadata.docs.rs] | ||
targets = ["x86_64-unknown-linux-gnu"] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
extern crate proc_macro2; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool idea to make a macro for this! It’s a nice approach on the definition side, and the macro itself looks pretty simple too, nice. |
||
|
||
use proc_macro::TokenStream; | ||
#[macro_use] | ||
extern crate quote; | ||
|
||
#[proc_macro_derive(ExportPrometheus)] | ||
pub fn derive_field_count(input: TokenStream) -> TokenStream { | ||
// Parse the input tokens into a syntax tree | ||
let ast = syn::parse(input).unwrap(); | ||
parse(&ast) | ||
} | ||
|
||
fn parse(ast: &syn::DeriveInput) -> TokenStream { | ||
let name = &ast.ident; | ||
let data = &ast.data; | ||
|
||
let idents: Vec<_> = match data { | ||
syn::Data::Struct(struct_data) => struct_data | ||
.fields | ||
.iter() | ||
.filter_map(|field| field.ident.as_ref().map(|ident| ident)) | ||
.collect(), | ||
_ => panic!("Should be derived from struct"), | ||
}; | ||
|
||
let expanded = quote! { | ||
impl #name { | ||
pub fn write_prometheus<W: std::io::Write>(&self, out: &mut W) -> std::io::Result<()> { | ||
use core::sync::atomic::Ordering; | ||
#(solana_prometheus_utils::write_metric( | ||
out, | ||
&solana_prometheus_utils::MetricFamily { | ||
name: &format!("solana_gossip_{}", stringify!(#idents)), | ||
help: "Auto generated with Prometheus macro", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to get the doc comment from the field and put it here? Doc comments are secretly attributes, but I don’t know if Or maybe alternatively, we should require a |
||
type_: "counter", | ||
metrics: vec![solana_prometheus_utils::Metric::new(self.#idents.0.load(Ordering::Relaxed))], | ||
}, | ||
)?;)* | ||
Ok(()) | ||
} | ||
} | ||
}; | ||
expanded.into() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use crate::banks_with_commitments::BanksWithCommitments; | ||
use solana_prometheus_utils::{write_metric, Metric, MetricFamily}; | ||
use solana_sdk::sysvar; | ||
use solana_sdk::sysvar::epoch_schedule::EpochSchedule; | ||
use std::io; | ||
|
||
pub fn write_bank_metrics<W: io::Write>( | ||
banks_with_commitments: &BanksWithCommitments, | ||
out: &mut W, | ||
) -> io::Result<()> { | ||
write_metric( | ||
out, | ||
&MetricFamily { | ||
name: "solana_block_slot", | ||
help: "Block Slot", | ||
type_: "gauge", | ||
metrics: banks_with_commitments | ||
.for_each_commitment(|bank| Some(Metric::new(bank.clock().slot))), | ||
}, | ||
)?; | ||
write_metric( | ||
out, | ||
&MetricFamily { | ||
name: "solana_block_epoch", | ||
help: "Block Epoch", | ||
type_: "gauge", | ||
metrics: banks_with_commitments | ||
.for_each_commitment(|bank| Some(Metric::new(bank.clock().epoch))), | ||
}, | ||
)?; | ||
write_metric( | ||
out, | ||
&MetricFamily { | ||
name: "solana_block_epoch_start_slot", | ||
help: "The first slot in the current epoch", | ||
type_: "gauge", | ||
metrics: banks_with_commitments | ||
.for_each_commitment(|bank| { | ||
// Note, the bank actually has a field that holds the EpochSchedule, | ||
// but it is not public, so we can't easily access it here. We could | ||
// make it public, but to make our patches less invasive, load the | ||
// epoch schedule from the sysvar instead. It should always exist. | ||
let epoch_schedule: EpochSchedule = bank | ||
.get_account(&sysvar::epoch_schedule::id())? | ||
.deserialize_data().ok()?; | ||
let clock = bank.clock(); | ||
Some(Metric::new(epoch_schedule.get_first_slot_in_epoch(clock.epoch))) | ||
}), | ||
}, | ||
)?; | ||
write_metric( | ||
out, | ||
&MetricFamily { | ||
name: "solana_block_epoch_slots_total", | ||
help: "The duration of the current epoch, in slots.", | ||
type_: "gauge", | ||
metrics: banks_with_commitments | ||
.for_each_commitment(|bank| { | ||
// Note, the bank actually has a field that holds the EpochSchedule, | ||
// but it is not public, so we can't easily access it here. We could | ||
// make it public, but to make our patches less invasive, load the | ||
// epoch schedule from the sysvar instead. It should always exist. | ||
let epoch_schedule: EpochSchedule = bank | ||
.get_account(&sysvar::epoch_schedule::id())? | ||
.deserialize_data().ok()?; | ||
let clock = bank.clock(); | ||
Some(Metric::new(epoch_schedule.get_slots_in_epoch(clock.epoch))) | ||
}), | ||
}, | ||
)?; | ||
write_metric( | ||
out, | ||
&MetricFamily { | ||
name: "solana_block_timestamp_seconds", | ||
help: "The block's UNIX timestamp, in seconds since epoch, UTC", | ||
type_: "gauge", | ||
metrics: banks_with_commitments | ||
.for_each_commitment(|bank| Some(Metric::new(bank.clock().unix_timestamp as u64))), | ||
}, | ||
)?; | ||
|
||
Ok(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So ”submit” actually resets the counters?
I can think of two ways to make this work upstream.
GossipStats
holds only counters, we could implementstd::ops::Sub
for it, and keep two instances of it: the current stats, and the last logged stats. Then when it is time to log, we logcurrent - last_logged
, and then setlast_logged = current
. That way the metrics remain increasing for Prometheus, and the log output remains unchanged.I think option 2 is kind of neat. It’s a bit more tedious in the
GossipStats
, but it may be simpler in the end than threading a CLI flag through everything to this point. And it’s nicer to not have to choose.