Versions Compared

Key

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

...

Parameter

Description

-d, --swarm_ip

IP address of the Swarm API endpoint (or set SCSP_HOST environment variable).

-p, --credentials

Admin credentials in the format admin:password.

-i, --log.level

New log level to set (values: 10, 15, 20, 30, 40, 50).

-t, --time

Duration in seconds to keep the new log level (optional).

--detach

Runs the script in a detachable session using screen or tmux, allowing continued operation if terminal session ends.

-v, --verbose

Enables verbose mode to display debug information.

Instruction for Use

Example 1: Set cluster log level to 20 and keep it for 10

...

minutes

Code Block
./castor-change-log-level.sh -d 192.168.8.84 -p admin:datacore -i 20 -t 10600

Example 2: Set node(s) log level to debug (10) and keep it for 10 secondsminutes

Code Block
./castor-change-log-level.sh -d 192.168.8.84,192.168.8.86 -p admin:datacore -i debug -t 10600

Example 3: Run in background mode

...

Code Block
./castor-change-log-level.sh -d 192.168.8.84 -p admin:datacore -i 20 -t 30 --detach -v

...

Running the Script at a Specific Time

The at command can used to schedule the scrip script to run at a later time. This is useful when you need to start collecting debug logs at a specific hour.

Example 54: Schedule the script to run at 3:00 AM and collect debug logs for 1 hour

...

  1. Log Level Change: Sets the log level to the specified value. If the current log level matches the requested level, the script skips the update.

  2. Countdown: During the specified duration, the script displays a countdown every second.

  3. Revert Log Level: After the countdown, the log level reverts to the initial value.

  4. Log Size Report: Provides approximately log size generated during the temporary log level change.Debug Mode: When -v is specified, debug messages display the script's internal operations.

Output Messages

Message

Description

Swarm IP:

Displays the specified Swarm IP address.

Credentials:

Credentials are masked for security.

Cluster Name:

Displays the cluster name retrieved from the Swarm API.

New log level:

Shows the new log level requested.

Current log level:

Displays the current log level.

Updating log level to X...

Indicates the beginning of the log level update process.

Log level changed successfully...

Confirms that the log level was successfully updated.

Keeping log level at X for Y...

Shows the temporary period for which the new log level is retained, with a countdown.

Time's up! Reverting log level...

Indicates that the temporary period has ended and the script is reverting the log level.

Approximate X new logs generated...

Provides information on the amount of logging activity generated during the temporary log level.

...

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: Auto detect CSN or SCS to adjust castor.log file path
#        - Enforced proper credential formatting: credentials must be in the username:password format.
# v1.2.1 - 2025-02-26 Address the issue of the- scriptFixed nothelp displaymessage correctshows whenscript thename castor.logwithout filehard iscode rotatedit.
# v1.2.21 - 2025-02-26 SUPSCR-209: EnforcedAuto properdetect credentialCSN formatting:or credentialsSCS mustto beadjust incastor.log the username:password formatfile 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---------------------------------------------------------------------------------------------------------------------
# Current Version: 1.2.2
# ----------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 minor bug fix and enhancement.
# -------------------------------------------------------------------------------------------------------------------
# KB: https://perifery.atlassian.net/wiki/spaces/public/pages/3872161835/Setting+and+Managing+Swarm+Log+Levels+with+script
# ----------
# Current Version: 1.3.0
# -----------------------------------------------------------------------------------------------------------------------------
# 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

# Function to display usage information
usage() {
    echo "Usage: ./castor-change-log-level10.sh -d swarm_ip -p admin:password [-i new_log_level | -L new_node_log_level] [-t duration_in_seconds] [-D]"
    echo "  -d, --swarm_ip-----------------------------------------------------------------------------------------------------------------

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

# 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
    ["default"]=30
)

# Function to get the current timestamp
timestamp() {
    date +"%Y-%m-%d_%H:%M:%S.%4N"
}

# Function to display debug messages if debug mode is enabled
debug_msg() {
    if $debug; then
        local caller_line=${BASH_LINENO[0]:-unknown}  # Fallback to "unknown" if empty
        echo -e "$(timestamp) [DEBUG] (Line $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
        debug_msg "detachable=${YELLOW}false${RESET}"
        debug_msg "Stopping the script..."
        exit 1
    fi
}

