Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagebash
#!/bin/bash
# -----------------------------------------------------------------------------------------------------------------------------
# Script: castor-change-log-level.sh
# -----------------------------------------------------------------------------------------------------------------------------
# Description:
# This script changes the log level for the Castor cluster or node(s) using the Swarm API.
# The script supports changing the log level for the entire cluster or individual node(s).
# The script can run in a detachable session using 'screen' or 'tmux'.
# -----------------------------------------------------------------------------------------------------------------------------
# Written by Milton Suen (milton.suen@datacore.com) Oct 31, 2024
# Revision History:
# v1.0.0 - Update to support running the script in a detachable session using screen or tmux.
# v1.1.0 - 2025-02-20 Add support node(s) level log level change.
# v1.2.0 - 2025-02-26 SUPSCR-208:
#        - Enforced proper credential formatting: credentials must be in the username:password format.
#        - Fixed help message shows script name without hard code it.
# v1.2.1 - 2025-02-26 SUPSCR-209: Auto detect CSN or SCS to adjust castor.log file path.
# v1.2.2 - 2025-02-27 Address the issue of the script not display correct when the castor.log file is rotated.
# v1.2.3 - 2025-02-27 Address the issue of log level not display correct within detach session.
# v1.2.4 - 2025-02-27 Bug fix: The default node-level log level is 0 (unset), which differs from the cluster-level default of 30.
# v1.2.5 - 2025-02-28 SUPSCR-208:
#        - Credentials validation and password prompt enhancements.
#        - screen or tmux required with detachable mode, script will stopped with '-D' option if neither is installed.
#        - Fixed an issue where users were prompted to enter password multiple times issue.
#        - Passwords are now hidden in debug output messages.
# v1.2.6 - 2025-02-28 SUPSCR-208:
#        - Disabled credential display on the screen.
#        - Bug fix: Resolved the "debug: command not found" error when removing the -d [IP address] option.
# v1.3.0 - 2025-02-28 minorMinor bug fix and enhancement.
# v1.3.1 - 2025-03-01 SUPSCR-208:
#        - Fixed an issue where credentials enclosed in single quotes (') were not processed correctly.
# v1.3.2 - 2025-03-02 minorMinor bug fix and enhancement.
# v1.3.3 - 2025-03-02 Fixed tmux command to long issue.
# -----------------------------------------------------------------------------------------------------------------------------
# Current Version: 1.3.23
# -----------------------------------------------------------------------------------------------------------------------------
# KB: https://perifery.atlassian.net/wiki/spaces/public/pages/3872161835/Setting+and+Managing+Swarm+Log+Levels+with+script
# -----------------------------------------------------------------------------------------------------------------------------

# Define colors
RED='\033[0;31m'
BOLD_RED='\033[1;31m'
GREEN='\033[0;32m'
BOLD_GREEN='\033[1;32m'
UNDERLINE_BOLD_GREEN='\033[4;32m'
YELLOW='\033[0;33m'
BOLD_YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD_BLUE='\033[1;34m'
MAGENTA='\033[0;35m'
BOLD_MAGENTA='\033[1;35m'
CYAN='\033[0;36m'
BOLD_CYAN='\033[1;36m'
RESET='\033[0m' # Reset color to default

SCRIPT_NAME=$(basename "$0")

# Function to display usage information
usage() {
    echo -e ""
    echo -e "${BOLD_GREEN}Usage:${RESET} ./$SCRIPT_NAME -d swarm_ip -p admin:password [-i new_log_level | -L new_node_log_level] [-t duration_in_seconds] [-D | --detach]"
    echo -e "  -d, --swarm_ip           IP address of the Swarm API endpoint. Supports single or multiple IPs separated by \",\", \";\" or \" \"."
    echo -e "                           If multiple IPs are provided, the script will update the log level for all nodes."
    echo -e "                           (Alternatively, set the SCSP_HOST environment variable to the Swarm IP.)"
    echo -e "  -p, --credentials        Credentials in the format admin:password"
    echo -e "  -i, --log.level          Set cluster log level to set (5, 10, 15, 20, 30, 40, 50)"
    echo -e "                           Aliases: chatter, debug, announce, info, error, critical, default."
    echo -e "  -L, --node.log.level     Set node log level to set (0, 5, 10, 15, 20, 30, 40, 50)"
    echo -e "                           Aliases: chatter, debug, announce, info, error, critical, default."
    echo -e "                           **Either -i or -L must be specified, but not both.**"
    echo -e "  -t, --time               (Optional) Duration in seconds to keep the new log level (must be greater than 0)"
    echo -e "  -D, --detach             (Optional) Detach the script from the current terminal and run in a detachable session using screen or tmux"
    echo -e ""
    exit 1
}

# Default options
detachable=false
debug=false
output_log="castor-change-log-level_output.log"		# Log file for capturing detachable session output
# log_level_type="cluster"							# Default log level type
# default_log_level=30								# Default log level
log_file="/var/log/datacore/castor.log"		        # Default log file location
SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
JQLOCATION=$SCRIPTDIR/jq
MAX_RETRIES=3                                       # Maximum number of password retries attempts
username="admin"                                    # Default username
password=""                                         # Default password

# Global associative array for log levels
declare -A log_levels=(
    [5]="chatter"
    [10]="debug"
    [15]="audit"
    [20]="info"
    [30]="warning"
    [40]="error"
    [45]="defect"
    [50]="critical"
    [60]="announce"
)

# Global associative array for log level names
declare -A log_level_names=(
    ["chatter"]=5
    ["debug"]=10
    ["audit"]=15
    ["info"]=20
    ["warning"]=30
    ["error"]=40
    ["defect"]=45
    ["critical"]=50
    ["announce"]=60
)

# Separate default values for cluster and node levels
declare -A default_log_levels=(
    ["cluster"]=30
    ["node"]=0
)

# Separate default values for cluster and node level names
declare -A default_log_level_names=(
    ["cluster"]="default"
    ["node"]="default"
)

# Function to get the current timestamp
timestamp() {
    date -u +"%Y-%m-%dT%H:%M:%S.%3NZ"
}

# Function to display debug messages if debug mode is enabled
debug_msg() {
    if $debug; then
        local caller_func=${FUNCNAME[1]:-main}                  # Fallback to "unknown" if empty
        local caller_line=${BASH_LINENO[0]:-unknown}            # Fallback to "unknown" if empty
        echo -e "$(timestamp) [DEBUG] ($caller_func:$caller_line) $*"
    fi
}

