Skip to content

Commit

Permalink
add json rpc metrics (#10836)
Browse files Browse the repository at this point in the history
## Description 

Add metrics to json rpc apis that asks for multi-things 

## Test Plan 

How did you test the new or updated feature?

---
If your changes are not user-facing and not a breaking change, you can
skip the following section. Otherwise, please indicate what changed, and
then add to the Release Notes section as highlighted during the release
process.

### Type of Change (Check all that apply)

- [ ] user-visible impact
- [ ] breaking change for a client SDKs
- [ ] breaking change for FNs (FN binary must upgrade)
- [ ] breaking change for validators or node operators (must upgrade
binaries)
- [ ] breaking change for on-chain data layout
- [ ] necessitate either a data wipe or data migration

### Release notes
  • Loading branch information
longbowlu authored Apr 14, 2023
1 parent 0a1687a commit 4c3a28d
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 19 deletions.
184 changes: 184 additions & 0 deletions crates/sui-json-rpc/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

use anyhow::anyhow;
use mysten_metrics::histogram::Histogram;

pub use coin::CoinReadApiClient;
pub use coin::CoinReadApiOpenRpc;
Expand All @@ -18,6 +19,7 @@ pub use indexer::IndexerApiServer;
pub use move_utils::MoveUtilsClient;
pub use move_utils::MoveUtilsOpenRpc;
pub use move_utils::MoveUtilsServer;
use prometheus::{register_int_counter_with_registry, IntCounter};
pub use read::ReadApiClient;
pub use read::ReadApiOpenRpc;
pub use read::ReadApiServer;
Expand Down Expand Up @@ -64,3 +66,185 @@ pub fn validate_limit(limit: Option<usize>, max: usize) -> Result<usize, anyhow:
None => Ok(max),
}
}

#[derive(Clone)]
pub struct JsonRpcMetrics {
pub get_objects_limit: Histogram,
pub get_objects_result_size: Histogram,
pub get_objects_result_size_total: IntCounter,
pub get_tx_blocks_limit: Histogram,
pub get_tx_blocks_result_size: Histogram,
pub get_tx_blocks_result_size_total: IntCounter,
pub get_checkpoints_limit: Histogram,
pub get_checkpoints_result_size: Histogram,
pub get_checkpoints_result_size_total: IntCounter,
pub get_owned_objects_limit: Histogram,
pub get_owned_objects_result_size: Histogram,
pub get_owned_objects_result_size_total: IntCounter,
pub get_coins_limit: Histogram,
pub get_coins_result_size: Histogram,
pub get_coins_result_size_total: IntCounter,
pub get_dynamic_fields_limit: Histogram,
pub get_dynamic_fields_result_size: Histogram,
pub get_dynamic_fields_result_size_total: IntCounter,
pub query_tx_blocks_limit: Histogram,
pub query_tx_blocks_result_size: Histogram,
pub query_tx_blocks_result_size_total: IntCounter,
pub query_events_limit: Histogram,
pub query_events_result_size: Histogram,
pub query_events_result_size_total: IntCounter,

pub get_stake_sui_result_size: Histogram,
pub get_stake_sui_result_size_total: IntCounter,
}

