#!/usr/bin/env bash
#  vim:ts=4:sts=4:sw=4:et
#
#  Author: Hari Sekhon
#  Date: 2024-08-26 14:38:31 +0200 (Mon, 26 Aug 2024)
#
#  https///github.com/HariSekhon/DevOps-Bash-tools
#
#  License: see accompanying Hari Sekhon LICENSE file
#
#  If you're using my code you're welcome to connect with me on LinkedIn and optionally send me feedback to help steer this or other code I publish
#
#  https://www.linkedin.com/in/HariSekhon
#

set -euo pipefail
[ -n "${DEBUG:-}" ] && set -x
#srcdir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

usage_description="
Dumps common command outputs to text files in a local tarball

Useful to collect support information for vendor support cases

Scp'd by ssh_dump_stats.sh to collect from remote servers


Creates a tarball in this name format:

stats-bundle.YYYY-MM-DD-HHSS.tar.gz


If this script is not run as root then prefixes sudo to every command to ensure that it succeeds


Export LSOF=true to dump the lsof output which is otherwise skipped by default because on a production VM it resulted in 599M of output which aside from taking 30 seconds was ballooning the even compressed tarball to 47MB instead of 108KB


If NO_REMOVE_STATS_DIR environment variable is set to any value then does not remove the intermediate stats-bundle.YYYY-MM-DD-HHSS directory


usage: ${0##*/}
"

if [ $# -gt 0 ]; then
    echo "$usage_description"
    exit 3
fi

tstamp="$(date '+%F_%H%M')"

stats_bundle_dir="stats-bundle-$tstamp"

mkdir -p -v "$stats_bundle_dir"

cd "$stats_bundle_dir"

sudo=""
if [ "$EUID" -ne 0 ]; then
    sudo=sudo
fi

mac=false
if uname -s | grep Darwin; then
    mac=true
fi

timestamp(){
    printf "%s\n" "$(date '+%F %T')  $*" >&2
}

dump(){
    local name="$1"
    shift
    local cmd=("$name")
    if [ $# -gt 0 ]; then
        cmd=("$@")
    fi
    cmd_name="${cmd[0]}"
    if ! type -P "$cmd_name" &>/dev/null; then
        timestamp "Command '$cmd_name' not found, skipping..."
        return
    fi
    log_file="$name-output.$tstamp.txt"
    # ignore && && || it works
    # shellcheck disable=SC2015
    timestamp "Collecting $name output" >&2
    $sudo "${cmd[@]}" > "$log_file"
    timestamp  "Collected $name output to file: $log_file"
    echo >&2
}

# ============================================================================ #
#                    Commands that work on both Linux and Mac
# ============================================================================ #

dump_common(){

    timestamp "Dumping common command outputs"
    echo >&2
    # -g for GB only works on Mac
    #dump df df -g
    dump df df -h
    dump dmesg
    # very expensive - takes 30 seconds and results in a 599MB output file on a production informatica secure agent server VM
    if [ "${LSOF:-}" = true ]; then
        dump lsof lsof -n -O
    fi
    dump netstat netstat -an
    dump ps_ef ps -ef
    dump uname uname -a
    dump uptime

}

# ============================================================================ #
#                         Commands that only work on Mac
# ============================================================================ #

dump_mac(){

    timestamp "Dumping Mac specific command outputs"
    echo >&2
    dump diskutil_list diskutil list
    dump iostat iostat -c 5
    dump memory_pressure
    dump ps_auxf ps aux
    dump top top -l 1
    dump top_mpstat top -l 1 -stats pid,command,cpu,th,pstate,time,cpu -ncols 16
    #dump vmstat  # not available on my macOS 14
}

# ============================================================================ #
#                        Commands that only work on Linux
# ============================================================================ #

dump_linux(){

    timestamp "Dumping Linux specific command outputs"
    echo >&2
    dump free free -g
    dump iostat iostat -x 1 5
    dump lsblk
    dump mpstat mpstat -P ALL 1 5
    dump ps_auxf ps auxf
    dump sar_5 sar -u 1 5
    dump sar_all sar -A
    dump top top -H -b -n 1
    dump vmstat vmstat 1 5
}

# ============================================================================ #

dump_common

if [ "$mac" = true ]; then
    dump_mac
else # assume Linux as the default case
    dump_linux
fi

timestamp "Finished collection"
echo >&2

tarball="$stats_bundle_dir.tar.gz"

timestamp "Creating compressed tarball '$tarball' for easier collection and space savings"

cd ..

tar czvf "$tarball" "$stats_bundle_dir"
echo

if [ -z "${NO_REMOVE_STATS_DIR:-}" ]; then
    timestamp "Removing directory: $stats_bundle_dir"
    rm -fr -- "$stats_bundle_dir"
    echo >&2
fi

timestamp "Collect tarball at: $PWD/$tarball"
