-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2576 from get10101/feat/stats
feat: store some metrics in db
- Loading branch information
Showing
13 changed files
with
121 additions
and
266 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
coordinator/migrations/2024-05-28-045644_add-metrics-table/down.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
drop table if exists metrics; |
6 changes: 6 additions & 0 deletions
6
coordinator/migrations/2024-05-28-045644_add-metrics-table/up.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
create table if not exists metrics | ||
( | ||
id SERIAL PRIMARY KEY NOT NULL, | ||
created_at timestamp WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
on_chain_balance_sats BIGINT NOT NULL | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
use crate::schema::metrics; | ||
use anyhow::ensure; | ||
use anyhow::Result; | ||
use diesel::ExpressionMethods; | ||
use diesel::PgConnection; | ||
use diesel::RunQueryDsl; | ||
|
||
pub fn create_metrics_entry(conn: &mut PgConnection, on_chain_balance: u64) -> Result<()> { | ||
let affected_rows = diesel::insert_into(metrics::table) | ||
.values(metrics::on_chain_balance_sats.eq(on_chain_balance as i64)) | ||
.execute(conn)?; | ||
|
||
ensure!(affected_rows > 0, "Could not insert metric entry"); | ||
|
||
Ok(()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,217 +1,20 @@ | ||
use crate::db; | ||
use crate::node::storage::NodeStorage; | ||
use crate::node::Node; | ||
use crate::storage::CoordinatorTenTenOneStorage; | ||
use lazy_static::lazy_static; | ||
use opentelemetry::global; | ||
use opentelemetry::metrics::Meter; | ||
use opentelemetry::metrics::ObservableGauge; | ||
use opentelemetry::sdk::export::metrics::aggregation; | ||
use opentelemetry::sdk::metrics::controllers; | ||
use opentelemetry::sdk::metrics::processors; | ||
use opentelemetry::sdk::metrics::selectors; | ||
use opentelemetry::Context; | ||
use opentelemetry::KeyValue; | ||
use opentelemetry_prometheus::PrometheusExporter; | ||
use std::sync::Arc; | ||
use std::time::Duration; | ||
use xxi_node::commons::ContractSymbol; | ||
use xxi_node::commons::Direction; | ||
|
||
lazy_static! { | ||
pub static ref METER: Meter = global::meter("maker"); | ||
|
||
// channel details metrics | ||
pub static ref CHANNEL_BALANCE_SATOSHI: ObservableGauge<u64> = METER | ||
.u64_observable_gauge("channel_balance_satoshi") | ||
.with_description("Current channel balance in satoshi") | ||
.init(); | ||
pub static ref CHANNEL_OUTBOUND_CAPACITY_SATOSHI: ObservableGauge<u64> = METER | ||
.u64_observable_gauge("channel_outbound_capacity_satoshi") | ||
.with_description("Channel outbound capacity in satoshi") | ||
.init(); | ||
pub static ref CHANNEL_INBOUND_CAPACITY_SATOSHI: ObservableGauge<u64> = METER | ||
.u64_observable_gauge("channel_inbound_capacity_satoshi") | ||
.with_description("Channel inbound capacity in satoshi") | ||
.init(); | ||
pub static ref CHANNEL_IS_USABLE: ObservableGauge<u64> = METER | ||
.u64_observable_gauge("channel_is_usable") | ||
.with_description("If a channel is usable") | ||
.init(); | ||
pub static ref DLC_CHANNELS_AMOUNT: ObservableGauge<u64> = METER | ||
.u64_observable_gauge("dlc_channel_amount") | ||
.with_description("Number of DLC channels") | ||
.init(); | ||
pub static ref PUNISHED_DLC_CHANNELS_AMOUNT: ObservableGauge<u64> = METER | ||
.u64_observable_gauge("punished_dlc_channel_amount") | ||
.with_description("Number of punished DLC channels") | ||
.init(); | ||
|
||
// general node metrics | ||
pub static ref CONNECTED_PEERS: ObservableGauge<u64> = METER | ||
.u64_observable_gauge("node_connected_peers_total") | ||
.with_description("Total number of connected peers") | ||
.init(); | ||
pub static ref NODE_BALANCE_SATOSHI: ObservableGauge<u64> = METER | ||
.u64_observable_gauge("node_balance_satoshi") | ||
.with_description("Node balance in satoshi") | ||
.init(); | ||
|
||
// position metrics | ||
pub static ref POSITION_QUANTITY: ObservableGauge<f64> = METER | ||
.f64_observable_gauge("position_quantity_contracts") | ||
.with_description("Current open position in contracts") | ||
.init(); | ||
pub static ref POSITION_MARGIN: ObservableGauge<i64> = METER | ||
.i64_observable_gauge("position_margin_sats") | ||
.with_description("Current open position margin in sats") | ||
.init(); | ||
} | ||
|
||
pub fn init_meter() -> PrometheusExporter { | ||
let controller = controllers::basic(processors::factory( | ||
selectors::simple::histogram([1.0, 2.0, 5.0, 10.0, 20.0, 50.0]), | ||
aggregation::cumulative_temporality_selector(), | ||
)) | ||
.with_collect_period(Duration::from_secs(10)) | ||
.build(); | ||
|
||
opentelemetry_prometheus::exporter(controller).init() | ||
} | ||
|
||
pub fn collect(node: Node) { | ||
let cx = opentelemetry::Context::current(); | ||
position_metrics(&cx, &node); | ||
|
||
let inner_node = node.inner; | ||
|
||
node_metrics(&cx, inner_node); | ||
} | ||
|
||
fn position_metrics(cx: &Context, node: &Node) { | ||
let mut conn = match node.pool.get() { | ||
Ok(conn) => conn, | ||
Err(e) => { | ||
tracing::error!("Failed to get pool connection. Error: {e:?}"); | ||
return; | ||
} | ||
}; | ||
|
||
let positions = match db::positions::Position::get_all_open_positions(&mut conn) { | ||
Ok(positions) => positions, | ||
Err(e) => { | ||
tracing::error!("Failed to get positions. Error: {e:?}"); | ||
return; | ||
} | ||
}; | ||
|
||
let mut margin_long = 0; | ||
let mut margin_short = 0; | ||
let mut quantity_long = 0.0; | ||
let mut quantity_short = 0.0; | ||
|
||
// Note: we should filter positions here by BTCUSD once we have multiple contract symbols | ||
|
||
for position in positions { | ||
debug_assert!( | ||
position.contract_symbol == ContractSymbol::BtcUsd, | ||
"We should filter positions here by BTCUSD once we have multiple contract symbols" | ||
); | ||
match position.trader_direction { | ||
Direction::Long => { | ||
// TODO: fix me: this was meant to be the traders margin | ||
margin_long += position.coordinator_margin; | ||
quantity_long += position.quantity; | ||
} | ||
Direction::Short => { | ||
margin_short += position.coordinator_margin; | ||
quantity_short += position.quantity; | ||
} | ||
} | ||
} | ||
POSITION_QUANTITY.observe( | ||
cx, | ||
quantity_long as f64, | ||
&[ | ||
KeyValue::new("symbol", "BTCUSD"), | ||
KeyValue::new("status", "open"), | ||
KeyValue::new("direction", "long"), | ||
], | ||
); | ||
POSITION_QUANTITY.observe( | ||
cx, | ||
quantity_short as f64, | ||
&[ | ||
KeyValue::new("symbol", "BTCUSD"), | ||
KeyValue::new("status", "open"), | ||
KeyValue::new("direction", "short"), | ||
], | ||
); | ||
POSITION_MARGIN.observe( | ||
cx, | ||
margin_long, | ||
&[ | ||
KeyValue::new("symbol", "BTCUSD"), | ||
KeyValue::new("status", "open"), | ||
KeyValue::new("direction", "long"), | ||
], | ||
); | ||
POSITION_MARGIN.observe( | ||
cx, | ||
margin_short, | ||
&[ | ||
KeyValue::new("symbol", "BTCUSD"), | ||
KeyValue::new("status", "open"), | ||
KeyValue::new("direction", "short"), | ||
], | ||
); | ||
} | ||
|
||
fn node_metrics( | ||
cx: &Context, | ||
inner_node: Arc< | ||
xxi_node::node::Node< | ||
bdk_file_store::Store<bdk::wallet::ChangeSet>, | ||
CoordinatorTenTenOneStorage, | ||
NodeStorage, | ||
>, | ||
>, | ||
) { | ||
let connected_peers = inner_node.list_peers().len(); | ||
CONNECTED_PEERS.observe(cx, connected_peers as u64, &[]); | ||
|
||
let balance = inner_node.get_on_chain_balance(); | ||
|
||
NODE_BALANCE_SATOSHI.observe( | ||
cx, | ||
balance.confirmed, | ||
&[ | ||
KeyValue::new("type", "on-chain"), | ||
KeyValue::new("status", "confirmed"), | ||
], | ||
); | ||
NODE_BALANCE_SATOSHI.observe( | ||
cx, | ||
balance.immature, | ||
&[ | ||
KeyValue::new("type", "on-chain"), | ||
KeyValue::new("status", "immature"), | ||
], | ||
); | ||
NODE_BALANCE_SATOSHI.observe( | ||
cx, | ||
balance.trusted_pending, | ||
&[ | ||
KeyValue::new("type", "on-chain"), | ||
KeyValue::new("status", "trusted_pending"), | ||
], | ||
); | ||
NODE_BALANCE_SATOSHI.observe( | ||
cx, | ||
balance.untrusted_pending, | ||
&[ | ||
KeyValue::new("type", "on-chain"), | ||
KeyValue::new("status", "untrusted_pending"), | ||
], | ||
); | ||
use anyhow::Result; | ||
use diesel::r2d2::ConnectionManager; | ||
use diesel::r2d2::PooledConnection; | ||
use diesel::PgConnection; | ||
|
||
pub fn collect_metrics( | ||
mut conn: PooledConnection<ConnectionManager<PgConnection>>, | ||
node: Node, | ||
) -> Result<()> { | ||
let balance = node.inner.wallet().get_balance(); | ||
db::metrics::create_metrics_entry( | ||
&mut conn, | ||
balance.confirmed + balance.untrusted_pending + balance.trusted_pending + balance.immature, | ||
)?; | ||
// TODO: also collect LN balance | ||
|
||
Ok(()) | ||
} |
Oops, something went wrong.