# Function to format file size
format_size() {
    local size=$1
    if (( size >= 1073741824 )); then
        echo "$(awk "BEGIN {printf \"%.1fGB\", $size/1073741824}")"
    elif (( 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() {
    if [[ -x "/usr/local/bin/jq" ]]; then
        echo "/usr/local/bin/jq"
    elif [[ -x "$(pwd)/jq" ]]; then
        echo "$(pwd)/jq"
    elif command -v jq &>/dev/null; then
        echo "jq"
    else
        echo "grep"
    fi
}

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() {
    if [[ -f "/var/log/datacore/castor.log" ]]; then
        echo "/var/log/datacore/castor.log"
    elif [[ -f "/var/log/caringo/castor.log" ]]; then
        echo "/var/log/caringo/castor.log"
    else
        echo "Error: Log file not found in /var/log/datacore/castor.log or /var/log/caringo/castor.log"
        exit 1
    fi
}

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 \"[hidden for security]\" -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}[hidden for security]${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"
            if ! [[ "$credentials" =~ ^[^:]+(:[^:]+)?$ ]]; then
                echo -e ""
                echo -e "Error: Credentials must be in the format ${BOLD_GREEN}username:password${RESET} or ${BOLD_GREEN}username${RESET}"
                exit 1
            fi
            if [[ "$credentials" =~ [^a-zA-Z0-9:] ]]; then
                echo -e ""
                echo -e "Warning: Password contains special characters. Please enclose the credentials with single quotes (${BOLD_YELLOW}'${BOLD_GREEN}username:password${RESET}${BOLD_YELLOW}'${RESET})."
                exit 1
            fi
            debug_msg "Set credentials"; 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
            if [[ ${log_level_names[$2]} ]]; then
                new_log_level=${log_level_names[$2]}
            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]}
            log_level_type="cluster"
            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
            if [[ ${log_level_names[$2]} ]]; then
                new_log_level=${log_level_names[$2]}
            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]}
            log_level_type="node"
            default_log_level=0
            debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)"
            shift 2
            ;;
        -t|--time)
            if IP[[ address of the Swarm API endpoint. Supports single or multiple IPs separated by \",\", \";\" or \" \"."-n "$2" && "$2" != -* && "$2" -gt 0 ]]; then
          echo "     duration="$2"
                debug_msg "Set duration to $duration"
If multiple IPs are provided, the script will update the log level for all nodes."  shift 2
 echo "          else
                (Alternatively, set the SCSP_HOST environment variable to the Swarm IP.)echo "Error: Duration must be a number greater than 0."
    echo "  -p, --credentials        Credentialsexit in1
the format admin:password"     echo "  -i, --log.level fi
        New cluster log level to;;
set (5,  10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default)" -D|--detach) detachable=true; debug_msg "Set detachable to true"; shift ;;
    echo "  -L, --node.log.level     New node log level to set (0, 5, 10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default)"
    echo "                           **Either -i or -L must be specified, but not both.**"
    echo "  -t, --time               (Optional) Duration in seconds to keep the new log level (must be greater than 0)"
    echo "  -D, --detach 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}"

# Set default values if not provided
debug_msg "Checking for default log level values..."

# Change the default log level based on Log Level Type
debug_msg "Changing default log level based on Log Level Type: ${YELLOW}$log_level_type${RESET}"
if [[ -n "$new_log_level" ]]; then
    if [[ "$log_level_type" == "node" ]]; then
        # new_log_level=0
        debug_msg "Checing node default log level"
           (Optional) Detach the script from the current terminal and run in a detachable session using screen or tmux"
default_log_level=0
        if [[ $new_log_level == 30 ]]; then
   exit 1 }  # Default options detachable=false debug=false outputnew_log_level="script$default_output.log"						# Log file for capturing detachable session output
log_level
            new_log_level_typename="cluster"									# Default log level type
default_log_level=30											# Default log level
log_file="/var/log/datacore/castor.log"		# Default log file location

# 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"
    [30]="default"
)

# 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
    ["default"]=30
)

# Function to display debug messages if debug mode is enabled
debug_msg() {
    if $debug; thendefault"
        fi
        debug_msg "node - new_log_level: to $new_log_level"
        debug_msg "node - new_log_level_name: to $new_log_level_name"
    elif [[ "$log_level_type" == "cluster" ]]; then
        default_log_level=30
    fi
    debug_msg "New log level: ${GREEN}$new_log_level${RESET}"
    debug_msg "New log level name: ${GREEN}$new_log_level_name${RESET}"
    debug_msg "Set default_log_level to: $default_log_level"
fi

# 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" ]]; then
        swarm_ip="$SCSP_HOST"
        debug_msg "Using Swarm IP from SCSP_HOST: $swarm_ip"
    else
        echo -e "[DEBUG] $1" >> "$output_log"Error: swarm_ip not provided and SCSP_HOST is not set."
    fi }  # Functionusage
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 "Error: Neither 'screen' nor 'tmux' is installed. Cannot run in detachable mode."
        detachable=false  # Disable detachable session
        debug_msg "detachable=${YELLOW}false${RESET}"
    fi
}

