diff --git a/Cargo.lock b/Cargo.lock index 35eb6480..6eb08255 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2297,6 +2297,8 @@ name = "dashboard_gen" version = "0.1.0" dependencies = [ "json-pretty-compact", + "sequencer_core_metrics", + "sequencer_service_metrics", "serde", "serde_json", ] @@ -9503,16 +9505,15 @@ dependencies = [ "logos-blockchain-key-management-system-service", "logos-blockchain-zone-sdk", "mempool", - "metrics", "num-bigint 0.4.6", "ping_core", "programs", "rand 0.8.6", "risc0-zkvm", + "sequencer_core_metrics", "serde", "serde_json", "storage", - "strum 0.28.0", "system_accounts", "tempfile", "test_programs", @@ -9524,6 +9525,15 @@ dependencies = [ "vault_core", ] +[[package]] +name = "sequencer_core_metrics" +version = "0.1.0" +dependencies = [ + "common", + "metrics", + "strum 0.28.0", +] + [[package]] name = "sequencer_service" version = "0.1.0" @@ -9540,16 +9550,23 @@ dependencies = [ "lee", "log", "mempool", - "metrics", "metrics-exporter-prometheus", "programs", "sequencer_core", + "sequencer_service_metrics", "sequencer_service_protocol", "sequencer_service_rpc", "tokio", "tokio-util", ] +[[package]] +name = "sequencer_service_metrics" +version = "0.1.0" +dependencies = [ + "metrics", +] + [[package]] name = "sequencer_service_protocol" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 467dd9dd..d5ebbe48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,11 @@ members = [ "lez/system_accounts", "lez/chain_state", "lez/sequencer/core", + "lez/sequencer/core/metrics", "lez/sequencer/service", "lez/sequencer/service/protocol", "lez/sequencer/service/rpc", + "lez/sequencer/service/metrics", "lez/indexer/core", "lez/indexer/service", "lez/indexer/service/protocol", @@ -79,8 +81,10 @@ mempool = { path = "lez/mempool" } storage = { path = "lez/storage" } key_protocol = { path = "lee/key_protocol" } sequencer_core = { path = "lez/sequencer/core" } +sequencer_core_metrics = { path = "lez/sequencer/core/metrics" } sequencer_service_protocol = { path = "lez/sequencer/service/protocol" } sequencer_service_rpc = { path = "lez/sequencer/service/rpc" } +sequencer_service_metrics = { path = "lez/sequencer/service/metrics" } sequencer_service = { path = "lez/sequencer/service" } indexer_core = { path = "lez/indexer/core" } indexer_service = { path = "lez/indexer/service" } diff --git a/lez/sequencer/core/Cargo.toml b/lez/sequencer/core/Cargo.toml index 41b70fca..08f359f7 100644 --- a/lez/sequencer/core/Cargo.toml +++ b/lez/sequencer/core/Cargo.toml @@ -12,6 +12,7 @@ lee.workspace = true lee_core.workspace = true chain_state.workspace = true common.workspace = true +sequencer_core_metrics = { workspace = true, features = ["writing"] } storage.workspace = true mempool.workspace = true logos-blockchain-zone-sdk.workspace = true @@ -34,7 +35,6 @@ humantime-serde.workspace = true tempfile.workspace = true chrono.workspace = true log.workspace = true -metrics.workspace = true tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } tokio-util.workspace = true rand.workspace = true @@ -46,7 +46,6 @@ num-bigint.workspace = true risc0-zkvm.workspace = true futures.workspace = true itertools.workspace = true -strum.workspace = true [features] default = [] diff --git a/lez/sequencer/core/metrics/Cargo.toml b/lez/sequencer/core/metrics/Cargo.toml new file mode 100644 index 00000000..541102b4 --- /dev/null +++ b/lez/sequencer/core/metrics/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "sequencer_core_metrics" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[lints] +workspace = true + +[features] +default = [] +# Enable metrics writing +writing = ["dep:common", "dep:metrics", "dep:strum"] + +[dependencies] +common = { workspace = true, optional = true } + +metrics = { workspace = true, optional = true } +strum = { workspace = true, optional = true } diff --git a/lez/sequencer/core/metrics/src/lib.rs b/lez/sequencer/core/metrics/src/lib.rs new file mode 100644 index 00000000..b633f2d2 --- /dev/null +++ b/lez/sequencer/core/metrics/src/lib.rs @@ -0,0 +1,9 @@ +//! This crate provides all metrics exposed by the sequencer core crate. + +#[cfg(feature = "writing")] +pub use writing::*; + +pub mod names; + +#[cfg(feature = "writing")] +pub mod writing; diff --git a/lez/sequencer/core/metrics/src/names.rs b/lez/sequencer/core/metrics/src/names.rs new file mode 100644 index 00000000..1ea87c26 --- /dev/null +++ b/lez/sequencer/core/metrics/src/names.rs @@ -0,0 +1,6 @@ +pub const BLOCK_CREATION_TIME: &str = "block_creation_time"; +pub const BLOCK_COUNT: &str = "block_count"; +pub const MEMPOOL_SIZE: &str = "mempool_size"; +pub const MEMPOOL_TRANSACTION_APPLICATION_TIME: &str = "mempool_transaction_application_time"; +pub const TRANSACTIONS_PER_BLOCK: &str = "transactions_per_block"; +pub const FAILED_TRANSACTION_COUNT: &str = "failed_transaction_count"; diff --git a/lez/sequencer/core/src/metrics.rs b/lez/sequencer/core/metrics/src/writing.rs similarity index 79% rename from lez/sequencer/core/src/metrics.rs rename to lez/sequencer/core/metrics/src/writing.rs index a6c79454..2a392b84 100644 --- a/lez/sequencer/core/src/metrics.rs +++ b/lez/sequencer/core/metrics/src/writing.rs @@ -1,5 +1,3 @@ -//! This module provides all metrics exposed by the sequencer core crate. - #![expect( clippy::cast_precision_loss, clippy::as_conversions, @@ -11,15 +9,12 @@ use std::time::Duration; use common::transaction::TxKind; use metrics::{Counter, Unit, counter, gauge, histogram}; -use crate::TransactionOrigin; +use crate::names; -mod names { - pub const BLOCK_CREATION_TIME: &str = "block_creation_time"; - pub const BLOCK_COUNT: &str = "block_count"; - pub const MEMPOOL_SIZE: &str = "mempool_size"; - pub const MEMPOOL_TRANSACTION_APPLICATION_TIME: &str = "mempool_transaction_application_time"; - pub const TRANSACTIONS_PER_BLOCK: &str = "transactions_per_block"; - pub const FAILED_TRANSACTION_COUNT: &str = "failed_transaction_count"; +#[derive(Clone, Copy, strum::IntoStaticStr)] +pub enum TransactionOrigin { + User, + Sequencer, } pub fn record_block_creation_time(duration: Duration) { diff --git a/lez/sequencer/core/src/lib.rs b/lez/sequencer/core/src/lib.rs index a56b3c88..7cbe8fa7 100644 --- a/lez/sequencer/core/src/lib.rs +++ b/lez/sequencer/core/src/lib.rs @@ -50,7 +50,6 @@ pub mod block_publisher; pub mod block_store; pub mod config; pub mod cross_zone_watcher; -mod metrics; #[cfg(feature = "mock")] pub mod mock; @@ -73,7 +72,7 @@ const RETIRE_DISPATCH_AFTER_FAILURES: u32 = 3; const MAX_DISPATCHES_PER_BLOCK: usize = 16; /// The origin of a transaction. -#[derive(Clone, Copy, strum::IntoStaticStr)] +#[derive(Clone, Copy)] pub enum TransactionOrigin { /// Basic transactions submitted by users via RPC. User, @@ -81,6 +80,15 @@ pub enum TransactionOrigin { Sequencer, } +impl From for sequencer_core_metrics::TransactionOrigin { + fn from(origin: TransactionOrigin) -> Self { + match origin { + TransactionOrigin::User => Self::User, + TransactionOrigin::Sequencer => Self::Sequencer, + } + } +} + #[derive(Clone, Debug, BorshDeserialize)] struct DepositMetadata { recipient_id: lee::AccountId, @@ -300,7 +308,7 @@ impl SequencerCore { watchers, }; - crate::metrics::set_block_count(sequencer_core.chain_height()); + sequencer_core_metrics::set_block_count(sequencer_core.chain_height()); (sequencer_core, mempool_handle) } @@ -805,7 +813,7 @@ impl SequencerCore { let clock_tx = clock_invocation(new_block_timestamp); let clock_lee_tx = LeeTransaction::Public(clock_tx.clone()); - crate::metrics::record_mempool_size(self.mempool.len()); + sequencer_core_metrics::record_mempool_size(self.mempool.len()); // Everything drained from the store first, then user work. `from_store` // is not the same as a `Sequencer` origin: it says the transaction has a // record behind it and so needs no requeue, where the origin only says @@ -885,8 +893,8 @@ impl SequencerCore { new_block_timestamp, &mut withdrawals, ); - crate::metrics::record_mempool_transaction_application_time( - origin, + sequencer_core_metrics::record_mempool_transaction_application_time( + origin.into(), tx.kind(), before_tx_apply.elapsed(), ); @@ -894,7 +902,7 @@ impl SequencerCore { if applied { valid_transactions.push(tx); } else { - crate::metrics::increment_failed_transaction_count(); + sequencer_core_metrics::increment_failed_transaction_count(); // A failed transaction is simply left out of the block, except a // dispatch: that one is re-fed from the store every turn, so one // that can never execute would fail on every block for ever. @@ -910,7 +918,7 @@ impl SequencerCore { .transition_from_public_transaction(&clock_tx, new_block_height, new_block_timestamp) .context("Clock transaction failed. Aborting block production.")?; valid_transactions.push(clock_lee_tx); - crate::metrics::record_transactions_per_block(valid_transactions.len()); + sequencer_core_metrics::record_transactions_per_block(valid_transactions.len()); let hashable_data = HashableBlockData { block_id: new_block_height, @@ -929,8 +937,8 @@ impl SequencerCore { now.elapsed().as_secs() ); - crate::metrics::record_block_creation_time(now.elapsed()); - crate::metrics::increment_block_count(); + sequencer_core_metrics::record_block_creation_time(now.elapsed()); + sequencer_core_metrics::increment_block_count(); Ok(BlockWithMeta { block, withdrawals }) } diff --git a/lez/sequencer/service/Cargo.toml b/lez/sequencer/service/Cargo.toml index 03400935..0b936e8b 100644 --- a/lez/sequencer/service/Cargo.toml +++ b/lez/sequencer/service/Cargo.toml @@ -15,6 +15,7 @@ mempool.workspace = true sequencer_core = { workspace = true, features = ["testnet"] } sequencer_service_protocol.workspace = true sequencer_service_rpc = { workspace = true, features = ["server"] } +sequencer_service_metrics = { workspace = true, features = ["writing"] } programs.workspace = true clap = { workspace = true, features = ["derive", "env"] } @@ -22,7 +23,6 @@ anyhow.workspace = true env_logger.workspace = true hex.workspace = true log.workspace = true -metrics.workspace = true metrics-exporter-prometheus.workspace = true tokio.workspace = true tokio-util.workspace = true diff --git a/lez/sequencer/service/metrics/Cargo.toml b/lez/sequencer/service/metrics/Cargo.toml new file mode 100644 index 00000000..4e242db4 --- /dev/null +++ b/lez/sequencer/service/metrics/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "sequencer_service_metrics" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[lints] +workspace = true + +[features] +default = [] +# Enable metrics writing +writing = ["dep:metrics"] + +[dependencies] +metrics = { workspace = true, optional = true } diff --git a/lez/sequencer/service/metrics/src/lib.rs b/lez/sequencer/service/metrics/src/lib.rs new file mode 100644 index 00000000..b633f2d2 --- /dev/null +++ b/lez/sequencer/service/metrics/src/lib.rs @@ -0,0 +1,9 @@ +//! This crate provides all metrics exposed by the sequencer core crate. + +#[cfg(feature = "writing")] +pub use writing::*; + +pub mod names; + +#[cfg(feature = "writing")] +pub mod writing; diff --git a/lez/sequencer/service/metrics/src/names.rs b/lez/sequencer/service/metrics/src/names.rs new file mode 100644 index 00000000..8bf61acb --- /dev/null +++ b/lez/sequencer/service/metrics/src/names.rs @@ -0,0 +1 @@ +pub const SUBMITTED_TRANSACTION_COUNT: &str = "submitted_transaction_count"; diff --git a/lez/sequencer/service/src/metrics.rs b/lez/sequencer/service/metrics/src/writing.rs similarity index 59% rename from lez/sequencer/service/src/metrics.rs rename to lez/sequencer/service/metrics/src/writing.rs index 27cd47d1..3b625006 100644 --- a/lez/sequencer/service/src/metrics.rs +++ b/lez/sequencer/service/metrics/src/writing.rs @@ -1,10 +1,6 @@ -//! This module provides all metrics exposed by the sequencer service crate. - use metrics::{Unit, counter}; -mod names { - pub const SUBMITTED_TRANSACTION_COUNT: &str = "submitted_transaction_count"; -} +use crate::names; pub fn increment_submitted_transaction_count() { counter!( diff --git a/lez/sequencer/service/src/lib.rs b/lez/sequencer/service/src/lib.rs index 5624cc91..ba5b68ec 100644 --- a/lez/sequencer/service/src/lib.rs +++ b/lez/sequencer/service/src/lib.rs @@ -21,7 +21,6 @@ use sequencer_service_rpc::RpcServer as _; use tokio::{sync::Mutex, task::JoinHandle}; use tokio_util::sync::CancellationToken; -mod metrics; pub mod service; const REQUEST_BODY_MAX_SIZE: ByteSize = ByteSize::mib(10); diff --git a/lez/sequencer/service/src/service.rs b/lez/sequencer/service/src/service.rs index d9eaf97f..309c9949 100644 --- a/lez/sequencer/service/src/service.rs +++ b/lez/sequencer/service/src/service.rs @@ -93,7 +93,7 @@ impl sequencer_service_rpc::Rpc .await .expect("Mempool is closed, this is a bug"); - crate::metrics::increment_submitted_transaction_count(); + sequencer_service_metrics::increment_submitted_transaction_count(); Ok(tx_hash) } diff --git a/tools/dashboard_gen/Cargo.toml b/tools/dashboard_gen/Cargo.toml index a21916e1..1a167db6 100644 --- a/tools/dashboard_gen/Cargo.toml +++ b/tools/dashboard_gen/Cargo.toml @@ -8,6 +8,9 @@ license = { workspace = true } workspace = true [dependencies] +sequencer_core_metrics.workspace = true +sequencer_service_metrics.workspace = true + serde = { workspace = true, features = ["derive", "alloc"] } serde_json.workspace = true json-pretty-compact = "0.1.2" diff --git a/tools/dashboard_gen/src/bin/gen_sequencer_dashboard.rs b/tools/dashboard_gen/src/bin/gen_sequencer_dashboard.rs index 22a4b8ee..8c1a9321 100644 --- a/tools/dashboard_gen/src/bin/gen_sequencer_dashboard.rs +++ b/tools/dashboard_gen/src/bin/gen_sequencer_dashboard.rs @@ -16,18 +16,6 @@ use dashboard_gen::{ use json_pretty_compact::PrettyCompactFormatter; use serde::Serialize as _; -// Rendered Prometheus metric names. In a real setup these would be re-exported -// from `sequencer_core::metrics` (base name + unit/counter suffix rule) so that -// a rename in the recorder is a compile error here — that is the whole point of -// generating dashboards from the same codebase that emits the metrics. -const BLOCK_COUNT: &str = "block_count_total"; -const BLOCK_CREATION_TIME: &str = "block_creation_time_seconds"; -const TX_APPLY_TIME: &str = "mempool_transaction_application_time_seconds"; -const MEMPOOL_SIZE: &str = "mempool_size"; -const TX_PER_BLOCK: &str = "transactions_per_block"; -const SUBMITTED_TX: &str = "submitted_transaction_count_total"; -const FAILED_TX: &str = "failed_transaction_count_total"; - const PERCENTILES: &[u32] = &[50, 90, 95, 99]; fn sequencer_dashboard() -> Dashboard { @@ -41,11 +29,16 @@ fn sequencer_dashboard() -> Dashboard { .unit("short") .decimals(0) .color(Color::fixed("blue")) - .target(Target::new(BLOCK_COUNT).legend("height")), + .target( + Target::new(sequencer_core_metrics::names::BLOCK_COUNT).legend("height"), + ), Panel::timeseries("Block production rate") .width(18) .unit("short") - .target(rate_per_min(BLOCK_COUNT, "blocks/min")), + .target(rate_per_min( + sequencer_core_metrics::names::BLOCK_COUNT, + "blocks/min", + )), ], ) .row( @@ -53,8 +46,11 @@ fn sequencer_dashboard() -> Dashboard { [Panel::timeseries("Block creation time") .width(24) .unit("s") - .targets(percentiles(BLOCK_CREATION_TIME, PERCENTILES)) - .target(avg(BLOCK_CREATION_TIME)) + .targets(percentiles( + sequencer_core_metrics::names::BLOCK_CREATION_TIME, + PERCENTILES, + )) + .target(avg(sequencer_core_metrics::names::BLOCK_CREATION_TIME)) .with_override( FieldOverride::by_name("avg") .dashed_line() @@ -68,7 +64,7 @@ fn sequencer_dashboard() -> Dashboard { .width(12) .unit("s") .targets(percentiles_labeled( - TX_APPLY_TIME, + sequencer_core_metrics::names::MEMPOOL_TRANSACTION_APPLICATION_TIME, PERCENTILES, " · {{kind}} · {{origin}}", )), @@ -76,7 +72,10 @@ fn sequencer_dashboard() -> Dashboard { .width(12) .unit("short") .span_nulls() - .target(Target::new(MEMPOOL_SIZE).legend("mempool size")), + .target( + Target::new(sequencer_core_metrics::names::MEMPOOL_SIZE) + .legend("mempool size"), + ), ], ) .row( @@ -85,8 +84,11 @@ fn sequencer_dashboard() -> Dashboard { Panel::timeseries("Transactions per block") .width(12) .unit("short") - .targets(percentiles(TX_PER_BLOCK, PERCENTILES)) - .target(avg(TX_PER_BLOCK)) + .targets(percentiles( + sequencer_core_metrics::names::TRANSACTIONS_PER_BLOCK, + PERCENTILES, + )) + .target(avg(sequencer_core_metrics::names::TRANSACTIONS_PER_BLOCK)) .with_override( FieldOverride::by_name("avg") .dashed_line() @@ -95,8 +97,14 @@ fn sequencer_dashboard() -> Dashboard { Panel::timeseries("Transaction throughput (per minute)") .width(12) .unit("short") - .target(rate_per_min(SUBMITTED_TX, "submitted")) - .target(rate_per_min(FAILED_TX, "failed")) + .target(rate_per_min( + sequencer_service_metrics::names::SUBMITTED_TRANSACTION_COUNT, + "submitted", + )) + .target(rate_per_min( + sequencer_core_metrics::names::FAILED_TRANSACTION_COUNT, + "failed", + )) .with_override(FieldOverride::by_name("failed").color(Color::fixed("red"))) .with_override( FieldOverride::by_name("submitted").color(Color::fixed("green")),