# Function to check if either 'screen' or 'tmux' is installed
check_screen_or_tmux() {
    if ! command -v screen &>/dev/null && ! command -v tmux &>/dev/null; then
        echo -e ""
        echo -e "---------------------------------------------------------------------------------------"
        echo -e "  ${YELLOW}Warning${RESET}: Neither '${BOLD_GREEN}screen${RESET}' nor '${BOLD_GREEN}tmux${RESET}' is installed. Cannot run in detachable mode."
        echo -e "  Please install either '${BOLD_GREEN}screen${RESET}' or '${BOLD_GREEN}tmux${RESET}' to run the script in a detachable session."
        echo -e "---------------------------------------------------------------------------------------"
        echo -e ""
        detachable=false  # Disable detachable session
        if [[ "$detachable" == false ]]; then
            debug_msg "detachable=${YELLOW}false${RESET}"usage
    fi
}

# Function to format file size
format_size() {
    local size=$1
    if (( debug_msg "Stopping the script..."
size >= 1073741824 )); then
        echo "$(awk "BEGIN exit 1
{printf \"%.1fGB\", $size/1073741824}")"
    elif ((  fi
    fi
}

# Function to format file size
format_size() {
    local size=$1
    if (( size >= 1073741824 )); then
        echo "$(awk "BEGIN {printf \"%.1fGB\", $size/1073741824}")"
    elif (( size >size >= 1048576 )); then
        echo "$(awk "BEGIN {printf \"%.1fMB\", $size/1048576}")"
    elif (( size >= 1024 )); then
        echo "$(awk "BEGIN {printf \"%.1fKB\", $size/1024}")"
    else
        echo "${size}B"
    fi
}

# Function to format duration
format_duration() {
    local duration=$1
    local hours=$((duration / 3600))
    local minutes=$(( (duration % 3600) / 60 ))
    local seconds=$((duration % 60))
    printf "%02d:%02d:%02d" $hours $minutes $seconds
}

# Function to check if jq is available and set up JSON parsing method
check_jq() {
    for jq_path in "/usr/local/bin/jq" "$(pwd)/jq"; do
        [[ -x "$jq_path" ]] && echo "$jq_path" && return
    done
    command -v jq &>/dev/null && echo "jq" || echo "grep"
}

if [[ -f "$JQLOCATION" ]]; then
    jq_or_grep=$JQLOCATION
else
    jq_or_grep=$(check_jq)
fi
debug_msg "jq_or_grep: $jq_or_grep"
#jq_or_grep=$(check_jq)

# Function to determine the log file path
determine_log_file() {
    for log in "/var/log/datacore/castor.log" "/var/log/caringo/castor.log"; do
        if [[ -f "$log" ]]; then
            echo "$log"
            return
        fi
    done
    echo -e "${RED}Error: Log file not found.${RESET}"
    exit 1
}

log_file=$(determine_log_file)

# Function to check if credentials are valid
check_credentials() {
    local CREDENTIALS="$1"
    local SWARM_IP="$2"
    debug_msg "Credentials: [hidden for security]"
    debug_msg "Swarm IP: $SWARM_IP"

    # API endpoint for validating user credentials
    local VALIDATE_URL="http://${SWARM_IP}:91/api/validateUser"
    debug_msg "Validate URL: $VALIDATE_URL"

    # Make the API request
    debug_msg "Validating user credentials..."
    debug_msg "curl -s -u \"********\" -X GET \"$VALIDATE_URL\" -H 'Content-Type: application/json'"
    RESPONSE=$(curl -s -u "$CREDENTIALS" -X GET "$VALIDATE_URL" -H 'Content-Type: application/json')
    debug_msg "Validate User Response: $RESPONSE"

    # Check if the response contains "isValid": true
    if echo "$RESPONSE" | "$jq_or_grep" -e '.isValid == true' > /dev/null 2>&1; then
        debug_msg "Authentication successful for user '${CREDENTIALS%%:*}'"
        return 0  # Success
    elif echo "$RESPONSE" | "$jq_or_grep" -e '.isValid == false' > /dev/null 2>&1; then
        debug_msg "Authentication failed for user '${CREDENTIALS%%:*}'"
        return 1  # Failure
    else
        debug_msg "Error: Unable to validate credentials. Please check your inputs."
        return 1  # Failure
    fi
}

# Function to print credentials - hide password
print_credentials() {
    local CREDENTIALS="$1"
    local USERNAME="${CREDENTIALS%%:*}"
    echo -e "${GREEN}$USERNAME${RESET}":"${GREEN}********${RESET}"
}

# Parse input arguments
while [[ "$#" -gt 0 ]]; do
    case $1 in
        -d|--swarm_ip) swarm_ip="$2"; debug_msg "Set swarm_ip to $swarm_ip"; shift 2 ;;
        -p|--credentials)
            credentials="$2"
            shift 2 ;;
        -i|--log.level)
            if [[ -n "$new_log_level" ]]; then
                echo "Error: Options -i (cluster log leve) and -L (node log level) cannot be used together."
                usage
            fi
            log_level_type="cluster"
            if [[ ${log_level_names[$2]} ]]; then
                new_log_level=${log_level_names[$2]}
            elif [[ "$2" == "default" ]]; then
                new_log_level=${default_log_levels[$log_level_type]}
                new_log_level_name="default"
            elif [[ ${log_levels[$2]} ]]; then
                new_log_level=$2
            else
                echo "Invalid log level: $2"
                exit 1
            fi
            new_log_level_name=${log_levels[$new_log_level]}
            default_log_level=30
            debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)"
            shift 2
            ;;
        -L|--node.log.level)
            if [[ -n "$new_log_level" ]]; then
                echo "Error: Options -i (cluster log leve) and -L (node log level) cannot be used together."
                usage
            fi
            log_level_type="node"
            if [[ ${log_level_names[$2]} ]]; then
                new_log_level=${log_level_names[$2]}
            elif [[ "$2" == "default" ]]; then
                new_log_level=${default_log_levels[$log_level_type]}
                new_log_level_name="default"
            elif [[ ${log_levels[$2]} || $2 -eq 0 ]]; then
                new_log_level=$2
                new_log_level_name="default"
            else
                echo "Invalid log level: $2"
                exit 1
            fi
            new_log_level_name=${log_levels[$new_log_level]}
            default_log_level=0
            debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)"
            shift 2
            ;;
        -t|--time)
            if [[ -n "$2" && "$2" != -* && "$2" -gt 0 ]]; then
                duration="$2"
                debug_msg "Set duration to $duration"
                shift 2
            else
                echo -e "Error: Duration must be a number greater than 0."
                exitecho 1
      -e "---------------------------------------------------------------------------------------"
     fi           echo -e ;;"    ${RED}Error${RESET}: Duration must be a  -D|--detach) detachable=true; debug_msg "Set detachable to true"; shift ;;number greater than ${BOLD_GREEN}0${RESET}."
             --debug) debug=true; debug_msg "Set debug to true with ${YELLOW}--debug${RESET}"; shift ;;
        *) usage ;;
    esac