# Function to format file size
format_size() {
    local size=$1
    if (( size >= 1073741824 )); then
        echo "$(awk "BEGIN {printf \"%.1fGB\", $size/1073741824}")"
    elif (( size >= 1048576 )); then
        echo "$(awk "BEGIN {printf \"%.1fMB\", $size/1048576}")"
    elif (( size >= 1024 )); then
        echo "$(awk "BEGIN {printf \"%.1fKB\", $size/1024}")"
    elsefi
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
    CREDENTIALS="$credentials"
    ATTEMPT=$MAX_RETRIES
    USERNAME=""
    PASSWORD=""
    debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS")"
    debug_msg "ATTEMPT: $ATTEMPT"
    debug_msg "USERNAME: $USERNAME"
    debug_msg "PASSWORD: $PASSWORD"

    # Check if credentials contain a colon (username:password format)
    if [[ "$CREDENTIALS" == *":"* ]]; then
        USERNAME="${CREDENTIALS%%:*}"
        PASSWORD="${CREDENTIALS#*:}"
        # Validate credentials
         echocheck_credentials "$CREDENTIALS" "${size}Bip_array[0]}"
    fi   } if # Function to format duration
format_duration() {[[ $? -ne 0 ]]; then
      local duration=$1     local hours=$((duration / 3600))
    local minutes=$(( (duration % 3600) / 60 ))debug_msg "Invalid credentials. Please check your username and password."
           local seconds=$((duration % 60)) echo ""
     printf "%02d:%02d:%02d" $hours $minutes $seconds }  # Function to check if jq is available and set up JSON parsing method
check_jq() {echo "${RED}Error${RESET}: Invalid credentials. Please check your username and password."
         if [[ -x "/usr/local/bin/jq" ]]; then exit 1
        fi
echo "/usr/local/bin/jq"     elif [[ -x "$(pwd)/jq" ]]; then debug_msg "Validate credentials"
        credentials=$CREDENTIALS
   echo "$(pwd)/jq"    return elif0
command -v jq &>/dev/null; then else
        echodebug_msg "jq"Credentials do not contain password"
 else       debug_msg  echo "grep"Username: $(print_credentials "$CREDENTIALS")"
    fi  }  jq_or_grep=$(check_jq)

# Function to determine the log file path
determine_log_file() {USERNAME="$CREDENTIALS"
        # Prompt for password
        ifwhile [[ $ATTEMPTS -f "/var/log/datacore/castor.log"lt $MAX_RETRIES ]]; do
  then          echo "/var/log/datacore/castor.log""
         elif   [[read -f "/var/log/caringo/castor.log" ]]; thensp "Enter password for user $USERNAME: " PASSWORD
            echo "/var/log/caringo/castor.log"

   else         echo ""Error:
Log file not found in /var/log/datacore/castor.log or /var/log/caringo/castor.log"     CREDENTIALS="$USERNAME:$PASSWORD"
   exit 1     fi }  log_file=debug_msg "CREDENTIALS: $(determine_log_file)

# Parse input arguments
while [[ "$#" -gt 0 ]]; doprint_credentials "$CREDENTIALS"))"
            check_credentials "$CREDENTIALS" "${ip_array[0]}"
     case $1 in     if [[ $?  -d|--swarm_ip) swarm_ip="$2"; debug_msg "Set swarm_ip to $swarm_ip"; shift 2 ;;
  -eq 0 ]]; then
                debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
     -p|--credentials)           debug_msg "Valid credentials="$2"
            if ! [[ "$credentials" credentials=~ ^[^:]+:[^:]+$ ]]; then$CREDENTIALS
                break
  echo -e ""        else
        echo -e "Error: Credentials must be in the format ${BOLD_GREEN}username:password${RESET}echo ""
                exit 1
       echo "${RED}Error${RESET}: Invalid credentials. Please check your username and password."
    fi        fi
    if [[ "$credentials" =~ [^a-zA-Z0-9:] ]]; then    ((ATTEMPTS++))
        done
    fi
echoelse
-e ""   if ! check_credentials "$credentials" "${ip_array[0]}"; then
        echo -e ""Warning: Password
