#!/bin/bash # Memory snapshot for landing-stats (source after json_str is defined). # Sets MEM_JSON (fields to embed inside performance.memory). # IMPORTANT: no pipelines around the /proc loop (bash subshell loses counters). mem_fmt_bytes() { awk -v b="${1:-0}" 'BEGIN{ b = b + 0 if (b < 1024) printf "%d B", b else if (b < 1048576) printf "%.1f KiB", b / 1024 else if (b < 1073741824) printf "%.1f MiB", b / 1048576 else printf "%.2f GiB", b / 1073741824 }' } mem_snapshot_json() { local rss_kb rss_b pid comm cmd short local sum_b=0 cgroup_b="" limit_b="" local postgres_b=0 taler_b=0 nginx_b=0 java_b=0 redis_b=0 other_b=0 local n_pg=0 n_taler=0 n_nginx=0 n_java=0 n_redis=0 n_other=0 local allf topf top_json top_n=0 lim_json cg_json hum cjs sjs hjs if [ -r /sys/fs/cgroup/memory.current ]; then cgroup_b=$(tr -d ' \n' /dev/null || true) if [ -r /sys/fs/cgroup/memory.max ]; then limit_b=$(tr -d ' \n' /dev/null || true) [ "$limit_b" = "max" ] && limit_b="" fi elif [ -r /sys/fs/cgroup/memory/memory.usage_in_bytes ]; then cgroup_b=$(tr -d ' \n' /dev/null || true) fi allf=$(mktemp) topf=$(mktemp) for st in /proc/[0-9]*/status; do [ -f "$st" ] || continue pid=${st#/proc/} pid=${pid%/status} rss_kb=$(awk '/^VmRSS:/{print $2; exit}' "$st" 2>/dev/null || true) [[ "$rss_kb" =~ ^[0-9]+$ ]] || continue rss_b=$((rss_kb * 1024)) sum_b=$((sum_b + rss_b)) comm=$(awk '/^Name:/{print $2; exit}' "$st" 2>/dev/null || echo "?") cmd="" if [ -r "/proc/$pid/cmdline" ]; then cmd=$(tr '\0' ' ' <"/proc/$pid/cmdline" 2>/dev/null | sed 's/[[:space:]]*$//') fi [ -n "$cmd" ] || cmd=$comm short=$(printf '%s' "$cmd" | cut -c1-100) case "$comm $cmd" in *postgres*|*postmaster*) postgres_b=$((postgres_b + rss_b)); n_pg=$((n_pg + 1)) ;; *taler-exchange*|*taler-merchant*|*taler-auditor*|*taler-helper*|*taler_*) taler_b=$((taler_b + rss_b)); n_taler=$((n_taler + 1)) ;; *nginx*) nginx_b=$((nginx_b + rss_b)); n_nginx=$((n_nginx + 1)) ;; *java*|*libeufin*|*MainKt*) java_b=$((java_b + rss_b)); n_java=$((n_java + 1)) ;; *redis-server*|*redis*) redis_b=$((redis_b + rss_b)); n_redis=$((n_redis + 1)) ;; *) other_b=$((other_b + rss_b)); n_other=$((n_other + 1)) ;; esac printf '%s\t%s\t%s\n' "$rss_b" "$comm" "$short" >>"$allf" done sort -t$'\t' -nr -k1,1 "$allf" 2>/dev/null | head -10 >"$topf" rm -f "$allf" local total_b=$sum_b if [[ "$cgroup_b" =~ ^[0-9]+$ ]] && [ "$cgroup_b" -gt 0 ]; then total_b=$cgroup_b fi top_json="[" top_n=0 while IFS=$'\t' read -r rss_b comm short; do [ -z "${rss_b:-}" ] && continue [ "$top_n" -gt 0 ] && top_json="${top_json}," top_n=$((top_n + 1)) hum=$(mem_fmt_bytes "$rss_b") cjs=$(json_str "$comm") sjs=$(json_str "$short") hjs=$(json_str "$hum") top_json="${top_json} {\"rss_bytes\": ${rss_b}, \"rss_human\": ${hjs}, \"comm\": ${cjs}, \"cmd\": ${sjs}}" done <"$topf" top_json="${top_json} ]" rm -f "$topf" lim_json="null" if [[ "$limit_b" =~ ^[0-9]+$ ]] && [ "$limit_b" -gt 0 ]; then lim_json=$limit_b fi cg_json="null" if [[ "$cgroup_b" =~ ^[0-9]+$ ]]; then cg_json=$cgroup_b fi MEM_JSON=" \"container_rss_bytes\": ${total_b}, \"container_rss_human\": $(json_str "$(mem_fmt_bytes "$total_b")"), \"proc_sum_rss_bytes\": ${sum_b}, \"proc_sum_rss_human\": $(json_str "$(mem_fmt_bytes "$sum_b")"), \"cgroup_bytes\": ${cg_json}, \"cgroup_limit_bytes\": ${lim_json}, \"postgres_rss_bytes\": ${postgres_b}, \"postgres_rss_human\": $(json_str "$(mem_fmt_bytes "$postgres_b")"), \"postgres_n\": ${n_pg}, \"taler_rss_bytes\": ${taler_b}, \"taler_rss_human\": $(json_str "$(mem_fmt_bytes "$taler_b")"), \"taler_n\": ${n_taler}, \"nginx_rss_bytes\": ${nginx_b}, \"nginx_rss_human\": $(json_str "$(mem_fmt_bytes "$nginx_b")"), \"nginx_n\": ${n_nginx}, \"java_rss_bytes\": ${java_b}, \"java_rss_human\": $(json_str "$(mem_fmt_bytes "$java_b")"), \"java_n\": ${n_java}, \"redis_rss_bytes\": ${redis_b}, \"redis_rss_human\": $(json_str "$(mem_fmt_bytes "$redis_b")"), \"redis_n\": ${n_redis}, \"other_rss_bytes\": ${other_b}, \"other_rss_human\": $(json_str "$(mem_fmt_bytes "$other_b")"), \"other_n\": ${n_other}, \"top\": ${top_json} " }