Skip to content

Commit

Permalink
feat: implement signer metrics exporter (#1084)
Browse files Browse the repository at this point in the history
* Add an initial metrics setup module
* Set up metrics from the settings
* Add a few counter and histogram metrics
  • Loading branch information
djordon authored Dec 10, 2024
1 parent 99bdb03 commit 5ce32bf
Show file tree
Hide file tree
Showing 14 changed files with 510 additions and 37 deletions.
116 changes: 103 additions & 13 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ config = "0.11.0"
futures = "0.3.24"
hashbrown = "0.14.5"
http = "1.1.0"
metrics = "0.24"
metrics-exporter-prometheus = { version = "0.16", default-features = false, features = ["http-listener"] }
# This is necessary to compile the AWS Lambda as a lambda.
openssl = { version = "0.10.66", features = ["vendored"] }
p256k1 = "7.1.0"
Expand Down
2 changes: 2 additions & 0 deletions signer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ config = "0.14"
futures.workspace = true
hashbrown.workspace = true
libp2p.workspace = true
metrics.workspace = true
metrics-exporter-prometheus.workspace = true
p256k1.workspace = true
prost.workspace = true
rand.workspace = true
Expand Down
26 changes: 26 additions & 0 deletions signer/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
fn main() {
set_up_build_info();
// compile_protos();
}

pub fn set_up_build_info() {
let output = std::process::Command::new("rustc")
.arg("--version")
.output()
.expect("Failed to execute rustc");

let version = String::from_utf8_lossy(&output.stdout);

let git_hash = std::process::Command::new("git")
.args(["rev-parse", "HEAD"])
.output()
.map(|output| String::from_utf8_lossy(&output.stdout).to_string())
.unwrap_or_default();

let env_abi = std::env::var("CARGO_CFG_TARGET_ENV").unwrap();
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();

// We capture these variables in our binary and use them in the
// build_info metric.
println!("cargo:rustc-env=CARGO_CFG_TARGET_ENV={}", env_abi.trim());
println!("cargo:rustc-env=CARGO_CFG_TARGET_ARCH={}", arch.trim());
println!("cargo:rustc-env=GIT_COMMIT={}", git_hash.trim());
println!("cargo:rustc-env=RUSTC_VERSION={}", version.trim());
}

pub fn compile_protos() {
let workingdir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
Expand Down
8 changes: 8 additions & 0 deletions signer/src/api/new_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use std::sync::OnceLock;
use crate::context::Context;
use crate::emily_client::EmilyInteract;
use crate::error::Error;
use crate::metrics::Metrics;
use crate::metrics::STACKS_BLOCKCHAIN;
use crate::stacks::events::CompletedDepositEvent;
use crate::stacks::events::KeyRotationEvent;
use crate::stacks::events::RegistryEvent;
Expand Down Expand Up @@ -79,6 +81,12 @@ enum UpdateResult {
#[tracing::instrument(skip_all, name = "new-block")]
pub async fn new_block_handler(state: State<ApiState<impl Context>>, body: String) -> StatusCode {
tracing::debug!("received a new block event from stacks-core");
metrics::counter!(
Metrics::BlocksObservedTotal,
"blockchain" => STACKS_BLOCKCHAIN,
)
.increment(1);

let api = state.0;

let registry_address = SBTC_REGISTRY_IDENTIFIER.get_or_init(|| {
Expand Down
36 changes: 32 additions & 4 deletions signer/src/block_observer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ use crate::context::SbtcLimits;
use crate::context::SignerEvent;
use crate::emily_client::EmilyInteract;
use crate::error::Error;
use crate::metrics::Metrics;
use crate::metrics::BITCOIN_BLOCKCHAIN;
use crate::stacks::api::StacksInteract;
use crate::stacks::api::TenureBlocks;
use crate::storage;
Expand Down Expand Up @@ -137,6 +139,11 @@ where
match poll.await {
Ok(Some(Ok(block_hash))) => {
tracing::info!("observed new bitcoin block from stream");
metrics::counter!(
Metrics::BlocksObservedTotal,
"blockchain" => BITCOIN_BLOCKCHAIN,
)
.increment(1);

let next_blocks = match self.next_blocks_to_process(block_hash).await {
Ok(blocks) => blocks,
Expand Down Expand Up @@ -203,17 +210,31 @@ impl<C: Context, B> BlockObserver<C, B> {
#[tracing::instrument(skip_all)]
pub async fn load_requests(&self, requests: &[CreateDepositRequest]) -> Result<(), Error> {
let mut deposit_requests = Vec::new();
let bitcoin_client = self.context.get_bitcoin_client();

for request in requests {
let deposit = request
.validate(&self.context.get_bitcoin_client())
.validate(&bitcoin_client)
.await
.inspect_err(|error| tracing::warn!(%error, "could not validate deposit request"));

// We log the error above, so we just need to extract the
// deposit now.
if let Ok(Some(deposit)) = deposit {
deposit_requests.push(deposit);
}
let deposit_status = match deposit {
Ok(Some(deposit)) => {
deposit_requests.push(deposit);
"success"
}
Ok(None) => "unconfirmed",
Err(_) => "failed",
};

metrics::counter!(
Metrics::DepositRequestsTotal,
"blockchain" => BITCOIN_BLOCKCHAIN,
"status" => deposit_status,
)
.increment(1);
}

self.store_deposit_requests(deposit_requests).await?;
Expand Down Expand Up @@ -435,6 +456,13 @@ impl<C: Context, B> BlockObserver<C, B> {

for prevout in tx_info.to_inputs(&signer_script_pubkeys) {
db.write_tx_prevout(&prevout).await?;
if prevout.prevout_type == model::TxPrevoutType::Deposit {
metrics::counter!(
Metrics::DepositsSweptTotal,
"blockchain" => BITCOIN_BLOCKCHAIN,
)
.increment(1);
}
}

for output in tx_info.to_outputs(&signer_script_pubkeys) {
Expand Down
9 changes: 8 additions & 1 deletion signer/src/config/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ dkg_max_duration = 120
# Environment: SIGNER_SIGNER__DKG_BEGIN_PAUSE
# dkg_begin_pause = 10

# When defined, this field sets the scrape endpoint as an IPv4 or IPv6
# socket address for exporting metrics for Prometheus.
#
# Required: false
# Environment: SIGNER_SIGNER__PROMETHEUS_EXPORTER_ENDPOINT
# prometheus_exporter_endpoint = "[::]:9184"

# !! ==============================================================================
# !! Stacks Event Observer Configuration
# !!
Expand Down Expand Up @@ -272,4 +279,4 @@ public_endpoints = []
# Default: false
# Required: false
# Environment: SIGNER_SIGNER__P2P__ENABLE_MDNS
enable_mdns = true
enable_mdns = true
Loading

0 comments on commit 5ce32bf

Please sign in to comment.