Skip to content
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

Add metrics to gas price service #2635

Merged
merged 9 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added
- [2635](https://github.com/FuelLabs/fuel-core/pull/2635): Add metrics to gas price service

### Changed
- [2387](https://github.com/FuelLabs/fuel-core/pull/2387): Update description `tx-max-depth` flag.
- [2630](https://github.com/FuelLabs/fuel-core/pull/2630): Removed some noisy `tracing::info!` logs
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 98 additions & 0 deletions crates/metrics/src/gas_price_metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use crate::global_registry;
use prometheus_client::metrics::gauge::Gauge;
use std::sync::OnceLock;

#[derive(Debug)]
pub struct GasPriceMetrics {
pub real_gas_price: Gauge,
pub exec_gas_price: Gauge,
pub da_gas_price: Gauge,
pub total_reward: Gauge,
pub total_known_costs: Gauge,
pub predicted_profit: Gauge,
pub unrecorded_bytes: Gauge,
pub latest_cost_per_byte: Gauge,
pub recorded_height: Gauge,
}

impl Default for GasPriceMetrics {
fn default() -> Self {
let real_gas_price = Gauge::default();
let exec_gas_price = Gauge::default();
let da_gas_price = Gauge::default();
let total_reward = Gauge::default();
let total_known_costs = Gauge::default();
let predicted_profit = Gauge::default();
let unrecorded_bytes = Gauge::default();
let latest_cost_per_byte = Gauge::default();
let recorded_height = Gauge::default();

let metrics = GasPriceMetrics {
real_gas_price,
exec_gas_price,
da_gas_price,
total_reward,
total_known_costs,
predicted_profit,
unrecorded_bytes,
latest_cost_per_byte,
recorded_height,
};

let mut registry = global_registry().registry.lock();
registry.register(
"gas_price_service_real_gas_price",
"The real gas price used on the most recent block",
metrics.real_gas_price.clone(),
);
registry.register(
"gas_price_service_exec_gas_price",
"The requested execution gas price for the next block",
metrics.exec_gas_price.clone(),
);
registry.register(
"gas_price_service_da_gas_price",
"The requested data availability gas price for the next block",
metrics.da_gas_price.clone(),
);
registry.register(
"gas_price_service_total_reward",
"The total reward received from DA gas price fees",
metrics.total_reward.clone(),
);
registry.register(
"gas_price_service_total_known_costs",
"The total known costs for committing L2 blocks to DA",
metrics.total_known_costs.clone(),
);
registry.register(
"gas_price_service_predicted_profit",
"The predicted profit based on the rewards, known costs, and predicted costs from price per byte",
metrics.predicted_profit.clone(),
);
registry.register(
"gas_price_service_unrecorded_bytes",
"The total bytes of all L2 blocks waiting to be recorded on DA",
metrics.unrecorded_bytes.clone(),
);
registry.register(
"gas_price_service_latest_cost_per_byte",
"The latest cost per byte to record L2 blocks on DA",
metrics.latest_cost_per_byte.clone(),
);

registry.register(
"gas_price_service_recorded_height",
"The height of the latest L2 block recorded on DA",
metrics.recorded_height.clone(),
);

metrics
}
}

static GAS_PRICE_METRICS: OnceLock<GasPriceMetrics> = OnceLock::new();

pub fn gas_price_metrics() -> &'static GasPriceMetrics {
GAS_PRICE_METRICS.get_or_init(GasPriceMetrics::default)
}
1 change: 1 addition & 0 deletions crates/metrics/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod buckets;
pub mod config;
pub mod core_metrics;
pub mod futures;
pub mod gas_price_metrics;
pub mod graphql_metrics;
pub mod importer;
pub mod p2p_metrics;
Expand Down
1 change: 1 addition & 0 deletions crates/services/gas_price_service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ repository = { workspace = true }
anyhow = { workspace = true }
async-trait = { workspace = true }
enum-iterator = { workspace = true }
fuel-core-metrics = { workspace = true }
fuel-core-services = { workspace = true }
fuel-core-storage = { workspace = true, features = ["std"] }
fuel-core-types = { workspace = true, features = ["std"] }
Expand Down
12 changes: 12 additions & 0 deletions crates/services/gas_price_service/src/v1/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ impl V1Metadata {
};
Ok(metadata)
}

pub fn new_exec_gas_price(&self) -> u64 {
self.new_scaled_exec_price
.checked_div(self.gas_price_factor.get())
.unwrap_or(0)
}

pub fn new_da_gas_price(&self) -> u64 {
self.new_scaled_da_gas_price
.checked_div(self.gas_price_factor.get())
.unwrap_or(0)
}
}