done

debug_msg "Set log_level_type to ${YELLOW}$log_level_type${RESET}"

# Check if 'screen' or 'tmux' is installed
if [[ "$detachable" == true ]]; then
    check_screen_or_tmux
fi

# If swarm_ip is not provided, try using SCSP_HOST environment variable
if [[ -z "$swarm_ip" ]]; then
    if [[ -n "$SCSP_HOST" ]]; thenecho -e "    Please specify the duration using the ${BOLD_GREEN}-t${RESET} ${GREEN}<seconds>${RESET} or ${BOLD_GREEN}--time${RESET} ${GREEN}<seconds>${RESET} option."
                echo -e "---------------------------------------------------------------------------------------"
                usage
            fi
 swarm_ip="$SCSP_HOST"         debug_msg "Using Swarm;;
IP from SCSP_HOST: $swarm_ip"     else
     -D|--detach) detachable=true; debug_msg "Set detachable to true"; shift ;;
  echo "Error: swarm_ip not provided and SCSP_HOST is not set."
        usage --debug) debug=true; debug_msg "Set debug to true with ${YELLOW}--debug${RESET}"; shift ;;
      fi fi *) #usage Check;;
if required arguments are providedesac
ifdone
[[ -z
debug_msg "$credentials" || -z "$new_log_level" ]]; then
    usage
fi

# Split the swarm_ip into an array of IP addresses if it contains delimiters
IFS=';, ' read -r -a ip_array <<< "$swarm_ip"

# Validate credentials before proceeding
debug_msg "Validating credentials..."
#if [[ "$credentials" =~ ^[^:]+$Set log_level_type to ${YELLOW}$log_level_type${RESET}"

# Check if 'screen' or 'tmux' is installed
if [[ "$detachable" == true ]]; then
    if [[ -nz "$credentials$duration" ]]; then
    CREDENTIALS="$credentials"     ATTEMPT=$MAX_RETRIES
    USERNAME=echo -e ""
    PASSWORD=""    echo debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS")"-e "---------------------------------------------------------------------------------------"
        debug_msg "ATTEMPT: $ATTEMPTecho -e "    ${RED}Error${RESET}: Duration #must Checkbe ifspecified credentialswhen containrunning ain colon (username:password format)detachable mode."
     debug_msg "Checking for colonecho in credentials...-e "    Please ifspecify [[ "$CREDENTIALS" == *":"* ]]; then
the duration using the ${BOLD_GREEN}-t${RESET} or ${BOLD_GREEN}--time${RESET} option."
       debug_msg "Credentialsecho contain colon"-e "---------------------------------------------------------------------------------------"
         USERNAME="${CREDENTIALS%%:*}"usage
    fi
    PASSWORD="${CREDENTIALS#*:}"

        # Validate credentials
        check_credentials "$CREDENTIALS" "${ip_array[0]}"
check_screen_or_tmux
fi

# If swarm_ip is not provided, try using SCSP_HOST environment variable
if [[ -z "$swarm_ip" ]]; then
       if [[ $? -ne 0n "$SCSP_HOST" ]]; then
        swarm_ip="$SCSP_HOST"
        debug_msg "Using Swarm IP "Invalid credentials. Please check your username and password."from SCSP_HOST: $swarm_ip"
    else
        echo "Error: swarm_ip not provided and SCSP_HOST echois -enot set.""
        usage
   echo -e "${RED}Error${RESET}: Invalid credentials. Please check your username and password."
            echo -e ""
            exit 1
        fi
        debug_msg "Validate credentials"
        credentials=$CREDENTIALS
    else
        debug_msg "Credentials do not contain password"
        debug_msg "Usernamefi
fi

# Check if required arguments are provided
if [[ -z "$credentials" || -z "$new_log_level" ]]; then
    usage
fi

# Split the swarm_ip into an array of IP addresses if it contains delimiters
IFS=';, ' read -r -a ip_array <<< "$swarm_ip"

# Validate credentials before proceeding
debug_msg "Validating credentials..."
#if [[ "$credentials" =~ ^[^:]+$ ]]; then
if [[ -n "$credentials" ]]; then
    CREDENTIALS="$credentials"
    ATTEMPT=$MAX_RETRIES
    USERNAME=""
    PASSWORD=""
    debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS")"
    debug_msg "ATTEMPT: $ATTEMPT"

    # Check USERNAME="$CREDENTIALS"if credentials contain a colon (username:password format)
  # Prompt for password
   debug_msg "Checking for colon in credentials..."
    whileif [[ $ATTEMPTS -lt $MAX_RETRIES"$CREDENTIALS" == *":"* ]]; dothen
        debug_msg "Credentials contain colon"
 echo ""      USERNAME="${CREDENTIALS%%:*}"
      read -sp "Enter password for user $USERNAME: " PASSWORD
    PASSWORD="${CREDENTIALS#*:}"

        # Validate credentials
        echocheck_credentials "$CREDENTIALS" "${ip_array[0]}"
        if [[ $? echo-ne ""0 ]]; then
          if [[ -z "$PASSWORD" ]]; then
    debug_msg "Invalid credentials. Please check your username and password."
            echo -e ""
            echo -e "${RED}Error${RESET}: Password cannot be empty Invalid credentials. Please check your username and password."
            echo -e ""
 ((ATTEMPTS++))           exit 1
    continue    fi
        fidebug_msg "Validate credentials"
        credentials=$CREDENTIALS
 CREDENTIALS="$USERNAME:$PASSWORD"   else
         debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
 Credentials do not contain password"
        debug_msg  check"Username: $(print_credentials "$CREDENTIALS" "${ip_array[0]}")"
        USERNAME="$CREDENTIALS"
   if [[ $? -eq 0 ]];# thenPrompt for password
        while [[ $ATTEMPTS -lt   debug$MAX_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"RETRIES ]]; do
                 debug_msgecho "Valid credentials"
            read -sp "Enter password credentials=$CREDENTIALSfor user $USERNAME: " PASSWORD
            breakecho ""
           else echo ""
            if [[ echo -ez "$PASSWORD" ]]; then
                echo -e "${RED}Error${RESET}: InvalidPassword credentials.cannot Please check your username and password."
   be empty."
        fi             ((ATTEMPTS++))
        done         if [[continue
$ATTEMPTS -ge $MAX_RETRIES ]]; then        fi
    echo -e ""             echo -e "${RED}Error${RESET}: Maximum number of password attempts reached. Exiting script.CREDENTIALS="$USERNAME:$PASSWORD"
            exit 1
   debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
    fi     fi else     if ! check_credentials "$credentials$CREDENTIALS" "${ip_array[0]}";
   then         echoif -e ""
   [[ $? -eq 0 ]]; then
    echo -e "${YELLOW}Warning${RESET}: ${RED}Invalid credentials${RESET}."         echo -e "debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
        exit 1     fi fi debug_msg #"Valid Retrievecredentials"
cluster name     and handle JSON parsing using the first IP address debug_msg "Retrieving the cluster name from Swarm API using IP: ${ip_array[0]}"
if [[ "$jq_or_grep" == "grep" ]]; then
    clusterName=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | grep -oP '"name":\s*"\K[^"]+')
else
    clusterName=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | "$jq_or_grep" -r '._embedded.clusters[0].name')
