#!/usr/bin/env bash # Shared Logging Library # Sprint: CI/CD Enhancement - Script Consolidation # # Purpose: Standard logging functions for all CI/CD scripts # Usage: source "$(dirname "${BASH_SOURCE[0]}")/lib/logging.sh" # # Log Levels: DEBUG, INFO, WARN, ERROR # Set LOG_LEVEL environment variable to control verbosity (default: INFO) # Prevent multiple sourcing if [[ -n "${__STELLAOPS_LOGGING_LOADED:-}" ]]; then return 0 fi export __STELLAOPS_LOGGING_LOADED=1 # Colors (disable with NO_COLOR=1) if [[ -z "${NO_COLOR:-}" ]] && [[ -t 1 ]]; then export LOG_COLOR_RED='\033[0;31m' export LOG_COLOR_GREEN='\033[0;32m' export LOG_COLOR_YELLOW='\033[1;33m' export LOG_COLOR_BLUE='\033[0;34m' export LOG_COLOR_MAGENTA='\033[0;35m' export LOG_COLOR_CYAN='\033[0;36m' export LOG_COLOR_GRAY='\033[0;90m' export LOG_COLOR_RESET='\033[0m' else export LOG_COLOR_RED='' export LOG_COLOR_GREEN='' export LOG_COLOR_YELLOW='' export LOG_COLOR_BLUE='' export LOG_COLOR_MAGENTA='' export LOG_COLOR_CYAN='' export LOG_COLOR_GRAY='' export LOG_COLOR_RESET='' fi # Log level configuration export LOG_LEVEL="${LOG_LEVEL:-INFO}" # Convert log level to numeric for comparison _log_level_to_num() { case "$1" in DEBUG) echo 0 ;; INFO) echo 1 ;; WARN) echo 2 ;; ERROR) echo 3 ;; *) echo 1 ;; esac } # Check if message should be logged based on level _should_log() { local msg_level="$1" local current_level="${LOG_LEVEL:-INFO}" local msg_num current_num msg_num=$(_log_level_to_num "$msg_level") current_num=$(_log_level_to_num "$current_level") [[ $msg_num -ge $current_num ]] } # Format timestamp _log_timestamp() { if [[ "${LOG_TIMESTAMPS:-true}" == "true" ]]; then date -u +"%Y-%m-%dT%H:%M:%SZ" fi } # Core logging function _log() { local level="$1" local color="$2" shift 2 if ! _should_log "$level"; then return 0 fi local timestamp timestamp=$(_log_timestamp) local prefix="" if [[ -n "$timestamp" ]]; then prefix="${LOG_COLOR_GRAY}${timestamp}${LOG_COLOR_RESET} " fi echo -e "${prefix}${color}[${level}]${LOG_COLOR_RESET} $*" } # Public logging functions log_debug() { _log "DEBUG" "${LOG_COLOR_GRAY}" "$@" } log_info() { _log "INFO" "${LOG_COLOR_GREEN}" "$@" } log_warn() { _log "WARN" "${LOG_COLOR_YELLOW}" "$@" } log_error() { _log "ERROR" "${LOG_COLOR_RED}" "$@" >&2 } # Step logging (for workflow stages) log_step() { _log "STEP" "${LOG_COLOR_BLUE}" "$@" } # Success message log_success() { _log "OK" "${LOG_COLOR_GREEN}" "$@" } # GitHub Actions annotations log_gh_notice() { if [[ -n "${GITHUB_ACTIONS:-}" ]]; then echo "::notice::$*" else log_info "$@" fi } log_gh_warning() { if [[ -n "${GITHUB_ACTIONS:-}" ]]; then echo "::warning::$*" else log_warn "$@" fi } log_gh_error() { if [[ -n "${GITHUB_ACTIONS:-}" ]]; then echo "::error::$*" else log_error "$@" fi } # Group logging (for GitHub Actions) log_group_start() { local title="$1" if [[ -n "${GITHUB_ACTIONS:-}" ]]; then echo "::group::$title" else log_step "=== $title ===" fi } log_group_end() { if [[ -n "${GITHUB_ACTIONS:-}" ]]; then echo "::endgroup::" fi } # Masked logging (for secrets) log_masked() { local value="$1" if [[ -n "${GITHUB_ACTIONS:-}" ]]; then echo "::add-mask::$value" fi } # Die with error message die() { log_error "$@" exit 1 } # Conditional die die_if() { local condition="$1" shift if eval "$condition"; then die "$@" fi }