feat: Add base HTML template and implement dashboard, logs, and service views

- Created a base HTML template for consistent layout across pages.
- Developed a dashboard page to display backup service metrics and statuses.
- Implemented a log viewer for detailed log file inspection.
- Added error handling page for better user experience during failures.
- Introduced service detail page to show specific service metrics and actions.
- Enhanced log filtering and viewing capabilities.
- Integrated auto-refresh functionality for real-time updates on metrics.
- Created integration and unit test scripts for backup metrics functionality.
This commit is contained in:
Peter Wood
2025-06-18 08:06:08 -04:00
parent d066f32b10
commit 6d726cb015
34 changed files with 6006 additions and 26 deletions

View File

@@ -0,0 +1,246 @@
#!/bin/bash
################################################################################
# Simplified Unified Backup Metrics Library
################################################################################
#
# Author: Peter Wood <peter@peterwood.dev>
# Description: Lightweight backup metrics tracking for personal backup systems.
# Provides essential status tracking without enterprise complexity.
#
# Features:
# - Simple JSON status files (one per service)
# - Basic timing and file counting
# - Minimal performance overhead
# - Easy to debug and maintain
# - Web interface ready
#
# Usage:
# source /home/acedanger/shell/lib/unified-backup-metrics-simple.sh
#
# metrics_backup_start "service-name" "description" "/backup/path"
# metrics_update_status "running" "Current operation"
# metrics_file_backup_complete "/path/to/file" "1024" "success"
# metrics_backup_complete "success" "Backup completed successfully"
#
################################################################################
# Configuration
METRICS_ROOT="${BACKUP_ROOT:-/mnt/share/media/backups}/metrics"
METRICS_DEBUG="${METRICS_DEBUG:-false}"
# Global state
declare -g METRICS_SERVICE=""
declare -g METRICS_START_TIME=""
declare -g METRICS_STATUS_FILE=""
declare -g METRICS_FILE_COUNT=0
declare -g METRICS_TOTAL_SIZE=0
# Debug function
metrics_debug() {
if [ "$METRICS_DEBUG" = "true" ]; then
echo "[METRICS] $1" >&2
fi
}
# Initialize metrics for a backup service
metrics_backup_start() {
local service_name="$1"
local description="$2"
local backup_path="$3"
if [ -z "$service_name" ]; then
metrics_debug "Warning: No service name provided to metrics_backup_start"
return 1
fi
# Set global state
METRICS_SERVICE="$service_name"
METRICS_START_TIME=$(date +%s)
METRICS_FILE_COUNT=0
METRICS_TOTAL_SIZE=0
# Create metrics directory
mkdir -p "$METRICS_ROOT"
# Set status file path
METRICS_STATUS_FILE="$METRICS_ROOT/${service_name}_status.json"
# Create initial status
cat > "$METRICS_STATUS_FILE" << EOF
{
"service": "$service_name",
"description": "$description",
"backup_path": "$backup_path",
"status": "running",
"start_time": "$(date -d "@$METRICS_START_TIME" --iso-8601=seconds)",
"start_timestamp": $METRICS_START_TIME,
"current_operation": "Starting backup",
"files_processed": 0,
"total_size_bytes": 0,
"last_updated": "$(date --iso-8601=seconds)",
"hostname": "$(hostname)"
}
EOF
metrics_debug "Started metrics tracking for $service_name"
return 0
}
# Update backup status
metrics_update_status() {
local status="$1"
local operation="$2"
if [ -z "$METRICS_STATUS_FILE" ] || [ ! -f "$METRICS_STATUS_FILE" ]; then
metrics_debug "Warning: No active metrics session for status update"
return 1
fi
# Update the status file using jq if available, otherwise simple replacement
if command -v jq >/dev/null 2>&1; then
local temp_file="${METRICS_STATUS_FILE}.tmp"
jq --arg status "$status" \
--arg operation "$operation" \
--arg updated "$(date --iso-8601=seconds)" \
'.status = $status | .current_operation = $operation | .last_updated = $updated' \
"$METRICS_STATUS_FILE" > "$temp_file" && mv "$temp_file" "$METRICS_STATUS_FILE"
else
# Fallback without jq - just add a simple status line to end of file
echo "# Status: $status - $operation ($(date --iso-8601=seconds))" >> "$METRICS_STATUS_FILE"
fi
metrics_debug "Updated status: $status - $operation"
return 0
}
# Track individual file backup completion
metrics_file_backup_complete() {
local file_path="$1"
local file_size="$2"
local status="$3" # "success", "failed", "skipped"
if [ -z "$METRICS_STATUS_FILE" ] || [ ! -f "$METRICS_STATUS_FILE" ]; then
metrics_debug "Warning: No active metrics session for file tracking"
return 1
fi
# Update counters
if [ "$status" = "success" ]; then
METRICS_FILE_COUNT=$((METRICS_FILE_COUNT + 1))
METRICS_TOTAL_SIZE=$((METRICS_TOTAL_SIZE + ${file_size:-0}))
fi
# Update status file with new counts if jq is available
if command -v jq >/dev/null 2>&1; then
local temp_file="${METRICS_STATUS_FILE}.tmp"
jq --argjson files "$METRICS_FILE_COUNT" \
--argjson size "$METRICS_TOTAL_SIZE" \
--arg updated "$(date --iso-8601=seconds)" \
'.files_processed = $files | .total_size_bytes = $size | .last_updated = $updated' \
"$METRICS_STATUS_FILE" > "$temp_file" && mv "$temp_file" "$METRICS_STATUS_FILE"
fi
metrics_debug "File tracked: $(basename "$file_path") ($status, ${file_size:-0} bytes)"
return 0
}
# Complete backup and finalize metrics
metrics_backup_complete() {
local final_status="$1" # "success", "failed", "completed_with_errors"
local message="$2"
if [ -z "$METRICS_STATUS_FILE" ] || [ ! -f "$METRICS_STATUS_FILE" ]; then
metrics_debug "Warning: No active metrics session to complete"
return 1
fi
local end_time=$(date +%s)
local duration=$((end_time - METRICS_START_TIME))
# Create final status file
if command -v jq >/dev/null 2>&1; then
local temp_file="${METRICS_STATUS_FILE}.tmp"
jq --arg status "$final_status" \
--arg message "$message" \
--arg end_time "$(date -d "@$end_time" --iso-8601=seconds)" \
--argjson end_timestamp "$end_time" \
--argjson duration "$duration" \
--argjson files "$METRICS_FILE_COUNT" \
--argjson size "$METRICS_TOTAL_SIZE" \
--arg updated "$(date --iso-8601=seconds)" \
'.status = $status |
.message = $message |
.end_time = $end_time |
.end_timestamp = $end_timestamp |
.duration_seconds = $duration |
.files_processed = $files |
.total_size_bytes = $size |
.current_operation = "Completed" |
.last_updated = $updated' \
"$METRICS_STATUS_FILE" > "$temp_file" && mv "$temp_file" "$METRICS_STATUS_FILE"
else
# Fallback - append completion info
cat >> "$METRICS_STATUS_FILE" << EOF
# COMPLETION: $final_status
# MESSAGE: $message
# END_TIME: $(date -d "@$end_time" --iso-8601=seconds)
# DURATION: ${duration}s
# FILES: $METRICS_FILE_COUNT
# SIZE: $METRICS_TOTAL_SIZE bytes
EOF
fi
metrics_debug "Backup completed: $final_status ($duration seconds, $METRICS_FILE_COUNT files)"
# Clear global state
METRICS_SERVICE=""
METRICS_START_TIME=""
METRICS_STATUS_FILE=""
METRICS_FILE_COUNT=0
METRICS_TOTAL_SIZE=0
return 0
}
# Legacy compatibility functions (for existing integrations)
metrics_init() {
metrics_backup_start "$1" "${2:-Backup operation}" "${3:-/backup}"
}
metrics_start_backup() {
metrics_update_status "running" "Backup in progress"
}
metrics_add_file() {
metrics_file_backup_complete "$1" "$3" "$2"
}
metrics_complete_backup() {
metrics_backup_complete "$1" "${2:-Backup operation completed}"
}
# Utility function to get current status
metrics_get_status() {
local service_name="$1"
local status_file="$METRICS_ROOT/${service_name}_status.json"
if [ -f "$status_file" ]; then
if command -v jq >/dev/null 2>&1; then
jq -r '.status' "$status_file" 2>/dev/null || echo "unknown"
else
echo "available"
fi
else
echo "never_run"
fi
}
# Utility function to list all services with metrics
metrics_list_services() {
if [ -d "$METRICS_ROOT" ]; then
find "$METRICS_ROOT" -name "*_status.json" -exec basename {} \; | sed 's/_status\.json$//' | sort
fi
}
metrics_debug "Simplified unified backup metrics library loaded"