contains special characters. Please enclose the credentials with singleecho quotes-e ("${BOLD_YELLOW}'${BOLD_GREEN}username:password${RESET}${BOLD_YELLOW}'$Warning${RESET}: ${RED}Invalid credentials${RESET})." Please check your username and password in the format ${GREEN}username:password${RESET}."
       exit 1echo -e ""
        usage
 fi       exit 1
    debug_msg "Set credentials"; shift 2 ;;
        -i|--log.level)
           fi
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 [[ -n "$new$jq_log_levelor_grep" == "grep" ]]; then
    clusterName=$(curl --user           echo "Error: Options -i (cluster log leve) and -L (node log level) cannot be used together."
"$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

usageif [[ -z "$clusterName" ]]; then
    echo "Failed to firetrieve the cluster name. Please check your inputs."
    exit if1
[[ ${log_level_names[$2]} ]]; then
          fi
debug_msg "Cluster Name: $clusterName"

# Main logic function to run the script tasks
main_script() {
    local newswarm_log_level=${log_level_names[$2]}ip="$1"
    local credentials="$2"
      elif [[ ${log_levels[$2]} ]]; thenlocal new_log_level="$3"
    local new_log_level_name="$4"
    local duration="$5"
     local new_log_level_type=$2"$6"
    #local log_file="/var/log/datacore/castor.log"
    if [[ else
       -z "$log_file" ]]; then
        echo "Invalid log level: $2"
log_file=$(determine_log_file)
    fi
    local initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
   exit 1local current_log_level
    local clusterName="$7"
     filocal jq_or_grep="$8"
    local detachable="$9"
      new_log_level_name=${log_levels[$new_log_level]}
  if [[ "$detachable" ]]; then
        local log_level_typedebug="cluster${10}"
        eval "$(echo "${11}" |  default_log_level=30
 sed 's/declare -A/declare -A/')"
        eval  debug_msg "Set new_log_level to $new_log_level ($new_log_level_name"$(echo "${12}" | sed 's/declare -A/declare -A/')"
    fi
       shift 2debug_msg "**********************************************************"
    debug_msg "local variables"
     ;;
        -L|--node.log.level)debug_msg "Log Level Type: ${GREEN}$log_level_type${RESET}"
    debug_msg "Default Log      if [[ -n "$newLevel: ${GREEN}$default_log_level" ]]; thenlevel${RESET}"
    debug_msg "Swarm IP: $swarm_ip"
         echo "Error: Options -i (cluster log leve) and -L (node log level) cannot be used together."
    debug_msg "Credentials: $(print_credentials "$credentials")"
    debug_msg "New Log Level: $new_log_level"
    debug_msg "New log Level Name: $new_log_level_name"
 usage   debug_msg "Duration: $duration"
    debug_msg "Log  fiFile: $log_file"
    debug_msg "Initial Log File Size: $initial_size"
  if [[ ${log_level_names[$2]} ]]; then
 debug_msg "Current Log Level: $current_log_level"
    debug_msg "Cluster Name: $clusterName"
      new_log_level=${log_level_names[$2]}debug_msg "jq_or_grep: $jq_or_grep"
    debug_msg "Detach: $detachable"
     elif [[ ${log_levels[$2]} || $2 -eq 0 ]]; thendebug_msg "Debug: $debug"
    debug_msg "**********************************************************"

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

    # Display initial information
   else if [[ "$log_level_type" == "cluster" ]]; then
        echo echo-e "InvalidSwarm log level: $2IP: ${GREEN}${ip_array[0]}${RESET}"
    else
        echo -e "Swarm exit 1IPs: ${GREEN}${ip_array[*]}${RESET}"
    fi
    # echo -e fi"Swarm      IP: ${GREEN}$swarm_ip${RESET}"
      log_level_type="node"
  debug_msg "Credentials: ${GREEN}[hidden for security]${RESET}"
    echo -e "Cluster Name:  default_log_level=0${GREEN}$clusterName${RESET}"

    debug_msg "Starting main_script function..."
    debug_msg "SetLog new_log_level totype: $new$log_log_level ($new_log_level_name)_type"

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

;;    if [[ $log_level_type   -t|--time)
 == "cluster" ]]; then
        debug_msg "Setting ifcluster [[log -n "$2" && "$2" != -* && "$2" -gt 0 ]]; then
    level to $new_log_level ($new_log_level_name)"
        # Retrieve current log level
        if [[  duration="$2"
 "$jq_or_grep" == "grep" ]]; then
            current_log_level=$(curl  debug_msg "Set duration to $duration"
                shift 2--user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | grep -oP '"value":\s*\K[0-9]+')
              else
            current_log_level=$(curl --user "$credentials" -sS echo "Error: Duration must be a number greater than 0."
   http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | "$jq_or_grep" -r '.value')
        fi
   exit 1      current_log_level_name=${log_levels[$current_log_level]}
      fi  debug_msg "Current cluster log   level: ${BOLD_GREEN}$current_log_level${RESET}"
    ;;         -D|--detach) detachable=true; debug_msg "SetCurrent log detachablelevel to true"; shift ;;name: ${BOLD_GREEN}$current_log_level_name${RESET}"
         echo --debug) debug=true; debug_msg "Set debug to true"; shift ;;e ""
        echo -e "New cluster log  *) usage ;;level: ${BOLD_GREEN}$new_log_level_name${RESET}"
      esac done echo debug_msg-e "SetCurrent cluster log_ level_type tois ${YELLOWGREEN}$log$current_log_level_type$name.${RESET}"

        # Set default values if not provided Skip update if new level matches the current level
        if [[ "$current_log_level" -zeq "$new_log_level" ]]; then
    if [[ "$log_level_type" == "cluster" ]]; then
        new_log_level=$default_log_level
    else        echo ""
            echo -e "Cluster log level is already set to ${BOLD_GREEN}$new_log_level_name${RESET}. No changes made."
          new_log_level=0  return
  fi     new_log_level_name="default"
 fi

  new_log_level_name=${log_levels[$new_log_level]}     debug_msg "Set# default new_log_level to $new_log_level ($new_log_level_name)"
fi