fi

if [[ -z "$clusterName" ]]; then
    echo "Failed to retrieve the cluster name. Please check your inputs."
    exit 1
fi
debug_msg "Cluster Name: $clusterName"

# Main logic function to run the script tasks
main_script() {
    local swarm_ip="$1"
    local credentials="$2"
    local new_log_level="$3"
    local new_log_level_name="$4"
    local duration="$5"
    local log_level_type="$6"
    #local log_file="/var/log/datacore/castor.log"
    if [[ -z "$log_file" ]]; then
        log_file=$(determine_log_file)
    fi
    local initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
    local current_log_level
    local clusterName="$7"
    local jq_or_grep="$8"
    local detachable="$9"
    if [[ "$detachable" ]]; then
        local debug="${10} credentials=$CREDENTIALS
                break
            else
                echo -e ""
                echo -e "${RED}Error${RESET}: Invalid credentials. Please check your username and password."
            fi
            ((ATTEMPTS++))
        done
        if [[ $ATTEMPTS -ge $MAX_RETRIES ]]; then
            echo -e ""
            echo -e "${RED}Error${RESET}: Maximum number of password attempts reached. Exiting script."
            exit 1
        fi
    fi
else
    if ! check_credentials "$credentials" "${ip_array[0]}"; then
        echo -e ""
        echo -e "${YELLOW}Warning${RESET}: ${RED}Invalid credentials${RESET}."
        eval "$(echoecho -e "${11}"
| sed 's/declare -A/declare -A/')"    exit 1
   eval "$(echo "${12}" | sed 's/declare -A/declare -A/')"
    fi
    local default_log_levels="$13"
    local default_log_levels_name="$14"
    debug_msg "**********************************************************"
    debug_msg "local variables"
    debug_msg "Log Level Type: ${GREEN}$log_level_type${RESET}"
    debug_msg "Default Log Level: ${GREEN}$default_log_level${RESET}"
    debug_msg "Swarm IP: $swarm_ip"
    debug_msg "Credentials: $(print_credentials "$credentials")"
    debug_msg "New Log Level: $new_log_level"
    debug_msg "New log Level Name: $new_log_level_name"
    debug_msg "Duration: $duration"
    debug_msg "Log File: $log_file"
    debug_msg "Initial Log File Size: $initial_size"
    debug_msg "Current Log Level: $current_log_level"
    debug_msg "Cluster Name: $clusterName"
    debug_msg "jq_or_grep: $jq_or_grep"
    debug_msg "Detach: $detachable"
    debug_msg "Debug: $debug"
    debug_msg "**********************************************************"

    # Split the swarm_ip into an array of IP addresses
    IFS=';, ' read -r -a ip_array <<< "$swarm_ip"
    debug_msg "IP Array: ${ip_array[*]}"

    # Display initial informationfi
fi

# Retrieve cluster name and handle JSON parsing using the first IP address
debug_msg "Retrieving the cluster name from Swarm API using IP: ${ip_array[0]}"
if [[ "$jq_or_grep" == "grep" ]]; then
    clusterName=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | grep -oP '"name":\s*"\K[^"]+')
else
    clusterName=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | "$jq_or_grep" -r '._embedded.clusters[0].name')
fi

if [[ -z "$clusterName" ]]; then
    echo "Failed to retrieve the cluster name. Please check your inputs."
    exit 1
fi
debug_msg "Cluster Name: $clusterName"

# Main logic function to run the script tasks
main_script() {
    local swarm_ip="$1"
    local credentials="$2"
    local new_log_level="$3"
    local new_log_level_name="$4"
    local duration="$5"
    local log_level_type="$6"
    #local log_file="/var/log/datacore/castor.log"
    if [[ -z "$log_file" ]]; then
        log_file=$(determine_log_file)
    fi
    local initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
    local current_log_level
    local clusterName="$7"
    local jq_or_grep="$8"
    local detachable="$9"
    if [[ "$log_level_type$detachable" == "cluster" ]]; then
        echo -e "Swarm IP: ${GREEN}${ip_array[0]}${RESETlocal debug="${10}"
    else    eval "$(echo "${11}" | sed echo's/declare -e "Swarm IPs: ${GREEN}${ip_array[*]}${RESET}"A/declare -A/')"
        fi
    # echo -e "Swarm IP: ${GREEN}$swarm_ip${RESETeval "$(echo "${12}" | sed 's/declare  debug_msg "Credentials: ${GREEN}[hidden for security]${RESET}"
-A/declare -A/')"
    fi
   echo -e "Cluster Name: ${GREEN}$clusterName${RESET}local default_log_levels="$13"
    local debug_msg "Starting main_script function...default_log_levels_name="$14"
    debug_msg "Log level type: $log_level_type"

    # Store the original log levels
    declare -A original_log_levels
    declare -A original_log_level_names

    default_log_level=${default_log_levels[$log_level_type]}
    default_log_level_name=${default_log_level_names[$log_level_type]}**********************************************************"
    debug_msg "local variables"
    debug_msg "Log Level Type: ${GREEN}$log_level_type${RESET}"
    debug_msg "Default Log Level: ${GREEN}$default_log_level${RESET}"
    debug_msg "DefaultSwarm log levelIP: $default$swarm_log_levelip"
    debug_msg "Default log level nameCredentials: $default_log_level_name$(print_credentials "$credentials")"
    debug_msg "New ifLog [[ $log_level_type == "cluster" ]]; thenLevel: $new_log_level"
        debug_msg "SettingNew cluster log level to $new_log_level (Level Name: $new_log_level_name)"
    debug_msg "Duration: $duration"
  # Retrieve current log level
debug_msg "Log File: $log_file"
    debug_msg "Initial Log ifFile [[ "$jq_or_grep" == "grep" ]]; then
    Size: $initial_size"
    debug_msg "Current Log Level: $current_log_level"
       current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | grep -oP '"value":\s*\K[0-9]+')
