- Resolves #1550 - Resolves #824 - Resolves #825 - Resolves #1131 - Resolves #1411 - Resolves #1256 - Resolve #1177 - Includes the `ShufflingId` struct initially defined in #1492. That PR is now closed and the changes are included here, with significant bug fixes. - Implement the https://github.com/ethereum/eth2.0-APIs in a new `http_api` crate using `warp`. This replaces the `rest_api` crate. - Add a new `common/eth2` crate which provides a wrapper around `reqwest`, providing the HTTP client that is used by the validator client and for testing. This replaces the `common/remote_beacon_node` crate. - Create a `http_metrics` crate which is a dedicated server for Prometheus metrics (they are no longer served on the same port as the REST API). We now have flags for `--metrics`, `--metrics-address`, etc. - Allow the `subnet_id` to be an optional parameter for `VerifiedUnaggregatedAttestation::verify`. This means it does not need to be provided unnecessarily by the validator client. - Move `fn map_attestation_committee` in `mod beacon_chain::attestation_verification` to a new `fn with_committee_cache` on the `BeaconChain` so the same cache can be used for obtaining validator duties. - Add some other helpers to `BeaconChain` to assist with common API duties (e.g., `block_root_at_slot`, `head_beacon_block_root`). - Change the `NaiveAggregationPool` so it can index attestations by `hash_tree_root(attestation.data)`. This is a requirement of the API. - Add functions to `BeaconChainHarness` to allow it to create slashings and exits. - Allow for `eth1::Eth1NetworkId` to go to/from a `String`. - Add functions to the `OperationPool` to allow getting all objects in the pool. - Add function to `BeaconState` to check if a committee cache is initialized. - Fix bug where `seconds_per_eth1_block` was not transferring over from `YamlConfig` to `ChainSpec`. - Add the `deposit_contract_address` to `YamlConfig` and `ChainSpec`. We needed to be able to return it in an API response. - Change some uses of serde `serialize_with` and `deserialize_with` to a single use of `with` (code quality). - Impl `Display` and `FromStr` for several BLS fields. - Check for clock discrepancy when VC polls BN for sync state (with +/- 1 slot tolerance). This is not intended to be comprehensive, it was just easy to do. - See #1434 for a per-endpoint overview. - Seeking clarity here: https://github.com/ethereum/eth2.0-APIs/issues/75 - [x] Add docs for prom port to close #1256 - [x] Follow up on this #1177 - [x] ~~Follow up with #1424~~ Will fix in future PR. - [x] Follow up with #1411 - [x] ~~Follow up with #1260~~ Will fix in future PR. - [x] Add quotes to all integers. - [x] Remove `rest_types` - [x] Address missing beacon block error. (#1629) - [x] ~~Add tests for lighthouse/peers endpoints~~ Wontfix - [x] ~~Follow up with validator status proposal~~ Tracked in #1434 - [x] Unify graffiti structs - [x] ~~Start server when waiting for genesis?~~ Will fix in future PR. - [x] TODO in http_api tests - [x] Move lighthouse endpoints off /eth/v1 - [x] Update docs to link to standard - ~~Blocked on #1586~~ Co-authored-by: Michael Sproul <michael@sigmaprime.io>
299 lines
9.5 KiB
Rust
299 lines
9.5 KiB
Rust
#![allow(clippy::needless_doctest_main)]
|
|
//! A wrapper around the `prometheus` crate that provides a global, `lazy_static` metrics registry
|
|
//! and functions to add and use the following components (more info at
|
|
//! [Prometheus docs](https://prometheus.io/docs/concepts/metric_types/)):
|
|
//!
|
|
//! - `Histogram`: used with `start_timer(..)` and `stop_timer(..)` to record durations (e.g.,
|
|
//! block processing time).
|
|
//! - `IncCounter`: used to represent an ideally ever-growing, never-shrinking integer (e.g.,
|
|
//! number of block processing requests).
|
|
//! - `IntGauge`: used to represent an varying integer (e.g., number of attestations per block).
|
|
//!
|
|
//! ## Important
|
|
//!
|
|
//! Metrics will fail if two items have the same `name`. All metrics must have a unique `name`.
|
|
//! Because we use a global registry there is no namespace per crate, it's one big global space.
|
|
//!
|
|
//! See the [Prometheus naming best practices](https://prometheus.io/docs/practices/naming/) when
|
|
//! choosing metric names.
|
|
//!
|
|
//! ## Example
|
|
//!
|
|
//! ```rust
|
|
//! #[macro_use]
|
|
//! extern crate lazy_static;
|
|
//! use lighthouse_metrics::*;
|
|
//!
|
|
//! // These metrics are "magically" linked to the global registry defined in `lighthouse_metrics`.
|
|
//! lazy_static! {
|
|
//! pub static ref RUN_COUNT: Result<IntCounter> = try_create_int_counter(
|
|
//! "runs_total",
|
|
//! "Total number of runs"
|
|
//! );
|
|
//! pub static ref CURRENT_VALUE: Result<IntGauge> = try_create_int_gauge(
|
|
//! "current_value",
|
|
//! "The current value"
|
|
//! );
|
|
//! pub static ref RUN_TIME: Result<Histogram> =
|
|
//! try_create_histogram("run_seconds", "Time taken (measured to high precision)");
|
|
//! }
|
|
//!
|
|
//!
|
|
//! fn main() {
|
|
//! for i in 0..100 {
|
|
//! inc_counter(&RUN_COUNT);
|
|
//! let timer = start_timer(&RUN_TIME);
|
|
//!
|
|
//! for j in 0..10 {
|
|
//! set_gauge(&CURRENT_VALUE, j);
|
|
//! println!("Howdy partner");
|
|
//! }
|
|
//!
|
|
//! stop_timer(timer);
|
|
//! }
|
|
//! }
|
|
//! ```
|
|
|
|
use prometheus::{HistogramOpts, HistogramTimer, Opts};
|
|
use std::time::Duration;
|
|
|
|
pub use prometheus::{
|
|
Encoder, Gauge, GaugeVec, Histogram, HistogramVec, IntCounter, IntCounterVec, IntGauge,
|
|
IntGaugeVec, Result, TextEncoder,
|
|
};
|
|
|
|
/// Collect all the metrics for reporting.
|
|
pub fn gather() -> Vec<prometheus::proto::MetricFamily> {
|
|
prometheus::gather()
|
|
}
|
|
|
|
/// Attempts to create an `IntCounter`, returning `Err` if the registry does not accept the counter
|
|
/// (potentially due to naming conflict).
|
|
pub fn try_create_int_counter(name: &str, help: &str) -> Result<IntCounter> {
|
|
let opts = Opts::new(name, help);
|
|
let counter = IntCounter::with_opts(opts)?;
|
|
prometheus::register(Box::new(counter.clone()))?;
|
|
Ok(counter)
|
|
}
|
|
|
|
/// Attempts to create an `IntGauge`, returning `Err` if the registry does not accept the counter
|
|
/// (potentially due to naming conflict).
|
|
pub fn try_create_int_gauge(name: &str, help: &str) -> Result<IntGauge> {
|
|
let opts = Opts::new(name, help);
|
|
let gauge = IntGauge::with_opts(opts)?;
|
|
prometheus::register(Box::new(gauge.clone()))?;
|
|
Ok(gauge)
|
|
}
|
|
|
|
/// Attempts to create a `Gauge`, returning `Err` if the registry does not accept the counter
|
|
/// (potentially due to naming conflict).
|
|
pub fn try_create_float_gauge(name: &str, help: &str) -> Result<Gauge> {
|
|
let opts = Opts::new(name, help);
|
|
let gauge = Gauge::with_opts(opts)?;
|
|
prometheus::register(Box::new(gauge.clone()))?;
|
|
Ok(gauge)
|
|
}
|
|
|
|
/// Attempts to create a `Histogram`, returning `Err` if the registry does not accept the counter
|
|
/// (potentially due to naming conflict).
|
|
pub fn try_create_histogram(name: &str, help: &str) -> Result<Histogram> {
|
|
let opts = HistogramOpts::new(name, help);
|
|
let histogram = Histogram::with_opts(opts)?;
|
|
prometheus::register(Box::new(histogram.clone()))?;
|
|
Ok(histogram)
|
|
}
|
|
|
|
/// Attempts to create a `HistogramVec`, returning `Err` if the registry does not accept the counter
|
|
/// (potentially due to naming conflict).
|
|
pub fn try_create_histogram_vec(
|
|
name: &str,
|
|
help: &str,
|
|
label_names: &[&str],
|
|
) -> Result<HistogramVec> {
|
|
let opts = HistogramOpts::new(name, help);
|
|
let histogram_vec = HistogramVec::new(opts, label_names)?;
|
|
prometheus::register(Box::new(histogram_vec.clone()))?;
|
|
Ok(histogram_vec)
|
|
}
|
|
|
|
/// Attempts to create a `IntGaugeVec`, returning `Err` if the registry does not accept the gauge
|
|
/// (potentially due to naming conflict).
|
|
pub fn try_create_int_gauge_vec(
|
|
name: &str,
|
|
help: &str,
|
|
label_names: &[&str],
|
|
) -> Result<IntGaugeVec> {
|
|
let opts = Opts::new(name, help);
|
|
let counter_vec = IntGaugeVec::new(opts, label_names)?;
|
|
prometheus::register(Box::new(counter_vec.clone()))?;
|
|
Ok(counter_vec)
|
|
}
|
|
|
|
/// Attempts to create a `GaugeVec`, returning `Err` if the registry does not accept the gauge
|
|
/// (potentially due to naming conflict).
|
|
pub fn try_create_float_gauge_vec(
|
|
name: &str,
|
|
help: &str,
|
|
label_names: &[&str],
|
|
) -> Result<GaugeVec> {
|
|
let opts = Opts::new(name, help);
|
|
let counter_vec = GaugeVec::new(opts, label_names)?;
|
|
prometheus::register(Box::new(counter_vec.clone()))?;
|
|
Ok(counter_vec)
|
|
}
|
|
|
|
/// Attempts to create a `IntGaugeVec`, returning `Err` if the registry does not accept the gauge
|
|
/// (potentially due to naming conflict).
|
|
pub fn try_create_int_counter_vec(
|
|
name: &str,
|
|
help: &str,
|
|
label_names: &[&str],
|
|
) -> Result<IntCounterVec> {
|
|
let opts = Opts::new(name, help);
|
|
let counter_vec = IntCounterVec::new(opts, label_names)?;
|
|
prometheus::register(Box::new(counter_vec.clone()))?;
|
|
Ok(counter_vec)
|
|
}
|
|
|
|
/// If `int_gauge_vec.is_ok()`, returns a gauge with the given `name`.
|
|
pub fn get_int_gauge(int_gauge_vec: &Result<IntGaugeVec>, name: &[&str]) -> Option<IntGauge> {
|
|
if let Ok(int_gauge_vec) = int_gauge_vec {
|
|
Some(int_gauge_vec.get_metric_with_label_values(name).ok()?)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// If `int_gauge_vec.is_ok()`, sets the gauge with the given `name` to the given `value`
|
|
/// otherwise returns false.
|
|
pub fn set_int_gauge(int_gauge_vec: &Result<IntGaugeVec>, name: &[&str], value: i64) -> bool {
|
|
if let Ok(int_gauge_vec) = int_gauge_vec {
|
|
int_gauge_vec
|
|
.get_metric_with_label_values(name)
|
|
.map(|v| {
|
|
v.set(value);
|
|
true
|
|
})
|
|
.unwrap_or_else(|_| false)
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
|
|
/// If `int_counter_vec.is_ok()`, returns a counter with the given `name`.
|
|
pub fn get_int_counter(
|
|
int_counter_vec: &Result<IntCounterVec>,
|
|
name: &[&str],
|
|
) -> Option<IntCounter> {
|
|
if let Ok(int_counter_vec) = int_counter_vec {
|
|
Some(int_counter_vec.get_metric_with_label_values(name).ok()?)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Increments the `int_counter_vec` with the given `name`.
|
|
pub fn inc_counter_vec(int_counter_vec: &Result<IntCounterVec>, name: &[&str]) {
|
|
if let Some(counter) = get_int_counter(int_counter_vec, name) {
|
|
counter.inc()
|
|
}
|
|
}
|
|
|
|
/// If `histogram_vec.is_ok()`, returns a histogram with the given `name`.
|
|
pub fn get_histogram(histogram_vec: &Result<HistogramVec>, name: &[&str]) -> Option<Histogram> {
|
|
if let Ok(histogram_vec) = histogram_vec {
|
|
Some(histogram_vec.get_metric_with_label_values(name).ok()?)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Starts a timer on `vec` with the given `name`.
|
|
pub fn start_timer_vec(vec: &Result<HistogramVec>, name: &[&str]) -> Option<HistogramTimer> {
|
|
get_histogram(vec, name).map(|h| h.start_timer())
|
|
}
|
|
|
|
/// Starts a timer for the given `Histogram`, stopping when it gets dropped or given to `stop_timer(..)`.
|
|
pub fn start_timer(histogram: &Result<Histogram>) -> Option<HistogramTimer> {
|
|
if let Ok(histogram) = histogram {
|
|
Some(histogram.start_timer())
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Starts a timer on `vec` with the given `name`.
|
|
pub fn observe_timer_vec(vec: &Result<HistogramVec>, name: &[&str], duration: Duration) {
|
|
// This conversion was taken from here:
|
|
//
|
|
// https://docs.rs/prometheus/0.5.0/src/prometheus/histogram.rs.html#550-555
|
|
let nanos = f64::from(duration.subsec_nanos()) / 1e9;
|
|
let secs = duration.as_secs() as f64 + nanos;
|
|
|
|
if let Some(h) = get_histogram(vec, name) {
|
|
h.observe(secs)
|
|
}
|
|
}
|
|
|
|
/// Stops a timer created with `start_timer(..)`.
|
|
pub fn stop_timer(timer: Option<HistogramTimer>) {
|
|
if let Some(t) = timer {
|
|
t.observe_duration()
|
|
}
|
|
}
|
|
|
|
pub fn inc_counter(counter: &Result<IntCounter>) {
|
|
if let Ok(counter) = counter {
|
|
counter.inc();
|
|
}
|
|
}
|
|
|
|
pub fn inc_counter_by(counter: &Result<IntCounter>, value: i64) {
|
|
if let Ok(counter) = counter {
|
|
counter.inc_by(value);
|
|
}
|
|
}
|
|
|
|
pub fn set_gauge(gauge: &Result<IntGauge>, value: i64) {
|
|
if let Ok(gauge) = gauge {
|
|
gauge.set(value);
|
|
}
|
|
}
|
|
|
|
pub fn set_float_gauge(gauge: &Result<Gauge>, value: f64) {
|
|
if let Ok(gauge) = gauge {
|
|
gauge.set(value);
|
|
}
|
|
}
|
|
|
|
pub fn inc_gauge(gauge: &Result<IntGauge>) {
|
|
if let Ok(gauge) = gauge {
|
|
gauge.inc();
|
|
}
|
|
}
|
|
|
|
pub fn dec_gauge(gauge: &Result<IntGauge>) {
|
|
if let Ok(gauge) = gauge {
|
|
gauge.dec();
|
|
}
|
|
}
|
|
|
|
pub fn maybe_set_gauge(gauge: &Result<IntGauge>, value_opt: Option<i64>) {
|
|
if let Some(value) = value_opt {
|
|
set_gauge(gauge, value)
|
|
}
|
|
}
|
|
|
|
pub fn maybe_set_float_gauge(gauge: &Result<Gauge>, value_opt: Option<f64>) {
|
|
if let Some(value) = value_opt {
|
|
set_float_gauge(gauge, value)
|
|
}
|
|
}
|
|
|
|
/// Sets the value of a `Histogram` manually.
|
|
pub fn observe(histogram: &Result<Histogram>, value: f64) {
|
|
if let Ok(histogram) = histogram {
|
|
histogram.observe(value);
|
|
}
|
|
}
|