Skip to content

Commit

Permalink
Merge pull request #4719 from stacks-network/feat/signer-metrics
Browse files Browse the repository at this point in the history
feat: signer monitoring server
  • Loading branch information
hstove committed May 7, 2024
2 parents de17b4b + 632ff51 commit 738c4c8
Show file tree
Hide file tree
Showing 14 changed files with 695 additions and 4 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

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

5 changes: 5 additions & 0 deletions libsigner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ path = "./src/libsigner.rs"
[dependencies]
clarity = { path = "../clarity" }
hashbrown = { workspace = true }
lazy_static = "1.4.0"
libc = "0.2"
libstackerdb = { path = "../libstackerdb" }
prometheus = { version = "0.9", optional = true }
serde = "1"
serde_derive = "1"
serde_stacker = "0.1"
Expand Down Expand Up @@ -50,3 +52,6 @@ sha2 = { version = "0.10", features = ["asm"] }

[target.'cfg(any(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64")), any(target_os = "windows")))'.dependencies]
sha2 = { version = "0.10" }

[features]
monitoring_prom = ["prometheus"]
6 changes: 6 additions & 0 deletions stacks-signer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ backoff = "0.4"
clarity = { path = "../clarity" }
clap = { version = "4.1.1", features = ["derive", "env"] }
hashbrown = { workspace = true }
lazy_static = "1.4.0"
libsigner = { path = "../libsigner" }
libstackerdb = { path = "../libstackerdb" }
prometheus = { version = "0.9", optional = true }
rand_core = "0.6"
reqwest = { version = "0.11.22", default-features = false, features = ["blocking", "json", "rustls-tls"] }
serde = "1"
Expand All @@ -37,6 +39,7 @@ slog-term = "2.6.0"
stacks-common = { path = "../stacks-common" }
stackslib = { path = "../stackslib" }
thiserror = "1.0"
tiny_http = { version = "0.12", optional = true }
toml = "0.5.6"
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
Expand All @@ -60,3 +63,6 @@ features = ["arbitrary_precision", "unbounded_depth"]
[dependencies.secp256k1]
version = "0.24.3"
features = ["serde", "recovery"]