debug_msg "Cluster Name: $clusterName"
    debug_msg "jq_or_grep: $jq_or_grep"
    debug_msg "Detach: $detachable"
else    debug_msg "Debug: $debug"
      current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | "$jq_or_grep" -r '.value')
        fi
        current_log_level_name=${log_levels[$current_log_level]}debug_msg "**********************************************************"

    # Split the swarm_ip into an array of IP addresses
    IFS=';, ' read -r -a ip_array <<< "$swarm_ip"
    debug_msg "IP Array: ${ip_array[*]}"

    # Display initial ifinformation
[[ $current_log_level    if [[ "$log_level_type" == 30"cluster" ]]; then
        echo -e "Swarm  current_log_level_name="default"IP: ${GREEN}${ip_array[0]}${RESET}"
    else
   fi     echo -e "Swarm  if [[ $new_log_level == 30 ]]; then
            new_log_level_name="default"
 IPs: ${GREEN}${ip_array[*]}${RESET}"
      fi
    # echo -e  debug_msg "Current cluster log levelSwarm IP: ${BOLD_GREEN}$current$swarm_log_level$ip${RESET}"
        debug_msg "Current log level nameCredentials: ${BOLD_GREEN}$current_log_level_name$GREEN}[hidden for security]${RESET}"

       echo -e ""
        echo -e "New cluster log levelCluster Name: ${BOLD_GREEN}$new_log_level_name$$clusterName${RESET} (${BOLD_GREEN}$new_log_level${RESET})""

    debug_msg "Starting main_script function..."
 echo -e "Current cluster logdebug_msg "Log level is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET}).type: $log_level_type"

    # Store the original #log Skiplevels
update if new level matches the current level   declare -A original_log_levels
    declare -A original_log_level_names

    default_log_level=${default_log_levels[$log_level_type]}
  if [[ "$current default_log_level_name=${default_log_level_names[$log_level_type]}
    debug_msg " -eq "$newDefault log level: $default_log_level"
 ]]; then  debug_msg "Default log level name: $default_log_level_name"

    echoif ""
    [[ $log_level_type == "cluster" ]]; then
       echo -edebug_msg "ClusterSetting cluster log level is already set to ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). No changes made."_level_name)"
        # Retrieve current log level
    return    if [[ "$jq_or_grep" ==  fi
"grep" ]]; then
        # Update the cluster current_log _level using PUT
        debug_msg "Updating cluster log level to $new_log_level_name"=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | grep -oP '"value":\s*\K[0-9]+')
        else
        debug_msg "Cluster Name: $clusterName"
        debug_msg "Credentials: $(print_credentials "$credentials")"
        debug_msg " current_log_level=$(curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -H \"Content-Type: application/json\" \"http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level\" -d| \"{\\\"value\\\": $new_log_level}\""
 "$jq_or_grep" -r '.value')
      response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
    fi
        current_log_level_name=${log_levels[$current_log_level]}
         "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
 if [[ $current_log_level == 30 ]]; then
          -d "{\"value\": $new current_log_level}_name="default")
        debug_msg "Response: $response"fi
           if [[ "$jq$new_orlog_grep"level == "grep"30 ]]; then
            updatednew_log_level_name=$(echo "$responsedefault" | grep
-oP '"value":\s*\K[0-9]+')       fi
 else       debug_msg "Current cluster log   updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
        filevel: ${BOLD_GREEN}$current_log_level${RESET}"
           debug_msg "UpdatedCurrent cluster log level name: $updated${BOLD_GREEN}$current_log_level_name${RESET}"
         if [[ "$updated_log_level"echo -eqe "$new_log_level" ]]; then
 
          echo -e "${GREEN}$(timestamp)${RESET} Log level changed successfully from New cluster log level: ${BOLD_GREEN}$current$new_log_level_name${RESET} (${BOLD_GREEN}$current$new_log_level${RESET})"
       -> echo -e "Current cluster log level is ${BOLD_GREEN}$new$current_log_level_name${RESET} (${BOLD_GREEN}$new$current_log_level${RESET})."

       else # Skip update if new level matches the current level
  echo   -e "${GREEN}$(timestamp)${RESET} Failed toif update[[ "$current_log _level." Response: ${RED}$response${RESET}"
 -eq "$new_log_level" ]]; then
          exit  1echo ""
       fi     echo -e "Cluster log level #is Countdownalready andset revert log level
   to ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). No changes made."
    if [[ -n "$duration" && "$duration" -gt 0 ]];return
then        fi

   echo -e "Keeping log level at ${YELLOW}$new_log_level_name${RESET} (${YELLOW}$new_log_level${RESET}) for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."# Update the cluster log level using PUT
        debug_msg "Updating cluster log level echo -e ""to $new_log_level_name"
        debug_msg "Cluster Name: $clusterName"