# Check if 'screen' or 'tmux' is installed
check_screen_or_tmux

# If swarm_ip is not provided, try using SCSP_HOST environment variable
if [[ -z "$swarm_ip" ]]; thenUpdate the cluster log level using PUT
        debug_msg "Updating cluster log level to $new_log_level_name"
      if [[ -n "$SCSP_HOST" ]]; then debug_msg "Cluster Name: $clusterName"
        debug_msg  swarm_ip="$SCSP_HOST"Credentials: $(print_credentials "$credentials")"
        debug_msg "curl --user "Using Swarm IP from SCSP_HOST: $swarm_ip"
    else
        echo "Error: swarm_ip not provided and SCSP_HOST is not set."\"$(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" usage-sS -X PUT -H  fi
fi"Content-Type: application/json" \
 # 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"

# Retrieve cluster name and handle JSON parsing using the first IP addresshttp://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
            -d "{\"value\": $new_log_level}")
        debug_msg "RetrievingResponse: $response"
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 updated_log_level=$(echo "$response" | grep -oP '"namevalue":\s*"\K[^"0-9]+')
        else
           clusterName updated_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | "$jq_or_grep" -r '._embedded.clusters[0].name')
fiecho "$response" | "$jq_or_grep" -r '.value')
        fi
        debug_msg "Updated cluster log level: $updated_log_level"

        if [[ -z "$clusterName"$updated_log_level" -eq "$new_log_level" ]]; then
    echo "Failed to retrieve the cluster name. Please checkecho your-e inputs."Log level changed successfully  exit 1
fi
debug_msg "Cluster Name: $clusterName"

# Main logic function to run the script tasks
main_script() {
    local swarm_ip="$1"from ${GREEN}$current_log_level${RESET} -> ${BOLD_GREEN}$new_log_level${RESET}."
        else
    local credentials="$2"     local new_log_level="$3"
    local new_log_level_name="$4 echo -e "Failed to update log level. Response: ${RED}$response${RESET}"
    local duration="$5"     local log_level_type="$6"
  exit 1
  # local log_file="/var/log/datacore/castor.log"    fi
local
initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)  # Countdown and localrevert current_log_ level
        if [[ -n "$duration" && local clusterName="$7$duration" -gt 0 ]]; then
 local jq_or_grep="$8"     local debug="$9"    echo debug_msg "**********************************************************"
    debug_msg "local variables"-e "Keeping log level at ${YELLOW}$new_log_level_name${RESET} for ${YELLOW}$duration${RESET} second(s)..."
     debug_msg "Swarm IP: $swarm_ip"    echo debug_msg-e "Credentials: $credentials"
    debug_msg "New Log Level: $new_log_level ($new_log_level_name)"   for  debug_msg "Duration: $duration"((i=duration; i>0; i--)); do
    debug_msg "Log Level Type: $log_level_type"     debug_msg "Log File: $log_file"
    debug_msg "Initial Log File Size: $initial_size"
    debug_msg "Current Log Level: $current_log_level" printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))
         debug_msg "Cluster Name: $clusterName"    echo debug_msg-ne "jq_or_grep: $jq_or_grep"
    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 information
    if [[ "$log_level_type" == "cluster" ]]; then
        echo -e "Swarm IP: ${GREEN}${ip_array[0]}${RESET}"
    elseCountdown: ${YELLOW}$countdown${RESET} remaining...\r"
                sleep 1
            done
            echo -e "\n\nTime's up! Reverting log level back to ${GREEN}$current_log_level${RESET}..."

            # Revert the log level back to the original value
            response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
              echo -e "Swarm IPs: http://${GREEN}${ip_array[*]}${RESET}"0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
         fi     # echo -ed "Swarm IP: ${GREEN}$swarm_ip${RESET}"
    echo -e "Credentials: ${GREEN}[hidden for security]${RESET}""{\"value\": $current_log_level}")
           echo -edebug_msg "Cluster NameResponse: ${GREEN}$clusterName${RESET}$response"

    debug_msg "Starting main_script function..."        if  debug_msg "Log level type: $log_level_type"
[[ "$jq_or_grep" == "grep" ]]; then
    # Store the original log levels     declare -A originalreverted_log_levels
    declare -A original_log_level_nameslevel=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
       if [[ $log_level_type == "cluster" ]]; then else
         debug_msg  "Setting cluster log level to $newreverted_log_level ($new_log_level_name)"=$(echo "$response" | "$jq_or_grep" -r '.value')
          # Retrieve currentfi
log level         if [[ "$jq_or_grep" == "grep" ]]; thendebug_msg "Reverted cluster log level: $reverted_log_level"

            currentfinal_log_levelsize=$(curlstat --userc%s "$credentials$log_file" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | grep -oP '"value":\s*\K[0-9]+')2>/dev/null || echo 0)
         else   debug_msg "Initial log file size: $initial_size"
    current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | "$jq_or_grep" -r '.value')
     debug_msg "Final log file size: $final_size"
   fi         current_log_level_name=${log_levels[$current_log_level]}
