Versions Compared

Key

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

...

  • Set and Revert Log Levels: Temporarily change the log level and revert after a specified duration.

  • Flexible JSON Parsing: Uses jq for JSON parsing if available; defaults to jq otherwise.

  • Detachable Session Execution: Runs in a detachable session using screen or tmux, allowing the script to continue running independently of the terminal session. If both screen and tmux are installed, the script will prioritize screen first.

  • Supports Cluster and Node Log Levels: Allows setting log level at both the cluster and individual node levels.

  • Log File Auto-Detection: Automatically detects and adjust the castor.log file path for CSN and SCS environments.

  • Log Size Monitoring: Reports the log size generated during the temporary log level change.

  • Countdown Display: Shows a countdown for the specified duration.

...

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

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

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

Example 3: Run in

...

detachable mode

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

...

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

Example 4: Secure password prompt if password are not provided

Code Block
./castor-change-log-level.sh -p admin -d 192.168.8.84 -i 10 -t 300

(You will be prompted to enter the password securely.)

Code Block
./castor-change-log-level.sh -p admin -d 192.168.8.84 -i 10 -t 300

Enter password for user admin:

Example 5: Schedule the script to run at 3:00 AM on 03/02/2025 and collect debug logs of node 192.168.8.84 and 192.168.8.89 for 1 hour

  1. Ensure the at service is installed, enabled and running

    Code Block
    dnf -y install epel-release
    dnf -y install at atd
    systemctl enable --now at
  2. Schedule the script execution using at:

    Code Block
    echo "/root/dist/castor-change-log-level.sh -i -p admin:datacore -d 192.168.8.84 -L '192.168.8.84,192.168.8.89' 10 -t 3600" | at 03:00 AM 03/02/2025

...

  1. To verify scheduled job:

    Code Block
    atq
    7	Sun Mar 02 03:00:00 2025 a root
  2. To remove a scheduled job (replace JOB_ID with the actual job number from atq output):

    Code Block
    atrm 7

Behavior

  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.

Output Messages

...

Message

...

Description

...

Swarm IP:

...

Displays the specified Swarm IP address.

...

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.

...

Reattaching to a Detached Session

For more details on using screen and tmux, refer to their official documentation:

If you accidentally close your terminal (e.g. putty, iterm2, etc) while the script is running in a detached session, you can reattach using the following commands:

For screen users:

  1. List active screen session:

    Code Block
    screen -ls
  2. Reattach to the session:

    Code Block
    screen -r <session_name>

For tmux users:

  1. List active tmux sessions:

    Code Block
    tmux ls
  2. Reattach to the session:

    Code Block
    tmux a -t <session_name>

If the session has ended or was not found, you may need to restart the script manually.

Behavior

  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.

Output Messages

Message

Description

Swarm IP:

Displays the specified Swarm IP address.

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:
#        - 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 ""
    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 "  ;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 "---------------------------------------------------------------------------------------"
        detachable=false  # Disable detachable session
        usage
    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() {
    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
          If multiple IPsecho are"$log"
provided, the script will update the log level for all nodes."  return
  echo "     fi
    done
    echo -e "${RED}Error: Log file not found.${RESET}"
    exit (Alternatively,1
set}
the
SCSP_HOST environment variable to the Swarm IP.)"
    echo "  -p, --credentialslog_file=$(determine_log_file)

# Function to check if credentials are valid
check_credentials() {
    local CREDENTIALS="$1"
  Credentials in the format admin:passwordlocal SWARM_IP="$2"
    echodebug_msg "Credentials: [hidden -i, --log.levelfor security]"
    debug_msg "Swarm IP: $SWARM_IP"

New cluster log level to# setAPI (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       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
       (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 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%%:*}'"
    echo ""   return 1 exit 1# }Failure
 # 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"		else
        debug_msg "Error: Unable to validate credentials. Please check your inputs."
        #return 1 Default log# fileFailure
location SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
JQLOCATION=$SCRIPTDIR/jq
MAX_RETRIES=3     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
 # Maximum number ofcase password$1 retriesin
attempts username="admin"       -d|--swarm_ip) swarm_ip="$2"; debug_msg "Set swarm_ip to $swarm_ip"; shift 2 ;;
        -p|--credentials)
          # Default username
passwordcredentials="$2"
            shift 2 ;;
        -i|--log.level)
            if [[ -n "$new_log_level" ]]; #then