for ((i=duration; i>0; i--)); do    debug_msg "Credentials: $(print_credentials "$credentials")"
        debug_msg printf"curl --vuser countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))
  \"$(print_credentials "$credentials")\" -sS -X PUT -H \"Content-Type: application/json\" \"http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level\" -d \"{\\\"value\\\": $new_log_level}\""
        response=$(curl --user "$credentials" -sS -X echoPUT -neH "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"Content-Type: application/json" \
                sleep 1
            done"http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
            echo -ed "{\n\nTime's up! Reverting log level back to ${GREEN}$current"value\": $new_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET}) ..."}")
        debug_msg "Response: $response"

  # Revert the log level back to theif original value
   [[ "$jq_or_grep" == "grep" ]]; then
        # echo -e "Level log revert on $(timestamp)"
            response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
        else
            updated_log_level=$(echo "$response" | "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \$jq_or_grep" -r '.value')
        fi
        -d "{\"value\": $currentdebug_msg "Updated cluster log level: $updated_log_level}")

        if [[  debug_msg "Response: $response"
"$updated_log_level" -eq "$new_log_level" ]]; then
            ifecho [[ "$jq_or_grep" == "grep" ]]; then-e "${GREEN}$(timestamp)${RESET} Log level changed successfully from ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET}) -> ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})."
        else
         reverted_log_level=$(echo "$response" | grepecho -oPe '"value":\s*\K[0-9]+')
      "${GREEN}$(timestamp)${RESET} Failed to update log level. Response: ${RED}$response${RESET}"
     else       exit 1
        reverted_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')fi

        # Countdown and revert log level
  fi      if [[ -n "$duration"    debug_msg "Reverted cluster log level: $reverted_log_level"&& "$duration" -gt 0 ]]; then
             final_size=$(statecho -c%se "$log_file" 2>/dev/null || echo 0)
            debug_msg "Initial log file size: $initial_size"Keeping log level at ${YELLOW}$new_log_level_name${RESET} (${YELLOW}$new_log_level${RESET}) for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."
            echo    debug_msg "Final log file size: $final_size"-e ""
                size_diff=$for (( final_size - initial_size ))
 i=duration; i>0; i--)); do
          size_diff_formatted=$(format_size "$size_diff")     printf -v countdown      duration_formatted=$(format_duration "$duration")
	    if (( size_diff < 0 )); then
		echo -e "castor.log file was rotated."
	    else
  "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))
                echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"
                sleep 1
         echo  -e ""done
            echo -e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new\n\nTime's up! Reverting log level back to ${GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$new$current_log_level${RESET}) ..."
Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})."
            # Revert the log level back to the original value
            # echo -e ""Level log 	revert on $(timestamp)"
 fi         if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then
     response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
       echo -e "${GREEN}$(timestamp)${RESET} Log level reverted successfully back to "http://${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."
ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
           echo -e ""   -d "{\"value\": $current_log_level}")
   else             echo -e "${GREEN}$(timestamp)${RESET} Failed to revert log level. Response: ${RED}$response${RESET}"debug_msg "Response: $response"

            echoif -e[[ "$jq_or_grep" == "grep" ]]; then
        exit 1       reverted_log_level=$(echo "$response" fi| grep -oP '"value":\s*\K[0-9]+')
            else
            echo -e "${GREEN}$(timestamp)${RESET} Log reverted_log_level change is permanent until manually modified."=$(echo "$response" | "$jq_or_grep" -r '.value')
        fi    fi
elif [[ "$log_level_type" == "node" ]]; then       debug_msg "Reverted #cluster Firstlog looplevel: Change the node log level$reverted_log_level"

           local samefinal_log_level=false
    size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
   for ip in "${ip_array[@]}"; do       debug_msg "Initial log file size: $initial_size"
    # Retrieve current node log level   debug_msg "Final log file size: $final_size"
    debug_msg "Retrieving current node log level for IP: $ip"
    size_diff=$(( final_size - initial_size ))
        debug_msg "curl -s -u \" size_diff_formatted=$(printformat_credentialssize "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\""$size_diff")
            currentduration_log_levelformatted=$(curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value')
            debug_msg "Current log level for IP $ip: $current_log_level"format_duration "$duration")
	    if (( size_diff < 0 )); then
		echo -e "castor.log file was rotated."
	    else
            echo  original_log_levels["$ip"]=$current_log_level-e ""
            echo debug_msg "Original log level for IP $ip:-e "Approximate ${original_log_levels["$ip"]}"
            if [[ "$current_log_level" == "0" ]]; then
                current_log_level_name="default"BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})."
            echo else-e ""
	    fi
        if [[ current"$reverted_log_level_name=${log_levels[" -eq "$current_log_level" ]}]; then
           fi echo -e "${GREEN}$(timestamp)${RESET} Log level reverted successfully back     originalto ${BOLD_GREEN}$current_log_level_names["$ip"]=_name${RESET} (${BOLD_GREEN}$current_log_level_namelevel${RESET})."
            debug_msg "Original log level name: ${original_log_level_names["$ip"]}"echo -e ""
        else
   if [[ "$new_log_level" == "0" ]]; then   echo -e "${GREEN}$(timestamp)${RESET} Failed to revert log level. Response: ${RED}$response${RESET}"
    new_log_level_name="default"        echo -e ""
  else          exit 1
     new_log_level_name=${log_levels[$new_log_level]}   fi
        else
fi            echo debug_msg "Current log-e "${GREEN}$(timestamp)${RESET} Log level forchange is IPpermanent $ip: $current_log_level ($current_log_level_name)"until manually modified."
        fi
     echoelif [[ "$log_level_type" == "node" ]]; then
        # First echoloop: -eChange "Newthe node log level: ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})"
        local same_log_level=false
  echo -e "Current node log level for IP ${BOLD_GREEN}$ip${RESET} is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."
ip in "${ip_array[@]}"; do
            # SkipRetrieve updatecurrent ifnode newlog level matches
