add system-logger
This commit is contained in:
parent
6d09b2d6f4
commit
53cc916be5
2 changed files with 196 additions and 0 deletions
60
modules/services/system-logger/default.nix
Normal file
60
modules/services/system-logger/default.nix
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
system-logger = pkgs.writeShellApplication {
|
||||||
|
name = "system-logger";
|
||||||
|
runtimeInputs = with pkgs; [curl jq zip gawk systemd];
|
||||||
|
text = builtins.readFile ./system-logger.sh;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
options.services.system-logger = {
|
||||||
|
enable = lib.mkEnableOption {
|
||||||
|
description = "Enable System Logger Service";
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
logDirectory = lib.mkOption {
|
||||||
|
type = lib.types.path;
|
||||||
|
default = "/var/lib/system-logger";
|
||||||
|
description = "Directory to store log archives";
|
||||||
|
};
|
||||||
|
|
||||||
|
maxSizeMB = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 1;
|
||||||
|
description = "Maximum size of daily log archive in megabytes";
|
||||||
|
};
|
||||||
|
|
||||||
|
retentionDays = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 30;
|
||||||
|
description = "Number of days to retain log archives";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.services.system-logger.enable {
|
||||||
|
systemd.timers.system-logger = {
|
||||||
|
description = "System Logger Timer";
|
||||||
|
wantedBy = ["timers.target"];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "daily";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.system-logger = {
|
||||||
|
description = "System Logger Service";
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${lib.getExe system-logger}";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 60;
|
||||||
|
User = "root";
|
||||||
|
Group = "root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
136
modules/services/system-logger/system-logger.sh
Executable file
136
modules/services/system-logger/system-logger.sh
Executable file
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
LOG_DIR="/var/lib/system-logger"
|
||||||
|
MAX_SIZE_MB=1
|
||||||
|
RETENTION_DAYS=30
|
||||||
|
DATE=$(date +%Y-%m-%d)
|
||||||
|
HOSTNAME=$(hostname)
|
||||||
|
TEMP_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
# Create log directory if it doesn't exist
|
||||||
|
mkdir -p "$LOG_DIR"
|
||||||
|
|
||||||
|
# Check if today's log already exists
|
||||||
|
if [ -f "$LOG_DIR/${DATE}-logs-${HOSTNAME}.zip" ]; then
|
||||||
|
echo "Logs for today already exist. Exiting..."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Starting system log collection for $DATE"
|
||||||
|
|
||||||
|
# Function to collect logs with size limit
|
||||||
|
collect_logs() {
|
||||||
|
local source="$1"
|
||||||
|
local output="$2"
|
||||||
|
local max_lines="$3"
|
||||||
|
|
||||||
|
if [ -f "$source" ]; then
|
||||||
|
# Get the last N lines to stay within size limit
|
||||||
|
tail -n "$max_lines" "$source" > "$output" 2>/dev/null || true
|
||||||
|
echo "Collected from $source"
|
||||||
|
else
|
||||||
|
echo "Source $source not found, skipping..."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to get journal logs with filtering
|
||||||
|
get_journal_logs() {
|
||||||
|
local output="$1"
|
||||||
|
local filter="$2"
|
||||||
|
local max_lines="$3"
|
||||||
|
|
||||||
|
journalctl --since "00:00:00" --until "23:59:59" \
|
||||||
|
--no-pager --output=short \
|
||||||
|
| grep -i "$filter" | tail -n "$max_lines" > "$output" 2>/dev/null || true
|
||||||
|
echo "Collected journal logs for $filter"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Calculate approximate lines per log type to stay under 1MB
|
||||||
|
# Assuming average line is ~100 bytes, we aim for ~10,000 total lines
|
||||||
|
TOTAL_LINES=10000
|
||||||
|
SSH_LINES=2000
|
||||||
|
KERNEL_LINES=2000
|
||||||
|
LOGIN_LINES=1000
|
||||||
|
SYSTEM_LINES=2000
|
||||||
|
AUTH_LINES=1000
|
||||||
|
FAILED_LOGIN_LINES=500
|
||||||
|
DISK_LINES=500
|
||||||
|
NETWORK_LINES=500
|
||||||
|
MEMORY_LINES=500
|
||||||
|
|
||||||
|
# Collect SSH connections
|
||||||
|
get_journal_logs "$TEMP_DIR/ssh.log" "sshd" "$SSH_LINES"
|
||||||
|
|
||||||
|
# Collect kernel warnings and errors
|
||||||
|
get_journal_logs "$TEMP_DIR/kernel.log" "kernel.*warning\|kernel.*error" "$KERNEL_LINES"
|
||||||
|
|
||||||
|
# Collect login/logout events
|
||||||
|
get_journal_logs "$TEMP_DIR/login.log" "session.*opened\|session.*closed\|login\|logout" "$LOGIN_LINES"
|
||||||
|
|
||||||
|
# Collect system messages
|
||||||
|
get_journal_logs "$TEMP_DIR/system.log" "systemd\|daemon" "$SYSTEM_LINES"
|
||||||
|
|
||||||
|
# Collect authentication events
|
||||||
|
get_journal_logs "$TEMP_DIR/auth.log" "authentication\|auth" "$AUTH_LINES"
|
||||||
|
|
||||||
|
# Collect failed login attempts
|
||||||
|
get_journal_logs "$TEMP_DIR/failed_login.log" "failed\|failure\|denied" "$FAILED_LOGIN_LINES"
|
||||||
|
|
||||||
|
# Collect disk usage and errors
|
||||||
|
get_journal_logs "$TEMP_DIR/disk.log" "disk\|storage\|iostat" "$DISK_LINES"
|
||||||
|
|
||||||
|
# Collect network events
|
||||||
|
get_journal_logs "$TEMP_DIR/network.log" "network\|connection\|interface" "$NETWORK_LINES"
|
||||||
|
|
||||||
|
# Collect memory usage
|
||||||
|
get_journal_logs "$TEMP_DIR/memory.log" "memory\|oom\|swap" "$MEMORY_LINES"
|
||||||
|
|
||||||
|
# Collect traditional log files if they exist
|
||||||
|
collect_logs "/var/log/auth.log" "$TEMP_DIR/auth_traditional.log" 1000
|
||||||
|
collect_logs "/var/log/syslog" "$TEMP_DIR/syslog_traditional.log" 1000
|
||||||
|
collect_logs "/var/log/messages" "$TEMP_DIR/messages_traditional.log" 1000
|
||||||
|
|
||||||
|
# Create a summary file
|
||||||
|
{
|
||||||
|
echo "=== System Log Summary for $DATE ==="
|
||||||
|
echo "Hostname: $HOSTNAME"
|
||||||
|
echo "Collection time: $(date)"
|
||||||
|
echo "Total lines collected:"
|
||||||
|
wc -l "$TEMP_DIR"/*.log 2>/dev/null || true
|
||||||
|
echo ""
|
||||||
|
echo "=== System Information ==="
|
||||||
|
echo "Uptime: $(uptime)"
|
||||||
|
echo "Load average: $(cat /proc/loadavg)"
|
||||||
|
echo "Memory usage:"
|
||||||
|
free -h
|
||||||
|
echo ""
|
||||||
|
echo "Disk usage:"
|
||||||
|
df -h
|
||||||
|
echo ""
|
||||||
|
echo "Active users:"
|
||||||
|
who
|
||||||
|
} > "$TEMP_DIR/summary.txt"
|
||||||
|
|
||||||
|
# Create the zip file
|
||||||
|
cd "$TEMP_DIR"
|
||||||
|
zip -r "$LOG_DIR/${DATE}-logs-${HOSTNAME}.zip" ./* > /dev/null
|
||||||
|
|
||||||
|
# Check file size and warn if too large
|
||||||
|
FILE_SIZE=$(stat -c%s "$LOG_DIR/${DATE}-logs-${HOSTNAME}.zip")
|
||||||
|
FILE_SIZE_MB=$((FILE_SIZE / 1024 / 1024))
|
||||||
|
|
||||||
|
if [ "$FILE_SIZE_MB" -gt "$MAX_SIZE_MB" ]; then
|
||||||
|
echo "WARNING: Log file size ($FILE_SIZE_MB MB) exceeds limit ($MAX_SIZE_MB MB)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Log collection completed: $LOG_DIR/${DATE}-logs-${HOSTNAME}.zip ($FILE_SIZE_MB MB)"
|
||||||
|
|
||||||
|
# Clean up old logs (older than RETENTION_DAYS)
|
||||||
|
find "$LOG_DIR" -name "*-logs-*.zip" -type f -mtime +$RETENTION_DAYS -delete 2>/dev/null || true
|
||||||
|
|
||||||
|
# Clean up temporary directory
|
||||||
|
rm -rf "$TEMP_DIR"
|
||||||
|
|
||||||
|
echo "System log collection finished successfully"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue