a1a17e81a1
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
523 lines
21 KiB
Bash
Executable File
523 lines
21 KiB
Bash
Executable File
#!/bin/bash
|
|
################################################################################
|
|
# Script Name: network-info-exporter.sh
|
|
# Description: Prometheus exporter for Linux network metrics
|
|
#
|
|
# Collects interface statistics, connection states, routing info, firewall
|
|
# rules, DNS configuration, protocol statistics, and latency measurements.
|
|
#
|
|
# Author: Phil Connor
|
|
# Contact: contact@mylinux.work
|
|
# Website: https://mylinux.work
|
|
# License: MIT
|
|
# Version: 3.0
|
|
#
|
|
# Usage:
|
|
# # Output to stdout
|
|
# ./network-info-exporter.sh
|
|
#
|
|
# # Textfile collector mode (atomic write)
|
|
# ./network-info-exporter.sh --textfile
|
|
#
|
|
# # Custom output file
|
|
# ./network-info-exporter.sh -o /path/to/metrics.prom
|
|
#
|
|
################################################################################
|
|
|
|
# ============================================================================
|
|
# CONFIGURATION VARIABLES
|
|
# ============================================================================
|
|
|
|
TEXTFILE_DIR="/var/lib/node_exporter"
|
|
OUTPUT_FILE=""
|
|
HOSTNAME=$(hostname)
|
|
|
|
PING_TARGETS="${PING_TARGETS:-8.8.8.8 1.1.1.1 google.com}"
|
|
PING_COUNT="${PING_COUNT:-5}"
|
|
PING_TIMEOUT="${PING_TIMEOUT:-2}"
|
|
|
|
# ============================================================================
|
|
# HELPER FUNCTIONS
|
|
# ============================================================================
|
|
|
|
show_usage() {
|
|
cat <<EOF
|
|
Usage: $0 [OPTIONS]
|
|
|
|
Export Linux network metrics as Prometheus metrics.
|
|
|
|
MODES:
|
|
--textfile Write to node_exporter textfile collector
|
|
(writes to $TEXTFILE_DIR/network_info.prom)
|
|
|
|
OPTIONS:
|
|
-o, --output Output file path (for custom locations)
|
|
-h, --help Show this help message
|
|
|
|
EXAMPLES:
|
|
$0 # Output to stdout
|
|
$0 --textfile # Write to textfile collector
|
|
$0 -o /tmp/network.prom # Write to custom file
|
|
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-h|--help) show_usage ;;
|
|
--textfile) OUTPUT_FILE="$TEXTFILE_DIR/network_info.prom"; shift ;;
|
|
-o|--output) OUTPUT_FILE="$2"; shift 2 ;;
|
|
*) echo "Unknown option: $1" >&2; exit 1 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# ============================================================================
|
|
# METRIC GENERATION
|
|
# ============================================================================
|
|
|
|
generate_metrics() {
|
|
local START_TIME
|
|
START_TIME=$(date +%s.%N)
|
|
|
|
# --- System info ---
|
|
echo "# HELP network_exporter_info Exporter and system information"
|
|
echo "# TYPE network_exporter_info gauge"
|
|
local kernel arch os_name os_version
|
|
kernel=$(uname -r)
|
|
arch=$(uname -m)
|
|
if [[ -f /etc/os-release ]]; then
|
|
. /etc/os-release
|
|
os_name="${NAME:-unknown}"
|
|
os_version="${VERSION_ID:-unknown}"
|
|
else
|
|
os_name="unknown"
|
|
os_version="unknown"
|
|
fi
|
|
echo "network_exporter_info{hostname=\"${HOSTNAME}\",kernel=\"${kernel}\",arch=\"${arch}\",os=\"${os_name}\",version=\"${os_version}\"} 1"
|
|
echo ""
|
|
|
|
# --- Interface counters from /proc/net/dev ---
|
|
if [[ -r /proc/net/dev ]]; then
|
|
awk '
|
|
NR > 2 {
|
|
sub(/:/, " ")
|
|
iface = $1
|
|
if (iface == "lo") next
|
|
devices[count++] = iface
|
|
rx_bytes[iface] = $2; rx_packets[iface] = $3
|
|
rx_errors[iface] = $4; rx_dropped[iface] = $5
|
|
tx_bytes[iface] = $10; tx_packets[iface] = $11
|
|
tx_errors[iface] = $12; tx_dropped[iface] = $13
|
|
}
|
|
END {
|
|
metrics["receive_bytes"] = "Total bytes received"; t["receive_bytes"] = "counter"
|
|
metrics["receive_packets"] = "Total packets received"; t["receive_packets"] = "counter"
|
|
metrics["receive_errors"] = "Total receive errors"; t["receive_errors"] = "counter"
|
|
metrics["receive_dropped"] = "Total receive drops"; t["receive_dropped"] = "counter"
|
|
metrics["transmit_bytes"] = "Total bytes transmitted"; t["transmit_bytes"] = "counter"
|
|
metrics["transmit_packets"] = "Total packets transmitted"; t["transmit_packets"] = "counter"
|
|
metrics["transmit_errors"] = "Total transmit errors"; t["transmit_errors"] = "counter"
|
|
metrics["transmit_dropped"] = "Total transmit drops"; t["transmit_dropped"] = "counter"
|
|
|
|
order[0]="receive_bytes"; order[1]="receive_packets"
|
|
order[2]="receive_errors"; order[3]="receive_dropped"
|
|
order[4]="transmit_bytes"; order[5]="transmit_packets"
|
|
order[6]="transmit_errors"; order[7]="transmit_dropped"
|
|
|
|
for (m = 0; m < 8; m++) {
|
|
key = order[m]
|
|
name = "network_" key "_total"
|
|
printf "# HELP %s %s\n", name, metrics[key]
|
|
printf "# TYPE %s %s\n", name, t[key]
|
|
for (i = 0; i < count; i++) {
|
|
d = devices[i]
|
|
if (key == "receive_bytes") v = rx_bytes[d]
|
|
else if (key == "receive_packets") v = rx_packets[d]
|
|
else if (key == "receive_errors") v = rx_errors[d]
|
|
else if (key == "receive_dropped") v = rx_dropped[d]
|
|
else if (key == "transmit_bytes") v = tx_bytes[d]
|
|
else if (key == "transmit_packets") v = tx_packets[d]
|
|
else if (key == "transmit_errors") v = tx_errors[d]
|
|
else if (key == "transmit_dropped") v = tx_dropped[d]
|
|
printf "%s{device=\"%s\",hostname=\"%s\"} %s\n", name, d, ENVIRON["HOSTNAME"], v
|
|
}
|
|
print ""
|
|
}
|
|
}
|
|
' /proc/net/dev
|
|
fi
|
|
|
|
# --- Interface status, MTU, queue length, speed ---
|
|
echo "# HELP network_interface_up Interface operational status (1=up, 0=down)"
|
|
echo "# TYPE network_interface_up gauge"
|
|
echo "# HELP network_interface_mtu Interface MTU size"
|
|
echo "# TYPE network_interface_mtu gauge"
|
|
echo "# HELP network_interface_tx_queue_length Interface transmit queue length"
|
|
echo "# TYPE network_interface_tx_queue_length gauge"
|
|
echo "# HELP network_interface_speed_mbps Interface link speed in Mbps"
|
|
echo "# TYPE network_interface_speed_mbps gauge"
|
|
|
|
for iface_path in /sys/class/net/*; do
|
|
iface=$(basename "$iface_path")
|
|
[[ "$iface" == "lo" ]] && continue
|
|
|
|
# status
|
|
local operstate
|
|
operstate=$(cat "$iface_path/operstate" 2>/dev/null) || operstate="unknown"
|
|
if [[ "$operstate" == "up" ]]; then
|
|
echo "network_interface_up{device=\"${iface}\",hostname=\"${HOSTNAME}\"} 1"
|
|
else
|
|
echo "network_interface_up{device=\"${iface}\",hostname=\"${HOSTNAME}\"} 0"
|
|
fi
|
|
|
|
# mtu
|
|
local mtu
|
|
mtu=$(cat "$iface_path/mtu" 2>/dev/null) || mtu=0
|
|
echo "network_interface_mtu{device=\"${iface}\",hostname=\"${HOSTNAME}\"} ${mtu}"
|
|
|
|
# tx queue length
|
|
local qlen
|
|
qlen=$(cat "$iface_path/tx_queue_len" 2>/dev/null) || qlen=0
|
|
echo "network_interface_tx_queue_length{device=\"${iface}\",hostname=\"${HOSTNAME}\"} ${qlen}"
|
|
|
|
# speed (only for physical interfaces with valid speed)
|
|
if [[ -r "$iface_path/speed" ]]; then
|
|
local speed
|
|
speed=$(cat "$iface_path/speed" 2>/dev/null) || speed=-1
|
|
if [[ "$speed" =~ ^[0-9]+$ ]] && [[ "$speed" -gt 0 ]]; then
|
|
echo "network_interface_speed_mbps{device=\"${iface}\",hostname=\"${HOSTNAME}\"} ${speed}"
|
|
fi
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
# --- Routing ---
|
|
echo "# HELP network_routes_total Route count by protocol"
|
|
echo "# TYPE network_routes_total gauge"
|
|
if command -v ip &>/dev/null; then
|
|
local ipv4_routes ipv6_routes default_routes
|
|
ipv4_routes=$(ip route show 2>/dev/null | wc -l)
|
|
ipv6_routes=$(ip -6 route show 2>/dev/null | wc -l)
|
|
default_routes=$(ip route show default 2>/dev/null | wc -l)
|
|
echo "network_routes_total{family=\"ipv4\",hostname=\"${HOSTNAME}\"} ${ipv4_routes}"
|
|
echo "network_routes_total{family=\"ipv6\",hostname=\"${HOSTNAME}\"} ${ipv6_routes}"
|
|
echo "network_routes_total{type=\"default\",hostname=\"${HOSTNAME}\"} ${default_routes}"
|
|
fi
|
|
echo ""
|
|
|
|
# --- DNS nameservers ---
|
|
echo "# HELP network_dns_nameservers_configured Number of configured DNS nameservers"
|
|
echo "# TYPE network_dns_nameservers_configured gauge"
|
|
local ns_count=0
|
|
if [[ -r /etc/resolv.conf ]]; then
|
|
ns_count=$(grep -c "^nameserver" /etc/resolv.conf 2>/dev/null) || ns_count=0
|
|
fi
|
|
echo "network_dns_nameservers_configured{hostname=\"${HOSTNAME}\"} ${ns_count}"
|
|
echo ""
|
|
|
|
# --- Firewall rules ---
|
|
echo "# HELP network_firewall_rules_total Firewall rule count"
|
|
echo "# TYPE network_firewall_rules_total gauge"
|
|
local ipt_rules=0 ip6t_rules=0
|
|
if command -v iptables &>/dev/null; then
|
|
ipt_rules=$(iptables -S 2>/dev/null | grep -c '^-A' 2>/dev/null) || ipt_rules=0
|
|
fi
|
|
if command -v ip6tables &>/dev/null; then
|
|
ip6t_rules=$(ip6tables -S 2>/dev/null | grep -c '^-A' 2>/dev/null) || ip6t_rules=0
|
|
fi
|
|
echo "network_firewall_rules_total{family=\"ipv4\",hostname=\"${HOSTNAME}\"} ${ipt_rules}"
|
|
echo "network_firewall_rules_total{family=\"ipv6\",hostname=\"${HOSTNAME}\"} ${ip6t_rules}"
|
|
echo ""
|
|
|
|
# --- Network service status ---
|
|
if command -v systemctl &>/dev/null; then
|
|
echo "# HELP network_service_active Network service status (1=active, 0=inactive)"
|
|
echo "# TYPE network_service_active gauge"
|
|
for svc in NetworkManager networking systemd-networkd dhcpcd wpa_supplicant; do
|
|
local status=0
|
|
systemctl is-active "$svc" &>/dev/null && status=1
|
|
echo "network_service_active{service=\"${svc}\",hostname=\"${HOSTNAME}\"} ${status}"
|
|
done
|
|
echo ""
|
|
fi
|
|
|
|
# --- Socket stats from /proc/net/sockstat ---
|
|
if [[ -r /proc/net/sockstat ]]; then
|
|
echo "# HELP network_sockets_inuse Sockets currently in use by protocol"
|
|
echo "# TYPE network_sockets_inuse gauge"
|
|
local tcp_inuse udp_inuse raw_inuse
|
|
tcp_inuse=$(awk '/^TCP:/ {print $3}' /proc/net/sockstat 2>/dev/null) || tcp_inuse=0
|
|
udp_inuse=$(awk '/^UDP:/ {print $3}' /proc/net/sockstat 2>/dev/null) || udp_inuse=0
|
|
raw_inuse=$(awk '/^RAW:/ {print $3}' /proc/net/sockstat 2>/dev/null) || raw_inuse=0
|
|
echo "network_sockets_inuse{protocol=\"tcp\",hostname=\"${HOSTNAME}\"} ${tcp_inuse:-0}"
|
|
echo "network_sockets_inuse{protocol=\"udp\",hostname=\"${HOSTNAME}\"} ${udp_inuse:-0}"
|
|
echo "network_sockets_inuse{protocol=\"raw\",hostname=\"${HOSTNAME}\"} ${raw_inuse:-0}"
|
|
echo ""
|
|
fi
|
|
|
|
# --- TCP retransmissions and listen overflows from /proc/net/netstat ---
|
|
if [[ -r /proc/net/netstat ]]; then
|
|
local tcp_retrans=0 listen_overflows=0 listen_drops=0
|
|
# Parse TcpExt header+values pair
|
|
local headers values
|
|
headers=$(grep "^TcpExt:" /proc/net/netstat | head -1)
|
|
values=$(grep "^TcpExt:" /proc/net/netstat | tail -1)
|
|
if [[ -n "$headers" && -n "$values" ]]; then
|
|
tcp_retrans=$(paste <(echo "$headers" | tr ' ' '\n') <(echo "$values" | tr ' ' '\n') | awk -F'\t' '$1=="TCPRetransSegs" {print $2}')
|
|
listen_overflows=$(paste <(echo "$headers" | tr ' ' '\n') <(echo "$values" | tr ' ' '\n') | awk -F'\t' '$1=="ListenOverflows" {print $2}')
|
|
listen_drops=$(paste <(echo "$headers" | tr ' ' '\n') <(echo "$values" | tr ' ' '\n') | awk -F'\t' '$1=="ListenDrops" {print $2}')
|
|
fi
|
|
|
|
echo "# HELP network_tcp_retransmit_segments_total TCP segments retransmitted"
|
|
echo "# TYPE network_tcp_retransmit_segments_total counter"
|
|
echo "network_tcp_retransmit_segments_total{hostname=\"${HOSTNAME}\"} ${tcp_retrans:-0}"
|
|
|
|
echo ""
|
|
echo "# HELP network_tcp_listen_overflows_total TCP listen queue overflows"
|
|
echo "# TYPE network_tcp_listen_overflows_total counter"
|
|
echo "network_tcp_listen_overflows_total{hostname=\"${HOSTNAME}\"} ${listen_overflows:-0}"
|
|
|
|
echo ""
|
|
echo "# HELP network_tcp_listen_drops_total TCP listen queue drops"
|
|
echo "# TYPE network_tcp_listen_drops_total counter"
|
|
echo "network_tcp_listen_drops_total{hostname=\"${HOSTNAME}\"} ${listen_drops:-0}"
|
|
echo ""
|
|
fi
|
|
|
|
# --- ARP table ---
|
|
if [[ -r /proc/net/arp ]]; then
|
|
echo "# HELP network_arp_entries_total ARP table entries"
|
|
echo "# TYPE network_arp_entries_total gauge"
|
|
local arp_count
|
|
arp_count=$(($(wc -l < /proc/net/arp) - 1))
|
|
[[ $arp_count -lt 0 ]] && arp_count=0
|
|
echo "network_arp_entries_total{hostname=\"${HOSTNAME}\"} ${arp_count}"
|
|
echo ""
|
|
fi
|
|
|
|
# --- UDP sockets ---
|
|
if [[ -r /proc/net/udp ]]; then
|
|
echo "# HELP network_udp_sockets_total UDP sockets"
|
|
echo "# TYPE network_udp_sockets_total gauge"
|
|
local udp_sockets
|
|
udp_sockets=$(($(wc -l < /proc/net/udp) - 1))
|
|
[[ $udp_sockets -lt 0 ]] && udp_sockets=0
|
|
echo "network_udp_sockets_total{hostname=\"${HOSTNAME}\"} ${udp_sockets}"
|
|
echo ""
|
|
fi
|
|
|
|
# --- ICMP stats from /proc/net/snmp ---
|
|
if [[ -r /proc/net/snmp ]]; then
|
|
local icmp_header icmp_values
|
|
icmp_header=$(grep "^Icmp:" /proc/net/snmp | head -1)
|
|
icmp_values=$(grep "^Icmp:" /proc/net/snmp | tail -1)
|
|
if [[ -n "$icmp_header" && -n "$icmp_values" ]]; then
|
|
local icmp_in icmp_out icmp_err_in icmp_err_out
|
|
icmp_in=$(paste <(echo "$icmp_header" | tr ' ' '\n') <(echo "$icmp_values" | tr ' ' '\n') | awk -F'\t' '$1=="InMsgs" {print $2}')
|
|
icmp_out=$(paste <(echo "$icmp_header" | tr ' ' '\n') <(echo "$icmp_values" | tr ' ' '\n') | awk -F'\t' '$1=="OutMsgs" {print $2}')
|
|
icmp_err_in=$(paste <(echo "$icmp_header" | tr ' ' '\n') <(echo "$icmp_values" | tr ' ' '\n') | awk -F'\t' '$1=="InErrors" {print $2}')
|
|
icmp_err_out=$(paste <(echo "$icmp_header" | tr ' ' '\n') <(echo "$icmp_values" | tr ' ' '\n') | awk -F'\t' '$1=="OutErrors" {print $2}')
|
|
|
|
echo "# HELP network_icmp_messages_total ICMP messages by direction"
|
|
echo "# TYPE network_icmp_messages_total counter"
|
|
echo "network_icmp_messages_total{direction=\"in\",hostname=\"${HOSTNAME}\"} ${icmp_in:-0}"
|
|
echo "network_icmp_messages_total{direction=\"out\",hostname=\"${HOSTNAME}\"} ${icmp_out:-0}"
|
|
|
|
echo ""
|
|
echo "# HELP network_icmp_errors_total ICMP errors by direction"
|
|
echo "# TYPE network_icmp_errors_total counter"
|
|
echo "network_icmp_errors_total{direction=\"in\",hostname=\"${HOSTNAME}\"} ${icmp_err_in:-0}"
|
|
echo "network_icmp_errors_total{direction=\"out\",hostname=\"${HOSTNAME}\"} ${icmp_err_out:-0}"
|
|
echo ""
|
|
fi
|
|
fi
|
|
|
|
# --- TCP connections by state ---
|
|
if [[ -r /proc/net/tcp ]]; then
|
|
echo "# HELP network_tcp_connections TCP connections by state"
|
|
echo "# TYPE network_tcp_connections gauge"
|
|
# hex state codes: 01=ESTABLISHED, 06=TIME_WAIT, 0A=LISTEN
|
|
local tcp_estab tcp_listen tcp_tw tcp_close_wait tcp_syn_recv
|
|
tcp_estab=$(awk '$4=="01" {c++} END {print c+0}' /proc/net/tcp 2>/dev/null)
|
|
tcp_listen=$(awk '$4=="0A" {c++} END {print c+0}' /proc/net/tcp 2>/dev/null)
|
|
tcp_tw=$(awk '$4=="06" {c++} END {print c+0}' /proc/net/tcp 2>/dev/null)
|
|
tcp_close_wait=$(awk '$4=="08" {c++} END {print c+0}' /proc/net/tcp 2>/dev/null)
|
|
tcp_syn_recv=$(awk '$4=="03" {c++} END {print c+0}' /proc/net/tcp 2>/dev/null)
|
|
echo "network_tcp_connections{state=\"established\",hostname=\"${HOSTNAME}\"} ${tcp_estab}"
|
|
echo "network_tcp_connections{state=\"listen\",hostname=\"${HOSTNAME}\"} ${tcp_listen}"
|
|
echo "network_tcp_connections{state=\"time_wait\",hostname=\"${HOSTNAME}\"} ${tcp_tw}"
|
|
echo "network_tcp_connections{state=\"close_wait\",hostname=\"${HOSTNAME}\"} ${tcp_close_wait}"
|
|
echo "network_tcp_connections{state=\"syn_recv\",hostname=\"${HOSTNAME}\"} ${tcp_syn_recv}"
|
|
echo ""
|
|
fi
|
|
|
|
# --- Conntrack ---
|
|
if [[ -r /proc/sys/net/netfilter/nf_conntrack_count ]]; then
|
|
echo "# HELP network_nf_conntrack_entries Conntrack table entries"
|
|
echo "# TYPE network_nf_conntrack_entries gauge"
|
|
echo "network_nf_conntrack_entries{hostname=\"${HOSTNAME}\"} $(cat /proc/sys/net/netfilter/nf_conntrack_count 2>/dev/null || echo 0)"
|
|
fi
|
|
if [[ -r /proc/sys/net/netfilter/nf_conntrack_max ]]; then
|
|
echo "# HELP network_nf_conntrack_entries_limit Conntrack table maximum"
|
|
echo "# TYPE network_nf_conntrack_entries_limit gauge"
|
|
echo "network_nf_conntrack_entries_limit{hostname=\"${HOSTNAME}\"} $(cat /proc/sys/net/netfilter/nf_conntrack_max 2>/dev/null || echo 0)"
|
|
echo ""
|
|
fi
|
|
|
|
# --- Latency (parallel ping) ---
|
|
if command -v ping &>/dev/null; then
|
|
read -ra targets <<< "$PING_TARGETS"
|
|
local tmp_files=() pids=() labels=()
|
|
|
|
for target in "${targets[@]}"; do
|
|
[[ -z "$target" ]] && continue
|
|
local label
|
|
label=$(echo "$target" | tr -c 'a-zA-Z0-9._-' '_' | sed 's/_*$//')
|
|
labels+=("$label")
|
|
|
|
local tmp
|
|
tmp=$(mktemp)
|
|
tmp_files+=("$tmp")
|
|
|
|
(
|
|
set +e
|
|
timeout $((PING_COUNT * PING_TIMEOUT + 5)) ping -c "$PING_COUNT" -W "$PING_TIMEOUT" "$target" > "$tmp" 2>&1
|
|
echo "EXIT=$?" >> "$tmp"
|
|
) &
|
|
pids+=($!)
|
|
done
|
|
|
|
[[ ${#pids[@]} -gt 0 ]] && wait "${pids[@]}"
|
|
|
|
# Collect parsed results
|
|
local all_min=() all_avg=() all_max=() all_stddev=() all_loss=()
|
|
|
|
for i in "${!tmp_files[@]}"; do
|
|
local tmp="${tmp_files[$i]}"
|
|
local exit_code min_v=0 avg_v=0 max_v=0 stddev_v=0 loss_v=100
|
|
|
|
if [[ -f "$tmp" ]]; then
|
|
exit_code=$(grep "^EXIT=" "$tmp" | tail -1 | cut -d= -f2)
|
|
if [[ "${exit_code:-1}" -eq 0 ]]; then
|
|
local stats
|
|
stats=$(grep -E 'rtt min/avg/max/(mdev|stddev)' "$tmp" | head -1)
|
|
if [[ -n "$stats" ]]; then
|
|
local vals
|
|
vals=$(echo "$stats" | cut -d= -f2 | awk '{print $1}')
|
|
min_v=$(echo "$vals" | cut -d/ -f1)
|
|
avg_v=$(echo "$vals" | cut -d/ -f2)
|
|
max_v=$(echo "$vals" | cut -d/ -f3)
|
|
stddev_v=$(echo "$vals" | cut -d/ -f4)
|
|
fi
|
|
loss_v=$(grep -oP '\d+(?=% packet loss)' "$tmp" | head -1)
|
|
fi
|
|
rm -f "$tmp"
|
|
fi
|
|
|
|
all_min+=("${min_v:-0}")
|
|
all_avg+=("${avg_v:-0}")
|
|
all_max+=("${max_v:-0}")
|
|
all_stddev+=("${stddev_v:-0}")
|
|
all_loss+=("${loss_v:-100}")
|
|
done
|
|
|
|
echo "# HELP network_ping_rtt_min_milliseconds Minimum ping RTT"
|
|
echo "# TYPE network_ping_rtt_min_milliseconds gauge"
|
|
for i in "${!labels[@]}"; do
|
|
echo "network_ping_rtt_min_milliseconds{target=\"${labels[$i]}\",hostname=\"${HOSTNAME}\"} ${all_min[$i]}"
|
|
done
|
|
|
|
echo ""
|
|
echo "# HELP network_ping_rtt_avg_milliseconds Average ping RTT"
|
|
echo "# TYPE network_ping_rtt_avg_milliseconds gauge"
|
|
for i in "${!labels[@]}"; do
|
|
echo "network_ping_rtt_avg_milliseconds{target=\"${labels[$i]}\",hostname=\"${HOSTNAME}\"} ${all_avg[$i]}"
|
|
done
|
|
|
|
echo ""
|
|
echo "# HELP network_ping_rtt_max_milliseconds Maximum ping RTT"
|
|
echo "# TYPE network_ping_rtt_max_milliseconds gauge"
|
|
for i in "${!labels[@]}"; do
|
|
echo "network_ping_rtt_max_milliseconds{target=\"${labels[$i]}\",hostname=\"${HOSTNAME}\"} ${all_max[$i]}"
|
|
done
|
|
|
|
echo ""
|
|
echo "# HELP network_ping_rtt_stddev_milliseconds Ping RTT standard deviation (jitter)"
|
|
echo "# TYPE network_ping_rtt_stddev_milliseconds gauge"
|
|
for i in "${!labels[@]}"; do
|
|
echo "network_ping_rtt_stddev_milliseconds{target=\"${labels[$i]}\",hostname=\"${HOSTNAME}\"} ${all_stddev[$i]}"
|
|
done
|
|
|
|
echo ""
|
|
echo "# HELP network_ping_packet_loss_percent Packet loss percentage"
|
|
echo "# TYPE network_ping_packet_loss_percent gauge"
|
|
for i in "${!labels[@]}"; do
|
|
echo "network_ping_packet_loss_percent{target=\"${labels[$i]}\",hostname=\"${HOSTNAME}\"} ${all_loss[$i]}"
|
|
done
|
|
echo ""
|
|
fi
|
|
|
|
# --- Exporter timing ---
|
|
local END_TIME DURATION
|
|
END_TIME=$(date +%s.%N)
|
|
DURATION=$(echo "$END_TIME - $START_TIME" | bc)
|
|
|
|
echo "# HELP network_exporter_duration_seconds Time to generate all metrics"
|
|
echo "# TYPE network_exporter_duration_seconds gauge"
|
|
echo "network_exporter_duration_seconds{hostname=\"${HOSTNAME}\"} ${DURATION}"
|
|
|
|
echo ""
|
|
echo "# HELP network_exporter_last_run_timestamp Unix timestamp of last successful run"
|
|
echo "# TYPE network_exporter_last_run_timestamp gauge"
|
|
echo "network_exporter_last_run_timestamp{hostname=\"${HOSTNAME}\"} $(date +%s)"
|
|
}
|
|
|
|
# ============================================================================
|
|
# MAIN EXECUTION
|
|
# ============================================================================
|
|
|
|
main() {
|
|
parse_args "$@"
|
|
|
|
if [[ $EUID -ne 0 ]]; then
|
|
echo "Error: This script must be run as root" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ -n "$OUTPUT_FILE" ]; then
|
|
local output_dir
|
|
output_dir="$(dirname "$OUTPUT_FILE")"
|
|
mkdir -p "$output_dir"
|
|
|
|
local temp_file
|
|
temp_file=$(mktemp "${output_dir}/.network_info.XXXXXX")
|
|
|
|
if ! generate_metrics > "$temp_file" 2>/dev/null; then
|
|
rm -f "$temp_file"
|
|
echo "ERROR: Failed to generate metrics" >&2
|
|
exit 1
|
|
fi
|
|
|
|
local file_lines
|
|
file_lines=$(wc -l < "$temp_file" 2>/dev/null || echo 0)
|
|
|
|
if [ "$file_lines" -lt 10 ]; then
|
|
rm -f "$temp_file"
|
|
echo "ERROR: Metrics file too small ($file_lines lines), keeping previous" >&2
|
|
exit 1
|
|
fi
|
|
|
|
chmod 644 "$temp_file"
|
|
mv -f "$temp_file" "$OUTPUT_FILE"
|
|
|
|
echo "Metrics written to $OUTPUT_FILE ($file_lines lines)" >&2
|
|
else
|
|
generate_metrics
|
|
fi
|
|
}
|
|
|
|
main "$@"
|