the current level          debug_msg "Retrieving current if [[ "$current_log_level" -eq "$new_log_level" ]]; then
node log level for IP: $ip"
               same_log_level=true
         debug_msg "curl -s -u \"$(print_credentials "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\""
            current_log_level=$(curl -s echo-u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value')
           echo -edebug_msg "NodeCurrent log level for IP ${BOLD_GREEN}$ip${RESET} is already set to ${BOLD_GREEN}$new$ip: $current_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). No changes made."
             original_log_levels["$ip"]=$current_log_level
  continue          debug_msg "Original log elselevel for IP               same_log_level=false
       $ip: ${original_log_levels["$ip"]}"
    fi              if [[ "$same$current_log_level" == false"0" ]]; then
                # Update the node log level using PUTcurrent_log_level_name="default"
            else
          debug_msg "Updating node log level to $newcurrent_log_level_name for IP $ip..."=${log_levels[$current_log_level]}
            fi
      debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level\"" original_log_level_names["$ip"]=$current_log_level_name
            debug_msg "Original log level name: ${original_log_level_names["$ip"]}"
            if [[   response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \"$new_log_level" == "0" ]]; then
                new_log_level_name="default"
           "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level") else
                debug_msg "Response: $response"new_log_level_name=${log_levels[$new_log_level]}
            fi
      if [[ "$jq_or_grep" == "grep" ]]; then
        debug_msg "Current log level for IP $ip: $current_log_level ($current_log_level_name)"
            updated_log_level=$(echo "$response" | grep
-oP '"value":\s*\K[0-9]+')           echo -e "New node log  else
                    updatedlevel: ${BOLD_GREEN}$new_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})"
            echo -e "Current node log level fifor IP ${BOLD_GREEN}$ip${RESET} is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."

          debug_msg "Updated log# levelSkip forupdate IPif $ip: $updated_log_level"

  new level matches the current level
             if [[ "$updated$current_log_level" -eq "$new_log_level" ]]; then
                 same_log_level=true
                echo ""
                echo -e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} changedis successfullyalready from ${BOLD_GREEN}$current_log_level_name${RESET} (${GREEN}$current_log_level${RESET}) ->set to ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). No changes made."
                elsecontinue
            else
         echo -e "${GREEN}$(timestamp)${RESET} Failed to update node same_log_level=false
 level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"      fi

            if exit 1
   [[ "$same_log_level" == false ]]; then
            fi    # Update the node log level using   fiPUT
        done        debug_msg "Updating #node Secondlog loop:level Countdown if duration is provided
        if [[ "$sameto $new_log_level_name for IP $ip..."
== false ]]; then\             if [[debug_msg "curl -n-user "$duration" && "$duration\"$(print_credentials "$credentials")\" -gtsS 0 ]]; then
    -X PUT -H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level\""
           echo -e     response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
             echo -e "Keeping node(s) log level at ${YELLOW}$new_log_level_name${RESET} (${YELLOW}$new_log_level${RESET}) for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..." "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level")
                debug_msg    "Response: $response"

  echo -e ""            if [[    for ((i=duration; i>0; i--)); do"$jq_or_grep" == "grep" ]]; then
                    printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
                else
    echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"              updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
 sleep 1              fi
  done              debug_msg "Updated log echolevel -e "\n\nTime's up! Reverting node log level back to original levels..."for IP $ip: $updated_log_level"

                if [[ "$updated_log_level"  # Third loop: Revert the node log level-eq "$new_log_level" ]]; then
                    echo for ip in "${ip_array[@]}"; do
                    current_log_level=${original_log_levels["$ip"]}-e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} changed successfully from ${BOLD_GREEN}$current_log_level_name${RESET} (${GREEN}$current_log_level${RESET}) -> ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})."
                else
   current_log_level_name=${original_log_level_names["$ip"]}                 echo -e "${GREEN}$(timestamp)${RESET} Failed debug_msg "Revertingto update node log level backfor toIP $current_log_level_name for IP $ip...${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"
                    debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\""exit 1
                fi
            fi
  # echo -e "Node level log revertdone
on
$(timestamp) for IP $ip"     # Second loop: Countdown if duration is provided
        response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" if [[ "$same_log_level" == false ]]; then\
            if [[ -n "$duration"         "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level")
  && "$duration" -gt 0 ]]; then
                echo debug_msg-e "Response: $response"
                echo -e "Keeping node(s) log iflevel [[ "$jq_or_grep" == "grep" ]]; then
  at ${YELLOW}$new_log_level_name${RESET} (${YELLOW}$new_log_level${RESET}) for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."
                echo -e ""
  reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')         for ((i=duration; i>0; i--)); do
       else             printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60    reverted_log_level=$(echo "$response" | "$jq_or_grep" -r '.value'))) $((i%60))
                    echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"
 fi                   sleep 1
 final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)              done
               size_diff=$(( final_size - initial_size ))
       echo -e "\n\nTime's up! Reverting node log level back to original levels..."

            debug_msg "Initial log file size: $initial_size"
     # Third loop: Revert the node log level
              debug_msg "Final logfor fileip size: $final_size"
in "${ip_array[@]}"; do
                   size current_difflog_formattedlevel=$(format_size "$size_diff"){original_log_levels["$ip"]}
                    duration_formatted=$(format_duration "$duration")
current_log_level_name=${original_log_level_names["$ip"]}
                    if [[ "$reverted_log_level" -eq " debug_msg "Reverting node log level back to $current_log_level_name for IP $ip..."
 ]]; then                  debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X echoPUT -eH "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} reverted successfully back to ${BOLD_GREEN}${current_log_level_name}${RESET} (${BOLD_GREEN}$current_log_level${RESET})."\"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\""
                            else
                       # echo -e "${GREEN}$(timestamp)${RESET} Failed toNode level log revert node log level on $(timestamp) for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}$ip"
                    response=$(curl --user "$credentials" -sS exit-X 1PUT -H "Content-Type: application/json" \
                fi            "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level")
    done                debug_msg "Response: #$response"
Combine
the log output for multiple IP addresses into a single summary             if (( size_diff < 0 ))[[ "$jq_or_grep" == "grep" ]]; then
            echo  -e "castor.log file was rotated."      reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
 else                   else
 echo -e ""                     reverted_log_level=$(echo -e"$response" | "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}) for IP ${ip_array[*]}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})."$jq_or_grep" -r '.value')
                    fi

                    echofinal_size=$(stat -ec%s "$log_file" 2>/dev/null || echo 0)
        fi             else
   size_diff=$(( final_size - initial_size ))
            echo    -e "${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified."debug_msg "Initial log file size: $initial_size"
              fi      debug_msg "Final log fifile size: $final_size"
  fi }  # Run in detachable or directly if $detachable; then     # Pass the main_script function to the screen session and store the output in a file size_diff_formatted=$(format_size "$size_diff")
                    debug_msg "**********************************************************" | tee -a "$output_log"duration_formatted=$(format_duration "$duration")

               debug_msg "Detach mode - Parameters passedif to main_script:" | tee -a "$output_log"
    debug_msg "[[ "$reverted_log_level" -eq "$current_log_level" ]]; then
        Swarm IP: $swarm_ip" | tee -a "$output_log"     debug_msg "    echo Credentials:-e "$(print_credentials "$credentials")"  | tee -a "$output_log"
    debug_msg "{GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} reverted successfully back to ${BOLD_GREEN}${current_log_level_name}${RESET} (${BOLD_GREEN}$current_log_level${RESET})."
     New Log Level: $new_log_level" | tee -a "$output_log"     debug_msg "  else
  New log Level Name: $new_log_level_name" | tee -a "$output_log"     debug_msg "     Duration: $duration" | teeecho -a "$output_log"
    debug_msg "     Log Level Type: $log_level_type" | tee -a "$output_log"e "${GREEN}$(timestamp)${RESET} Failed to revert node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"
          debug_msg "     Log File: $log_file" | tee -a "$output_log"  exit 1
 debug_msg "     Initial Log File Size: $initial_size" | tee -a "$output_log"     debug_msgfi