size_diff=$(( final_size - initial_size ))
       debug_msg "Current cluster log level: ${BOLD_GREEN}$current_log_level${RESET}" size_diff_formatted=$(format_size "$size_diff")
        debug_msg "Current log level: ${BOLD_GREEN}$current_log_level_name${RESET}"
duration_formatted=$(format_duration "$duration")
	    if (( size_diff < 0 )); then
		echo -e "castor.log file was rotated."
	    else
            echo -e "New clusterApproximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level: ${BOLD_GREEN}$new_log_level_name$level${RESET}"
        echo -e "Current cluster log level. Current castor.log size is ${BOLD_GREEN}$current_log_level_name.$(format_size "$final_size")${RESET}" after $duration_formatted."
	    fi

 # Skip update if new level matches the current level         if [[ "$current$reverted_log_level" -eq "$new$current_log_level" ]]; then
 
          echo ""             echo -e "ClusterLog log level isreverted alreadysuccessfully setback to ${BOLD_GREEN}$new$current_log_level_name$level${RESET}. No changes made."
            return
        fielse
          # Update the cluster log level using PUT        echo debug_msg-e "UpdatingFailed to clusterrevert log level. to $new_log_level_name"
Response: ${RED}$response${RESET}"
       debug_msg "Cluster Name: $clusterName"         response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \exit 1
            fi
       "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \ else
            -decho "{\"value\": $new_log_level}")
        debug_msg "Response: $response"Log level change is permanent until manually modified."
        fi
     ifelif [[ "$jq$log_orlevel_greptype" == "grepnode" ]]; then
        #    updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
    First loop: Change the node log level
   else             updatedlocal same_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')false
        for ip    fi
        debug_msg "Updated cluster log level: $updated_log_level"in "${ip_array[@]}"; do
            if# [[ "$updated_log_level" -eq "$new_log_level" ]]; thenRetrieve current node log level
            debug_msg "Retrieving echocurrent -enode "Loglog level changed successfully from ${GREEN}$current_log_level${RESET} → ${BOLD_GREEN}$new_log_level${RESET}." for IP: $ip"
            debug_msg "curl else-s -u \"$(print_credentials "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\""
        echo -e "Failed to update current_log level. Response: ${RED}$response${RESET}"
       _level=$(curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value')
    exit 1       debug_msg "Current filog level for IP       # Countdown and revert log level$ip: $current_log_level"
        if [[ -n "$duration" && "$duration" -gt 0 ]]; then original_log_levels["$ip"]=$current_log_level
            echo -e "Keepingdebug_msg "Original log level at for IP $ip: ${YELLOW}$neworiginal_log_level${RESET} for ${YELLOW}$duration${RESET} second(s)..."levels["$ip"]}"
            if  echo -e[[ "$current_log_level" == "0" ]]; then
           for ((i=duration; i>0; i--)); do
       current_log_level_name="default"
            else
             printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) current_log_level_name=${log_levels[$current_log_level]}
            fi
          echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r" original_log_level_names["$ip"]=$current_log_level_name
            debug_msg "Original log level  sleep 1name: ${original_log_level_names["$ip"]}"
            if done
    [[ "$new_log_level" == "0" ]]; then
       echo -e "\n\nTime's up! Reverting log level back to ${GREEN}$currentnew_log_level${RESET}...level_name="default"
            else