impl JsonRpcMetrics {
pub fn new(registry: &prometheus::Registry) -> Self {
Self {
get_objects_limit: Histogram::new_in_registry(
"json_rpc_get_objects_limit",
"The input limit for multi_get_objects, after applying the cap",
registry,
),
get_objects_result_size: Histogram::new_in_registry(
"json_rpc_get_objects_result_size",
"The return size for multi_get_objects",
registry,
),
get_objects_result_size_total: register_int_counter_with_registry!(
"json_rpc_get_objects_result_size_total",
"The total return size for multi_get_objects",
registry
)
.unwrap(),
get_tx_blocks_limit: Histogram::new_in_registry(
"json_rpc_get_tx_blocks_limit",
"The input limit for get_tx_blocks, after applying the cap",
registry,
),
get_tx_blocks_result_size: Histogram::new_in_registry(
"json_rpc_get_tx_blocks_result_size",
"The return size for get_tx_blocks",
registry,
),
get_tx_blocks_result_size_total: register_int_counter_with_registry!(
"json_rpc_get_tx_blocks_result_size_total",
"The total return size for get_tx_blocks",
registry
)
.unwrap(),
get_checkpoints_limit: Histogram::new_in_registry(
"json_rpc_get_checkpoints_limit",
"The input limit for get_checkpoints, after applying the cap",
registry,
),
get_checkpoints_result_size: Histogram::new_in_registry(
"json_rpc_get_checkpoints_result_size",
"The return size for get_checkpoints",
registry,
),
get_checkpoints_result_size_total: register_int_counter_with_registry!(
"json_rpc_get_checkpoints_result_size_total",
"The total return size for get_checkpoints",
registry
)
.unwrap(),
get_owned_objects_limit: Histogram::new_in_registry(
"json_rpc_get_owned_objects_limit",
"The input limit for get_owned_objects, after applying the cap",
registry,
),
get_owned_objects_result_size: Histogram::new_in_registry(
"json_rpc_get_owned_objects_result_size",
"The return size for get_owned_objects",
registry,
),
get_owned_objects_result_size_total: register_int_counter_with_registry!(
"json_rpc_get_owned_objects_result_size_total",
"The total return size for get_owned_objects",
registry
)
.unwrap(),
get_coins_limit: Histogram::new_in_registry(
"json_rpc_get_coins_limit",
"The input limit for get_coins, after applying the cap",
registry,
),
get_coins_result_size: Histogram::new_in_registry(
"json_rpc_get_coins_result_size",
"The return size for get_coins",
registry,
),
get_coins_result_size_total: register_int_counter_with_registry!(
"json_rpc_get_coins_result_size_total",
"The total return size for get_coins",
registry
)
.unwrap(),
get_dynamic_fields_limit: Histogram::new_in_registry(
"json_rpc_get_dynamic_fields_limit",
"The input limit for get_dynamic_fields, after applying the cap",
registry,
),
get_dynamic_fields_result_size: Histogram::new_in_registry(
"json_rpc_get_dynamic_fields_result_size",
"The return size for get_dynamic_fields",
registry,
),
get_dynamic_fields_result_size_total: register_int_counter_with_registry!(
"json_rpc_get_dynamic_fields_result_size_total",
"The total return size for get_dynamic_fields",
registry
)
.unwrap(),
query_tx_blocks_limit: Histogram::new_in_registry(
"json_rpc_query_tx_blocks_limit",
"The input limit for query_tx_blocks, after applying the cap",
registry,
),
query_tx_blocks_result_size: Histogram::new_in_registry(
"json_rpc_query_tx_blocks_result_size",
"The return size for query_tx_blocks",
registry,
),
query_tx_blocks_result_size_total: register_int_counter_with_registry!(
"json_rpc_query_tx_blocks_result_size_total",
"The total return size for query_tx_blocks",
registry
)
.unwrap(),
query_events_limit: Histogram::new_in_registry(
"json_rpc_query_events_limit",
"The input limit for query_events, after applying the cap",
registry,
),
query_events_result_size: Histogram::new_in_registry(
"json_rpc_query_events_result_size",
"The return size for query_events",
registry,
),
query_events_result_size_total: register_int_counter_with_registry!(
"json_rpc_query_events_result_size_total",
"The total return size for query_events",
registry
)
.unwrap(),
get_stake_sui_result_size: Histogram::new_in_registry(
"json_rpc_get_stake_sui_result_size",
"The return size for get_stake_sui",
registry,
),
get_stake_sui_result_size_total: register_int_counter_with_registry!(
"json_rpc_get_stake_sui_result_size_total",
"The total return size for get_stake_sui",
registry
)
.unwrap(),
}
}

pub fn new_for_tests() -> Self {
let registry = prometheus::Registry::new();
Self::new(&registry)
}
}
12 changes: 9 additions & 3 deletions crates/sui-json-rpc/src/coin_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ use sui_types::messages::TransactionEffectsAPI;
use sui_types::object::{Object, Owner};
use sui_types::parse_sui_struct_tag;