"     Current Log Level: $current_log_level" | tee -a "$output_log"    done
debug_msg
"     Cluster Name: $clusterName" | tee -a "$output_log"     debug_msg# "Combine the log output  jq_or_grep: $jq_or_grep" | tee -a "$output_log"
    debug_msg "for multiple IP addresses into a single summary
            if (( size_diff < 0 )); then
         Detach: $detachable" | teeecho -ae "$output_log"castor.log file was rotated."
            else
         debug_msg   "     Debug: $debug" | teeecho -ae "$output_log"
    debug_msg "**********************************************************" | tee -a "$output_log"

    # Convert associative arrays to strings and pass them to the screen session
    log_levels_string=$(declare -p log_levels)
    log_level_names_string=$(declare -p log_level_names)
    debug_msg "log_levels_string: $log_levels_string" | tee -a "$output_log"
    debug_msg "log_level_names_string: $log_level_names_string" | tee -a "$output_log"

    if command -v screen"
                    echo -e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}) for IP ${ip_array[*]}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})."
                    echo -e ""
            fi
            else
                echo -e "${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified."
            fi
        fi
    fi
}

# Run in detachable or directly
if $detachable; then
    # Pass the main_script function to the screen session and store the output in a file
    debug_msg "**********************************************************" | tee -a "$output_log"
    debug_msg "Detach mode - Parameters passed to main_script:" | tee -a "$output_log"
    debug_msg "     Swarm IP: $swarm_ip" | tee -a "$output_log"
    debug_msg "     Credentials: $(print_credentials "$credentials")"  | tee -a "$output_log"
    debug_msg "     New Log Level: $new_log_level" | tee -a "$output_log"
    debug_msg "     New log Level Name: $new_log_level_name" | tee -a "$output_log"
    debug_msg "     Duration: $duration" | tee -a "$output_log"
    debug_msg "     Log Level Type: $log_level_type" | tee -a "$output_log"
    debug_msg "     Log File: $log_file" | tee -a "$output_log"
    debug_msg "     Initial Log File Size: $initial_size" | tee -a "$output_log"
    debug_msg "     Current Log Level: $current_log_level" | tee -a "$output_log"
    debug_msg "     Cluster Name: $clusterName" | tee -a "$output_log"
    debug_msg "     jq_or_grep: $jq_or_grep" | tee -a "$output_log"
    debug_msg "     Detach: $detachable" | tee -a "$output_log"
    debug_msg "     Debug: $debug" | tee -a "$output_log"
    debug_msg "**********************************************************" | tee -a "$output_log"

    # Convert associative arrays to strings and pass them to the screen session
    log_levels_string=$(declare -p log_levels)
    log_level_names_string=$(declare -p log_level_names)
    debug_msg "log_levels_string: $log_levels_string" | tee -a "$output_log"
    debug_msg "log_level_names_string: $log_level_names_string" | tee -a "$output_log"

    if command -v screen &>/dev/null; then
        echo -e "Running in ${YELLOW}screen${RESET} detachable mode..." | tee -a "$output_log"
        screen -dmS castor_log_script bash -c "$(declare -f main_script timestamp debug_msg format_size format_duration check_jq determine_log_file print_credentials); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$detachable\" \"$debug\" \"${log_levels_string}\" \"${log_level_names_string}\" \"${default_log_levels}\" \"${default_log_levels_name}\" | tee \"$output_log\""
        screen -r castor_log_script
        # Wait for the screen session to complete and then display the output log
        sleep 1
        while screen -list | grep -q "castor_log_script"; do
            sleep 1
        done
    elif command -v tmux &>/dev/null; then
        echo -e "Running in ${YELLOW}screen$tmux${RESET} detachable mode..." > "$output_log"  # Truncate log file to remove old entries

        # Create a temp script file
        temp_script="$SCRIPTDIR/castor_log_script.sh" | tee -a "$output_log"

        # Write the script to a file to avoid printing function definitions
        cat screen<<EOF -dmS castor_log> "$temp_script"
#!/bin/bash
-c "$(declare -f main_script timestamp debug_msg format_size format_duration check_jq determine_log_file print_credentials);
main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$detachable\" \"$debug\" \"${log_levels_string}\" \"${log_level_names_string}\" \"${default_log_levels}\" \"${default_log_levels_name}\" | tee -a \"$output_log\""
rm -f "$temp_script"         screen -r castor_log_script         # WaitRemove for the screenscript sessionfile
totmux complete and then display the output logkill-session -t castor_log_script
EOF

        # Ensure sleepthe 1script is executable
      while screen -listchmod | grep -q "castor_log_script"; do+x "$temp_script"

        # Start tmux session sleepand 1execute the script   inside
   done     eliftmux commandnew-session -vd tmux &>/dev/null; then
-s castor_log_script "bash $temp_script"

      echo -e "Running# in ${YELLOW}tmux${RESET} detachable mode..." | tee -a "$output_log"Attach session only if it's still running
        while tmux newhas-session -d -st castor_log_script "$(declare -f main_script timestamp debug_msg format_size format_duration check_jq determine_log_file print_credentials); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$detachable\" \"$debug\" \"${log_levels_string}\" \"${log_level_names_string}\" \"${default_log_levels}\" \"${default_log_levels_name}\" | tee \"$output_log\""
    2>/dev/null; do
            tmux attach-session -t castor_log_script
        done
        # if tmux has-session -t castor_log_script 2>/dev/null; then
        #     tmux attach-session -t castor_log_script
        # fi
    else
        echo "Error: Neither screen nor tmux available. Run without --detachable."
        exit 1
    fi

    echo ""
    cat "$output_log"
else
    # main_script "$swarm_ip" "$credentials" "$new_log_level" "$duration" "$clusterName" "$jq_or_grep" | tee "$output_log"
    debug_msg "**********************************************************"
    debug_msg "Parameters passed to main_script:"
    debug_msg "Swarm IP: $swarm_ip"
    debug_msg "Credentials: $(print_credentials "$credentials")"
    debug_msg "New Log Level: $new_log_level"
    debug_msg "Duration: $duration"
    debug_msg "Cluster Name: $clusterName"
    debug_msg "jq_or_grep: $jq_or_grep"
    debug_msg "**********************************************************"
    debug_msg "Running main_script function..."
    main_script "$swarm_ip" "$credentials" "$new_log_level" "$new_log_level_name" "$duration" "$log_level_type" "$clusterName" "$jq_or_grep" | tee "$output_log"
fi

...