# Revert the log level back to the original value       new_log_level_name=${log_levels[$new_log_level]}
     response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ fi
            debug_msg "Current log level for IP "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \$ip: $current_log_level ($current_log_level_name)"
            echo ""
            echo -de "{\"value\": $currentNew node log level: ${BOLD_GREEN}$new_log_level_name${RESET}")
            debug_msg "Response: $response"

            if [[ "$jq_or_grep" == "grep" ]]; thenecho -e "Current node log level for IP $ip is ${GREEN}$current_log_level_name.${RESET}"

            # Skip update if new level  reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')matches the current level
            if [[ "$current_log_level" -eq "$new_log_level" ]]; elsethen
                revertedsame_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')true
                echo ""
    fi            echo debug_msg-e "Reverted clusterNode log level: $reverted for IP $ip is already set to ${BOLD_GREEN}$new_log_level"

 _name${RESET}. No changes made."
          final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)continue
            size_diff=$(( final_size - initial_size ))else
                sizesame_difflog_formatted=$(format_size "$size_diff")level=false
            fi

      duration_formatted=$(format_duration "$duration") 	    if (( size_diff < 0 )); then
		echo -e "castor.log file was rotated."
	    else
     [[ "$same_log_level" == false ]]; then
                # Update the node log level using PUT
          echo -e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated atdebug_msg "Updating node log level ${BOLD_GREEN}to $new_log_level${RESET}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after $duration_formatted."
	    fi_level_name for IP $ip..."
                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\""
                 if [[ "$reverted_log_levelresponse=$(curl --user "$credentials" -eq "$current_log_level" ]]; then
  sS -X PUT -H "Content-Type: application/json" \
             echo -e "Log level reverted successfully back to ${BOLD_GREEN}$current_log_level${RESET}." "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level")
               else debug_msg "Response: $response"

            echo -e "Failed to revertif log level. Response: ${RED}$response${RESET}"
[[ "$jq_or_grep" == "grep" ]]; then
                exit 1   updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
    fi         else   else
         echo "Log level change is permanent until manually modified."   updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
fi     elif [[ "$log_level_type" == "node" ]]; then     fi
    # First loop: Change the node log level     debug_msg "Updated log level for ipIP in "${ip_array[@]}"; do$ip: $updated_log_level"

              # Retrieve currentif node[[ "$updated_log_level" -eq "$new_log_level" ]]; then
          debug_msg "Retrieving current node log level for IP: $ip"  echo -e "Node log level for IP $ip changed successfully  debug_msg "curl -s -u \"$credentials\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\""from ${GREEN}$current_log_level_name${RESET} -> ${BOLD_GREEN}$new_log_level_name${RESET}."
                 current_log_level=$(curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value')else
                    echo  original_log_levels["$ip"]=$current_log_level
   -e "Failed to update node log level for IP $ip. Response: ${RED}$response${RESET}"
         if [[ "$current_log_level" == "0" ]]; then     exit 1
          current_log_level_name="default"      fi
      else      fi
        done

current_log_level_name=${log_levels[$current_log_level]}        # Second loop: Countdown if fiduration is provided
        if [[ original"$same_log_level_names["$ip"]=$current_log_level_name" == false ]]; then\
            if [[ -n "$new_log_level$duration" ==&& "$duration" -gt 0" ]]; then
                echo  new_log_level_name="default-e ""
            else    echo -e "Keeping node(s) log level        newat ${YELLOW}$new_log_level_name=${log_levels[$new_log_level]}name${RESET} for ${YELLOW}$duration${RESET} second(s)..."
            fi    echo -e ""
      debug_msg "Current log level for IP $ip: $current_log_level ($current_log_level_name)"  for ((i=duration; i>0; i--)); do
      echo ""             echoprintf -e "New node log level: ${BOLD_GREEN}$new_log_level_name${RESET}"v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))
             echo -e "Current node log level for IPecho $ip is-ne "Countdown: ${GREEN}$current_log_level_name.$YELLOW}$countdown${RESET} remaining...\r"
             # Skip update if new level matches thesleep current1
level             if [[ "$current_log_level" -eq "$new_log_level" ]]; then done
                echo -e  echo ""
        "\n\nTime's up! Reverting node log level back to original levels..."

      echo -e "Node log level for IP $ip is already set to ${BOLD_GREEN}$new_log_level_name${RESET}. No changes made."
     # Third loop: Revert the node log level
           continue     for ip in "${ip_array[@]}"; do
   fi              # Update the node current_log level using PUT_level=${original_log_levels["$ip"]}
              debug_msg "Updating node log level to $newcurrent_log_level_name for IP $ip..."=${original_log_level_names["$ip"]}
            debug_msg "curl --user \"$credentials\" -sS -X PUT -H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level\"" debug_msg "Reverting node log level back to $current_log_level_name for IP $ip..."
                    response=$(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$current_log_level")
            debug_msg "Response: $response"

            if [[ "$jq_or_grep" == "grep" ]]; then\""
                    updated_log_levelresponse=$(echocurl --user "$response$credentials" | grep-sS -X PUT -oPH '"value":\s*\K[0-9]+')
 Content-Type: application/json" \
          else                 updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value'"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level")
            fi             debug_msg "Response: $response"Updated

 log level for IP $ip: $updated_log_level"              if [[ "$updated$jq_logor_levelgrep" -eq== "$new_log_levelgrep" ]]; then
  
             echo -e "Node log level for IP $ip changed successfully from ${GREEN}$currentreverted_log_level_name${RESET} → ${BOLD_GREEN}$new_log_level_name${RESET}."=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
            else        else
        echo -e "Failed to update node log level for IP $ip. Response: ${RED}$response${RESET}"     reverted_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
      exit 1             fi

       done           # Second loop: Countdown if duration is provided
 final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
       if [[ -n "$duration" && "$duration" -gt 0 ]]; then    size_diff=$(( final_size - initial_size ))
    echo -e ""             echo -edebug_msg "KeepingInitial node(s) log levelfile at ${YELLOW}$new_log_level_name${RESET} for ${YELLOW}$duration${RESET} second(s)..."size: $initial_size"
                   echo -edebug_msg "Final log file size: $final_size"
            for ((i=duration; i>0; i--)); do        size_diff_formatted=$(format_size "$size_diff")
                  printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) duration_formatted=$(format_duration "$duration")

                    if  echo[[ "$reverted_log_level" -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"eq "$current_log_level" ]]; then
                  sleep 1     echo -e "Node log level for IP $ip donereverted successfully back to ${BOLD_GREEN}${current_log_level_name}${RESET}."
        echo -e "\n\nTime's up! Reverting node log level back to original levels..." else
            # Third loop: Revert the node log level     echo -e "Failed to revert node log level for ip in "${ip_array[@]}"; doIP $ip. Response: ${RED}$response${RESET}"
                       current_log_level=${original_log_levels["$ip"]} exit 1
                current_log_level_name=${original_log_level_names["$ip"]}    fi
            debug_msg "Reverting node log leveldone
back
to $current_log_level_name for IP $ip..."            # Combine the log output debug_msg "curl --user \"$credentials\" -sS -X PUT -H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\""for multiple IP addresses into a single summary
            if (( size_diff < 0 )); then
response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \   echo -e "castor.log file was rotated."
            "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level")else
                debug_msg "Response: $response"  echo -e ""
             if [[ "$jq_or_grep" == "grep" ]]; then echo -e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} for IP ${ip_array[*]}. Current castor.log size is  reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')${BOLD_GREEN}$(format_size "$final_size")${RESET} after $duration_formatted."
            fi
        else    else
                reverted_log_level=$(echo "$response"Log | "$jq_or_grep" -r '.value')
   level change is permanent until manually modified."
            fi
        fi
    fi
}

 final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