use crate::api::{cap_page_limit, CoinReadApiServer};
use crate::api::{cap_page_limit, CoinReadApiServer, JsonRpcMetrics};
use crate::error::Error;
use crate::SuiRpcModule;

pub struct CoinReadApi {
state: Arc<AuthorityState>,
pub metrics: Arc<JsonRpcMetrics>,
}

impl CoinReadApi {
pub fn new(state: Arc<AuthorityState>) -> Self {
Self { state }
pub fn new(state: Arc<AuthorityState>, metrics: Arc<JsonRpcMetrics>) -> Self {
Self { state, metrics }
}

fn get_coins_iterator(
Expand All @@ -46,6 +47,7 @@ impl CoinReadApi {
one_coin_type_only: bool,
) -> anyhow::Result<CoinPage> {
let limit = cap_page_limit(limit);
self.metrics.get_coins_limit.report(limit as u64);
let coins = self
.state
.get_owned_coins_iterator_with_cursor(owner, cursor, limit + 1, one_coin_type_only)?
Expand All @@ -66,6 +68,10 @@ impl CoinReadApi {
let has_next_page = data.len() > limit;
data.truncate(limit);

self.metrics.get_coins_result_size.report(data.len() as u64);
self.metrics
.get_coins_result_size_total
.inc_by(data.len() as u64);
let next_cursor = data.last().map(|coin| coin.coin_object_id);
Ok(CoinPage {
data,
Expand Down
18 changes: 13 additions & 5 deletions crates/sui-json-rpc/src/governance_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,32 @@ use sui_types::sui_system_state::{
get_validator_from_table, sui_system_state_summary::get_validator_by_pool_id, SuiSystemState,
};

use crate::api::GovernanceReadApiServer;
use crate::api::{GovernanceReadApiServer, JsonRpcMetrics};
use crate::error::Error;
use crate::SuiRpcModule;

pub struct GovernanceReadApi {
state: Arc<AuthorityState>,
pub metrics: Arc<JsonRpcMetrics>,
}

impl GovernanceReadApi {
pub fn new(state: Arc<AuthorityState>) -> Self {
Self { state }
pub fn new(state: Arc<AuthorityState>, metrics: Arc<JsonRpcMetrics>) -> Self {
Self { state, metrics }
}

async fn get_staked_sui(&self, owner: SuiAddress) -> Result<Vec<StakedSui>, Error> {
Ok(self
let result = self
.state
.get_move_objects(owner, MoveObjectType::staked_sui())
.await?)
.await?;
self.metrics
.get_stake_sui_result_size
.report(result.len() as u64);
self.metrics
.get_stake_sui_result_size_total
.inc_by(result.len() as u64);
Ok(result)
}

async fn get_stakes_by_ids(
Expand Down
40 changes: 38 additions & 2 deletions crates/sui-json-rpc/src/indexer_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ use sui_types::dynamic_field::DynamicFieldName;
use sui_types::event::EventID;

use crate::api::{
cap_page_limit, validate_limit, IndexerApiServer, ReadApiServer, QUERY_MAX_RESULT_LIMIT_OBJECTS,
cap_page_limit, validate_limit, IndexerApiServer, JsonRpcMetrics, ReadApiServer,
QUERY_MAX_RESULT_LIMIT_OBJECTS,
};
use crate::SuiRpcModule;

Expand Down Expand Up @@ -63,14 +64,21 @@ pub struct IndexerApi<R> {
state: Arc<AuthorityState>,
read_api: R,
ns_resolver_id: Option<ObjectID>,
pub metrics: Arc<JsonRpcMetrics>,
}

impl<R: ReadApiServer> IndexerApi<R> {
pub fn new(state: Arc<AuthorityState>, read_api: R, ns_resolver_id: Option<ObjectID>) -> Self {
pub fn new(
state: Arc<AuthorityState>,
read_api: R,
ns_resolver_id: Option<ObjectID>,
metrics: Arc<JsonRpcMetrics>,
) -> Self {
Self {
state,
read_api,
ns_resolver_id,
metrics,
}
}
}
Expand All @@ -85,6 +93,7 @@ impl<R: ReadApiServer> IndexerApiServer for IndexerApi<R> {
limit: Option<usize>,
) -> RpcResult<ObjectsPage> {
let limit = validate_limit(limit, QUERY_MAX_RESULT_LIMIT_OBJECTS)?;
self.metrics.get_owned_objects_limit.report(limit as u64);
let SuiObjectResponseQuery { filter, options } = query.unwrap_or_default();
let options = options.unwrap_or_default();
let mut objects = self
Expand All @@ -111,6 +120,12 @@ impl<R: ReadApiServer> IndexerApiServer for IndexerApi<R> {
.collect::<Result<Vec<SuiObjectResponse>, _>>()?,
};

self.metrics
.get_owned_objects_result_size
.report(data.len() as u64);
self.metrics
.get_owned_objects_result_size_total
.inc_by(data.len() as u64);
Ok(Page {
data,
next_cursor,
Expand All @@ -127,6 +142,7 @@ impl<R: ReadApiServer> IndexerApiServer for IndexerApi<R> {
descending_order: Option<bool>,
) -> RpcResult<TransactionBlocksPage> {
let limit = cap_page_limit(limit);
self.metrics.query_tx_blocks_limit.report(limit as u64);
let descending = descending_order.unwrap_or_default();
let opts = query.options.unwrap_or_default();

Expand All @@ -150,6 +166,12 @@ impl<R: ReadApiServer> IndexerApiServer for IndexerApi<R> {
.multi_get_transaction_blocks(digests, Some(opts))?
};

self.metrics
.query_tx_blocks_result_size
.report(data.len() as u64);
self.metrics
.query_tx_blocks_result_size_total
.inc_by(data.len() as u64);
Ok(Page {
data,
next_cursor,
Expand All @@ -173,13 +195,20 @@ impl<R: ReadApiServer> IndexerApiServer for IndexerApi<R> {
);
let descending = descending_order.unwrap_or_default();
let limit = cap_page_limit(limit);
self.metrics.query_events_limit.report(limit as u64);
// Retrieve 1 extra item for next cursor
let mut data = self
.state
.query_events(query, cursor.clone(), limit + 1, descending)?;
let has_next_page = data.len() > limit;
data.truncate(limit);
let next_cursor = data.last().map_or(cursor, |e| Some(e.id.clone()));
self.metrics
.query_events_result_size
.report(data.len() as u64);
self.metrics
.query_events_result_size_total
.inc_by(data.len() as u64);
Ok(EventPage {
data,
next_cursor,
Expand All @@ -200,13 +229,20 @@ impl<R: ReadApiServer> IndexerApiServer for IndexerApi<R> {
limit: Option<usize>,
) -> RpcResult<DynamicFieldPage> {
let limit = cap_page_limit(limit);
self.metrics.get_dynamic_fields_limit.report(limit as u64);
let mut data = self
.state
.get_dynamic_fields(parent_object_id, cursor, limit + 1)
.map_err(|e| anyhow!("{e}"))?;
let has_next_page = data.len() > limit;
data.truncate(limit);
let next_cursor = data.last().cloned().map_or(cursor, |c| Some(c.object_id));
self.metrics
.get_dynamic_fields_result_size
.report(data.len() as u64);
self.metrics
.get_dynamic_fields_result_size_total
.inc_by(data.len() as u64);
Ok(DynamicFieldPage {
data,
next_cursor,
Expand Down
Loading

2 comments on commit 4c3a28d

@vercel
Copy link

@vercel vercel bot commented on 4c3a28d Apr 14, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

explorer-storybook – ./apps/explorer

explorer-storybook-git-main-mysten-labs.vercel.app
explorer-storybook.vercel.app
explorer-storybook-mysten-labs.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 4c3a28d Apr 14, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

wallet-adapter – ./sdk/wallet-adapter/example

wallet-adapter-git-main-mysten-labs.vercel.app
sui-wallet-adapter.vercel.app
wallet-adapter-mysten-labs.vercel.app

Please sign in to comment.