#[derive(Debug, Clone, PartialEq)]
Expand Down
67 changes: 62 additions & 5 deletions crates/services/gas_price_service/src/v1/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use crate::{
};
use anyhow::anyhow;
use async_trait::async_trait;
use fuel_core_metrics::gas_price_metrics::gas_price_metrics;
use fuel_core_services::{
RunnableService,
RunnableTask,
Expand All @@ -48,7 +49,10 @@ use fuel_core_services::{
StateWatcher,
TaskNextAction,
};
use fuel_core_types::fuel_types::BlockHeight;
use fuel_core_types::{
fuel_types::BlockHeight,
services::txpool::Metadata,
};
use fuel_gas_price_algorithm::{
v0::AlgorithmUpdaterV0,
v1::{
Expand Down Expand Up @@ -251,17 +255,19 @@ where
block_gas_capacity: u64,
block_bytes: u64,
block_fees: u64,
gas_price: u64,
) -> anyhow::Result<()> {
let capacity = Self::validate_block_gas_capacity(block_gas_capacity)?;
let mut storage_tx = self.storage_tx_provider.begin_transaction()?;
let mut new_recorded_height = match storage_tx
let (old_recorded_height, mut new_recorded_height) = match storage_tx
.get_recorded_height()
.map_err(|err| anyhow!(err))?
{
Some(_) => None,
Some(old) => (Some(old), None),
None => {
// Sets it on first run
self.initial_recorded_height.take()
let initial = self.initial_recorded_height.take();
(initial, initial)
}
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this change?

Copy link
Member Author

@MitchTurner MitchTurner Jan 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe (None, initial) would be clearer.


Expand Down Expand Up @@ -303,12 +309,61 @@ where
AtomicStorage::commit_transaction(storage_tx)?;
let new_algo = self.algorithm_updater.algorithm();
tracing::debug!("Updating gas price: {}", &new_algo.calculate());
self.shared_algo.update(new_algo);
self.shared_algo.update(new_algo).await;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why await here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by the error:

    pub async fn update(&mut self, new_algo: A) {
        let mut write_lock = self.0.write();
        *write_lock = new_algo;
    }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm need to pull

let best_recorded_height = new_recorded_height.or(old_recorded_height);
Self::record_metrics(&metadata, gas_price, best_recorded_height);
// Clear the buffer after committing changes
self.da_block_costs_buffer.clear();
Ok(())
}

fn record_metrics(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should conditionally export metrics, see description of #2310 for reference

metadata: &UpdaterMetadata,
gas_price: u64,
recorded_height: Option<BlockHeight>,
) {
if let UpdaterMetadata::V1(v1_metadata) = metadata {
let metrics = gas_price_metrics();
let real_gas_price_i64 = gas_price.try_into().unwrap_or(i64::MAX);
let exec_gas_price_i64 = v1_metadata
.new_exec_gas_price()
.try_into()
.unwrap_or(i64::MAX);
Comment on lines +332 to +335
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I generally prefer explicit conversions for readability. I.e. i64::try_from().

I'm also uncertain if it makes sense to report i64::MAX if we're out of range. Wouldn't it be better to not report any metrics and log an error in this case?

let da_gas_price_i64 = v1_metadata
.new_da_gas_price()
.try_into()
.unwrap_or(i64::MAX);
let total_reward_i64 =
v1_metadata.total_da_rewards.try_into().unwrap_or(i64::MAX);
let total_known_costs_i64 = v1_metadata
.latest_known_total_da_cost
.try_into()
.unwrap_or(i64::MAX);
let predicted_profit_i64 =
v1_metadata.last_profit.try_into().unwrap_or(i64::MAX);
let unrecorded_bytes_i64 = v1_metadata
.unrecorded_block_bytes
.try_into()
.unwrap_or(i64::MAX);
let latest_cost_per_byte_i64 = v1_metadata
.latest_da_cost_per_byte
.try_into()
.unwrap_or(i64::MAX);
metrics.real_gas_price.set(real_gas_price_i64);
metrics.exec_gas_price.set(exec_gas_price_i64);
metrics.da_gas_price.set(da_gas_price_i64);
metrics.total_reward.set(total_reward_i64);
metrics.total_known_costs.set(total_known_costs_i64);
metrics.predicted_profit.set(predicted_profit_i64);
metrics.unrecorded_bytes.set(unrecorded_bytes_i64);
metrics.latest_cost_per_byte.set(latest_cost_per_byte_i64);
if let Some(height) = recorded_height {
let inner: u32 = height.into();
metrics.recorded_height.set(inner.into());
}
}
}

async fn apply_block_info_to_gas_algorithm(
&mut self,
l2_block: BlockInfo,
Expand All @@ -328,6 +383,7 @@ where
block_gas_capacity,
block_bytes,
block_fees,
gas_price,
..
} => {
self.handle_normal_block(
Expand All @@ -336,6 +392,7 @@ where
block_gas_capacity,
block_bytes,
block_fees,
gas_price,
)
.await?;
}
Expand Down
Loading