# Run in detachable or directly
if $detachable; then
    # Pass the main_script function to the screen session and  size_diff=$(( final_size - initial_size ))store the output in a file
                size_diff_formatted=$(format_size "$size_diff")debug_msg "**********************************************************" | tee -a "$output_log"
    debug_msg "Detach mode - Parameters passed to main_script:" | tee -a  duration_formatted=$(format_duration "$duration")"$output_log"
    debug_msg "     Swarm IP: $swarm_ip"     if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then
   | tee -a "$output_log"
    debug_msg "     Credentials: $(print_credentials "$credentials")"  | tee -a "$output_log"
    echo -e "Node log level for IP $ip reverted successfully back to ${BOLD_GREEN}${current_log_level_name}${RESET}."
   debug_msg "     New Log Level: $new_log_level" | tee -a "$output_log"
    debug_msg "     New log elseLevel Name: $new_log_level_name" | tee -a "$output_log"
    debug_msg "     Duration: $duration" | tee echo -ea "Failed to revert node log level for IP $ip. Response: ${RED}$response${RESET}$output_log"
    debug_msg "     Log Level Type: $log_level_type" | tee -a "$output_log"
        exit 1debug_msg "     Log File: $log_file" | tee -a "$output_log"
    debug_msg " fi    Initial Log File Size: $initial_size" | tee -a "$output_log"
done    debug_msg "     Current Log Level:  # Combine the log output for multiple IP addresses into a single summary
	    if (( size_diff < 0 )); then
		echo -e "castor.log file was rotated."
	    else
                echo -e "$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   echo -ea "$output_log"Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} for IP ${ip_array[*]}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after $duration_formatted."
	    fi
        else
            echo "Log level change is permanent until manually modified."
        fi
    fi
}

# Run in detachable or directly
if $detachable
    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
    # Pass the main_script functionecho to the screen session and store the output in a file
    if command -v screen &>/dev/null; then
-e "Running in ${YELLOW}screen${RESET} detachable mode..." | tee -a "$output_log"
       # screen -dmS indexercastor_log_script bash -c "$(declare -f main_script timestamp debug_msg format_size format_duration check_jq debug 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_type\" \"$clusterName\" \"$jq_or_grep\" | tee \"$output_log\""_names_string}\" | tee \"$output_log\""
        screen -r castor_log_script
        # Wait for the screen session to complete and then display the output log
        sleep screen1
-dmS indexer_script bash -c "$(declare -f main_script debug_msg format_size format_duration check_jq); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$debug\" | tee \"$output_log\""
  while screen -list | grep -q "castor_log_script"; do
            sleep 1
      screen -r indexer_scriptdone
    elif command -v tmux &>/dev/null; then
        # tmuxecho new-sessione -d -s indexer_script "$(declare -f main_script format_size format_duration check_jq debug); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\"Running in ${YELLOW}tmux${RESET} detachable mode..." | tee \-a "$output_log\""
        tmux new-session -d -s indexercastor_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\" \"$debug$detachable\" | tee \"$output_log$debug\""
        tmux attach-session -t indexer_script
    else
        echo "Error: Neither screen nor tmux available. Run without --detachable."
        exit 1 \"${log_levels_string}\" \"${log_level_names_string}\" | tee \"$output_log\""
    fi    tmux attach-session # Wait for the screen session to complete and then display the output log
    sleep 1
    while screen -list | grep -q "indexer_script"; do-t castor_log_script
    else
        echo "Error: Neither screen nor tmux available. Run without --detachable."
        exit sleep 1
    donefi

    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

...