Default password  # Global associative array for log levels declare -A log_levels=(    echo [5]="chatter"
    [10]="debug"
    [15]="audit"
    [20]="info"Error: Options -i (cluster log leve) and -L (node log level) cannot be used together."
    [30]="warning"
    [40]="error"          [45]="defect"  usage
  [50]="critical"     [60]="announce"     [30]="default"
)fi
  # Global associative array for log level names declare -A log_level_namestype=("cluster"
    ["chatter"]=5     ["debug"]=10   if [[ ["audit"]=15${log_level_names[$2]} ]]; then
      ["info"]=20     ["warning"]=30     ["error"]=40new_log_level=${log_level_names[$2]}
    ["defect"]=45     ["critical"]=50    elif ["announce"]=60
    [[ "$2" == "default" ]=30]; )then
 # 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 new_log_level=${default_log_levels[$log_level_type]}
                new_log_level_name="default"
            elif local caller_line=[[ ${BASHlog_LINENOlevels[0$2]:-unknown} ]]; #then
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() { new_log_level=$2
            else
       if ! command -v screen &>/dev/null && ! command -vecho tmux &>/dev/null; then
"Invalid log level: $2"
       echo -e ""       exit 1
echo -e "---------------------------------------------------------------------------------------"            fi
        echo -e "  ${YELLOW}Warning${RESET}: Neither '${BOLD_GREEN}screen${RESET}' nor '${BOLD_GREEN}tmux${RESET}' is installed. Cannot run in detachable mode."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
         echo -e " ;;
Please install either '${BOLD_GREEN}screen${RESET}' or '${BOLD_GREEN}tmux${RESET}' to run the script in a detachable session." -L|--node.log.level)
            if echo[[ -e "---------------------------------------------------------------------------------------"n "$new_log_level" ]]; then
                echo -e """Error: Options -i (cluster log leve) and -L (node log level) cannot be used together."
                usage
          detachable=false  #fi
 Disable detachable session         debug_msg "detachable=${YELLOW}false${RESET}log_level_type="node"
        debug_msg "Stopping the script..." if [[ ${log_level_names[$2]} ]]; then
   exit 1     fi }  # Function to format file size
format_size() { new_log_level=${log_level_names[$2]}
       local size=$1    elif if (( size >= 1073741824 ))[[ "$2" == "default" ]]; then
        echo "$(awk "BEGIN {printf \"%.1fGB\", $size/1073741824}")"        new_log_level=${default_log_levels[$log_level_type]}
    elif (( size >= 1048576 )); then      new_log_level_name="default"
  echo "$(awk "BEGIN {printf \"%.1fMB\", $size/1048576}")"     elif (( size >= 1024 )) [[ ${log_levels[$2]} || $2 -eq 0 ]]; then
        echo "$(awk "BEGIN {printf \"%.1fKB\", $size/1024}")"   new_log_level=$2
 else         echo "${size}B"     fi
}new_log_level_name="default"
  # Function to format duration format_duration() {    else
local duration=$1     local hours=$((duration / 3600))     local minutes=$(( (duration % 3600) / 60 )) echo "Invalid log level: $2"
     local seconds=$((duration % 60))     printf "%02d:%02d:%02d" $hours $minutes $seconds }exit 1
# Function to check if jq is available and set up JSON parsingfi
method check_jq()  {     if [[ -x "/usr/local/bin/jq" ]]; then new_log_level_name=${log_levels[$new_log_level]}
         echo "/usr/local/bin/jq"  default_log_level=0
  elif [[ -x "$(pwd)/jq" ]]; then     debug_msg "Set new_log_level to echo "$(pwd)/jq$new_log_level ($new_log_level_name)"
    elif command -v jq &>/dev/null; then       shift 2
echo "jq"     else      ;;
  echo "grep"     fi
}-t|--time)
  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 [[ -n "$2" && "$2" != -* && "$2" -gt 0 ]]; then
             if [[ -f "/var/log/datacore/castor.log" ]]; thenduration="$2"
                echo "/var/log/datacore/castor.log"
 debug_msg "Set duration to $duration"
  elif [[ -f "/var/log/caringo/castor.log" ]]; then            shift 2
  echo "/var/log/caringo/castor.log"     else    else
    echo "Error: Log file not found in /var/log/datacore/castor.log or /var/log/caringo/castor.log"   echo -e ""
   exit 1     fi }  log_file=$(determine_log_file)  # Function toecho check if credentials are valid
check_credentials() {
    local CREDENTIALS="$1"
    local SWARM_IP="$2"-e "---------------------------------------------------------------------------------------"
         debug_msg "Credentials: [hidden for security]"   echo  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-e "    ${RED}Error${RESET}: Duration must be a number greater than ${BOLD_GREEN}0${RESET}."
                echo -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
        debug_msg "Authentication successful for user '${CREDENTIALS%%:*}'"fi
         return 0  #;;
Success     elif echo "$RESPONSE" -D| "$jq_or_grep" -e '.isValid == false' > /dev/null 2>&1; then--detach) detachable=true; debug_msg "Set detachable to true"; shift ;;
          --debug) debug=true; debug_msg "AuthenticationSet debug failedto fortrue userwith '${CREDENTIALS%%:*}'"
   YELLOW}--debug${RESET}"; shift ;;
        *) usage ;;
    returnesac
1done

# 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)debug_msg "Set log_level_type to ${YELLOW}$log_level_type${RESET}"

# Check if 'screen' or 'tmux' is installed
if [[ "$detachable" == true ]]; then
    if [[ -z "$duration" ]]; then
        echo -e ""
        echo -e "---------------------------------------------------------------------------------------"
        echo -e "    ${RED}Error${RESET}: Duration must be specified when running in detachable mode."
        echo -e "    Please specify the duration using the ${BOLD_GREEN}-t${RESET} or ${BOLD_GREEN}--time${RESET} option."
        echo -e "---------------------------------------------------------------------------------------"
        usage
   credentials="$2" fi
    check_screen_or_tmux
fi

# If swarm_ip is shiftnot 2provided, ;;try using        -i|--log.level)
       SCSP_HOST environment variable
if [[ -z "$swarm_ip" ]]; then
    if [[ -n "$new$SCSP_log_levelHOST" ]]; then
        swarm_ip="$SCSP_HOST"
       echo debug_msg "Error:Using OptionsSwarm -iIP (cluster log leve) and -L (node log level) cannot be used together."from SCSP_HOST: $swarm_ip"
    else
        echo "Error: swarm_ip not provided and SCSP_HOST is not set."
  usage      usage
     fi
fi

# Check if required arguments are provided
if [[ -z "$credentials" if [[ ${|| -z "$new_log_level_names[$2]}" ]]; then
    usage
fi

# Split the swarm_ip into an array of IP addresses if it contains delimiters
IFS=';, ' read -r -a new_log_level=${log_level_names[$2]}
            elif [[ ${log_levels[$2]}ip_array <<< "$swarm_ip"

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

    # # Capture   the original command as executed by exitthe 1user
    # ORIGINAL_INPUT=$(ps -o args= -p $$)
  fi  # debug_msg "ORIGINAL_INPUT: $ORIGINAL_INPUT"

    #  new_log_level_name=${log_levels[$new_log_level]}
     Check if credentials contain a colon (username:password format)
    if  log_level_type="cluster[[ "$CREDENTIALS" == *":"* ]]; then
        default_log_level=30
    debug_msg "Checking for colon in credentials..."
        debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)Credentials contain colon"
            shift 2USERNAME="${CREDENTIALS%%:*}"
        PASSWORD="${CREDENTIALS#*:}"
     ;;   debug_msg "Username: $USERNAME"
   -L|--node.log.level)     debug_msg "Password: $PASSWORD"

    if [[ -n "$new_log_level" ]]; then
      # Define special characters that may cause issues
        debug_msg "Defining echospecial "Error: Options -i (cluster log leve) and -L (node log level) cannot be used together."characters..."
        SPECIAL_CHARS="!@#\$%^&*()_+{}|:<>?~\`-=[]\\;',./\""
        debug_msg "Special characters: $SPECIAL_CHARS"

   usage     # Debug: Show the final regex pattern
  fi      debug_msg "Special characters regex: $SPECIAL_REGEX"

 if [[ ${log_level_names[$2]} ]]; then   # Check if password start with '$'
       new_log_level=${log_level_names[$2]}
 #    When credentials contains ":" and password is empty
elif [[ ${log_levels[$2]} || $2 -eq 0 ]]; then#    it will be treated as environment variable 
     new_log_level=$2   #    Bash will try to expand the variable and if  new_log_level_name="default"
 it starts with '$'
        if [[ else-z "$PASSWORD" ]]; then
             echodebug_msg "InvalidPassword logis level: $2"
       empty, bash may interpret the password as an environment variable."
        exit 1   echo -e ""
       fi     echo -e "${RED}Error${RESET}: Password cannot start   new_log_level_name=${log_levels[$new_log_level]}with '${BOLD_YELLOW}\$'${RESET}."
            log_level_type="node"
       echo -e "Bash may interpret the password as an environment variable."
     default_log_level=0       echo -e "To prevent issues, enclose debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)the password in single quotes (${BOLD_YELLOW}'${RESET})."
            shiftecho 2-e "Example: ${BOLD_YELLOW}'${RESET}${GREEN}admin:\$password123${RESET}${BOLD_YELLOW}'${RESET}"
          ;;  echo -e ""
    -t|--time)        exit 1
    if [[ -n "$2" &&fi
"$2" != -* && "$2" -gt 0 ]]; then
        # Validate credentials
     duration="$2"   check_credentials "$CREDENTIALS" "${ip_array[0]}"
        if [[  debug_msg "Set duration to $duration"$? -ne 0 ]]; then
            debug_msg "Invalid credentials. Please check shiftyour 2username and password."
          else  echo -e ""
            echo -e "Error${RED}Error${RESET}: DurationInvalid mustcredentials. bePlease acheck numberyour greaterusername thanand 0password."
            echo -e "If your password exitcontains 1special characters, enclose it in single quotes (${BOLD_YELLOW}'${RESET}) to prevent misinterpretation by the fisystem."
            ;;echo -e "${GREEN}Special characters include${RESET}: ${YELLOW}$SPECIAL_CHARS${RESET}"
    -D|--detach) detachable=true; debug_msg "Set detachable to true"; shift ;;echo -e ""
      --debug) debug=true; debug_msg "Set debug to trueecho with-e "${YELLOWGREEN}--debug$Example${RESET}:";
shift ;;         *) usage ;;echo -e "   esac done

debug_msg "Set log_level_type to ${YELLOW}$log_level_type$-p ${BOLD_YELLOW}'${RESET}${GREEN}admin:password!@#${RESET}${BOLD_YELLOW}'${RESET}"
 # Set default values if not provided debug_msg "Checking for default logecho 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-e ""
            exit 1
        fi
        debug_msg "Validate credentials"
     if [[ "$log_level_type" credentials==$CREDENTIALS
 "node" ]]; then else
       # new_log_level=0debug_msg "Credentials do not contain password"
        debug_msg "Checing node default log level "Username: $(print_credentials "$CREDENTIALS")"
        USERNAME="$CREDENTIALS"
        default_log_level=0# Prompt for password
        ifwhile [[ $new_log_level == 30$ATTEMPTS -lt $MAX_RETRIES ]]; do
     then       echo ""
    new_log_level=$default_log_level        read -sp "Enter password for  new_log_level_name="default"
user $USERNAME: " PASSWORD
       fi     echo ""
  debug_msg "node - new_log_level: to $new_log_level"     echo ""
  debug_msg "node - new_log_level_name: to $new_log_level_name"     elifif [[ "$log_level_type" == "cluster-z "$PASSWORD" ]]; then
        default_log_level=30     fi     debug_msg "New log level: ${GREEN}$new_log_level${RESET}echo -e "${RED}Error${RESET}: Password cannot be empty."
    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((ATTEMPTS++))
                continue
        check_screen_or_tmux fi  # Iffi
swarm_ip is not provided, try using SCSP_HOST environment variable if [[ -z "$swarm_ip" ]]; thenCREDENTIALS="$USERNAME:$PASSWORD"
          if [[ -n "$SCSP_HOST" ]]; then debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
            swarm_ip="$SCSP_HOSTcheck_credentials "$CREDENTIALS" "${ip_array[0]}"
        debug_msg  "Using Swarm IPif from SCSP_HOST: $swarm_ip"
    else[[ $? -eq 0 ]]; then
          echo "Error: swarm_ip not provided and SCSPdebug_HOSTmsg is not set."CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
        usage       fi fidebug_msg "Valid #credentials"
 Check if required arguments are provided if [[ -z "$credentials" || -z "$new_log_level" ]]; then credentials=$CREDENTIALS
   usage fi  # Split the swarm_ip into an array of IP addresses ifbreak
it contains delimiters IFS=';, ' read -r -a ip_array <<< "$swarm_ip"  #else
Validate credentials before proceeding debug_msg "Validating credentials..." #if [[ "$credentials" =~ ^[^:]+$ ]]; then
if [[ -n "$credentials" ]]; then      echo -e ""
        CREDENTIALS="$credentials"     ATTEMPT=$MAX_RETRIES   echo -e USERNAME=""${RED}Error${RESET}: Invalid credentials. Please check your username and password."
    PASSWORD=""     debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS")"    echo debug_msg-e "ATTEMPT: $ATTEMPT"
     # Check if credentials contain a colon (username:password format)fi
     debug_msg "Checking for colon in credentials..."  ((ATTEMPTS++))
  if [[ "$CREDENTIALS" == *":"* ]]; thendone
        debug_msg "Credentials contain colon"
  if [[ $ATTEMPTS -ge $MAX_RETRIES ]]; then
     USERNAME="${CREDENTIALS%%:*}"       echo -e PASSWORD="${CREDENTIALS#*:}"
         # Validate credentials echo -e "${RED}Error${RESET}: Maximum number of password  check_credentials "$CREDENTIALS" "${ip_array[0]}"attempts reached. Exiting script."
         if [[ $? -neexit 01
]]; then       fi
    fi
debug_msgelse
"Invalid credentials. Please check yourif username! and password."
 check_credentials "$credentials" "${ip_array[0]}"; then
          echo -e ""
            echo -e "${REDYELLOW}Error$Warning${RESET}: Invalid credentials. Please check your username and password."
${RED}Invalid credentials${RESET}."
           echo -e ""
        exit 1
  exit 1 fi
fi

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

# Prompt for password
        while if [[ $ATTEMPTS -lt $MAX_RETRIESz "$clusterName" ]]; do
 then
          echo ""Failed to retrieve the cluster name. Please check      read -sp "Enter password for user $USERNAME: " PASSWORDyour inputs."
    exit 1
       echo ""
            echo ""fi
debug_msg "Cluster Name: $clusterName"

# Main logic function to run the script tasks
main_script() {
    local swarm_ip="$1"
    local  CREDENTIALScredentials="$USERNAME:$PASSWORD$2"
    local new_log_level="$3"
    local  debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"new_log_level_name="$4"
    local duration="$5"
    local  check_credentials "$CREDENTIALS" "${ip_array[0]}"log_level_type="$6"
    #local log_file="/var/log/datacore/castor.log"
       if [[ $? -eq 0z "$log_file" ]]; then
        log_file=$(determine_log_file)
    fi
    local   debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
   initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
    local current_log_level
      debug_msg "Valid credentialslocal clusterName="$7"
    local jq_or_grep="$8"
          credentials=$CREDENTIALSlocal detachable="$9"
    if [[ "$detachable" ]]; then
       break local debug="${10}"
        eval  else
    "$(echo "${11}" | sed 's/declare -A/declare -A/')"
        eval   "$(echo -e ""${12}" | sed     's/declare -A/declare -A/')"
    fi
    echo -e "${RED}Error${RESET}: Invalid credentials. Please check your username and password.local default_log_levels="$13"
    local default_log_levels_name="$14"
    debug_msg "**********************************************************"
    debug_msg "local fivariables"
    debug_msg "Log Level Type:     ((ATTEMPTS++))${GREEN}$log_level_type${RESET}"
    debug_msg "Default Log Level: ${GREEN}$default_log_level${RESET}"
 done   debug_msg "Swarm fi
elseIP: $swarm_ip"
    if ! checkdebug_msg "Credentials: $(print_credentials "$credentials")"
"${ip_array[0]}"; then    debug_msg "New Log Level: $new_log_level"
    debug_msg "New log Level  echo -e ""Name: $new_log_level_name"
    debug_msg "Duration: $duration"
   echo -e "${YELLOW}Warning${RESET}: ${RED}Invalid credentials${RESET}.debug_msg "Log File: $log_file"
    debug_msg "Initial Log File echo -e ""Size: $initial_size"
    debug_msg "Current Log  exit 1Level: $current_log_level"
    debug_msg fi"Cluster fiName: $clusterName"
# Retrieve cluster name and handle JSON parsing using the first IP addressdebug_msg "jq_or_grep: $jq_or_grep"
    debug_msg "RetrievingDetach: the$detachable"
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}"
        eval "$(echo "${11}" | sed 's/declare -A/declare -A/')"
        eval "$(echo "${12}" | sed 's/declare -A/declare -A/')"
    fi
    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 information
    if [[ "$log_level_type" == "cluster" ]]; then
        echo -e "Swarm IP: ${GREEN}${ip_array[0]}${RESET}"
    elsedebug_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}"
    else
        echo -e "Swarm IPs: ${GREEN}${ip_array[*]}${RESET}"
    fi
    # echo -e "Swarm IP: ${GREEN}$swarm_ip${RESET}"
    debug_msg "Credentials: ${GREEN}[hidden for security]${RESET}"
    echo -e "Cluster Name: ${GREEN}$clusterName${RESET}"

    debug_msg "Starting main_script function..."
    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 "Default log level: $default_log_level"
    debug_msg "Default log level name: $default_log_level_name"

    if [[ $log_level_type == "cluster" ]]; then
        debug_msg "Setting cluster log level to $new_log_level ($new_log_level_name)"
        # Retrieve current log level
        if [[ "$jq_or_grep" == "grep" ]]; then
            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]+')
        else
            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]}
        if [[ $current_log_level == 30 ]]; then
            current_log_level_name="default"
        fi
        if [[ $new_log_level == 30 ]]; then
            new_log_level_name="default"
        fi
        debug_msg "Current cluster log level: ${BOLD_GREEN}$current_log_level${RESET}"
        debug_msg "Current log level name: ${BOLD_GREEN}$current_log_level_name${RESET}"
        echo -e "Swarm IPs: ${GREEN}${ip_array[*]}${RESET}"
 
  fi     # echo -e "Swarm IPNew cluster log level: ${BOLD_GREEN}$swarm_ip$$new_log_level_name${RESET}"
    debug_msg "Credentials:  (${BOLD_GREEN}[hidden for security]$$new_log_level${RESET})"
        echo -e "Cluster Name: ${GREEN}$clusterName${RESET}Current cluster log level is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."

    debug_msg "Starting main_script function..." # Skip update if debug_msg "Log level type: $log_level_type"

    # Store the original log levels
    declare -A original_log_levels
    declare -A original_log_level_namesnew level matches the current level
        if [[ "$current_log_level" -eq "$new_log_level" ]]; then
          if [[ $log_level_type == "cluster" ]]; then echo ""
            echo debug_msg-e "SettingCluster cluster log level is already set to ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level_name)"level${RESET}). No changes made."
            return
     #   fi
Retrieve
current log level      # Update the ifcluster [[ "$jq_or_grep" == "grep" ]]; thenlog level using PUT
        debug_msg "Updating cluster log level to current$new_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]+')
_name"
        debug_msg "Cluster Name: $clusterName"
       else debug_msg "Credentials: $(print_credentials "$credentials")"
        current_log_level=$(curl --user "$credentials" -sS debug_msg "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 "$jq_or_grep" -r '.value')
        fi\"{\\\"value\\\": $new_log_level}\""
        response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
            current_log_level_name="http://${logip_levels[$current_log_level]}array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
         debug_msg "Current cluster log level: ${BOLD_GREEN}$current_log_level${RESET}"-d "{\"value\": $new_log_level}")
        debug_msg "CurrentResponse: log$response"
level
name: ${BOLD_GREEN}$current_log_level_name${RESET}"       if  echo -e[[ "$jq_or_grep" == "grep" ]]; then
      echo -e "New cluster log level: ${BOLD_GREEN}$new updated_log_level_name${RESET}"=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
        echo -e "Current cluster log level is ${GREEN}$currentelse
            updated_log_level_name.${RESET}"=$(echo "$response" | "$jq_or_grep" -r '.value')
        fi
    # Skip update if new level matches the current leveldebug_msg "Updated cluster log level: $updated_log_level"

        if [[ "$current$updated_log_level" -eq "$new_log_level" ]]; then
            echo ""
            echo -e "Cluster log${GREEN}$(timestamp)${RESET} Log level ischanged alreadysuccessfully setfrom to ${BOLD_GREEN}$new$current_log_level_name${RESET}. No changes made."
            return
        fi (${BOLD_GREEN}$current_log_level${RESET}) -> ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})."
        else
# Update the cluster log level using PUT     echo -e "${GREEN}$(timestamp)${RESET} Failed debug_msg "Updating clusterto update log level to $new_log_level_name"
        debug_msg "Cluster Name: $clusterName. Response: ${RED}$response${RESET}"
        debug_msg "Credentials: $(print_credentials "$credentials")" exit  1
     debug_msg "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}\""
        response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
            "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \ fi

        # Countdown and revert log level
        if [[ -n "$duration" && "$duration" -gt 0 ]]; then
            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}) ..."
            echo -de "{\"value\":
$new_log_level}")         debug_msg "Response: $response" for ((i=duration; i>0; i--)); do
    if [[ "$jq_or_grep" == "grep" ]]; then      printf -v countdown     updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
   "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))
    else             updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')-ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"
        fi        sleep debug_msg1
"Updated cluster log level: $updated_log_level"        done
 if [[ "$updated_log_level" -eq "$new_log_level" ]]; then             echo -e "${GREEN}$(timestamp)${RESET} Log\n\nTime's up! Reverting log level changedback successfullyto from ${GREEN}$current_log_level_level$name${RESET} -> (${BOLD_GREEN}$new$current_log_level${RESET}) ..."


      else      # Revert the log level back to echothe -e "${GREEN}$(timestamp)${RESET} Failed to update log level. Response: ${RED}$response${RESET}"original value
            # echo -e "Level log revert on exit$(timestamp)"
1         fi   response=$(curl --user "$credentials" -sS -X PUT  # Countdown and revert log level-H "Content-Type: application/json" \
           if [[ -n "$duration" && "$duration" -gt 0 ]]; then "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
               echo -e "Keeping log level at ${YELLOW}$newd "{\"value\": $current_log_level_name${RESET}")
for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."       debug_msg "Response: $response"

  echo -e ""        if [[ "$jq_or_grep" ==  for ((i=duration; i>0; i--)); do"grep" ]]; then
                reverted_log_level=$(echo "$response" | printfgrep -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))oP '"value":\s*\K[0-9]+')
            else
                reverted_log_level=$(echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r""$response" | "$jq_or_grep" -r '.value')
            fi
   sleep 1        debug_msg "Reverted cluster log  donelevel: $reverted_log_level"

            echofinal_size=$(stat -e "\n\nTime's up! Reverting log level back to ${GREEN}$current_log_level${RESET}..."c%s "$log_file" 2>/dev/null || echo 0)
            debug_msg "Initial log file size: $initial_size"
 # Revert the log level back to the original value  debug_msg "Final log file size: $final_size"
     # echo -e "Level log revert on size_diff=$(timestamp)"( final_size - initial_size ))
            responsesize_diff_formatted=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
   format_size "$size_diff")
            duration_formatted=$(format_duration "$duration")
	    if (( size_diff < 0 )); then
		echo  "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
  -e "castor.log file was rotated."
	    else
            echo -de "{\"value\":
$current_log_level}")            echo debug_msg-e "Response: $response"

            if [[ "$jq_or_grep" == "grep" ]]; then
   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}). Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})."
            reverted_log_level=$(echo "$response" | grep -oPe '"value":\s*\K[0-9]+')

	    fi
       else if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then
         reverted_log_level=$(echo "$response" | "$jq_or_grep" echo -r '.value')
       e "${GREEN}$(timestamp)${RESET} Log level reverted successfully back to ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."
    fi        echo -e ""
  debug_msg "Reverted cluster log level: $reverted_log_level" else
            final_size=$(statecho -c%s "$log_file" 2>/dev/null || echo 0)
  e "${GREEN}$(timestamp)${RESET} Failed to revert log level. Response: ${RED}$response${RESET}"
         debug_msg "Initial log fileecho size: $initial_size-e ""
            debug_msg "Final log file size: $final_size"exit 1
        fi
       size_diff=$(( final_size - initial_size )) else
            echo   size_diff_formatted=$(format_size "$size_diff")-e "${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified."
        fi
    elif  duration_formatted=$(format_duration "$duration")
	[[ "$log_level_type" == "node" ]]; then
     if (( size_diff <# 0 )); then
		echo -e "castor.log file was rotated."
	First loop: Change the node log level
      else  local same_log_level=false
        for echoip -ein "${ip_array[@]}"; do
            # Retrieve current node echo -e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${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})."log level
            debug_msg "Retrieving current node log level for IP: $ip"
            debug_msg "curl -s  echo -e ""
	-u \"$(print_credentials "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\""
     fi       current_log_level=$(curl -s if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then-u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value')
            echo -e "${GREEN}$(timestamp)${RESET} Logdebug_msg "Current log level revertedfor successfullyIP back to ${BOLD_GREEN}$ip: $current_log_level${RESET}.level"
            echo -e ""original_log_levels["$ip"]=$current_log_level
        else             echo -e "${GREEN}$(timestamp)${RESET} Failed to revertdebug_msg "Original log level. Response: ${RED}$response${RESET}"
            echo -e "for IP $ip: ${original_log_levels["$ip"]}"
            exitif 1
    [[ "$current_log_level" == "0" ]]; then
   fi         else    current_log_level_name="default"
        echo "$(timestamp) Log level change iselse
permanent until manually modified."         fi     elif [[ "$logcurrent_log_level_type" == "node" ]]; thenname=${log_levels[$current_log_level]}
         # First loop: Changefi
the node log level         local sameoriginal_log_level=false_names["$ip"]=$current_log_level_name
          for ip indebug_msg "Original log level name: ${ip_array[@original_log_level_names["$ip"]}";
do            if # Retrieve current node log level[[ "$new_log_level" == "0" ]]; then
            debug_msg "Retrieving current node new_log level for IP: $ip_level_name="default"
            debug_msgelse
"curl -s -u \"$(print_credentials "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\""             currentnew_log_level_name=$(curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value'){log_levels[$new_log_level]}
            fi
            debug_msg "Current log level for IP $ip: $current_log_level ($current_log_level_name)"
            original_log_levels["$ip"]=$current_log_levelecho ""
            echo -e "New node log level: ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})"
            debug_msgecho -e "OriginalCurrent node log level for IP $ip: ${original_log_levels["$ip"]}"${BOLD_GREEN}$ip${RESET} is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."

            # Skip update if [[ "$current_log_level" == "0" ]]; thennew level matches the current level
            if [[ "$current_log_level" -eq current"$new_log_level_name="default" ]]; then
          else                 currentsame_log_level_name=${log_levels[$current_log_level]}=true
            fi             original_log_level_names["$ip"]=$current_log_level_nameecho ""
            debug_msg "Original log level name: ${original_log_level_names["$ip"]}"    echo -e "Node log level for IP ${BOLD_GREEN}$ip${RESET} is if [[ "already set to ${BOLD_GREEN}$new_log_level" == "0" ]]; then_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). No changes made."
                new_log_level_name="default"continue
            else
                newsame_log_level_name=${log_levels[$new_log_level]}=false
            fi

           debug_msg "Currentif log level for IP $ip: $current[[ "$same_log_level ($current_log_level_name)" == false ]]; then
        echo ""             echo -e "New# Update the node log level: ${BOLD_GREEN}$new_log_level_name${RESET}" using PUT
               echo -edebug_msg "CurrentUpdating node log level for IP ${BOLD_GREEN}$ip${RESET} is ${GREEN}$currentto $new_log_level_name.${RESET}" for IP $ip..."
          # Skip update if new level matches the current level
            if [[ "$current_log_level" -eq "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\""
]]; then                 same_log_level=true
                echo ""
      response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
         echo -e "Node log level for IP ${BOLD_GREEN}$ip${RESET} is already set to ${BOLD_GREEN} "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level_name${RESET}. No changes made."")
                continue
         debug_msg "Response: $response"

 else               if [[ same"$jq_log_level=false
   or_grep" == "grep" ]]; then
        fi              if [[ "$sameupdated_log_level=$(echo " == false ]]; then$response" | grep -oP '"value":\s*\K[0-9]+')
                else
 # Update the node log level using PUT            updated_log_level=$(echo "$response" | "$jq_or_grep"  debug_msg "Updating node log level to $new_log_level_name for IP $ip..."-r '.value')
                fi
        debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -Hdebug_msg \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level\"""Updated log level for IP $ip: $updated_log_level"

                response=$(curl --user "$credentialsif [[ "$updated_log_level" -sS -X PUT -H "Content-Type: application/json" \eq "$new_log_level" ]]; then
                    echo  "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level")
                debug_msg "Response: $response"-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})."
                  if [[ "$jq_or_grep" == "grep" ]]; thenelse
                    updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
          -e "${GREEN}$(timestamp)${RESET} Failed to update node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"
     else               exit 1
    updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')            fi
          fi  fi
        done

    debug_msg "Updated log level for# IPSecond $iploop: $updated_log_level"

      Countdown if duration is provided
         if [[ "$updated$same_log_level" -eq "$new_log_level"== false ]]; then
                    echo -e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} changed successfully from ${GREEN}$current_log_level_name${RESET} -> ${BOLD_GREEN}$new_log_level_name${RESET}."
  \
            if [[ -n "$duration" && "$duration" -gt 0 ]]; then
             else   echo -e ""
                echo -e "${GREEN}$(timestamp)${RESET} Failed to update node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}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}) ..."
                echo -e ""
 exit 1              for ((i=duration;  fii>0; i--)); do
            fi        printf done-v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))
# Second loop: Countdown if duration is provided         if [[ "$same_log_level" == false ]]; then\
 echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"
          if [[ -n "$duration" && "$duration" -gt 0 ]]; then sleep 1
              echo -e ""done
                echo -e "Keeping node(s) log level at ${YELLOW}$new_log_level_name${RESET} for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) \n\nTime's up! Reverting node log level back to original levels..."

               echo -e# ""Third loop: Revert the node log level
          for ((i=duration; i>0; i--)); do  for ip in "${ip_array[@]}"; do
              printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) current_log_level=${original_log_levels["$ip"]}
                    echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"current_log_level_name=${original_log_level_names["$ip"]}
                    debug_msg sleep"Reverting 1node log level back to $current_log_level_name for IP $ip..."
        done            debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X echoPUT -eH \"\n\nTime's up! Reverting node log level back to original levels..."Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\""
                     # Thirdecho loop: Revert the node log level
    -e "Node level log revert on $(timestamp) for IP $ip"
           for ip in "${ip_array[@]}"; do     response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
      current_log_level=${original_log_levels["$ip"]}                     current_log_level_name=${original"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level_names["$ip"]}")
                    debug_msg "RevertingResponse: node$response"
log
level back to $current_log_level_name for IP $ip..."              if [[ "$jq_or_grep" == "grep"   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\""
    ]]; then
                        reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
               # echo -e "Node level logelse
revert on $(timestamp) for IP $ip"                     responsereverted_log_level=$(curlecho --user "$credentials$response" -sS -X PUT -H "Content-Type: application/json" \
| "$jq_or_grep" -r '.value')
                    fi

 "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level")                   final_size=$(stat -c%s debug"$log_msg file"Response: $response"

  2>/dev/null || echo 0)
                  if [[ "$jq_or_grep" == "grep" ]]; then
  size_diff=$(( final_size - initial_size ))
                     reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')debug_msg "Initial log file size: $initial_size"
                    debug_msg else"Final log file size: $final_size"
                    revertedsize_logdiff_levelformatted=$(echoformat_size "$response$size_diff")
| "$jq_or_grep" -r '.value')                 duration_formatted=$(format_duration "$duration")

 fi                   if   final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)[[ "$reverted_log_level" -eq "$current_log_level" ]]; then
                        echo  size_diff=$(( final_size - initial_size ))-e "${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})."
                    debug_msgelse
"Initial log file size: $initial_size"                    echo debug_msg "Final log file size: $final_size-e "${GREEN}$(timestamp)${RESET} Failed to revert node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"
                    size_diff_formatted=$(format_size "$size_diff")   exit 1
                duration_formatted=$(format_duration "$duration")   fi
                done

if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then          # Combine the log output for multiple IP addresses into a single summary
  echo -e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} reverted successfullyif back to ${BOLD_GREEN}${current_log_level_name}${RESET}."
            (( size_diff < 0 )); then
       else     echo -e "castor.log file was rotated."
            else
 echo -e "${GREEN}$(timestamp)${RESET} Failed to revert node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"      echo -e ""
                exit 1   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 fisize        is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})."
        done            echo -e ""
   # Combine the log output for multiple IP addresses into afi
single summary           else
 if (( size_diff < 0 )); then             echo -e "castor.log file was rotated."
    ${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified."
       else     fi
        fi
    fi
}
echo
-e# ""Run in detachable or directly
if $detachable; then
    # Pass the main_script function to    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 ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})."
                    echo -e ""
            fi
            else
                echo "${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 "**********************************************************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 "Detach   mode - ParametersCurrent passedLog to main_script:Level: $current_log_level" | tee -a "$output_log"
    debug_msg "     SwarmCluster IPName: $swarm_ip$clusterName" | tee -a "$output_log"
    debug_msg "     Credentialsjq_or_grep: $(print_credentials "$credentials")"  $jq_or_grep" | tee -a "$output_log"
    debug_msg "     New Log LevelDetach: $new_log_level$detachable" | tee -a "$output_log"
    debug_msg "     Debug: $debug" | New log Level Name: $new_log_level_nametee -a "$output_log"
    debug_msg "**********************************************************" | tee -a "$output_log"

   debug_msg "# Convert associative arrays to Duration:strings $duration"and |pass teethem -a "$output_log"
 to the screen session
  debug_msg "     Log Level Type: $log_level_type" | tee -a "$output_log"log_levels_string=$(declare -p log_levels)
    debug_msg "     Log File: $log_file" | tee -a "$output_log"log_level_names_string=$(declare -p log_level_names)
    debug_msg "     Initial Log File Size: $initial_sizelog_levels_string: $log_levels_string" | tee -a "$output_log"
    debug_msg "     Current Log Level: $current_log_levellog_level_names_string: $log_level_names_string" | tee -a "$output_log"

   debug_msg "     Cluster Name: $clusterName if command -v screen &>/dev/null; then
        echo -e "Running in ${YELLOW}screen${RESET} detachable mode..." | tee -a "$output_log"
    debug_msg "   screen -dmS jqcastor_orlog_grep: $jq_or_grep" | tee -a "$output_log"
   script bash -c "$(declare -f main_script timestamp 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 toformat_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 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"

    ifdisplay the output log
        sleep 1
        while screen -list | grep -q "castor_log_script"; do
            sleep 1
        done
    elif command -v screentmux &>/dev/null; then
        echo -e "Running in ${YELLOW}screen$tmux${RESET} detachable mode..." | tee -a "$output_log"" > "$output_log"  # Truncate log file to remove old entries

        # Create a temp script file
        temp_script="$SCRIPTDIR/castor_log_script.sh"

        # Write the script to a file to avoid printing function definitions
        cat screen<<EOF -dmS> castor"$temp_log_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"                    # Remove the script file
tmux screenkill-session -rt castor_log_script
EOF

        # Wait for the screen session to complete and then display the output log
        sleep 1
 Ensure the script is executable
        chmod +x "$temp_script"

        # Start tmux session and execute the script inside
       while screentmux new-listsession |-d grep -qs "castor_log_script "; dobash $temp_script"

        # Attach session sleeponly 1if it's still running
     done   while tmux elifhas-session command -v tmux &>t castor_log_script 2>/dev/null; then
        echo -e "Running in ${YELLOW}tmux${RESET} detachable mode..." | tee -a "$output_log"do
            tmux newattach-session -dt -s 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}\" | tee \"$output_log\""
   
        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

...