Last active
September 21, 2018 07:12
-
-
Save meeDamian/fec388a943e0d4e64c876e6196a8d18f to your computer and use it in GitHub Desktop.
This is a series of utility functions to interface with RBP metrics, bitcoind, lnd and lightningd. To install, download and execute `install.sh` file.
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
#!/bin/sh | |
. /usr/local/lib/metrics/utilities.sh | |
# BITCOIN CORE | |
# ------------ | |
# | |
# * assumes default ~/.bitcoin folder location | |
# * tries to detect bitcoin-cli path | |
# * tries to determine user running bitcoind | |
# * whenever possible or makes sense the fn will try to cache the result | |
# Returns full path to bitcoin-cli | |
get_bitcoind_binary_path() { | |
_cache "command -v bitcoin-cli" | |
} | |
# Returns user under which bitcoind is running | |
get_bitcoind_user() { | |
_cache "ps -eo user:10,command | grep \"[b]itcoind\" | awk '{ print \$1 }' | grep -v root | head -n 1" | |
} | |
# Returns full path to bitcoind' data dir | |
get_bitcoind_data_dir_path() { | |
user="$(get_bitcoind_user)" | |
if [ -z "${user}" ]; then | |
return 1 | |
fi | |
path="/home/${user}/.bitcoin" | |
if [ ! -d "${path}" ]; then | |
return 1 | |
fi | |
echo "${path}" | |
} | |
# Returns exist code=0 if bitcoind is available, or exit code=1 otherwise | |
is_bitcoind_available() { | |
if [ -z "$(get_bitcoind_binary_path)" ] || [ -z "$(get_bitcoind_data_dir_path)" ]; then | |
return 1 | |
fi | |
return 0 | |
} | |
# Returns complete bitcoind command | |
get_bitcoind_full_cmd() { | |
if is_bitcoind_available; [ "$?" -ne "0" ]; then | |
return 1 | |
fi | |
echo "timeout 5s ${SUDO} $(get_bitcoind_binary_path) -datadir=$(get_bitcoind_data_dir_path)" | tr -s " " | |
} | |
# Returns & caches the output of `getblockchaininfo` command | |
_cache_bitcoind_getblockchaininfo() { | |
_cache_node "bitcoind" "getblockchaininfo" | |
} | |
# Returns & caches the output of `getpeerinfo` command | |
_cache_bitcoind_getpeerinfo() { | |
_cache_node "bitcoind" "getpeerinfo" | |
} | |
# Returns & caches the output of `getnetworkinfo` command | |
_cache_bitcoind_getnetworkinfo() { | |
_cache_node "bitcoind" "getnetworkinfo" | |
} | |
# Returns & caches the output of `getmempoolinfo` command | |
_cache_bitcoind_getmempoolinfo() { | |
_cache_node "bitcoind" "getmempoolinfo" | |
} | |
# Returns chain on which bitcoind instance is running: {mainnet,testnet,regnet} | |
get_bitcoind_chain() { | |
chain="$(_cache_bitcoind_getblockchaininfo | jq -r '.chain')" | |
if [ -z "${chain}" ]; then | |
return 1 | |
fi | |
echo "${chain}net" | |
} | |
# Returns the amount of blocks on the currently followed chain | |
get_bitcoind_blocks() { | |
blocks="$(_cache_bitcoind_getblockchaininfo | jq -r '.blocks')" | |
if [ -z "${blocks}" ]; then | |
return 1 | |
fi | |
echo "${blocks}" | |
} | |
# Return bitcoind chain sync progress (in %) | |
get_bitcoind_progress() { | |
progress="$(_cache_bitcoind_getblockchaininfo | jq -r '.verificationprogress')" | |
if [ -z "${progress}" ]; then | |
return 1 | |
fi | |
printf "%.2f%%" "$(echo ${progress} | awk '{print 100 * $1}')" | |
} | |
# Returns the amount of peers the node is currently connected to | |
# probably the same number as get_bitcoind_connection_count | |
get_bitcoind_peer_count() { | |
peers="$(_cache_bitcoind_getpeerinfo | jq 'length')" | |
if [ -z "${peers}" ]; then | |
return 1 | |
fi | |
echo "${peers}" | |
} | |
# Returns semver-like version of the running instance | |
get_bitcoind_version() { | |
version="$(_cache_bitcoind_getnetworkinfo | jq -r '.subversion' | grep -Po '((\d+\.?){3})')" | |
if [ -z "${version}" ]; then | |
return 1 | |
fi | |
echo "${version}" | |
} | |
# Returns a newline-separated list of addresses under which bitcoind should be reachable | |
get_bitcoind_addresses() { | |
addresses="$(_cache_bitcoind_getnetworkinfo | jq -r '[.localaddresses[] | [.address, .port|tostring] | join(":")] | join("\n")')" | |
if [ -z "${addresses}" ]; then | |
return 1 | |
fi | |
echo "${addresses}" | |
} | |
# Returns the amount of connections bitcoind has open | |
# probably the same number as get_bitcoind_peer_count | |
get_bitcoind_connection_count() { | |
connections="$(_cache_bitcoind_getnetworkinfo | jq -r '.connections')" | |
if [ -z "${connections}" ]; then | |
return 1 | |
fi | |
echo "${connections}" | |
} | |
# Returns the amount of transactions currently in the local mempool | |
get_bitcoind_mempool_count() { | |
mempool="$(_cache_bitcoind_getmempoolinfo | jq -r '.size')" | |
if [ -z "${mempool}" ]; then | |
return 1 | |
fi | |
echo "${mempool}" | |
} | |
# Returns current bitcoind balance | |
get_bitcoind_balance() { | |
# NOTE: special case/direct call/no cache | |
cmd="$(get_bitcoind_full_cmd)" | |
if [ -z "${cmd}" ]; then | |
return 1 | |
fi | |
balance=$(${cmd} getbalance 2>/dev/null) | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "${balance}" | |
return 0 | |
fi | |
echo "$(btc_to_sat ${balance})" | |
} | |
metrics_bitcoind_print_all() { | |
echo "~~~ BITCOIND ~~~" | |
_pair "path" "$(_handle_empty "$(get_bitcoind_binary_path)")" | |
_pair "user" "$(_handle_empty "$(get_bitcoind_user)")" | |
_pair "data" "$(_handle_empty "$(get_bitcoind_data_dir_path)")" | |
_pair "avail" "$(is_bitcoind_available && echo "yes" || echo "no")" | |
_pair "cmd" "$(_handle_empty "$(get_bitcoind_full_cmd)")" | |
_pair "chain" "$(_handle_empty "$(get_bitcoind_chain)")" | |
_pair "block" "$(_handle_empty "$(get_bitcoind_blocks)")" | |
_pair "ver" "$(_handle_empty "$(get_bitcoind_version)")" | |
_pair "addrs" "$(_handle_empty "$(get_bitcoind_addresses | tr "\n" " ")")" | |
_pair "sync" "$(_handle_empty "$(get_bitcoind_progress)")" | |
_pair "peers" "$(_handle_empty "$(get_bitcoind_peer_count)")" | |
_pair "conns" "$(_handle_empty "$(get_bitcoind_connection_count)")" | |
_pair "mempl" "$(_handle_empty "$(get_bitcoind_mempool_count)")" | |
_print_all_monetary_fmts "balance" "get_bitcoind_balance" | |
} |
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
#!/bin/sh | |
. /usr/local/lib/metrics/utilities.sh | |
# GENERAL RBP METRICS | |
# =================== | |
# Returns RBP hostname | |
get_host() { | |
hostname | |
} | |
# Returns current temperature (in C) as self-reported by RBP | |
get_temp() { | |
temp="$(/opt/vc/bin/vcgencmd measure_temp)" | |
if [ "$?" -ne "0" ]; then | |
return 1 | |
fi | |
echo "${temp}" | cut -d "'" -f 1 | cut -d "=" -f 2 | |
} | |
# Returns current voltage (in V) as self-reported by RBP | |
get_volt() { | |
volt="$(/opt/vc/bin/vcgencmd measure_volts core)" | |
if [ "$?" -ne "0" ]; then | |
return 1 | |
fi | |
echo "${volt}" | tr -d V | cut -d "=" -f 2 | |
} | |
# Returns current CPU frequency (in GHz) as self-reported by RBP | |
get_freq() { | |
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq | jq '. / 1e6' | |
} | |
get_is_undervolt() { | |
vcgencmd get_throttled | cut -d 'x' -f 2 | awk '{print "obase=2; ibase=16; "$1}' | bc | awk '{printf "%20s", $1}' | tr ' ' '0' | rev | cut -c $((0 + 1)) | |
} | |
get_is_throttled() { | |
vcgencmd get_throttled | cut -d 'x' -f 2 | awk '{print "obase=2; ibase=16; "$1}' | bc | awk '{printf "%20s", $1}' | tr ' ' '0' | rev | cut -c $((2 + 1)) | |
} | |
get_was_undervolt() { | |
vcgencmd get_throttled | cut -d 'x' -f 2 | awk '{print "obase=2; ibase=16; "$1}' | bc | awk '{printf "%20s", $1}' | tr ' ' '0' | rev | cut -c $((16 + 1)) | |
} | |
get_was_throttled() { | |
vcgencmd get_throttled | cut -d 'x' -f 2 | awk '{print "obase=2; ibase=16; "$1}' | bc | awk '{printf "%20s", $1}' | tr ' ' '0' | rev | cut -c $((18 + 1)) | |
} | |
# Returns SSID of the current WiFi | |
get_ssid() { | |
${SUDO} iwgetid --raw | |
} | |
# Returns currently assigned local IP | |
get_local_ip() { | |
ip route get 1 | awk '{print $NF;exit}' | |
} | |
# Returns currently assigned public IP | |
get_public_ip() { | |
curl -s ipinfo.io/ip | |
} | |
# Returns uptime in seconds | |
get_uptime() { | |
cat /proc/uptime | cut -d '.' -f 1 | |
} | |
is_external_storage_available() { | |
if df | grep "/dev/sd" 2>&1 1>/dev/null; [ "$?" -eq "0" ]; then | |
return 0 # available | |
fi | |
return 1 # not available | |
} | |
# Returns storage status specification in a form: | |
# {sd,ext} {total,used,free}: bytes human-readeable | |
# | |
# Example usage: | |
# get_storage | grep sd | grep free | cut -f 3 # for bytes | |
# get_storage | grep ext | grep free | cut -f 4 # for human-readeable | |
get_storage() { | |
_stor_mem_format "sd" "total" "$(df | grep '/$' | awk '{s = $3+$4} END {print s}')000" | |
_stor_mem_format "sd" "used" "$(df | grep '/$' | awk '{print $3}')000" | |
_stor_mem_format "sd" "free" "$(df | grep '/$' | awk '{print $4}')000" | |
if is_external_storage_available; [ "$?" -eq "0" ]; then | |
_stor_mem_format "ext" "total" "$(df | grep '/dev/sd' | awk '{s += $3+$4} END {print s}')000" | |
_stor_mem_format "ext" "used" "$(df | grep '/dev/sd' | awk '{s += $3 } END {print s}')000" | |
_stor_mem_format "ext" "free" "$(df | grep '/dev/sd' | awk '{s += $4} END {print s}')000" | |
fi | |
} | |
# Returns exit code=0 if SWAP is enabled, or exit code=1 otherwise | |
is_swap_enabled() { | |
if [ "$(cat /proc/swaps | wc -l)" -ge "2" ]; then | |
return 0 # enabled | |
fi | |
return 1 # disabled | |
} | |
# Returns memory status specification in a form: | |
# {ram,swap} {total,used,free}: bytes human-readeable | |
# | |
# Example usage: | |
# get_memory | grep ram | grep free | cut -f 3 # for bytes | |
# get_memory | grep swap | grep free | cut -f 4 # for human-readeable | |
get_memory() { | |
_stor_mem_format "ram" "total" "$(free -b | grep 'Mem' | awk '{print $2}')" | |
_stor_mem_format "ram" "used" "$(free -b | grep 'Mem' | awk '{print $3}')" | |
_stor_mem_format "ram" "free" "$(free -b | grep 'Mem' | awk '{print $4}')" | |
if is_swap_enabled; [ "$?" -eq "0" ]; then | |
_stor_mem_format "swap" "total" "$(free -b | grep 'Swap' | awk '{print $2}')" | |
_stor_mem_format "swap" "used" "$(free -b | grep 'Swap' | awk '{print $3}')" | |
_stor_mem_format "swap" "free" "$(free -b | grep 'Swap' | awk '{print $4}')" | |
fi | |
} | |
metrics_board_print_all() { | |
echo "~~~ BOARD ~~~" | |
_pair "host" "$(get_host)" | |
_pair "temp" "$(_handle_empty "$(get_temp)")" | |
_pair "volt" "$(_handle_empty "$(get_volt)")" | |
_pair "freq" "$(get_freq)" | |
_pair "ssid" "$(_handle_empty "$(get_ssid)")" | |
_pair "lan_ip" "$(get_local_ip)" | |
_pair "pub_ip" "$(get_public_ip)" | |
_pair "uptime" "$(get_uptime)" | |
_pair "is_undervolt" "$(get_is_undervolt)" | |
_pair "is_throttled" "$(get_is_throttled)" | |
_pair "was_undervolt" "$(get_was_undervolt)" | |
_pair "was_throttled" "$(get_was_throttled)" | |
_pair "ext_avail" "$(is_external_storage_available && echo "yes" || echo "no")" | |
get_storage | |
_pair "swap_enabled" "$(is_swap_enabled && echo "yes" || echo "no")" | |
get_memory | |
} |
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
#!/bin/sh | |
# Line below ensures that TERM is set, so that colors | |
# are displayed properly even if env is empty (ex. motd) | |
# src: https://unix.stackexchange.com/a/417223/31104 | |
export TERM="${TERM:-xterm-256color}" | |
BOLD=$(tput bold) | |
RED=$(tput setaf 1) | |
GREEN=$(tput setaf 2) | |
YELLOW=$(tput setaf 3) | |
BLUE=$(tput setaf 4) | |
VIOLET=$(tput setaf 5) | |
SOME_COLOR=$(tput setaf 6) | |
WHITE=$(tput setaf 7) | |
RESET_STYLE=$(tput sgr0) |
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
#!/bin/sh | |
if [ "$(id -u)" -ne "0" ]; then | |
echo "Installing these functions requires root" | |
exit 1 | |
fi | |
if command -v jq 2>&1 1>/dev/null; [ "$?" -ne "0" ]; then | |
echo "'jq' is needed by functions within this script. If you're on Debian-based system, you can install it with:" | |
echo " sudo apt install jq" | |
exit 1 | |
fi | |
if command -v bc 2>&1 1>/dev/null; [ "$?" -ne "0" ]; then | |
echo "'bc' is needed by functions within this script. If you're on Debian-based system, you can install it with:" | |
echo " sudo apt install bc" | |
exit 1 | |
fi | |
DEST=/usr/local/lib/metrics | |
mkdir -p "${DEST}" | |
wget -qN 'https://gist.githubusercontent.com/meeDamian/fec388a943e0d4e64c876e6196a8d18f/raw/36bb0af82a8ce1690ef37a2e5b0527824079e838/bitcoind.sh' -P "${DEST}" | |
wget -qN 'https://gist.githubusercontent.com/meeDamian/fec388a943e0d4e64c876e6196a8d18f/raw/33e976d80a41a8de5d3cc647e5e403e37e343d21/board.sh' -P "${DEST}" | |
wget -qN 'https://gist.githubusercontent.com/meeDamian/fec388a943e0d4e64c876e6196a8d18f/raw/9de742af6393df8ac61599aa27027c8801aa4a65/colors.sh' -P "${DEST}" | |
wget -qN 'https://gist.githubusercontent.com/meeDamian/fec388a943e0d4e64c876e6196a8d18f/raw/cf6d7804ffc424b2be93a224ed18c426f73680fe/lightningd.sh' -P "${DEST}" | |
wget -qN 'https://gist.githubusercontent.com/meeDamian/fec388a943e0d4e64c876e6196a8d18f/raw/97782561a08ebdc9635ab7584d8d2c82957b9bfe/lnd.sh' -P "${DEST}" | |
wget -qN 'https://gist.githubusercontent.com/meeDamian/fec388a943e0d4e64c876e6196a8d18f/raw/67306628651c2d3342df24cf7ad764141809306d/print.sh' -P "${DEST}" | |
wget -qN 'https://gist.githubusercontent.com/meeDamian/fec388a943e0d4e64c876e6196a8d18f/raw/a501bf1f76b7d891fb66a6ef3b27ab21391275af/utilities.sh' -P "${DEST}" | |
chmod -R +x "${DEST}/" | |
"${DEST}/print.sh" |
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
#!/bin/sh | |
. /usr/local/lib/metrics/utilities.sh | |
# C-LIGHTNING | |
# ----------- | |
# | |
# * assumes default ~/.lightning folder location | |
# * tries to detect lightning-cli path | |
# * tries to determine user running lightningd | |
# * whenever possible or makes sense the fn will try to cache the result | |
# Returns full path to lightning-cli | |
get_lightningd_binary_path() { | |
_cache "command -v lightning-cli" | |
} | |
# Returns user under which lightningd is running | |
get_lightningd_user() { | |
_cache "ps -eo user:10,command | grep \"[l]ightningd\" | awk '{ print \$1 }' | grep -v root | head -n 1" | |
} | |
# Returns full path to lightningd' data dir | |
get_lightningd_data_dir_path() { | |
user="$(get_lightningd_user)" | |
if [ -z "${user}" ]; then | |
return 1 | |
fi | |
path="/home/${user}/.lightning" | |
if [ ! -d "${path}" ]; then | |
return 1 | |
fi | |
echo "${path}" | |
} | |
# Returns exist code=0 if lightningd is available, or exit code=1 otherwise | |
is_lightningd_available() { | |
if [ -z "$(get_lightningd_binary_path)" ] || [ -z "$(get_lightningd_data_dir_path)" ]; then | |
return 1 | |
fi | |
return 0 | |
} | |
# Returns complete lightningd command | |
get_lightningd_full_cmd() { | |
if is_lightningd_available; [ "$?" -ne "0" ]; then | |
return 1 | |
fi | |
echo "timeout 5s ${SUDO} $(get_lightningd_binary_path) --lightning-dir=$(get_lightningd_data_dir_path)" | tr -s " " | |
} | |
# Returns & caches the output of `getinfo` command | |
_cache_lightningd_getinfo() { | |
_cache_node "lightningd" "getinfo" | |
} | |
# Returns & caches the output of `listpeers` command | |
_cache_lightningd_listpeers() { | |
_cache_node "lightningd" "listpeers" | |
} | |
# Returns & caches the output of `listfunds` command | |
_cache_lightningd_listfunds() { | |
_cache_node "lightningd" "listfunds" | |
} | |
# Returns & caches the output of `listconfigs` command | |
_cache_lightningd_listconfigs() { | |
_cache_node "lightningd" "listconfigs" | |
} | |
# Returns node's user-defined alias | |
get_lightningd_alias() { | |
alias="$(_cache_lightningd_listconfigs | jq -r '.alias')" | |
if [ -z "${alias}" ]; then | |
return 1 | |
fi | |
echo "${alias}" | |
} | |
# Returns chain on which lightningd instance is running: {mainnet,testnet,regnet} | |
get_lightningd_chain() { | |
chain="$(_cache_lightningd_getinfo | jq -r '.network')" | |
if [ -z "${chain}" ]; then | |
return 1 | |
fi | |
if [ "${chain}" = "bitcoin" ]; then | |
chain="mainnet" | |
fi | |
echo "${chain}" | |
} | |
# Returns the amount of blocks on the currently followed chain | |
get_lightningd_blocks() { | |
blocks="$(_cache_lightningd_getinfo | jq -r '.blockheight')" | |
if [ -z "${blocks}" ]; then | |
return 1 | |
fi | |
echo "${blocks}" | |
} | |
# Returns semver-like version of the running instance | |
get_lightningd_version() { | |
version="$(_cache_lightningd_getinfo | jq -r '.version')" | |
if [ -z "${version}" ]; then | |
return 1 | |
fi | |
echo "${version}" | |
} | |
# Returns pubkey | |
get_lightningd_pubkey() { | |
pubkey="$(_cache_lightningd_getinfo | jq -r '.id')" | |
if [ -z "${pubkey}" ]; then | |
return 1 | |
fi | |
echo "${pubkey}" | |
} | |
# Returns a tab-separated list of addresses under which lightningd should be reachable | |
get_lightningd_addresses() { | |
addresses="$(_cache_lightningd_getinfo | jq -r '[.address[] | [.address, .port|tostring] | join(":")] | join("\n")')" | |
if [ -z "${addresses}" ]; then | |
return 1 | |
fi | |
echo "${addresses}" | |
} | |
get_lightningd_address() { | |
if [ "$1" != "ipv4" ] && [ "$1" != "ipv6" ] && [ "$1" != "torv2" ] && [ "$1" != "torv3" ]; then | |
return 1 | |
fi | |
addresses="$(_cache_lightningd_getinfo | jq -r '[.address[] | select(.type == "'$1'") | [.address, .port|tostring] | join(":")] | join(" ")')" | |
if [ -z "${addresses}" ]; then | |
return 1 | |
fi | |
echo "${addresses}" | |
} | |
# Returns the amount of peers the node is currently connected to | |
get_lightningd_peer_count() { | |
peers="$(_cache_lightningd_listpeers | jq '.peers | length')" | |
if [ -z "${peers}" ]; then | |
return 1 | |
fi | |
echo "${peers}" | |
} | |
get_lightningd_channels_count_all() { | |
listpeers="$(_cache_lightningd_listpeers)" | |
if [ -z "${listpeers}" ]; then | |
return 1 | |
fi | |
all="$(echo "${listpeers}" | jq -r '[.peers[].channels | select(. != null)] | length')" | |
echo "${all:-0}" | |
} | |
get_lightningd_channels_count_pending() { | |
STATES="OPENINGD CHANNELD_AWAITING_LOCKIN" | |
listpeers="$(_cache_lightningd_listpeers)" | |
if [ -z "${listpeers}" ]; then | |
return 1 | |
fi | |
pending="$(echo "${listpeers}" | jq -r '.peers[].channels | select(. != null) | .[].state' | sort | uniq -c | grep "$(echo "${STATES}" | sed "s/ /\\\|/g")" | awk '{s += $1} END {print s}')" | |
echo "${pending:-0}" | |
} | |
get_lightningd_channels_count_open() { | |
STATES="CHANNELD_NORMAL" | |
listpeers="$(_cache_lightningd_listpeers)" | |
if [ -z "${listpeers}" ]; then | |
return 1 | |
fi | |
open="$(echo "${listpeers}" | jq -r '.peers[].channels | select(. != null) | .[].state' | sort | uniq -c | grep "$(echo "${STATES}" | sed "s/ /\\\|/g")" | awk '{s += $1} END {print s}')" | |
echo "${open:-0}" | |
} | |
get_lightningd_channels_count_closing() { | |
STATES="CHANNELD_SHUTTING_DOWN CLOSINGD_SIGEXCHANGE CLOSINGD_COMPLETE FUNDING_SPEND_SEEN" | |
listpeers="$(_cache_lightningd_listpeers)" | |
if [ -z "${listpeers}" ]; then | |
return 1 | |
fi | |
closing="$(echo "${listpeers}" | jq -r '.peers[].channels | select(. != null) | .[].state' | sort | uniq -c | grep "$(echo "${STATES}" | sed "s/ /\\\|/g")" | awk '{s += $1} END {print s}')" | |
echo "${closing:-0}" | |
} | |
get_lightningd_channels_count_other() { | |
NOT_STATES="OPENINGD CHANNELD_AWAITING_LOCKIN CHANNELD_NORMAL CHANNELD_SHUTTING_DOWN CLOSINGD_SIGEXCHANGE CLOSINGD_COMPLETE FUNDING_SPEND_SEEN" | |
listpeers="$(_cache_lightningd_listpeers)" | |
if [ -z "${listpeers}" ]; then | |
return 1 | |
fi | |
other="$(echo "${listpeers}" | jq -r '.peers[].channels | select(. != null) | .[].state' | sort | uniq -c | grep -v "$(echo "${NOT_STATES}" | sed "s/ /\\\|/g")" | awk '{s += $1} END {print s}')" | |
echo "${other:-0}" | |
} | |
get_lightningd_funds_onchain() { | |
listfunds="$(_cache_lightningd_listfunds)" | |
if [ -z "${listfunds}" ]; then | |
return 1 | |
fi | |
onchain="$(echo "${listfunds}" | jq '[.outputs[].value] | add | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${onchain}")" | |
return 0 | |
fi | |
echo "${onchain}" | |
} | |
get_lightningd_funds_chan_spend_total() { | |
listfunds="$(_cache_lightningd_listfunds)" | |
if [ -z "${listfunds}" ]; then | |
return 1 | |
fi | |
chan_spend_total="$(echo "${listfunds}" | jq '[.channels[].channel_sat] | add | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${chan_spend_total}")" | |
return 0 | |
fi | |
echo "${chan_spend_total}" | |
} | |
get_lightningd_funds_chan_spend_max() { | |
listfunds="$(_cache_lightningd_listfunds)" | |
if [ -z "${listfunds}" ]; then | |
return 1 | |
fi | |
chan_spend_max="$(echo "${listfunds}" | jq '[.channels[].channel_sat] | max | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${chan_spend_max}")" | |
return 0 | |
fi | |
echo "${chan_spend_max}" | |
} | |
get_lightningd_funds_chan_receive_total() { | |
listfunds="$(_cache_lightningd_listfunds)" | |
if [ -z "${listfunds}" ]; then | |
return 1 | |
fi | |
chan_receive_total="$(echo "${listfunds}" | jq '[.channels[] | .channel_total_sat - .channel_sat] | add | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${chan_receive_total}")" | |
return 0 | |
fi | |
echo "${chan_receive_total}" | |
} | |
get_lightningd_funds_chan_receive_max() { | |
listfunds="$(_cache_lightningd_listfunds)" | |
if [ -z "${listfunds}" ]; then | |
return 1 | |
fi | |
chan_receive_max="$(echo "${listfunds}" | jq '[.channels[] | .channel_total_sat - .channel_sat] | max | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${chan_receive_max}")" | |
return 0 | |
fi | |
echo "${chan_receive_max}" | |
} | |
metrics_lightningd_print_all() { | |
echo "~~~ C-LIGHTNING ~~~" | |
_pair "path" "$(_handle_empty "$(get_lightningd_binary_path)")" | |
_pair "user" "$(_handle_empty "$(get_lightningd_user)")" | |
_pair "data" "$(_handle_empty "$(get_lightningd_data_dir_path)")" | |
_pair "avail" "$(is_lightningd_available && echo "yes" || echo "no")" | |
_pair "cmd" "$(_handle_empty "$(get_lightningd_full_cmd)")" | |
_pair "alias" "$(_handle_empty "$(get_lightningd_alias)")" | |
_pair "chain" "$(_handle_empty "$(get_lightningd_chain)")" | |
_pair "block" "$(_handle_empty "$(get_lightningd_blocks)")" | |
_pair "ver" "$(_handle_empty "$(get_lightningd_version)")" | |
_pair "pubkey" "$(_handle_empty "$(get_lightningd_pubkey)")" | |
_pair "addrs" "$(_handle_empty "$(get_lightningd_addresses | tr "\n" " ")")" | |
_pair "ipv4" "$(_handle_empty "$(get_lightningd_address ipv4)")" | |
_pair "ipv6" "$(_handle_empty "$(get_lightningd_address ipv6)")" | |
_pair "torv2" "$(_handle_empty "$(get_lightningd_address torv2)")" | |
_pair "torv3" "$(_handle_empty "$(get_lightningd_address torv3)")" | |
_pair "peers" "$(_handle_empty "$(get_lightningd_peer_count)")" | |
_pair "chan_all" "$(_handle_empty "$(get_lightningd_channels_count_all)")" | |
_pair "chan_pending" "$(_handle_empty "$(get_lightningd_channels_count_pending)")" | |
_pair "chan_open" "$(_handle_empty "$(get_lightningd_channels_count_open)")" | |
_pair "chan_closing" "$(_handle_empty "$(get_lightningd_channels_count_closing)")" | |
_pair "chan_other" "$(_handle_empty "$(get_lightningd_channels_count_other)")" | |
_print_all_monetary_fmts "funds_chain" "get_lightningd_funds_onchain" | |
_print_all_monetary_fmts "spendable_tot" "get_lightningd_funds_chan_spend_total" | |
_print_all_monetary_fmts "spendable_max" "get_lightningd_funds_chan_spend_max" | |
_print_all_monetary_fmts "receive_tot" "get_lightningd_funds_chan_receive_total" | |
_print_all_monetary_fmts "receive_max" "get_lightningd_funds_chan_receive_max" | |
} |
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
#!/bin/sh | |
. /usr/local/lib/metrics/utilities.sh | |
# LND | |
# ----------- | |
# | |
# * assumes default ~/.lnd folder location | |
# * tries to detect lncli path | |
# * tries to determine user running lnd | |
# * whenever possible or makes sense the fn will try to cache the result | |
# Returns full path to lncli | |
get_lnd_binary_path() { | |
_cache "command -v lncli" | |
} | |
# Returns user under which lnd is running | |
get_lnd_user() { | |
_cache "ps -eo user:10,command | grep \"[l]nd\" | awk '{ print \$1 }' | grep -v root | head -n 1" | |
} | |
# Returns full path to lnd' data dir | |
get_lnd_data_dir_path() { | |
user="$(get_lnd_user)" | |
if [ -z "${user}" ]; then | |
return 1 | |
fi | |
path="/home/${user}/.lnd" | |
if [ ! -d "${path}" ]; then | |
return 1 | |
fi | |
echo "${path}" | |
} | |
# Returns exist code=0 if lnd is available, or exit code=1 otherwise | |
is_lnd_available() { | |
if [ -z "$(get_lnd_binary_path)" ] || [ -z "$(get_lnd_data_dir_path)" ]; then | |
return 1 | |
fi | |
return 0 | |
} | |
# Returns complete lnd command | |
get_lnd_full_cmd() { | |
if is_lnd_available; [ "$?" -ne "0" ]; then | |
return 1 | |
fi | |
# NOTE: starting with lnd version 0.5 `lncli` requires `-n={test,main,reg}net` param to be passed | |
# NOTE: this is a rather naive approach, but should work for now… | |
ver="$($(get_lnd_binary_path) --version | awk '{print $3}')" | |
major="$(echo ${ver} | cut -d '.' -f 1)" | |
minor="$(echo ${ver} | cut -d '.' -f 2)" | |
if [ "${major}" -ge "0" ] && [ "${minor}" -ge "5" ]; then | |
networks="mainnet testnet regnet" | |
for NETWORK in ${networks}; do | |
if [ -f "$(get_lnd_data_dir_path)/data/chain/bitcoin/${NETWORK}/admin.macaroon" ]; then | |
network_flag="--network=${NETWORK}" | |
break | |
fi | |
done | |
fi | |
echo "timeout 5s ${SUDO} $(get_lnd_binary_path) ${network_flag} --lnddir=$(get_lnd_data_dir_path)" | tr -s " " | |
} | |
# Returns & caches the output of `getinfo` command | |
_cache_lnd_getinfo() { | |
_cache_node "lnd" "getinfo" | |
} | |
# Returns & caches the output of `pendingchannels` command | |
_cache_lnd_pendingchannels() { | |
_cache_node "lnd" "pendingchannels" | |
} | |
# Returns & caches the output of `listchannels` command | |
_cache_lnd_listchannels() { | |
_cache_node "lnd" "listchannels" | |
} | |
# Returns & caches the output of `walletbalance` command | |
_cache_lnd_walletbalance() { | |
_cache_node "lnd" "walletbalance" | |
} | |
# Returns & caches the output of `walletbalance` command | |
_cache_lnd_fwdinghistory() { | |
_cache_node "lnd" "fwdinghistory --max_events=10000000 --start_time=1 --end_time=$(date +%s)" | |
} | |
# Returns node's user-defined alias | |
get_lnd_alias() { | |
alias="$(_cache_lnd_getinfo | jq -r '.alias')" | |
if [ -z "${alias}" ]; then | |
return 1 | |
fi | |
echo "${alias}" | |
} | |
# Returns chain on which lnd instance is running: {mainnet,testnet} | |
get_lnd_chain() { | |
is_testnet="$(_cache_lnd_getinfo | jq -r '.testnet')" | |
if [ -z "${is_testnet}" ]; then | |
return 1 | |
fi | |
chain="mainnet" | |
if [ "${is_testnet}" = "true" ]; then | |
chain="testnet" | |
fi | |
echo "${chain}" | |
} | |
# Returns the amount of blocks on the currently followed chain | |
get_lnd_blocks() { | |
blocks="$(_cache_lnd_getinfo | jq -r '.block_height')" | |
if [ -z "${blocks}" ]; then | |
return 1 | |
fi | |
echo "${blocks}" | |
} | |
# Returns semver-like version of the running instance | |
get_lnd_version() { | |
version="$(_cache_lnd_getinfo | jq -r '.version' | cut -d ' ' -f 1)" | |
if [ -z "${version}" ]; then | |
return 1 | |
fi | |
echo "${version}" | |
} | |
# Returns pubkey | |
get_lnd_pubkey() { | |
pubkey="$(_cache_lnd_getinfo | jq -r '.identity_pubkey')" | |
if [ -z "${pubkey}" ]; then | |
return 1 | |
fi | |
echo "${pubkey}" | |
} | |
# Returns a tab-separated list of addresses under which lnd should be reachable | |
get_lnd_addresses() { | |
addresses="$(_cache_lnd_getinfo | jq -r '.uris | map(split ("@")[1]) | join("\n")')" | |
if [ -z "${addresses}" ]; then | |
return 1 | |
fi | |
echo "${addresses}" | |
} | |
# get_lnd_address() { | |
# if [ "$1" != "ipv4" ] && [ "$1" != "ipv6" ] && [ "$1" != "torv2" ] && [ "$1" != "torv3" ]; then | |
# return 1 | |
# fi | |
# | |
# addresses="$(_cache_lnd_getinfo | jq -r '[.address[] | select(.type == "'$1'") | [.address, .port|tostring] | join(":")] | join(" ")')" | |
# if [ -z "${addresses}" ]; then | |
# return 1 | |
# fi | |
# | |
# echo "${addresses}" | |
# } | |
# Returns the amount of peers the node is currently connected to | |
get_lnd_peer_count() { | |
peers="$(_cache_lnd_getinfo | jq '.num_peers')" | |
if [ -z "${peers}" ]; then | |
return 1 | |
fi | |
echo "${peers}" | |
} | |
get_lnd_channels_count_all() { | |
ch_pending="$(get_lnd_channels_count_pending)" | |
ch_open="$(get_lnd_channels_count_open)" | |
ch_closing="$(get_lnd_channels_count_closing)" | |
if [ "$?" -ne "0" ]; then | |
return 1 | |
fi | |
echo $(( ${ch_pending:-0} + ${ch_open:-0} + ${ch_closing:-0} )) | |
} | |
get_lnd_channels_count_pending() { | |
pendingchannels="$(_cache_lnd_pendingchannels)" | |
if [ -z "${pendingchannels}" ]; then | |
return 1 | |
fi | |
pending="$(echo "${pendingchannels}" | jq -r '.pending_open_channels | length')" | |
if [ "$?" -ne "0" ]; then | |
return 1 | |
fi | |
echo "${pending:-0}" | |
} | |
get_lnd_channels_count_open() { | |
listchannels="$(_cache_lnd_listchannels)" | |
if [ -z "${listchannels}" ]; then | |
return 1 | |
fi | |
open="$(echo "${listchannels}" | jq -r '.channels | length')" | |
echo "${open:-0}" | |
} | |
get_lnd_channels_count_closing() { | |
pendingchannels="$(_cache_lnd_pendingchannels)" | |
if [ -z "${pendingchannels}" ]; then | |
return 1 | |
fi | |
closing="$(echo "${pendingchannels}" | jq -r '[.pending_closing_channels, .pending_force_closing_channels, .waiting_close_channels] | map(length) | add')" | |
echo "${closing:-0}" | |
} | |
get_lnd_relayed_txs_count() { | |
relays="$(_cache_lnd_fwdinghistory)" | |
if [ -z "${relays}" ]; then | |
return 1 | |
fi | |
echo "${relays}" | jq '.forwarding_events | length | if . == null then 0 else . end' | |
} | |
get_lnd_relayed_txs_earned() { | |
relays="$(_cache_lnd_fwdinghistory)" | |
if [ -z "${relays}" ]; then | |
return 1 | |
fi | |
earned="$(echo "${relays}" | jq '[.forwarding_events[].fee | tonumber] | add | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${earned}")" | |
return 0 | |
fi | |
echo "${earned}" | |
} | |
get_lnd_funds_onchain() { | |
walletbalance="$(_cache_lnd_walletbalance)" | |
if [ -z "${walletbalance}" ]; then | |
return 1 | |
fi | |
onchain="$(echo "${walletbalance}" | jq -r '.total_balance | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${onchain}")" | |
return 0 | |
fi | |
echo "${onchain}" | |
} | |
get_lnd_funds_chan_spend_total() { | |
listchannels="$(_cache_lnd_listchannels)" | |
if [ -z "${listchannels}" ]; then | |
return 1 | |
fi | |
chan_spend_total="$(echo "${listchannels}" | jq '[.channels[].local_balance] | map(tonumber) | add | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${chan_spend_total}")" | |
return 0 | |
fi | |
echo "${chan_spend_total}" | |
} | |
get_lnd_funds_chan_spend_max() { | |
listchannels="$(_cache_lnd_listchannels)" | |
if [ -z "${listchannels}" ]; then | |
return 1 | |
fi | |
chan_spend_max="$(echo "${listchannels}" | jq '[.channels[].local_balance] | map(tonumber) | max | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${chan_spend_max}")" | |
return 0 | |
fi | |
echo "${chan_spend_max}" | |
} | |
get_lnd_funds_chan_receive_total() { | |
listchannels="$(_cache_lnd_listchannels)" | |
if [ -z "${listchannels}" ]; then | |
return 1 | |
fi | |
chan_receive_total="$(echo "${listchannels}" | jq '[.channels[] | .remote_balance] | map(tonumber) | add | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${chan_receive_total}")" | |
return 0 | |
fi | |
echo "${chan_receive_total}" | |
} | |
get_lnd_funds_chan_receive_max() { | |
listchannels="$(_cache_lnd_listchannels)" | |
if [ -z "${listchannels}" ]; then | |
return 1 | |
fi | |
chan_receive_max="$(echo "${listchannels}" | jq '[.channels[] | .remote_balance] | map(tonumber) | max | if . == null then 0 else . end')" | |
if [ "$1" = "btc" ]; then | |
printf "%0.8f" "$(sat_to_btc "${chan_receive_max}")" | |
return 0 | |
fi | |
echo "${chan_receive_max}" | |
} | |
metrics_lnd_print_all() { | |
echo "~~~ LND ~~~" | |
_pair "path" "$(_handle_empty "$(get_lnd_binary_path)")" | |
_pair "user" "$(_handle_empty "$(get_lnd_user)")" | |
_pair "data" "$(_handle_empty "$(get_lnd_data_dir_path)")" | |
_pair "avail" "$(is_lnd_available && echo "yes" || echo "no")" | |
_pair "cmd" "$(_handle_empty "$(get_lnd_full_cmd)")" | |
_pair "alias" "$(_handle_empty "$(get_lnd_alias)")" | |
_pair "chain" "$(_handle_empty "$(get_lnd_chain)")" | |
_pair "block" "$(_handle_empty "$(get_lnd_blocks)")" | |
_pair "ver" "$(_handle_empty "$(get_lnd_version)")" | |
_pair "pubkey" "$(_handle_empty "$(get_lnd_pubkey)")" | |
_pair "addrs" "$(_handle_empty "$(get_lnd_addresses | tr "\n" " ")")" | |
# _pair "ipv4" "$(_handle_empty "$(get_lnd_address ipv4)")" | |
# _pair "ipv6" "$(_handle_empty "$(get_lnd_address ipv6)")" | |
# _pair "torv2" "$(_handle_empty "$(get_lnd_address torv2)")" | |
# _pair "torv3" "$(_handle_empty "$(get_lnd_address torv3)")" | |
_pair "peers" "$(_handle_empty "$(get_lnd_peer_count)")" | |
_pair "chan_all" "$(_handle_empty "$(get_lnd_channels_count_all)")" | |
_pair "chan_pending" "$(_handle_empty "$(get_lnd_channels_count_pending)")" | |
_pair "chan_open" "$(_handle_empty "$(get_lnd_channels_count_open)")" | |
_pair "chan_closing" "$(_handle_empty "$(get_lnd_channels_count_closing)")" | |
_pair "relay_count" "$(_handle_empty "$(get_lnd_relayed_txs_count)")" | |
_print_all_monetary_fmts "relay_earn" "get_lnd_relayed_txs_earned" | |
_print_all_monetary_fmts "funds_chain" "get_lnd_funds_onchain" | |
_print_all_monetary_fmts "spendable_tot" "get_lnd_funds_chan_spend_total" | |
_print_all_monetary_fmts "spendable_max" "get_lnd_funds_chan_spend_max" | |
_print_all_monetary_fmts "receive_tot" "get_lnd_funds_chan_receive_total" | |
_print_all_monetary_fmts "receive_max" "get_lnd_funds_chan_receive_max" | |
} |
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
#!/bin/sh | |
# GOALS OF THIS SCRIPT: | |
# * create minimal functions that return data in predictable format | |
# * make sure that whatever makes sense to be cached, is cached | |
scope="$1" | |
if [ -z "${scope}" ]; then | |
scope="all" | |
fi | |
if [ "${scope}" = "board" ] || [ "${scope}" = "all" ]; then | |
. /usr/local/lib/metrics/board.sh | |
metrics_board_print_all | |
fi | |
if [ "${scope}" = "bitcoind" ] || [ "${scope}" = "all" ]; then | |
. /usr/local/lib/metrics/bitcoind.sh | |
echo | |
metrics_bitcoind_print_all | |
fi | |
if [ "${scope}" = "lightningd" ] || [ "${scope}" = "all" ]; then | |
. /usr/local/lib/metrics/lightningd.sh | |
echo | |
metrics_lightningd_print_all | |
fi | |
if [ "${scope}" = "lnd" ] || [ "${scope}" = "all" ]; then | |
. /usr/local/lib/metrics/lnd.sh | |
echo | |
metrics_lnd_print_all | |
fi |
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
#!/bin/sh | |
# UTILITY FUNCTIONS | |
# ================= | |
# Returns $1, if available or `-`, if not | |
_handle_empty() { | |
[ -z "$1" ] && echo "-" || echo "$1" | |
} | |
# Formats $1/key and $2/value for display purposes | |
_pair() { | |
echo "$1: $2" | |
} | |
# Formats line to a format: | |
# $1<tab>$2:<tab>to_num($3)<tab>to_human_readeable($3) | |
_stor_mem_format() { | |
val="-" | |
if [ ! -z "$3" ]; then | |
val="$(echo ${3} | numfmt) $(echo "${3}" | numfmt --to=si)" | |
fi | |
_pair "$1 $2" "${val}" | |
} | |
_print_all_monetary_fmts() { | |
btc="$($2 btc)" | |
if [ "$?" -ne "0" ]; then | |
_pair "$1" "-" | |
return 1 | |
fi | |
sat="$($2)" | |
_pair "$1" "$(_handle_empty ${btc}) $(_handle_empty "$(fmt_simplify "${btc}")") $(_handle_empty ${sat})" | |
} | |
_cache() { | |
_CACHE_PATH="/tmp/metrics/$(whoami)" | |
if [ -z "$1" ]; then | |
return 1 | |
fi | |
cmd="$1" | |
if [ ! -z "$2" ]; then | |
cmd="${cmd} $2" | |
fi | |
filename="$(echo "${cmd}" | sed "s/[^a-zA-Z0-9]/_/g" | tr -s '_')" | |
full_path="${_CACHE_PATH}/${filename}" | |
if [ ! -f "${full_path}" ] || [ ! -z "$(find ${full_path} -mmin +1)" ]; then | |
mkdir -p "${_CACHE_PATH}" | |
if result="$(eval "${cmd} 2>&1")"; then | |
out="${result}" | |
else | |
logger -t metrics "${result}" | |
return 1 | |
fi | |
echo "${out}" > ${full_path} | |
chmod 777 "$full_path" | |
fi | |
echo "$(cat ${full_path})" | |
} | |
_cache_node() { | |
if [ -z "$1" ]; then | |
return 1 | |
fi | |
cmd="$(get_$1_full_cmd)" | |
if [ "$?" -ne "0" ]; then | |
return 1 | |
fi | |
_cache "${cmd}" "$2" | |
} | |
# Determines `sudo` capabilities, and returns prefix accordingly: | |
# if `root` - no sudo prefix necessary | |
# if user can do `sudo` - return prefix for non-interactive sudo | |
# if user can't do `sudo` - return `exit 1 &&` as prefix to quickly terminate command that would fail anyway | |
# | |
# Usage: | |
# Prepend ${SUDO} to a command that needs `sudo` privileges | |
_sudo_prefix() { | |
if [ "$(id -u)" -eq "0" ]; then | |
return 0 | |
fi | |
if sudo -n true 2> /dev/null; [ "$?" -eq "0" ]; then | |
echo "sudo -n" | |
return 0 | |
fi | |
logger -t metrics "can't grant sudo to $(whoami)" | |
echo "exit 1 &&" | |
} | |
SUDO="$(_sudo_prefix)" | |
btc_to_sat() { | |
echo "$1" | jq '. * 1e8' | |
} | |
sat_to_btc() { | |
echo "$1" | jq '. / 1e8' | |
} | |
fmt_simplify() { | |
echo "$1" | jq '.' | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment