-
-
Save itcaat/45edeaf15f2d508bee766daa9a97400c to your computer and use it in GitHub Desktop.
Smart and fast diagnostic script for Linux Systems with Telegram Notifications
This file contains hidden or 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/bash | |
| ############################################# | |
| # Linux System Diagnostic Script | |
| # Version: 1.1 | |
| # Author: Nikita Rukavkov | |
| # Telegram: https://t.me/devopsbrain | |
| ############################################# | |
| # Status symbols | |
| CHECK_OK="β" | |
| CHECK_WARN="β " | |
| CHECK_CRIT="β" | |
| # Summary variables | |
| WARNINGS=0 | |
| CRITICALS=0 | |
| PROBLEM_SECTIONS=() # Array to track sections with problems | |
| # Function for section headers | |
| print_section() { | |
| echo "" | |
| echo "βββββββββββββββββββββββββββββββββββββββββββββββββββββββ" | |
| echo " $1" | |
| echo "βββββββββββββββββββββββββββββββββββββββββββββββββββββββ" | |
| echo "" | |
| } | |
| # Function for output with status icons | |
| print_status() { | |
| local status=$1 | |
| local message=$2 | |
| local section=$3 # Optional: section name for tracking | |
| case $status in | |
| "ok") | |
| echo "${CHECK_OK} $message" | |
| ;; | |
| "warn") | |
| echo "${CHECK_WARN} $message" | |
| ((WARNINGS++)) | |
| # Add section to problem list if provided and not already there | |
| if [ ! -z "$section" ]; then | |
| if [[ ! " ${PROBLEM_SECTIONS[@]} " =~ " ${section} " ]]; then | |
| PROBLEM_SECTIONS+=("$section") | |
| fi | |
| fi | |
| ;; | |
| "crit") | |
| echo "${CHECK_CRIT} $message" | |
| ((CRITICALS++)) | |
| # Add section to problem list if provided and not already there | |
| if [ ! -z "$section" ]; then | |
| if [[ ! " ${PROBLEM_SECTIONS[@]} " =~ " ${section} " ]]; then | |
| PROBLEM_SECTIONS+=("$section") | |
| fi | |
| fi | |
| ;; | |
| esac | |
| } | |
| # Check if command exists | |
| command_exists() { | |
| command -v "$1" >/dev/null 2>&1 | |
| } | |
| # Ping function (10 packets) | |
| do_ping() { | |
| local host=$1 | |
| local description=$2 | |
| local section=$3 | |
| echo " Testing $description ($host):" | |
| echo -n " Ping (10 packets): " | |
| PING_RESULT=$(ping -c 10 -q "$host" 2>/dev/null) | |
| if [ $? -eq 0 ]; then | |
| PACKET_LOSS=$(echo "$PING_RESULT" | grep "packet loss" | awk '{print $6}') | |
| AVG_TIME=$(echo "$PING_RESULT" | grep "rtt" | awk -F'/' '{print $5}') | |
| echo "Loss: $PACKET_LOSS, Avg: ${AVG_TIME}ms" | |
| # Check packet loss | |
| LOSS_PERCENT=$(echo "$PACKET_LOSS" | sed 's/%//') | |
| if [ "$LOSS_PERCENT" -gt 20 ]; then | |
| print_status "crit" "High packet loss to $description!" "$section" | |
| elif [ "$LOSS_PERCENT" -gt 5 ]; then | |
| print_status "warn" "Packet loss detected to $description" "$section" | |
| else | |
| print_status "ok" "$description is reachable" | |
| fi | |
| else | |
| echo "Failed" | |
| print_status "crit" "Cannot reach $description!" "$section" | |
| fi | |
| echo "" | |
| } | |
| ############################################# | |
| # 1. SYSTEM INFORMATION | |
| ############################################# | |
| check_system_info() { | |
| print_section "SYSTEM INFORMATION" | |
| echo "Hostname: $(hostname)" | |
| echo "OS: $(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d'"' -f2 || uname -s)" | |
| echo "Kernel: $(uname -r)" | |
| echo "Architecture: $(uname -m)" | |
| echo "Uptime: $(uptime -p 2>/dev/null || uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}')" | |
| # External IP address (using public services) | |
| if command_exists curl; then | |
| # Try to get IP from 2ip.ru, fallback to icanhazip.com | |
| EXTERNAL_IP=$(curl -s --max-time 5 https://2ip.ru 2>/dev/null || curl -s --max-time 5 https://icanhazip.com 2>/dev/null || echo "N/A") | |
| # Clean result - extract only IPv4 address | |
| EXTERNAL_IP=$(echo "$EXTERNAL_IP" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1) | |
| if [ -z "$EXTERNAL_IP" ]; then | |
| EXTERNAL_IP="N/A" | |
| fi | |
| echo "External IP: $EXTERNAL_IP" | |
| fi | |
| # CPU information | |
| if [ -f /proc/cpuinfo ]; then | |
| CPU_MODEL=$(grep "model name" /proc/cpuinfo | head -1 | cut -d':' -f2 | xargs) | |
| CPU_CORES=$(grep -c "processor" /proc/cpuinfo) | |
| echo "CPU: $CPU_MODEL ($CPU_CORES cores)" | |
| fi | |
| # RAM information | |
| if command_exists free; then | |
| TOTAL_RAM=$(free -h | awk '/^Mem:/ {print $2}') | |
| echo "Total RAM: $TOTAL_RAM" | |
| fi | |
| } | |
| ############################################# | |
| # 2. SYSTEM RESOURCES | |
| ############################################# | |
| check_resources() { | |
| print_section "RESOURCE USAGE" | |
| # Load Average | |
| if [ -f /proc/loadavg ]; then | |
| LOAD_AVG=$(cat /proc/loadavg | awk '{print $1, $2, $3}') | |
| CPU_CORES=$(grep -c "processor" /proc/cpuinfo) | |
| LOAD_1MIN=$(cat /proc/loadavg | awk '{print $1}') | |
| echo "Load Average: $LOAD_AVG (${CPU_CORES} cores)" | |
| # Check load | |
| if (( $(echo "$LOAD_1MIN > $CPU_CORES * 2" | bc -l) )); then | |
| print_status "crit" "High CPU load!" "Resources" | |
| elif (( $(echo "$LOAD_1MIN > $CPU_CORES" | bc -l) )); then | |
| print_status "warn" "Elevated CPU load" "Resources" | |
| else | |
| print_status "ok" "Load is normal" | |
| fi | |
| fi | |
| echo "" | |
| # Memory | |
| if command_exists free; then | |
| echo "Memory:" | |
| free -h | |
| # Check memory usage | |
| MEM_USED_PERCENT=$(free | grep Mem | awk '{print int($3/$2 * 100)}') | |
| echo "" | |
| if [ "$MEM_USED_PERCENT" -gt 90 ]; then | |
| print_status "crit" "Memory usage: ${MEM_USED_PERCENT}% (critical!)" "Resources" | |
| elif [ "$MEM_USED_PERCENT" -gt 80 ]; then | |
| print_status "warn" "Memory usage: ${MEM_USED_PERCENT}%" "Resources" | |
| else | |
| print_status "ok" "Memory usage: ${MEM_USED_PERCENT}%" | |
| fi | |
| # Check swap | |
| SWAP_USED_PERCENT=$(free | grep Swap | awk '{if ($2 > 0) print int($3/$2 * 100); else print 0}') | |
| if [ "$SWAP_USED_PERCENT" -gt 50 ]; then | |
| print_status "warn" "Swap usage: ${SWAP_USED_PERCENT}%" "Resources" | |
| elif [ "$SWAP_USED_PERCENT" -gt 0 ]; then | |
| print_status "ok" "Swap usage: ${SWAP_USED_PERCENT}%" | |
| fi | |
| fi | |
| } | |
| ############################################# | |
| # 3. TEMPERATURE | |
| ############################################# | |
| check_temperature() { | |
| print_section "TEMPERATURE" | |
| # Check sensors (lm-sensors) | |
| if command_exists sensors; then | |
| sensors 2>/dev/null | grep -E "^(Core|CPU|temp)" | head -10 | |
| echo "" | |
| # Check critical temperatures | |
| HIGH_TEMP=$(sensors 2>/dev/null | grep -oP '\+\K[0-9]+' | awk '{if ($1 > 80) print $1}' | head -1) | |
| if [ ! -z "$HIGH_TEMP" ]; then | |
| print_status "crit" "High temperature detected: ${HIGH_TEMP}Β°C!" "Temperature" | |
| else | |
| print_status "ok" "Temperature is normal" | |
| fi | |
| else | |
| print_status "warn" "'sensors' utility not installed" "Temperature" | |
| echo "" | |
| echo "To install lm-sensors:" | |
| echo " Ubuntu/Debian: sudo apt install lm-sensors && sudo sensors-detect" | |
| echo " CentOS/RHEL: sudo yum install lm_sensors" | |
| echo " Fedora: sudo dnf install lm_sensors" | |
| echo " Arch: sudo pacman -S lm_sensors" | |
| fi | |
| } | |
| ############################################# | |
| # 4. DISK SPACE | |
| ############################################# | |
| check_disk_space() { | |
| print_section "DISK SPACE" | |
| echo "Partition usage:" | |
| df -h -x tmpfs -x devtmpfs | grep -v "^Filesystem" | |
| echo "" | |
| # Check partition usage | |
| df -h -x tmpfs -x devtmpfs | grep -v "^Filesystem" | awk '{print $5 " " $6}' | while read line; do | |
| USAGE=$(echo $line | awk '{print $1}' | sed 's/%//') | |
| MOUNT=$(echo $line | awk '{print $2}') | |
| if [ "$USAGE" -gt 90 ]; then | |
| print_status "crit" "Partition $MOUNT is ${USAGE}% full!" "Disk Space" | |
| elif [ "$USAGE" -gt 80 ]; then | |
| print_status "warn" "Partition $MOUNT is ${USAGE}% full" "Disk Space" | |
| fi | |
| done | |
| # Check inodes | |
| echo "" | |
| echo "Inodes usage (top-5 partitions):" | |
| df -i -x tmpfs -x devtmpfs | grep -v "^Filesystem" | awk '{print $5 " " $6}' | while read line; do | |
| USAGE_PERCENT=$(echo $line | awk '{print $1}') | |
| MOUNT=$(echo $line | awk '{print $2}') | |
| USAGE=$(echo $USAGE_PERCENT | sed 's/%//' | grep -E '^[0-9]+$') | |
| if [ ! -z "$USAGE" ]; then | |
| echo " $MOUNT: ${USAGE_PERCENT}" | |
| if [ "$USAGE" -gt 90 ]; then | |
| print_status "crit" "Inodes on $MOUNT critically full!" "Disk Space" | |
| elif [ "$USAGE" -gt 80 ]; then | |
| print_status "warn" "Inodes on $MOUNT need attention" "Disk Space" | |
| fi | |
| fi | |
| done | head -15 | |
| # SMART status (if available) | |
| if command_exists smartctl; then | |
| echo "" | |
| echo "SMART disk status:" | |
| for disk in $(lsblk -d -o name,type 2>/dev/null | awk '$2=="disk" {print $1}'); do | |
| SMART_STATUS=$(smartctl -H /dev/$disk 2>/dev/null | grep "SMART overall-health") | |
| if [ -z "$SMART_STATUS" ]; then | |
| echo " /dev/$disk: N/A" | |
| else | |
| echo " /dev/$disk: $SMART_STATUS" | |
| # Check for FAILED | |
| if echo "$SMART_STATUS" | grep -qi "FAILED"; then | |
| print_status "crit" "Disk /dev/$disk has SMART problems!" "Disk Space" | |
| fi | |
| fi | |
| done | |
| fi | |
| } | |
| ############################################# | |
| # 4.5. DISK SPEED TEST | |
| ############################################# | |
| check_disk_speed() { | |
| print_section "DISK SPEED TEST" | |
| # Check if dd is available | |
| if ! command_exists dd; then | |
| print_status "warn" "'dd' utility not found" | |
| return | |
| fi | |
| # Get root partition | |
| ROOT_MOUNT=$(df / | tail -1 | awk '{print $6}') | |
| TEST_FILE="/tmp/disk_speed_test_$$" | |
| echo "Write/Read speed test for $ROOT_MOUNT:" | |
| echo " (using 100MB temporary file)" | |
| echo "" | |
| # Write speed test | |
| echo -n " Write speed: " | |
| WRITE_SPEED=$(dd if=/dev/zero of="$TEST_FILE" bs=1M count=100 oflag=direct 2>&1 | grep -oP '[0-9.]+ MB/s' | head -1) | |
| if [ -z "$WRITE_SPEED" ]; then | |
| # Alternative parsing for different dd versions | |
| WRITE_SPEED=$(dd if=/dev/zero of="$TEST_FILE" bs=1M count=100 oflag=direct 2>&1 | tail -1 | awk '{print $(NF-1), $NF}') | |
| fi | |
| echo "$WRITE_SPEED" | |
| # Clear cache (if permissions allow) | |
| sync | |
| if [ -w /proc/sys/vm/drop_caches ]; then | |
| echo 3 > /proc/sys/vm/drop_caches 2>/dev/null | |
| fi | |
| # Read speed test | |
| echo -n " Read speed: " | |
| READ_SPEED=$(dd if="$TEST_FILE" of=/dev/null bs=1M 2>&1 | grep -oP '[0-9.]+ MB/s' | head -1) | |
| if [ -z "$READ_SPEED" ]; then | |
| # Alternative parsing for different dd versions | |
| READ_SPEED=$(dd if="$TEST_FILE" of=/dev/null bs=1M 2>&1 | tail -1 | awk '{print $(NF-1), $NF}') | |
| fi | |
| echo "$READ_SPEED" | |
| # Remove test file | |
| rm -f "$TEST_FILE" | |
| echo "" | |
| print_status "ok" "Disk speed test completed" | |
| echo "" | |
| echo "Note: This is a basic test. For detailed analysis use fio or hdparm." | |
| } | |
| ############################################# | |
| # 6. NETWORK DIAGNOSTICS | |
| ############################################# | |
| check_network() { | |
| print_section "NETWORK DIAGNOSTICS" | |
| echo "Network interfaces:" | |
| if command_exists ip; then | |
| ip -br addr show | grep -v "^lo" | |
| else | |
| ifconfig | grep -E "^[a-z]|inet " | |
| fi | |
| echo "" | |
| # Check interface errors | |
| if [ -f /proc/net/dev ]; then | |
| echo "Interface errors:" | |
| awk 'NR>2 {print $1, $4, $12}' /proc/net/dev | while read iface rx_errors tx_errors; do | |
| iface=$(echo $iface | sed 's/:$//') | |
| if [ "$iface" != "lo" ]; then | |
| TOTAL_ERRORS=$((rx_errors + tx_errors)) | |
| if [ "$TOTAL_ERRORS" -gt 100 ]; then | |
| print_status "warn" "$iface: RX errors: $rx_errors, TX errors: $tx_errors" "Network" | |
| fi | |
| fi | |
| done | |
| fi | |
| echo "" | |
| # Active connections (external) | |
| echo "Top-10 external connections (by IP):" | |
| # Get local IP addresses for filtering | |
| LOCAL_IPS=$(ip addr show 2>/dev/null | grep -oP 'inet \K[\d.]+' | grep -v '^127\.') | |
| if command_exists ss; then | |
| CONNECTIONS=$(ss -tun state established 2>/dev/null | awk 'NR>1 {print $5}' | grep -v "^$" | sed 's/:[0-9]*$//' | grep -E '^[0-9]+\.' | grep -v "^127\.\|^0\.0\.0\.0") | |
| else | |
| CONNECTIONS=$(netstat -tun 2>/dev/null | grep ESTABLISHED | awk '{print $5}' | sed 's/:[0-9]*$//' | grep -E '^[0-9]+\.' | grep -v "^127\.\|^0\.0\.0\.0") | |
| fi | |
| # Filter local IPs | |
| FILTERED_CONNECTIONS="" | |
| for ip in $CONNECTIONS; do | |
| IS_LOCAL=0 | |
| for local_ip in $LOCAL_IPS; do | |
| if [ "$ip" = "$local_ip" ]; then | |
| IS_LOCAL=1 | |
| break | |
| fi | |
| done | |
| if [ $IS_LOCAL -eq 0 ]; then | |
| FILTERED_CONNECTIONS="$FILTERED_CONNECTIONS$ip\n" | |
| fi | |
| done | |
| if [ -z "$FILTERED_CONNECTIONS" ]; then | |
| echo " No active external connections" | |
| else | |
| echo -e "$FILTERED_CONNECTIONS" | grep -v "^$" | sort | uniq -c | sort -rn | head -10 | |
| fi | |
| # Network connectivity tests | |
| echo "" | |
| echo "Network connectivity tests:" | |
| echo "" | |
| # 1. Ping to gateway | |
| GATEWAY=$(ip route | grep default | awk '{print $3}' | head -1) | |
| if [ ! -z "$GATEWAY" ]; then | |
| do_ping "$GATEWAY" "Gateway" "Network" | |
| else | |
| echo " Gateway: Not found" | |
| print_status "warn" "No default gateway found" "Network" | |
| echo "" | |
| fi | |
| # 2. Ping to ya.ru | |
| do_ping "ya.ru" "ya.ru (DNS + connectivity)" "Network" | |
| # 3. Ping to 8.8.8.8 | |
| do_ping "8.8.8.8" "Google DNS" "Network" | |
| # Internet speed test (optional) | |
| echo "" | |
| if command_exists curl; then | |
| echo "Internet speed test:" | |
| echo -n " Download (testing 100MB file): " | |
| # Test download speed using curl | |
| # %{speed_download} returns speed in bytes/sec | |
| DOWNLOAD_SPEED=$(curl -o /dev/null -s -w '%{speed_download}' --max-time 15 http://speedtest.selectel.ru/100MB 2>/dev/null) | |
| if [ ! -z "$DOWNLOAD_SPEED" ] && [ "$DOWNLOAD_SPEED" != "0.000" ] && [ "$DOWNLOAD_SPEED" != "0" ]; then | |
| # Convert bytes/sec to MB/s (divide by 1048576) | |
| if command_exists bc; then | |
| DOWNLOAD_MBPS=$(echo "scale=2; $DOWNLOAD_SPEED / 1048576" | bc 2>/dev/null) | |
| else | |
| # Without bc use awk | |
| DOWNLOAD_MBPS=$(awk "BEGIN {printf \"%.2f\", $DOWNLOAD_SPEED / 1048576}") | |
| fi | |
| if [ ! -z "$DOWNLOAD_MBPS" ] && [ "$DOWNLOAD_MBPS" != "0.00" ]; then | |
| echo "${DOWNLOAD_MBPS} MB/s" | |
| else | |
| echo "N/A (file too small for measurement)" | |
| fi | |
| else | |
| echo "N/A (check internet connection)" | |
| fi | |
| fi | |
| } | |
| ############################################# | |
| # 7. PROCESSES | |
| ############################################# | |
| check_processes() { | |
| print_section "PROCESSES" | |
| echo "Top-10 processes by CPU:" | |
| ps aux --sort=-%cpu | head -11 | tail -10 | |
| echo "" | |
| echo "Top-10 processes by memory:" | |
| ps aux --sort=-%mem | head -11 | tail -10 | |
| # Zombie processes | |
| echo "" | |
| ZOMBIE_COUNT=$(ps aux | awk '{if ($8 == "Z") print $0}' | wc -l) | |
| if [ "$ZOMBIE_COUNT" -gt 0 ]; then | |
| print_status "warn" "Found zombie processes: $ZOMBIE_COUNT" "Processes" | |
| ps aux | awk '{if ($8 == "Z") print $0}' | |
| else | |
| print_status "ok" "No zombie processes found" | |
| fi | |
| # Total processes | |
| echo "" | |
| TOTAL_PROCESSES=$(ps aux | wc -l) | |
| echo "Total processes: $TOTAL_PROCESSES" | |
| } | |
| ############################################# | |
| # 8. LOG ANALYSIS | |
| ############################################# | |
| check_logs() { | |
| print_section "SYSTEM LOG ANALYSIS" | |
| # Detect logging system | |
| if command_exists journalctl; then | |
| echo "Critical errors in last 24 hours (journalctl):" | |
| journalctl -p err -S "24 hours ago" --no-pager | tail -20 | |
| echo "" | |
| echo "OOM (Out of Memory) events:" | |
| journalctl -k | grep -i "out of memory\|oom" | tail -10 | |
| elif [ -f /var/log/syslog ]; then | |
| echo "Critical errors (syslog):" | |
| grep -i "error\|critical\|fail" /var/log/syslog | tail -20 | |
| echo "" | |
| echo "OOM events:" | |
| grep -i "out of memory\|oom" /var/log/syslog | tail -10 | |
| elif [ -f /var/log/messages ]; then | |
| echo "Critical errors (messages):" | |
| grep -i "error\|critical\|fail" /var/log/messages | tail -20 | |
| echo "" | |
| echo "OOM events:" | |
| grep -i "out of memory\|oom" /var/log/messages | tail -10 | |
| fi | |
| # Kernel warnings | |
| echo "" | |
| echo "Kernel warnings (dmesg):" | |
| if command_exists dmesg; then | |
| # Use -T to show real time (if supported) | |
| if dmesg -T >/dev/null 2>&1; then | |
| dmesg -T -l err,crit,alert,emerg 2>/dev/null | tail -15 | |
| else | |
| # For older versions without -T support | |
| dmesg -l err,crit,alert,emerg 2>/dev/null | tail -15 | |
| fi | |
| fi | |
| # Failed SSH attempts | |
| echo "" | |
| echo "Failed SSH attempts (last 10):" | |
| if [ -f /var/log/auth.log ]; then | |
| grep "Failed password" /var/log/auth.log | tail -10 | |
| elif [ -f /var/log/secure ]; then | |
| grep "Failed password" /var/log/secure | tail -10 | |
| fi | |
| } | |
| ############################################# | |
| # 9. SYSTEM SERVICES | |
| ############################################# | |
| check_services() { | |
| print_section "SYSTEM SERVICES" | |
| if command_exists systemctl; then | |
| echo "Failed services:" | |
| FAILED_SERVICES=$(systemctl list-units --state=failed --no-pager --no-legend) | |
| if [ -z "$FAILED_SERVICES" ]; then | |
| print_status "ok" "No failed services found" | |
| else | |
| print_status "crit" "Failed services found:" "Services" | |
| echo "$FAILED_SERVICES" | |
| fi | |
| else | |
| echo "systemctl not found, check services manually" | |
| fi | |
| } | |
| ############################################# | |
| # 10. SECURITY | |
| ############################################# | |
| check_security() { | |
| print_section "SECURITY" | |
| # Last successful logins | |
| echo "Last successful logins:" | |
| if command_exists last; then | |
| last -n 10 | grep -v "^$\|^wtmp" | |
| fi | |
| echo "" | |
| # Active SSH sessions | |
| echo "Active SSH sessions:" | |
| who | grep -v "^$" | |
| # Check number of active SSH sessions | |
| SSH_COUNT=$(who | wc -l) | |
| if [ "$SSH_COUNT" -gt 5 ]; then | |
| print_status "warn" "Detected $SSH_COUNT active SSH sessions" "Security" | |
| fi | |
| echo "" | |
| # Sudo activity in last 24 hours | |
| echo "Sudo activity in last 24 hours:" | |
| if [ -f /var/log/auth.log ]; then | |
| grep "sudo.*COMMAND" /var/log/auth.log | tail -10 | |
| elif [ -f /var/log/secure ]; then | |
| grep "sudo.*COMMAND" /var/log/secure | tail -10 | |
| fi | |
| } | |
| ############################################# | |
| # 11. DOCKER (if installed) | |
| ############################################# | |
| check_docker() { | |
| if command_exists docker; then | |
| print_section "DOCKER" | |
| echo "Container status:" | |
| docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" | |
| echo "" | |
| # Check for exited containers | |
| EXITED_CONTAINERS=$(docker ps -a --filter "status=exited" --format "{{.Names}}" | wc -l) | |
| if [ "$EXITED_CONTAINERS" -gt 0 ]; then | |
| print_status "warn" "Found stopped containers: $EXITED_CONTAINERS" "Docker" | |
| else | |
| print_status "ok" "All containers are running" | |
| fi | |
| echo "" | |
| echo "Resource usage by containers:" | |
| docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" | |
| fi | |
| } | |
| ############################################# | |
| # FINAL REPORT | |
| ############################################# | |
| generate_summary() { | |
| print_section "DIAGNOSTIC SUMMARY" | |
| echo "Check date and time: $(date '+%Y-%m-%d %H:%M:%S')" | |
| echo "Hostname: $(hostname)" | |
| echo "" | |
| # Hardware summary | |
| echo "Hardware Summary:" | |
| echo "" | |
| # CPU info | |
| if [ -f /proc/cpuinfo ]; then | |
| CPU_MODEL=$(grep "model name" /proc/cpuinfo | head -1 | cut -d':' -f2 | xargs) | |
| CPU_CORES=$(grep -c "processor" /proc/cpuinfo) | |
| echo " CPU: $CPU_MODEL" | |
| echo " Cores: $CPU_CORES" | |
| fi | |
| # RAM info | |
| if command_exists free; then | |
| TOTAL_RAM=$(free -h | awk '/^Mem:/ {print $2}') | |
| USED_RAM=$(free -h | awk '/^Mem:/ {print $3}') | |
| MEM_PERCENT=$(free | grep Mem | awk '{print int($3/$2 * 100)}') | |
| echo " RAM: $USED_RAM / $TOTAL_RAM (${MEM_PERCENT}%)" | |
| fi | |
| # Disk info | |
| if command_exists df; then | |
| TOTAL_DISK=$(df -h --total 2>/dev/null | grep total | awk '{print $2}' || df -h / | tail -1 | awk '{print $2}') | |
| USED_DISK=$(df -h --total 2>/dev/null | grep total | awk '{print $3}' || df -h / | tail -1 | awk '{print $3}') | |
| echo " Disk: $USED_DISK / $TOTAL_DISK" | |
| fi | |
| # Load Average | |
| if [ -f /proc/loadavg ]; then | |
| LOAD_AVG=$(cat /proc/loadavg | awk '{print $1, $2, $3}') | |
| echo " Load Average: $LOAD_AVG" | |
| fi | |
| # Uptime | |
| UPTIME=$(uptime -p 2>/dev/null || uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}') | |
| echo " Uptime: $UPTIME" | |
| echo "" | |
| echo "Diagnostic Results:" | |
| echo "" | |
| if [ "$CRITICALS" -eq 0 ] && [ "$WARNINGS" -eq 0 ]; then | |
| echo "${CHECK_OK} System is in excellent condition!" | |
| elif [ "$CRITICALS" -eq 0 ]; then | |
| echo "${CHECK_WARN} Warnings detected: $WARNINGS" | |
| echo "Recommended to pay attention to the indicated issues." | |
| else | |
| echo "${CHECK_CRIT} ATTENTION! Critical problems detected!" | |
| echo "Critical: $CRITICALS" | |
| echo "Warnings: $WARNINGS" | |
| fi | |
| # Show problem sections if any | |
| if [ ${#PROBLEM_SECTIONS[@]} -gt 0 ]; then | |
| echo "" | |
| echo "Sections with problems:" | |
| for section in "${PROBLEM_SECTIONS[@]}"; do | |
| echo " β’ $section" | |
| done | |
| fi | |
| echo "" | |
| echo "Recommendations:" | |
| if [ "$CRITICALS" -gt 0 ] || [ "$WARNINGS" -gt 0 ]; then | |
| echo " β’ Review the report above and fix the detected problems" | |
| echo " β’ Check logs for detailed information" | |
| echo " β’ Free up disk space if necessary" | |
| echo " β’ Restart failed services" | |
| else | |
| echo " β’ Continue regular system monitoring" | |
| echo " β’ Recommended to run this script once a day" | |
| fi | |
| # Return error code for monitoring systems integration | |
| if [ "$CRITICALS" -gt 0 ]; then | |
| return 2 # Critical problems exist | |
| elif [ "$WARNINGS" -gt 0 ]; then | |
| return 1 # Warnings exist | |
| else | |
| return 0 # All is good | |
| fi | |
| } | |
| ############################################# | |
| # TELEGRAM NOTIFICATION | |
| ############################################# | |
| send_telegram_notification() { | |
| local exit_code=$1 | |
| local report_file=$2 | |
| # Check if Telegram credentials are set | |
| if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then | |
| return 0 | |
| fi | |
| # Only send if there are problems | |
| if [ "$exit_code" -eq 0 ]; then | |
| return 0 | |
| fi | |
| # Check if curl is available | |
| if ! command_exists curl; then | |
| echo "Warning: curl not found, cannot send Telegram notification" | |
| return 1 | |
| fi | |
| # Prepare message | |
| local hostname=$(hostname) | |
| local timestamp=$(date '+%Y-%m-%d %H:%M:%S') | |
| local status_emoji="" | |
| local status_text="" | |
| if [ "$exit_code" -eq 2 ]; then | |
| status_emoji="π¨" | |
| status_text="CRITICAL PROBLEMS" | |
| else | |
| status_emoji="β οΈ" | |
| status_text="WARNINGS" | |
| fi | |
| # Build message | |
| local message="${status_emoji} ${status_text} on ${hostname}! | |
| Time: ${timestamp} | |
| Critical: ${CRITICALS} | |
| Warnings: ${WARNINGS}" | |
| # Add problem sections if any | |
| if [ ${#PROBLEM_SECTIONS[@]} -gt 0 ]; then | |
| message="${message} | |
| Sections with problems:" | |
| for section in "${PROBLEM_SECTIONS[@]}"; do | |
| message="${message} | |
| β’ ${section}" | |
| done | |
| fi | |
| message="${message} | |
| Please check the detailed report." | |
| # Send message | |
| curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ | |
| -d chat_id="${TELEGRAM_CHAT_ID}" \ | |
| -d text="${message}" >/dev/null 2>&1 | |
| # Send report file if it exists | |
| if [ -f "$report_file" ]; then | |
| curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendDocument" \ | |
| -F chat_id="${TELEGRAM_CHAT_ID}" \ | |
| -F document=@"${report_file}" \ | |
| -F caption="Full diagnostic report" >/dev/null 2>&1 | |
| fi | |
| } | |
| ############################################# | |
| # MAIN FUNCTION | |
| ############################################# | |
| main() { | |
| # Temporary file for report | |
| TEMP_REPORT="/tmp/system_diagnostic_$(date +%Y%m%d_%H%M%S).txt" | |
| TEMP_COUNTERS="/tmp/system_diagnostic_counters_$$.tmp" | |
| # Run diagnostics and capture output | |
| { | |
| clear | |
| echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" | |
| echo "β β" | |
| echo "β LINUX SYSTEM DIAGNOSTICS β" | |
| echo "β System Diagnostic Script v1.0 β" | |
| echo "β β" | |
| echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ" | |
| echo "" | |
| # Check root privileges (some checks require sudo) | |
| if [ "$EUID" -ne 0 ]; then | |
| echo "${CHECK_WARN} Script running without root privileges. Some checks may be unavailable." | |
| echo "For full diagnostics run: sudo $0" | |
| echo "" | |
| fi | |
| # Run all checks | |
| check_system_info | |
| check_resources | |
| check_temperature | |
| check_disk_space | |
| check_disk_speed | |
| check_network | |
| check_processes | |
| check_logs | |
| check_services | |
| check_security | |
| check_docker | |
| # Final summary | |
| generate_summary | |
| # Save counters and problem sections to file (to survive tee subshell) | |
| echo "$CRITICALS" > "$TEMP_COUNTERS" | |
| echo "$WARNINGS" >> "$TEMP_COUNTERS" | |
| # Save problem sections (one per line) | |
| for section in "${PROBLEM_SECTIONS[@]}"; do | |
| echo "$section" >> "$TEMP_COUNTERS" | |
| done | |
| } | tee "$TEMP_REPORT" | |
| # Read counters from file | |
| if [ -f "$TEMP_COUNTERS" ]; then | |
| CRITICALS=$(sed -n '1p' "$TEMP_COUNTERS") | |
| WARNINGS=$(sed -n '2p' "$TEMP_COUNTERS") | |
| # Read problem sections (starting from line 3) | |
| PROBLEM_SECTIONS=() | |
| while IFS= read -r section; do | |
| PROBLEM_SECTIONS+=("$section") | |
| done < <(tail -n +3 "$TEMP_COUNTERS") | |
| rm -f "$TEMP_COUNTERS" | |
| fi | |
| # Determine exit code from counters | |
| if [ "$CRITICALS" -gt 0 ]; then | |
| EXIT_CODE=2 | |
| elif [ "$WARNINGS" -gt 0 ]; then | |
| EXIT_CODE=1 | |
| else | |
| EXIT_CODE=0 | |
| fi | |
| # Send Telegram notification if configured and there are problems | |
| send_telegram_notification "$EXIT_CODE" "$TEMP_REPORT" | |
| # Clean up temp files | |
| if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then | |
| rm -f "$TEMP_REPORT" | |
| else | |
| # Keep report for a short time in case of retry | |
| (sleep 60 && rm -f "$TEMP_REPORT") & | |
| fi | |
| # Clean up counter file if exists | |
| rm -f "$TEMP_COUNTERS" | |
| # Exit with appropriate code | |
| exit $EXIT_CODE | |
| } | |
| # Run script | |
| main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment