From a2baa16a9b324018362ea7077a6f68e5087c8a1a Mon Sep 17 00:00:00 2001 From: SamNet-dev Date: Thu, 5 Feb 2026 12:23:04 -0600 Subject: [PATCH] fix: Improve traffic tracking accuracy and reduce CPU usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix tracker double-counting by capturing only on external interface instead of all interfaces (-i any → -i $CAPTURE_IFACE) - Increase docker logs tail from 30 to 200 for reliable stats capture - Add stats caching to show last known values when logs are busy - Reduce dashboard refresh interval from 4s to 10s for lower CPU load - Add docker stats caching (refresh every 20s) to reduce docker overhead --- conduit.sh | 72 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/conduit.sh b/conduit.sh index 0dcc00f..9c7e290 100644 --- a/conduit.sh +++ b/conduit.sh @@ -1293,7 +1293,7 @@ show_dashboard() { echo -e "\033[K" fi - echo -e "${BOLD}Refreshes every 5 seconds. Press any key to return to menu...${NC}\033[K" + echo -e "${BOLD}Refreshes every 10 seconds. Press any key to return to menu...${NC}\033[K" # Clear any leftover lines below the dashboard content (Erase to End of Display) # This only cleans up if the dashboard gets shorter @@ -1301,9 +1301,9 @@ show_dashboard() { printf "\033[J" fi - # Wait 4 seconds for keypress (compensating for processing time) + # Wait 10 seconds for keypress (balances responsiveness with CPU usage) # Redirect from /dev/tty ensures it works when the script is piped - if read -t 4 -n 1 -s < /dev/tty 2>/dev/null; then + if read -t 10 -n 1 -s < /dev/tty 2>/dev/null; then stop_dashboard=1 fi done @@ -1630,10 +1630,15 @@ touch "$STATS_FILE" "$IPS_FILE" TCPDUMP_BIN=$(command -v tcpdump 2>/dev/null || echo "tcpdump") AWK_BIN=$(command -v gawk 2>/dev/null || command -v awk 2>/dev/null || echo "awk") -# Detect local IP +# Detect local IP and primary external interface LOCAL_IP=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src") print $(i+1)}') [ -z "$LOCAL_IP" ] && LOCAL_IP=$(hostname -I 2>/dev/null | awk '{print $1}') +# Detect primary external interface (to avoid double-counting on docker bridges) +CAPTURE_IFACE=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}') +[ -z "$CAPTURE_IFACE" ] && CAPTURE_IFACE=$(ip route show default 2>/dev/null | awk '{print $5; exit}') +[ -z "$CAPTURE_IFACE" ] && CAPTURE_IFACE="any" + # Batch process: resolve GeoIP + merge into cumulative files in bulk process_batch() { local batch="$1" @@ -1861,7 +1866,7 @@ while true; do break fi fi - done < <($TCPDUMP_BIN -tt -l -ni any -n -q -s 96 "(tcp or udp) and not port 22" 2>/dev/null | $AWK_BIN -v local_ip="$LOCAL_IP" ' + done < <($TCPDUMP_BIN -tt -l -ni "$CAPTURE_IFACE" -n -q -s 96 "(tcp or udp) and not port 22" 2>/dev/null | $AWK_BIN -v local_ip="$LOCAL_IP" ' BEGIN { last_sync = 0; OFMT = "%.0f"; CONVFMT = "%.0f" } { # Parse timestamp @@ -2035,7 +2040,7 @@ show_advanced_stats() { local cname=$(get_container_name $ci) if echo "$docker_ps_cache" | grep -q "^${cname}$"; then adv_running_names+=" $cname" - ( docker logs --tail 30 "$cname" 2>&1 | grep "\[STATS\]" | tail -1 > "$_adv_tmpdir/logs_${ci}" ) & + ( docker logs --tail 200 "$cname" 2>&1 | grep "\[STATS\]" | tail -1 > "$_adv_tmpdir/logs_${ci}" ) & fi done local adv_all_stats="" @@ -2319,7 +2324,7 @@ show_peers() { for ci in $(seq 1 $CONTAINER_COUNT); do local cname=$(get_container_name $ci) if echo "$docker_ps_cache" | grep -q "^${cname}$"; then - ( docker logs --tail 30 "$cname" 2>&1 | grep "\[STATS\]" | tail -1 > "$_peer_tmpdir/logs_${ci}" ) & + ( docker logs --tail 200 "$cname" 2>&1 | grep "\[STATS\]" | tail -1 > "$_peer_tmpdir/logs_${ci}" ) & fi done wait @@ -2466,6 +2471,13 @@ get_net_speed() { fi } +# Global cache for container stats (persists between show_status calls) +declare -A _STATS_CACHE_UP _STATS_CACHE_DOWN _STATS_CACHE_CONN _STATS_CACHE_CING + +# Global cache for docker stats (CPU/RAM) - refreshes every 2 cycles (20s) +_DOCKER_STATS_CACHE="" +_DOCKER_STATS_CYCLE=0 + show_status() { local mode="${1:-normal}" # 'live' mode adds line clearing local EL="" @@ -2500,7 +2512,7 @@ show_status() { if echo "$docker_ps_cache" | grep -q "[[:space:]]${cname}$"; then _c_running[$i]=true running_count=$((running_count + 1)) - ( docker logs --tail 30 "$cname" 2>&1 | grep "\[STATS\]" | tail -1 > "$_st_tmpdir/logs_${i}" ) & + ( docker logs --tail 200 "$cname" 2>&1 | grep "\[STATS\]" | tail -1 > "$_st_tmpdir/logs_${i}" ) & fi done wait @@ -2524,11 +2536,26 @@ show_status() { _c_cing[$i]="${c_connecting:-0}" _c_up[$i]="${c_up_val}" _c_down[$i]="${c_down_val}" + # Update global cache with fresh data + _STATS_CACHE_UP[$i]="${c_up_val}" + _STATS_CACHE_DOWN[$i]="${c_down_val}" + _STATS_CACHE_CONN[$i]="${c_connected:-0}" + _STATS_CACHE_CING[$i]="${c_connecting:-0}" total_connecting=$((total_connecting + ${c_connecting:-0})) total_connected=$((total_connected + ${c_connected:-0})) if [ -z "$uptime" ]; then uptime="${c_uptime_val}" fi + else + # No stats in logs - use cached values if available + if [ -n "${_STATS_CACHE_UP[$i]}" ]; then + _c_up[$i]="${_STATS_CACHE_UP[$i]}" + _c_down[$i]="${_STATS_CACHE_DOWN[$i]}" + _c_conn[$i]="${_STATS_CACHE_CONN[$i]:-0}" + _c_cing[$i]="${_STATS_CACHE_CING[$i]:-0}" + total_connecting=$((total_connecting + ${_c_cing[$i]:-0})) + total_connected=$((total_connected + ${_c_conn[$i]:-0})) + fi fi fi done @@ -2588,15 +2615,24 @@ show_status() { if [ "$running_count" -gt 0 ]; then - # Run all 3 resource stat calls in parallel + # Run resource stat calls (docker stats cached every 2 cycles for CPU savings) local _rs_tmpdir=$(mktemp -d /tmp/.conduit_rs.XXXXXX) - # mktemp already created the directory - ( get_container_stats > "$_rs_tmpdir/cstats" ) & + _DOCKER_STATS_CYCLE=$(( (_DOCKER_STATS_CYCLE + 1) % 2 )) + if [ "$_DOCKER_STATS_CYCLE" -eq 1 ] || [ -z "$_DOCKER_STATS_CACHE" ]; then + # Fresh fetch cycle - get new docker stats + ( get_container_stats > "$_rs_tmpdir/cstats" ) & + fi ( get_system_stats > "$_rs_tmpdir/sys" ) & ( get_net_speed > "$_rs_tmpdir/net" ) & wait - local stats=$(cat "$_rs_tmpdir/cstats" 2>/dev/null) + local stats + if [ -f "$_rs_tmpdir/cstats" ]; then + stats=$(cat "$_rs_tmpdir/cstats" 2>/dev/null) + _DOCKER_STATS_CACHE="$stats" + else + stats="$_DOCKER_STATS_CACHE" + fi local sys_stats=$(cat "$_rs_tmpdir/sys" 2>/dev/null) local net_speed=$(cat "$_rs_tmpdir/net" 2>/dev/null) rm -rf "$_rs_tmpdir" @@ -3495,7 +3531,7 @@ manage_containers() { if echo "$docker_ps_cache" | grep -q "^${cname}$"; then running_names+=" $cname" # Fetch logs in parallel background jobs - ( docker logs --tail 30 "$cname" 2>&1 | grep "\[STATS\]" | tail -1 > "$_mc_tmpdir/logs_${ci}" ) & + ( docker logs --tail 200 "$cname" 2>&1 | grep "\[STATS\]" | tail -1 > "$_mc_tmpdir/logs_${ci}" ) & fi done # Fetch stats in parallel with logs @@ -3538,6 +3574,16 @@ manage_containers() { c_down="${mc_down:-"-"}" [ -z "$c_up" ] && c_up="-" [ -z "$c_down" ] && c_down="-" + # Update global cache + _STATS_CACHE_UP[$ci]="${mc_up}" + _STATS_CACHE_DOWN[$ci]="${mc_down}" + _STATS_CACHE_CONN[$ci]="${conn:-0}" + _STATS_CACHE_CING[$ci]="${cing:-0}" + elif [ -n "${_STATS_CACHE_UP[$ci]}" ]; then + # Use cached values as fallback + c_clients="${_STATS_CACHE_CONN[$ci]:-0}/${_STATS_CACHE_CING[$ci]:-0}" + c_up="${_STATS_CACHE_UP[$ci]:-"-"}" + c_down="${_STATS_CACHE_DOWN[$ci]:-"-"}" fi local dstats_line=$(echo "$all_dstats" | grep "^${cname} " 2>/dev/null) if [ -n "$dstats_line" ]; then