[features]
monitoring_prom = ["libsigner/monitoring_prom", "prometheus", "tiny_http"]
28 changes: 27 additions & 1 deletion stacks-signer/src/client/stacks_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ impl StacksClient {
estimated_len: Some(tx.tx_len()),
transaction_payload: to_hex(&tx.payload.serialize_to_vec()),
};
let timer =
crate::monitoring::new_rpc_call_timer(&self.fees_transaction_path(), &self.http_origin);
let send_request = || {
self.stacks_node_client
.post(self.fees_transaction_path())
Expand All @@ -219,6 +221,7 @@ impl StacksClient {
if !response.status().is_success() {
return Err(ClientError::RequestFailure(response.status()));
}
timer.stop_and_record();
let fee_estimate_response = response.json::<RPCFeeEstimateResponse>()?;
let fee = fee_estimate_response
.estimations
Expand Down Expand Up @@ -268,6 +271,8 @@ impl StacksClient {
block,
chain_id: self.chain_id,
};
let timer =
crate::monitoring::new_rpc_call_timer(&self.block_proposal_path(), &self.http_origin);
let send_request = || {
self.stacks_node_client
.post(self.block_proposal_path())
Expand All @@ -279,6 +284,7 @@ impl StacksClient {
};

let response = retry_with_exponential_backoff(send_request)?;
timer.stop_and_record();
if !response.status().is_success() {
return Err(ClientError::RequestFailure(response.status()));
}
Expand Down Expand Up @@ -355,13 +361,16 @@ impl StacksClient {
/// Get the current peer info data from the stacks node
pub fn get_peer_info(&self) -> Result<RPCPeerInfoData, ClientError> {
debug!("Getting stacks node info...");
let timer =
crate::monitoring::new_rpc_call_timer(&self.core_info_path(), &self.http_origin);
let send_request = || {
self.stacks_node_client
.get(self.core_info_path())
.send()
.map_err(backoff::Error::transient)
};
let response = retry_with_exponential_backoff(send_request)?;
timer.stop_and_record();
if !response.status().is_success() {
return Err(ClientError::RequestFailure(response.status()));
}
Expand Down Expand Up @@ -402,13 +411,18 @@ impl StacksClient {
reward_cycle: u64,
) -> Result<Option<Vec<NakamotoSignerEntry>>, ClientError> {
debug!("Getting reward set for reward cycle {reward_cycle}...");
let timer = crate::monitoring::new_rpc_call_timer(
&self.reward_set_path(reward_cycle),
&self.http_origin,
);
let send_request = || {
self.stacks_node_client
.get(self.reward_set_path(reward_cycle))
.send()
.map_err(backoff::Error::transient)
};
let response = retry_with_exponential_backoff(send_request)?;
timer.stop_and_record();
if !response.status().is_success() {
return Err(ClientError::RequestFailure(response.status()));
}
Expand All @@ -419,13 +433,17 @@ impl StacksClient {
/// Retreive the current pox data from the stacks node
pub fn get_pox_data(&self) -> Result<RPCPoxInfoData, ClientError> {
debug!("Getting pox data...");
#[cfg(feature = "monitoring_prom")]
let timer = crate::monitoring::new_rpc_call_timer(&self.pox_path(), &self.http_origin);
let send_request = || {
self.stacks_node_client
.get(self.pox_path())
.send()
.map_err(backoff::Error::transient)
};
let response = retry_with_exponential_backoff(send_request)?;
#[cfg(feature = "monitoring_prom")]
timer.stop_and_record();
if !response.status().is_success() {
return Err(ClientError::RequestFailure(response.status()));
}
Expand Down Expand Up @@ -458,18 +476,21 @@ impl StacksClient {
}

/// Helper function to retrieve the account info from the stacks node for a specific address
fn get_account_entry(
pub fn get_account_entry(
&self,
address: &StacksAddress,
) -> Result<AccountEntryResponse, ClientError> {
debug!("Getting account info...");
let timer =
crate::monitoring::new_rpc_call_timer(&self.accounts_path(address), &self.http_origin);
let send_request = || {
self.stacks_node_client
.get(self.accounts_path(address))
.send()
.map_err(backoff::Error::transient)
};
let response = retry_with_exponential_backoff(send_request)?;
timer.stop_and_record();
if !response.status().is_success() {
return Err(ClientError::RequestFailure(response.status()));
}
Expand Down Expand Up @@ -536,6 +557,8 @@ impl StacksClient {
pub fn submit_transaction(&self, tx: &StacksTransaction) -> Result<Txid, ClientError> {
let txid = tx.txid();
let tx = tx.serialize_to_vec();
let timer =
crate::monitoring::new_rpc_call_timer(&self.transaction_path(), &self.http_origin);
let send_request = || {
self.stacks_node_client
.post(self.transaction_path())
Expand All @@ -548,6 +571,7 @@ impl StacksClient {
})
};
let response = retry_with_exponential_backoff(send_request)?;
timer.stop_and_record();
if !response.status().is_success() {
return Err(ClientError::RequestFailure(response.status()));
}
Expand Down Expand Up @@ -576,12 +600,14 @@ impl StacksClient {
let body =
json!({"sender": self.stacks_address.to_string(), "arguments": args}).to_string();
let path = self.read_only_path(contract_addr, contract_name, function_name);
let timer = crate::monitoring::new_rpc_call_timer(&path, &self.http_origin);
let response = self
.stacks_node_client
.post(path)
.header("Content-Type", "application/json")
.body(body)
.send()?;
timer.stop_and_record();
if !response.status().is_success() {
return Err(ClientError::RequestFailure(response.status()));
}
Expand Down
45 changes: 44 additions & 1 deletion stacks-signer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ pub struct GlobalConfig {
pub auth_password: String,
/// The path to the signer's database file
pub db_path: PathBuf,
/// Metrics endpoint
pub metrics_endpoint: Option<SocketAddr>,
}

/// Internal struct for loading up the config file
Expand Down Expand Up @@ -221,6 +223,8 @@ struct RawConfigFile {
pub auth_password: String,
/// The path to the signer's database file or :memory: for an in-memory database
pub db_path: String,
/// Metrics endpoint
pub metrics_endpoint: Option<String>,
}

impl RawConfigFile {
Expand Down Expand Up @@ -298,6 +302,19 @@ impl TryFrom<RawConfigFile> for GlobalConfig {
let sign_timeout = raw_data.sign_timeout_ms.map(Duration::from_millis);
let db_path = raw_data.db_path.into();

let metrics_endpoint = match raw_data.metrics_endpoint {
Some(endpoint) => Some(
endpoint
.to_socket_addrs()
.map_err(|_| ConfigError::BadField("endpoint".to_string(), endpoint.clone()))?
.next()
.ok_or_else(|| {
ConfigError::BadField("endpoint".to_string(), endpoint.clone())
})?,
),
None => None,
};

Ok(Self {
node_host: raw_data.node_host,
endpoint,
Expand All @@ -315,6 +332,7 @@ impl TryFrom<RawConfigFile> for GlobalConfig {
max_tx_fee_ustx: raw_data.max_tx_fee_ustx,
auth_password: raw_data.auth_password,
db_path,
metrics_endpoint,
})
}
}
Expand Down Expand Up @@ -345,6 +363,10 @@ impl GlobalConfig {
0 => "default".to_string(),
_ => (self.tx_fee_ustx as f64 / 1_000_000.0).to_string(),
};
let metrics_endpoint = match &self.metrics_endpoint {
Some(endpoint) => endpoint.to_string(),
None => "None".to_string(),
};
format!(
r#"
Stacks node host: {node_host}
Expand All @@ -354,14 +376,16 @@ Public key: {public_key}
Network: {network}
Database path: {db_path}
DKG transaction fee: {tx_fee} uSTX
Metrics endpoint: {metrics_endpoint}
"#,
node_host = self.node_host,
endpoint = self.endpoint,
stacks_address = self.stacks_address,
public_key = StacksPublicKey::from_private(&self.stacks_private_key).to_hex(),
network = self.network,
db_path = self.db_path.to_str().unwrap_or_default(),
tx_fee = tx_fee
tx_fee = tx_fee,
metrics_endpoint = metrics_endpoint,
)
}
}
Expand All @@ -384,6 +408,7 @@ pub fn build_signer_config_tomls(
mut port_start: usize,
max_tx_fee_ustx: Option<u64>,
tx_fee_ustx: Option<u64>,
mut metrics_port_start: Option<usize>,
) -> Vec<String> {
let mut signer_config_tomls = vec![];

Expand Down Expand Up @@ -438,6 +463,17 @@ tx_fee_ustx = {tx_fee_ustx}
)
}

if let Some(metrics_port) = metrics_port_start {
let metrics_endpoint = format!("localhost:{}", metrics_port);
signer_config_toml = format!(
r#"
{signer_config_toml}
metrics_endpoint = "{metrics_endpoint}"
"#
);
metrics_port_start = Some(metrics_port + 1);
}

signer_config_tomls.push(signer_config_toml);
}

Expand Down Expand Up @@ -469,6 +505,7 @@ mod tests {
3000,
None,
None,
Some(4000),
);

let config =
Expand All @@ -477,6 +514,7 @@ mod tests {
assert_eq!(config.auth_password, "melon");
assert!(config.max_tx_fee_ustx.is_none());
assert!(config.tx_fee_ustx.is_none());
assert_eq!(config.metrics_endpoint, Some("localhost:4000".to_string()));
}

#[test]
Expand All @@ -501,6 +539,7 @@ mod tests {
3000,
None,
None,
None,
);

let config =
Expand All @@ -526,6 +565,7 @@ mod tests {
3000,
max_tx_fee_ustx,
tx_fee_ustx,
None,
);

let config =
Expand All @@ -546,6 +586,7 @@ mod tests {
3000,
max_tx_fee_ustx,
None,
None,
);

let config =
Expand All @@ -570,6 +611,7 @@ mod tests {
3000,
None,
tx_fee_ustx,
None,
);

let config =
Expand Down Expand Up @@ -598,6 +640,7 @@ Public key: 03bc489f27da3701d9f9e577c88de5567cf4023111b7577042d55cde4d823a3505
Network: testnet
Database path: :memory:
DKG transaction fee: 0.01 uSTX
Metrics endpoint: 0.0.0.0:9090
"#
)
);
Expand Down
3 changes: 3 additions & 0 deletions stacks-signer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ pub mod runloop;
pub mod signer;
/// The state module for the signer
pub mod signerdb;

/// The monitoring server for the signer
pub mod monitoring;

0 comments on commit 738c4c8

Please sign in to comment.