Functions and Script ArchitectureLesson 3.4
How to write a Bash logging library
log levels, color output with tput, stderr vs stdout logging, log to file and terminal simultaneously, timestamps in logs, log verbosity flag, disabling color in CI
Every Script Needs Structured Logging
Ad-hoc echo statements don't scale. A small logging library pays for itself on the first production incident.
#!/usr/bin/env bash
# lib/logging.sh
LOG_LEVEL="${LOG_LEVEL:-INFO}" # override via env var
LOG_FILE="${LOG_FILE:-/dev/null}"
# Use tput for colors; fall back gracefully in CI
if [[ -t 2 ]] && tput colors &>/dev/null; then
RED=$(tput setaf 1)
YELLOW=$(tput setaf 3)
GREEN=$(tput setaf 2)
RESET=$(tput sgr0)
else
RED="" YELLOW="" GREEN="" RESET=""
fi
log() {
local level="$1"
shift
local message="$*"
local ts
ts=$(date "+%Y-%m-%d %H:%M:%S")
local color=""
case "$level" in
ERROR) color="$RED" ;;
WARN) color="$YELLOW" ;;
INFO) color="$GREEN" ;;
esac
# Always write plain text to log file
echo "[$ts] [$level] $message" >> "$LOG_FILE"
# Write colored output to stderr
echo -e "${color}[$ts] [$level]${RESET} $message" >&2
}
log_info() { log INFO "$@"; }
log_warn() { log WARN "$@"; }
log_error() { log ERROR "$@"; }Check [[ -t 2 ]] (is stderr a terminal?) before emitting colors. CI systems like GitHub Actions set TERM=dumb or pipe stderr — colors become garbled escape codes in logs.
