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 grep 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.

Requirements

  • jq (optional): Used for parsing JSON responses; falls back to grep if unavailable.

  • screen or tmux (optional): Required for background execution.

  • Permissions: Ensure sufficient permissions to execute on the DataCore Swarm server and access required files.

...

Code Block
./castor-change-log-level.sh -d <node_ip> -p <admin:password> [-i <newnew_log_level | -L new_node_log_level>level] [-t <duration_in_seconds>] [-D --detach] [-v]

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. Secure password entry is prompted if not provided.

-i, --log.level

New log level to set (values: 5, 10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default).

-t, L --time

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

--detach

Runs the node.log.level

New node log level to set (values: 0, 5, 10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default).

-t, --time

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

-D, --detach

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

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 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 --detachD

Running the Script at a Specific Time

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:

...

Ensure the at service is installed, enabled and running

Code Block
dnf -y install at atd
systemctl enable --now at

Schedule the script execution using at:

...

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

...

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.

...

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.

Example Output

Code Block
[root@scs dist]# ./castor-change-log-level.sh -p admin:datacore -i 10 -t 300
Swarm IP: 192.168.1.84
Credentials: [hidden for security]
Cluster Name: gatewayadmindomain

New log level: 10
Current log level is 30.
Updating log level to 10...
Log level changed successfully from 30 → 10.
Keeping log level at 10 for 300 second(s)...
Countdown: 00:00:01 remaining...

Time's up! Reverting log level back to 30...
Approximate 69.4MB new logs were generated at log level 10. Current castor.log size is 371.3MB after 00:05:00.
Log level reverted successfully back to 30.

[root@scs dist]#

Error Handling

...

Missing Parameters: Missing parameters prompt a usage message.

...

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

    Code Block

...

atq
7	Sun Feb 16 03:00:00 2025 a root

...

To remove a scheduled job (replace JOB_ID with the actual job number from atq output):

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

    Code Block
    echo "/root/dist/castor-change-log-level.sh -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

This schedules the script to run at 3:00 AM on Feb 16 2025 and collects log at debug level for 1 hour.

  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

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.

Example Output

Code Block
[root@scs dist]# ./castor-change-log-level.sh -p admin:datacore -i 10 -t 300
Swarm IP: 192.168.1.84
Cluster Name: msuen-scs1.suen.work

New log level: debug
Current log level is default.
2025-03-02T05:15:49.901Z Log level changed successfully from 30 → 10.
Keeping log level at debug for 300 second (00:05:00) ...
Countdown: 00:00:01 remaining...

Time's up! Reverting log level back to 30...
Approximate 88.9MB new logs were generated at log level 10. Current castor.log size is 371.3MB after 300 seconds (00:05:00).
2025-03-02T05:20:50.483Z Log level reverted successfully back to 30.

[root@scs dist]#

Error Handling

  • Missing Parameters: Missing parameters prompt a usage message.

  • Invalid Log Levels: If an unsupported log level is specified, the script will prompt the user to enter a valid value.

  • Invalid Duration: If a non-numeric duration is provided, you’re prompted to enter a valid duration in seconds.

  • Connection Issues: If unable to connect to the Swarm API, check the IP, credentials, and network access.

...

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 "                           If multiple IPs are provided, the script will update the log level for all nodes."
    echo "-

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

SCRIPT_NAME=$(basename "$0")

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

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

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

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

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

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

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

# Function to display debug messages if debug mode is enabled
debug_msg() {
    if $debug; then
        local caller_func=${FUNCNAME[1]:-main}                  # Fallback to "unknown" if empty
          (Alternatively, set the SCSP_HOST environment variable to the Swarm IP.)"
    echo "  -p, --credentialslocal caller_line=${BASH_LINENO[0]:-unknown}            # Fallback to "unknown" if empty
        Credentialsecho in the format admin:password-e "$(timestamp) [DEBUG] ($caller_func:$caller_line) $*"
    echofi
"}

-i, --log.level          New cluster log level to set (5, 10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default)"# 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 " echo -L, --node.log.levele ""
    New node log level toecho set (0, 5, 10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default)"
    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 **Either -i or -L must be specified, but not both.**"run the script in a detachable session."
     echo  " echo -t, --timee "---------------------------------------------------------------------------------------"
        detachable=false  # Disable detachable session
(Optional) Duration in seconds to keep the new logusage
level (must be greater thanfi
0)"}

# Function to echoformat "file  -D, --detachsize
format_size() {
    local  size=$1
    if (Optional)( Detachsize the>= script1073741824 from the current terminal and run in a detachable session using screen or tmux"
    echo ""
    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="" )); 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 # Default password"$JQLOCATION" ]]; then
 # 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
 jq_or_grep=$JQLOCATION
else
    jq_or_grep=$(check_jq)
fi
debug_msg "jq_or_grep: $jq_or_grep"
#jq_or_grep=$(check_jq)

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

log_file=$(determine_log_file)

# Function to getcheck if thecredentials currentare timestampvalid
timestampcheck_credentials() {
    date -u +"%Y-%m-%dT%H:%M:%S.%3NZ"
}

# Function to display debug messages if debug mode is enabled
debug_msg() {local CREDENTIALS="$1"
    local SWARM_IP="$2"
    debug_msg "Credentials: [hidden for security]"
    debug_msg "Swarm IP: $SWARM_IP"

    if# $debug;API thenendpoint for validating user credentials
    local callerVALIDATE_lineURL="http://${BASH_LINENO[0]:-unknown}  # Fallback to "unknown" if emptySWARM_IP}:91/api/validateUser"
    debug_msg "Validate URL: $VALIDATE_URL"

    # Make the API echorequest
-e "$(timestamp) [DEBUG] (Line $callerdebug_line)msg $*"Validating user credentials..."
  fi } debug_msg #"curl Function-s 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 "---------------------------------------------------------------------------------------"
-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
       echo -edebug_msg "Authentication successful for user '${YELLOW}Warning${RESET}: Neither '${BOLD_GREEN}screen${RESET}' nor '${BOLD_GREEN}tmux${RESET}' is installed. Cannot run in detachable mode."
 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
 echo -e "  Please install either '${BOLD_GREEN}screen${RESET}' or '${BOLD_GREEN}tmux${RESET}'debug_msg "Error: Unable to runvalidate thecredentials. scriptPlease incheck ayour detachable sessioninputs."
        return 1  # echoFailure
-e "---------------------------------------------------------------------------------------"   fi
}

# Function to print echocredentials -e ""hide password
print_credentials() {
    local detachableCREDENTIALS=false"$1"
 # Disable detachable session
local USERNAME="${CREDENTIALS%%:*}"
    echo   debug_msg "detachable=${YELLOW}false$-e "${GREEN}$USERNAME${RESET}":"${GREEN}********${RESET}"
}

# Parse input arguments
while [[ debug_msg "Stopping the script..."$#" -gt 0 ]]; do
    exitcase 1$1 in
   fi }  # Function to format file size
format_size() {
    local size=$1
 -d|--swarm_ip) swarm_ip="$2"; debug_msg "Set swarm_ip to $swarm_ip"; shift 2 ;;
   if (( size >= 1073741824 )); then-p|--credentials)
         echo "$(awk "BEGIN {printf \"%.1fGB\", $size/1073741824}")" credentials="$2"
     elif (( size >= 1048576 )); then shift 2 ;;
     echo "$(awk "BEGIN {printf \"%.1fMB\", $size/1048576}")" -i|--log.level)
    elif (( size >= 1024 )); then  if       echo "$(awk "BEGIN {printf \"%.1fKB\", $size/1024}")"[[ -n "$new_log_level" ]]; then
       else         echo "${size}B"
    fi
}

# Function to format duration
format_duration() {Error: Options -i (cluster log leve) and -L (node log level) cannot be used together."
       local duration=$1     local hours=$((duration / 3600))usage
    local minutes=$(( (duration % 3600) / 60 )) fi
   local seconds=$((duration % 60))     printf "%02d:%02d:%02dlog_level_type="cluster"
$hours  $minutes $seconds }  # Function to check if jq isif available and set up JSON parsing method
check_jq() {[[ ${log_level_names[$2]} ]]; then
         if [[ -x "/usr/local/bin/jq" ]]; then  new_log_level=${log_level_names[$2]}
      echo "/usr/local/bin/jq"     elif [[ -x"$2" == "$(pwd)/jqdefault" ]]; then
         echo "$(pwd)/jq"       elif command -v jq &>/dev/null; thennew_log_level=${default_log_levels[$log_level_type]}
               echo "jq new_log_level_name="default"
    else         echo "grep"
elif [[ ${log_levels[$2]} ]]; then
   fi }  if [[ -f "$JQLOCATION" ]]; then     jqnew_orlog_greplevel=$JQLOCATION$2
 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() { else
              if [[ -fecho "/var/log/datacore/castor.log" ]]; thenInvalid log level: $2"
           echo "/var/log/datacore/castor.log"    exit elif1
 [[ -f "/var/log/caringo/castor.log" ]]; then       fi
 echo "/var/log/caringo/castor.log"     else     new_log_level_name=${log_levels[$new_log_level]}
   echo "Error: Log file not found in /var/log/datacore/castor.log or /var/log/caringo/castor.log"default_log_level=30
        exit 1   debug_msg  fi
}

log_file=$(determine_log_file)

# Function to check if credentials are valid
check_credentials() {
    local CREDENTIALS="$1""Set new_log_level to $new_log_level ($new_log_level_name)"
            shift 2
       local SWARM_IP="$2"    ;;
debug_msg "Credentials: [hidden for security]"     debug_msg "Swarm IP: $SWARM_IP"-L|--node.log.level)
     # API endpoint for validating user credentials if [[   local VALIDATE_URL="http://${SWARM_IP}:91/api/validateUser"
    debug_msg "Validate URL: $VALIDATE_URL"-n "$new_log_level" ]]; then
     # Make the API request     debug_msg "Validating userecho credentials..."Error: Options -i (cluster log debug_msg "curlleve) and -sL -u \"********\" -X GET \"$VALIDATE_URL\" -H 'Content-Type: application/json'"
    RESPONSE=$(curl -s -u "$CREDENTIALS" -X GET "$VALIDATE_URL" -H 'Content-Type: application/json')(node log level) cannot be used together."
                debug_msgusage
"Validate User Response: $RESPONSE"      # Check if thefi
response contains "isValid": true     if echo "$RESPONSE" | "$jqlog_or_grep" -e '.isValid == true' > /dev/null 2>&1; then
   level_type="node"
            if [[ ${log_level_names[$2]} ]]; then
    debug_msg "Authentication successful for user '${CREDENTIALS%%:*}'"       new_log_level=${log_level_names[$2]}
 return 0  # Success     elif echo "$RESPONSE" | "$jq_or_grep" -e '.isValid == false' > /dev/null 2>&1; thenelif [[ "$2" == "default" ]]; then
           debug_msg "Authentication failed for user '${CREDENTIALS%%:*}'" new_log_level=${default_log_levels[$log_level_type]}
        return 1  # Failure     elsenew_log_level_name="default"
         debug_msg "Error: Unable toelif validate credentials. Please check your inputs."
 [[ ${log_levels[$2]} || $2 -eq 0 ]]; then
      return 1  # Failure     fi
} new_log_level=$2
 # Function to print credentials - hide password print_credentials() {     local CREDENTIALS new_log_level_name="$1default"
    local USERNAME="${CREDENTIALS%%:*}"     echo -e "${GREEN}$USERNAME${RESET}":"${GREEN}********${RESET}"
}

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

debug_msg "Set log_level_type ifto [[ ${logYELLOW}$log_level_names[$2]}type${RESET}"

# Check if 'screen' or 'tmux' is installed
if [[ "$detachable" == true ]]; then
    if [[ -z "$duration" ]]; then
       new_log_level=${log_level_names[$2]}
   echo -e ""
        echo elif [[ ${log_levels[$2]} || $2 -eq 0 ]]; then
                new_log_level=$2-e "---------------------------------------------------------------------------------------"
        echo -e "    ${RED}Error${RESET}: Duration must be specified when running in detachable mode."
        echo -e "    Please  new_log_level_name="default"
     specify the duration using the ${BOLD_GREEN}-t${RESET} or ${BOLD_GREEN}--time${RESET} option."
      else  echo               echo "Invalid log level: $2"-e "---------------------------------------------------------------------------------------"
        usage
    fi
     exit 1
            fi
   check_screen_or_tmux
fi

# If swarm_ip is not provided, try using SCSP_HOST environment variable
if [[ -z "$swarm_ip" ]]; then
        new_log_level_name=${log_levels[$new_log_level]}
            log_level_type="node"
     if [[ -n "$SCSP_HOST" ]]; then
      default_log_level=0    swarm_ip="$SCSP_HOST"
        debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)Using Swarm IP from SCSP_HOST: $swarm_ip"
    else
       shift 2echo "Error: swarm_ip not provided and SCSP_HOST is not set."
   ;;     usage
   -t|--time) fi
fi

# Check if required arguments are   provided
if [[ -nz "$2$credentials" && "$2" != -* && "$2" -gt 0 || -z "$new_log_level" ]]; then
    usage
fi

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

# Validate credentials before proceeding
debug_msg "Set duration to $durationValidating credentials..."
#if [[ "$credentials" =~ ^[^:]+$ ]]; then
if [[ -n "$credentials" ]]; then
   shift 2CREDENTIALS="$credentials"
    ATTEMPT=$MAX_RETRIES
    USERNAME=""
  else  PASSWORD=""
    debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS")"
      echodebug_msg "ErrorATTEMPT: Duration must be a number greater than 0.$ATTEMPT"

    # Check if credentials contain a colon (username:password format)
  exit 1 debug_msg "Checking for colon         fi
in credentials..."
    if [[ "$CREDENTIALS" ==    ;*":"* ]]; then
       -D|--detach) detachable=true; debug_msg "SetCredentials detachablecontain to truecolon";
shift ;;         --debug) debug=true; debug_msg "Set debug to true with ${YELLOW}--debug${RESET}"; shift ;;USERNAME="${CREDENTIALS%%:*}"
        PASSWORD="${CREDENTIALS#*:}"

        # *)Validate usagecredentials
;;     esac done  debugcheck_msgcredentials "Set log_level_type to ${YELLOW}$log_level_type${RESET$CREDENTIALS" "${ip_array[0]}"
 # Set default values if not provided debug_msg "Checking for default log level values..."

# Change the default log level based on Log Level Typeif [[ $? -ne 0 ]]; then
            debug_msg "ChangingInvalid defaultcredentials. logPlease levelcheck basedyour onusername Log Level Type: ${YELLOW}$log_level_type${RESET}"
if [[ -n "$new_log_level" ]]; thenand password."
          if [[ "$log_level_type" == echo -e "node"
]]; then         # new_log_level=0 echo -e "${RED}Error${RESET}: Invalid credentials. Please check your debug_msg "Checing node default log levelusername and password."
        default_log_level=0    echo -e    if [[ $new_log_level == 30 ]]; then""
            exit 1
    new_log_level=$default_log_level    fi
        new_log_level_name="default"debug_msg "Validate credentials"
        credentials=$CREDENTIALS
 fi   else
        debug_msg "nodeCredentials - new_log_level: to $new_log_leveldo not contain password"
        debug_msg "node - new_log_level_name: to $new_log_level_name"Username: $(print_credentials "$CREDENTIALS")"
      elif [[ "$log_level_type" == "cluster" ]]; thenUSERNAME="$CREDENTIALS"
        # Prompt for password
  default_log_level=30     fi while [[ $ATTEMPTS -lt debug_msg "New log level: ${GREEN}$new_log_level${RESET}"$MAX_RETRIES ]]; do
        debug_msg "New log level name: ${GREEN}$new_log_level_name${RESET}"echo ""
     debug_msg "Set default_log_level to: $default_log_level" fi  #read Check-sp if 'screen' or 'tmux' is installed
if [[ "$detachable" == true ]]; then"Enter password for user $USERNAME: " PASSWORD
          check_screen_or_tmux fi echo #""
If swarm_ip is not provided, try using SCSP_HOST environment variable if [[ -zecho "$swarm_ip" ]]; then"
            if [[ -nz "$SCSP_HOST$PASSWORD" ]]; then
        swarm_ip="$SCSP_HOST"        echo debug_msg-e "Using Swarm IP from SCSP_HOST: $swarm_ip${RED}Error${RESET}: Password cannot be empty."
    else         echo "Error: swarm_ip not provided and SCSP_HOST is not set." ((ATTEMPTS++))
              usage  continue
  fi fi  # Check if required arguments are provided iffi
[[ -z "$credentials" || -z "$new_log_level" ]]; then     usage
fiCREDENTIALS="$USERNAME:$PASSWORD"
  # 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" =~ ^[^:]+$ ]]; thendebug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
            check_credentials "$CREDENTIALS" "${ip_array[0]}"
            if [[ $? -neq "$credentials"0 ]]; then
    CREDENTIALS="$credentials"
    ATTEMPT=$MAX_RETRIES
    USERNAME=""     PASSWORD=""     debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
    debug_msg "ATTEMPT: $ATTEMPT"      # Check if credentials contain a colon (username:password format)
    debug_msg "Checking for colon in credentials...Valid credentials"
    if [[ "$CREDENTIALS" == *":"* ]]; then         debug_msg "Credentials contain colon"credentials=$CREDENTIALS
           USERNAME="${CREDENTIALS%%:*}"     break
   PASSWORD="${CREDENTIALS#*:}"         else
# # Check if credentials contains special characters         # debug_msgecho -e "Checking"
  for special characters in credentials..."         # ifecho [[ "$PASSWORD" == *['!@#\$%^\&*()_+''-']* ]]; then-e "${RED}Error${RESET}: Invalid credentials. Please check your username and password."
        #    fi
debug_msg "Credentials contain special characters"        ((ATTEMPTS++))
#     debug_msg "Username: $USERNAME" done
       # if [[ $ATTEMPTS -ge debug$MAX_msg "Password: $PASSWORD"RETRIES ]]; then
        #     echo -e ""
        #     echo -e "${YELLOWRED}Warning$Error${RESET}: PasswordMaximum containsnumber specialof characters.password Pleaseattempts enclosereached. the credentials in single quotes. ('username:password')Exiting script."
        #     echo -e ""
        #     exit 1

       # fi
    fi
else
  # Validate credentialsif !        check_credentials "$CREDENTIALS$credentials" "${ip_array[0]}"; then
        if [[ $? -ne 0 ]]; thenecho -e ""
        echo -e "${YELLOW}Warning${RESET}: ${RED}Invalid credentials${RESET}."
        echo -e ""
   debug_msg "Invalid credentials. Please check yourexit username1
and password."   fi
fi

# Retrieve cluster name and handle JSON echoparsing -eusing ""the first IP address
debug_msg "Retrieving the cluster name from Swarm API using echo -e "${RED}Error${RESET}: Invalid credentials. Please check your username and password."
            echo -e ""
            exit 1
        fi
        debug_msg "Validate credentials"
        credentials=$CREDENTIALS
    else
        debug_msg "Credentials do not contain password"
        debug_msg "Username: $(print_credentials "$CREDENTIALS")"
        USERNAME="$CREDENTIALS"
        # Prompt for password
        while [[ $ATTEMPTS -lt $MAX_RETRIES ]]; do
            echo ""
            read -sp "Enter password for user $USERNAME: " PASSWORD
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)
  echo "" fi
    local initial_size=$(stat -c%s "$log_file"   2>/dev/null || echo ""0)
    local current_log_level
    local  CREDENTIALSclusterName="$USERNAME:$PASSWORD$7"
            debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"local jq_or_grep="$8"
    local detachable="$9"
    if [[ check_credentials "$CREDENTIALS$detachable" "${ip_array[0]}"
]]; then
        local debug="${10}"
 if [[ $? -eq 0 ]]; then eval "$(echo "${11}" | sed 's/declare -A/declare -A/')"
        debug_msgeval "CREDENTIALS: $(print_credentialsecho "$CREDENTIALS"))"
    ${12}" | sed 's/declare -A/declare -A/')"
    fi
    local  debug_msg "Valid credentialsdefault_log_levels="$13"
                credentials=$CREDENTIALSlocal default_log_levels_name="$14"
    debug_msg "**********************************************************"
    debug_msg "local variables"
   break debug_msg "Log Level Type: ${GREEN}$log_level_type${RESET}"
    debug_msg "Default Log else
Level: ${GREEN}$default_log_level${RESET}"
    debug_msg "Swarm IP: $swarm_ip"
    debug_msg "Credentials:  echo -e "$(print_credentials "$credentials")"
    debug_msg "New Log          echo -e "${RED}Error${RESET}: Invalid credentials. Please check your username and password."
            fi
     Level: $new_log_level"
    debug_msg "New log Level Name: $new_log_level_name"
    debug_msg "Duration: $duration"
    debug_msg  ((ATTEMPTS++))
"Log File: $log_file"
    debug_msg "Initial Log doneFile Size: $initial_size"
  fi else debug_msg "Current Log  if ! check_credentials "$credentials" "${ip_array[0]}"; thenLevel: $current_log_level"
    debug_msg "Cluster Name: $clusterName"
 echo -e "" debug_msg "jq_or_grep: $jq_or_grep"
     echo -e "${YELLOW}Warning${RESET}: ${RED}Invalid credentials${RESET}.debug_msg "Detach: $detachable"
        echo -e ""debug_msg "Debug: $debug"
    debug_msg "**********************************************************"

 exit 1  # Split the fiswarm_ip fiinto an #array Retrieveof clusterIP nameaddresses
and handle JSON parsing using the first IP address
debug_msg "Retrieving the cluster name from Swarm API using IPIFS=';, ' read -r -a ip_array <<< "$swarm_ip"
    debug_msg "IP Array: ${ip_array[0]}"*]}"

    # Display initial information
    if [[ "$jq$log_orlevel_greptype" == "grepcluster" ]]; then
    clusterName=$(curl --user "$credentials" -sS "http://    echo -e "Swarm IP: ${GREEN}${ip_array[0]}:91/api/storage/clusters${RESET}"
| 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 echo -e "Swarm IPs: ${GREEN}${ip_array[*]}${RESET}"
    fi
    # echo -e "Swarm IP: ${GREEN}$swarm_ip${RESET}"
    debug_msg "Cluster NameCredentials: $clusterName"

# Main logic function to run the script tasks
main_script() {${GREEN}[hidden for security]${RESET}"
    echo -e "Cluster Name: ${GREEN}$clusterName${RESET}"

   local swarmdebug_ip="$1"
    local credentials="$2"msg "Starting main_script function..."
    local new_log_level="$3"
    local new_log_level_name="$4"debug_msg "Log level type: $log_level_type"

   local duration="$5"# Store the original log local log_level_type="$6"levels
    declare #local-A original_log_file="/var/log/datacore/castor.log"levels
    ifdeclare [[ -z "$log_file" ]]; thenA original_log_level_names

    default_log_level=${default_log_levels[$log_level_type]}
    default_log_filelevel_name=$(determine{default_log_file)_level_names[$log_level_type]}
    fidebug_msg "Default log   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}"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 eval "$(echo "${11}" | sed 's/declare -A/declare -A/')"[[ "$jq_or_grep" == "grep" ]]; then
           eval "$(echo "${12} current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | sedgrep -oP 's/declare -A/declare -A/')""value":\s*\K[0-9]+')
    fi    else
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: $newcurrent_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"
    debug_msg "Duration: $duration"  fi
  debug_msg "Log File: $log_file"   if [[ debug_msg "Initial Log File Size: $initial_size"$new_log_level == 30 ]]; then
        debug_msg "Current Log Level: $currentnew_log_level_name="default"
     debug_msg "Cluster Name: $clusterName"   fi
        debug_msg "jq_or_grep: $jq_or_grep"
    debug_msg "Detach: $detachable"Current cluster log level: ${BOLD_GREEN}$current_log_level${RESET}"
        debug_msg "Debug: $debugCurrent log level name: ${BOLD_GREEN}$current_log_level_name${RESET}"
    debug_msg "**********************************************************    echo -e ""
     #   Splitecho the swarm_ip into an array of IP addresses-e "New cluster log level: ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})"
     IFS=';, ' read -recho -a ip_array <<<e "$swarm_ip"Current cluster log level  debug_msg "IP Array: ${ip_array[*]}is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."

        # Display initial information Skip update if new level matches the current level
        if [[ "$log$current_log_level_type" ==-eq "cluster$new_log_level" ]]; then
         echo -e "Swarm IP: ${GREEN}${ip_array[0]}${RESET}echo ""
    else
        echo -e "Swarm IPs:e "Cluster log level is already set to ${BOLD_GREEN}$new_log_level_name${RESET} (${ip_array[*]}$BOLD_GREEN}$new_log_level${RESET}). No changes made."
    fi      # echo -ereturn
"Swarm IP: ${GREEN}$swarm_ip${RESET}"     debug_msg "Credentials: ${GREEN}[hidden for security]${RESET}" fi

      echo -e "Cluster# Name: ${GREEN}$clusterName${RESET}"

    debug_msg "Starting main_script function..."Update the cluster log level using PUT
        debug_msg "LogUpdating cluster log level type: $logto $new_log_level_type"

    # Store the original log levelsname"
      declare -A originaldebug_log_levelsmsg "Cluster Name: $clusterName"
 declare -A original_log_level_names      if [[ $log_level_type == "cluster" ]]; thendebug_msg "Credentials: $(print_credentials "$credentials")"
        debug_msg "curl  debug_msg "Setting cluster log level to $new_log_level ($new_log_level_name)--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}\""
        # Retrieve current log level
        if [[ "$jq_or_grep" == "grep" ]]; thenresponse=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
             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]+')       -d  else"{\"value\": $new_log_level}")
        debug_msg "Response: $response"

current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" |         if [[ "$jq_or_grep" -r '.value')
 == "grep" ]]; then
      fi         currentupdated_log_level_name=${log_levels[$current_log_level]}
    (echo "$response" | grep -oP '"value":\s*\K[0-9]+')
   debug_msg "Current cluster log level: ${BOLD_GREEN}$current_log_level${RESET}" else
        debug_msg "Current log level name: ${BOLD_GREEN}$current updated_log_level_name${RESET}"
 =$(echo "$response" | "$jq_or_grep" -r '.value')
      echo -e ""fi
        echo -edebug_msg "NewUpdated cluster log level: ${BOLD_GREEN}$new_$updated_log_level_name${RESET}"

       echo -e "Current cluster log level is ${GREEN}$current if [[ "$updated_log_level" -eq "$new_log_level_name.${RESET}" ]]; then
       # Skip update if new levelecho matches the current-e "${GREEN}$(timestamp)${RESET} Log level changed successfully from      if [[ "${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level"level${RESET}) -eq "> ${BOLD_GREEN}$new_log_level" ]]; then_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})."
              echo ""else
             echo -e "Cluster log level is already set to ${BOLD_GREEN}$new_log_level_name${RESET}. No changes made."${GREEN}$(timestamp)${RESET} Failed to update log level. Response: ${RED}$response${RESET}"
            exit 1
 return         fi

        # UpdateCountdown theand clusterrevert log level using PUT
        debug_msg "Updating cluster log level to $new_log_level_name"       if  debug_msg[[ -n "Cluster Name: $clusterName$duration" && "$duration" -gt 0 ]]; then
    debug_msg "Credentials: $(print_credentials "$credentials")"     echo -e "Keeping log 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}\""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 ""
            for response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \((i=duration; i>0; i--)); do
                printf -v countdown "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))
                echo -dne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"value\":
$new_log_level}")         debug_msg "Response: $response"     sleep 1
   if [[ "$jq_or_grep" == "grep" ]]; then   done
         updated_log_level=$(echo "$response" | grepecho -oPe '"value":\s*\K[0-9]+')
    n\nTime's up! Reverting log level back to ${GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET}) ..."

  else          # Revert the updated_log_ level=$(echo "$response" | "$jq_or_grep" -r '.value')
 back to the original value
       fi     # echo   debug_msg "Updated cluster log level: $updated_log_level-e "Level log revert on $(timestamp)"
         if  [[ "$updated_log_level" -eq "$new_log_level" ]]; then
     response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
       echo -e "${GREEN}$(timestamp)${RESET} Log level changed successfully from ${GREEN}$current_log_level${RESET} -> ${BOLD_GREEN}$new_log_level${RESET}."
 "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
       else         -d "{\"value\": $current_log_level}")
     echo -e "${GREEN}$(timestamp)${RESET} Failed to update log level.debug_msg "Response: ${RED}$response${RESET}$response"

           exit 1if [[ "$jq_or_grep" == "grep" ]]; then
  fi          # Countdown and revert reverted_log _level=$(echo "$response" | grep      if [[ -n "$duration" && "$duration" -gt 0 ]]; then
 -oP '"value":\s*\K[0-9]+')
            else
          echo -e "Keeping log level at ${YELLOW}$newreverted_log_level_name${RESET} for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."
   =$(echo "$response" | "$jq_or_grep" -r '.value')
        echo -e ""  fi
          for ((i=duration; i>0; i--)); do
   debug_msg "Reverted cluster log level: $reverted_log_level"

            printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
            debug_msg "Initial log file echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"size: $initial_size"
            debug_msg "Final log file size: $final_size"
sleep 1           size_diff=$((  done
final_size - initial_size ))
           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
 size_diff_formatted=$(format_size "$size_diff")
            duration_formatted=$(format_duration "$duration")
	    if (( size_diff < 0 )); then
		echo -e "castor.log file was rotated."
	    else
           # echo -e "Level log revert on $(timestamp)"
            response=$(curlecho --usere "$credentials" -sS -X PUT -H "Content-Type: application/json" \
                "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \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})."
              echo   -de "{\"value\": $current_log_level}")
 "
	    fi
        if  debug_msg "Response: $response"

[[ "$reverted_log_level" -eq "$current_log_level" ]]; then
           if [[ "$jq_or_grep" == "grep" ]]; then
     echo -e "${GREEN}$(timestamp)${RESET} Log level reverted successfully back to ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."
          reverted_log_level=$(echo "$response" | grepecho -oPe '"value":\s*\K[0-9]+')

           else
            echo    reverted_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
  -e "${GREEN}$(timestamp)${RESET} Failed to revert log level. Response: ${RED}$response${RESET}"
         fi   echo -e  ""
      debug_msg  "Reverted cluster log level: $reverted_log_level"
 exit 1
        fi
   final_size=$(stat -c%s "$log_file" 2>/dev/null || echoelse
0)            echo debug_msg "Initial log file size: $initial_size"
 -e "${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified."
        fi
 debug_msg "Final log fileelif size: $final_size"
   [[ "$log_level_type" == "node" ]]; then
        size_diff=$(( final_size - initial_size ))
  # First loop: Change the node log level
        local size_diff_formatted=$(format_size "$size_diff")same_log_level=false
        for ip in  duration_formatted=$(format_duration "$duration")
	"${ip_array[@]}"; do
       if (( size_diff < 0 ));# thenRetrieve 		echo -e "castor.current node log filelevel
was rotated." 	    else      debug_msg "Retrieving current node log level  echo -e ""for IP: $ip"
            debug_msg "curl echo-s -eu \"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})."(print_credentials "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\""
            current_log_level=$(curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value')
            debug_msg "Current echolog -elevel ""for 	IP $ip: $current_log_level"
 fi         if [[ "$revertedoriginal_log_level" -eq "levels["$ip"]=$current_log_level"
]]; then             echo -e "${GREEN}$(timestamp)${RESET} Logdebug_msg "Original log level revertedfor successfully back toIP $ip: ${BOLDoriginal_GREEN}$current_log_level${RESET}.levels["$ip"]}"
            echoif -e[[ "$current_log_level" == "0" ]]; then
    else             echo -e "${GREEN}$(timestamp)${RESET} Failed to revert log level. Response: ${RED}$response${RESET}"
  current_log_level_name="default"
            else
         echo -e ""     current_log_level_name=${log_levels[$current_log_level]}
       exit 1    fi
    fi         elseoriginal_log_level_names["$ip"]=$current_log_level_name
            debug_msg echo "$(timestamp) Log"Original log level change is permanent until manually modified.name: ${original_log_level_names["$ip"]}"
        fi    if elif [[ "$log$new_log_level_type" == "node0" ]]; then
        #   First loop: Change the node new_log level_level_name="default"
            else
  local same_log_level=false           for ip in " new_log_level_name=${iplog_array[@levels[$new_log_level]}";
do             # Retrieve current node log levelfi
            debug_msg "Retrieving current nodeCurrent log level for IP $ip: $ip$current_log_level ($current_log_level_name)"
            debug_msgecho "curl"
-s -u \"$(print_credentials "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\""        echo -e "New node log  currentlevel: ${BOLD_GREEN}$new_log_level=$(curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value')_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})"
            echo debug_msg-e "Current node log level for IP $ip: ${BOLD_GREEN}$ip${RESET} is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."

           original_log_levels["$ip"]=$current_log_level
   # Skip update if new level matches the current level
         debug_msg "Original log levelif for IP $ip: ${original[[ "$current_log_level" -eq "$new_log_levels["$ip"]}"level" ]]; then
              if [[ "$currentsame_log_level" == "0" ]]; then=true
                 current_log_level_name="defaultecho ""
            else    echo -e "Node log level for IP ${BOLD_GREEN}$ip${RESET} is already set   currentto ${BOLD_GREEN}$new_log_level_name=name${RESET} (${log_levels[$currentBOLD_GREEN}$new_log_level]}
  level${RESET}). No changes made."
         fi       continue
     original_log_level_names["$ip"]=$current_log_level_name       else
     debug_msg "Original log level name: ${original_log_level_names["$ip"]}"             if [[ "$newsame_log_level" == "0" ]]; thenfalse
            fi

   new_log_level_name="default"         if [[ "$same_log_level" == elsefalse ]]; then
              new_log_level_name=${log_levels[$new_log_level]}  # Update the node log level using PUT
   fi             debug_msg "CurrentUpdating node log level for IP $ip: $currentto $new_log_level ($current_log_level_name)" for IP $ip..."
         echo ""      debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X echoPUT -eH \"New node log level: ${BOLD_GREEN}Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level_name${RESET}\""
            echo -e "Current node log level for IP ${BOLD_GREEN}$ip${RESET} is ${GREEN}$current_log_level_name.${RESET}"

            # Skip update if new level matches the current level response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
                        if [[ "$current_log_level" -eq "$new_log_level" ]]; then"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level")
                same_log_level=true
 debug_msg "Response: $response"

             echo ""  if [[ "$jq_or_grep" == "grep" ]]; then
        echo -e "Node log level for IP ${BOLD_GREEN}$ip${RESET} is already set to ${BOLD_GREEN}$new_log_level_name${RESET}. No changes made."updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
                 continueelse
                    else
   updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
            same_log_level=false    fi
        fi        debug_msg "Updated log level for IP if [[ "$same$ip: $updated_log_level"
==
 false ]]; then             if [[ "$updated_log_level"  # Update the node log level using PUT-eq "$new_log_level" ]]; then
                    echo debug_msg "Updating node log level to $new_log_level_name-e "${GREEN}$(timestamp)${RESET} Node log level 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\""${BOLD_GREEN}$ip${RESET} changed successfully from ${BOLD_GREEN}$current_log_level_name${RESET} (${GREEN}$current_log_level${RESET}) -> ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})."
                else
 response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \          echo -e "${GREEN}$(timestamp)${RESET} Failed to update node log level for  "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level")IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"
                 debug_msg "Response: $response" exit 1
               if [[ "$jq_or_grep" == "grep" ]]; thenfi
            fi
        done

  updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
        # Second loop: Countdown if duration is provided
        elseif [[ "$same_log_level" == false ]]; then\
            if  updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
 [[ -n "$duration" && "$duration" -gt 0 ]]; then
              fi  echo -e ""
            debug_msg "Updated log level for IP $ip: $updated_log_level"

                if [[ "$updated_log_level" -eq "$new_log_level" ]]; then
echo -e "Keeping node(s) log level at ${YELLOW}$new_log_level_name${RESET} (${YELLOW}$new_log_level${RESET}) for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."
                   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}.""
                for ((i=duration; i>0; i--)); do
       else             printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / echo60 -e)) "${GREEN}$(timestamp)${RESET} Failed to update node log level for IP ${BOLD_GREEN}$ip${RESET}. Response((i%60))
                    echo -ne "Countdown: ${REDYELLOW}$response$$countdown${RESET} remaining...\r"
                    exitsleep 1
                fidone
            fi    echo -e "\n\nTime's up! Reverting donenode log level back to original levels..."

  # Second loop: Countdown if duration is provided       #  if [[ "$same_log_level" == false ]]; then\Third loop: Revert the node log level
                iffor [[ip -nin "$duration" && "$duration" -gt 0 ]]; then${ip_array[@]}"; do
                     echo -e ""current_log_level=${original_log_levels["$ip"]}
                echo -e "Keeping node(s) current_log level at _level_name=${YELLOW}$neworiginal_log_level_name${RESET} for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."names["$ip"]}
                   echo -edebug_msg ""Reverting node log level back to $current_log_level_name for IP $ip..."
       for ((i=duration; i>0; i--)); do         debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT     printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))-H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\""
                    #   echo -nee "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"
     Node level log revert on $(timestamp) for IP $ip"
              sleep 1     response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json"  \
 done                 echo -e "\n\nTime's up! Reverting node log level back to original levels..." "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level")
                 # Third loop: Revert the node log level   debug_msg "Response: $response"

                   for ipif in[[ "${ip_array[@]}"; do$jq_or_grep" == "grep" ]]; then
                        currentreverted_log_level=${original_log_levels["$ip"]}
   (echo "$response" | grep -oP '"value":\s*\K[0-9]+')
                current_log_level_name=${original_log_level_names["$ip"]}       else
                 debug_msg "Reverting node log level back to $currentreverted_log_level_name for IP $ip..."=$(echo "$response" | "$jq_or_grep" -r '.value')
                    fi

         debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\""
      final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
              # echo -e "Node level log revert on $(timestamp) for IP $ip"
 size_diff=$(( final_size - initial_size ))
                   response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ debug_msg "Initial log file size: $initial_size"
                    debug_msg "Final log file  "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level")size: $final_size"
                    debug_msg "Response: $response"

  size_diff_formatted=$(format_size "$size_diff")
                 if [[ "$jq_or_grep" == "grep" ]]; then duration_formatted=$(format_duration "$duration")

                    if     reverted[[ "$reverted_log_level=$(echo "$response" | grep -oPeq '"value":\s*\K[0-9]+')
$current_log_level" ]]; then
                   else     echo -e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} reverted successfully back         revertedto ${BOLD_GREEN}${current_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')_name}${RESET} (${BOLD_GREEN}$current_log_level${RESET})."
                    fielse
                     final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
                    size_diff=$(( final_size - initial_size ))
                    debug_msg "Initial log file size: $initial_size"-e "${GREEN}$(timestamp)${RESET} Failed to revert node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"
                        debug_msg "Final log file size: $final_size"exit 1
                    fi
  size_diff_formatted=$(format_size "$size_diff")             done

      duration_formatted=$(format_duration "$duration")         # Combine the log output for multiple IP addresses into a single summary
if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then      if (( size_diff < 0 )); then
            echo -e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} reverted successfully back to ${BOLD_GREEN}${current_log_level_name}${RESET}."
castor.log file was rotated."
            else
                   else echo -e ""
                     echo -e "Approximate ${BOLD_GREEN}$(timestamp)$$size_diff_formatted${RESET} new Failedlogs towere revertgenerated nodeat log level ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}) for IP ${ip_array[*]}. Current castor.log size is ${BOLD_GREEN}$ip$}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET}. Response:seconds (${REDYELLOW}$response$$duration_formatted${RESET})."
                    echo -e ""
 exit 1           fi
            else
     fi           echo -e "${GREEN}$(timestamp)${RESET} Log level change is permanent doneuntil manually modified."
            fi
  # Combine the log output for multiplefi
IP addresses into a singlefi
summary}

# Run in detachable or      directly
if (( size_diff < 0 ))$detachable; then
    # Pass the main_script function to the screen echosession -e "castor.log file was rotated."
 and store the output in a file
          else
  debug_msg "**********************************************************" | tee -a "$output_log"
    debug_msg "Detach mode - Parameters passed to main_script:" | tee    echo -ea "$output_log"
    debug_msg "     Swarm IP: $swarm_ip" |       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 "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 fiLevel Name: $new_log_level_name" | tee -a "$output_log"
    debug_msg "  else   Duration: $duration" | tee -a "$output_log"
    debug_msg "   echo "${GREEN}$(timestamp)${RESET} Log levelLevel change is permanent until manually modified.Type: $log_level_type" | tee -a "$output_log"
    debug_msg "     Log  fi
   File: $log_file" | tee -a "$output_log"
    fidebug_msg "    fi }Initial Log #File Run in detachable or directly
if $detachable; then
    # Pass the main_script function to the screen session and store the output in a fileSize: $initial_size" | tee -a "$output_log"
    debug_msg "     Current Log Level: $current_log_level" | tee -a "$output_log"
    debug_msg "**********************************************************     Cluster Name: $clusterName" | tee -a "$output_log"
    debug_msg "Detach mode - Parameters passed to main_script: jq_or_grep: $jq_or_grep" | tee -a "$output_log"
    debug_msg "     Swarm IPDetach: $swarm_ip$detachable" | tee -a "$output_log"
    debug_msg "     CredentialsDebug: $(print_credentials "$credentials")$debug"  | tee -a "$output_log"
    debug_msg "**********************************************************" | tee -a  New Log Level: $new_log_level" | tee -a "$output_log"
    debug_msg "     New log Level Name: $new_log_level_name" | tee -a "$output_log""$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 "     Duration: $durationlog_levels_string: $log_levels_string" | tee -a "$output_log"
    debug_msg "     Log Level Typelog_level_names_string: $log_level_names_typestring" | tee -a "$output_log"

   debug_msg "if command -v screen  Log File: $log_file" | tee -a "$output_log"&>/dev/null; then
          debug_msgecho -e "     Initial Log File Size: $initial_sizeRunning in ${YELLOW}screen${RESET} detachable mode..." | tee -a "$output_log"
    debug_msg "   screen  Current Log Level: $current-dmS castor_log_level" | teescript bash -ac "$output_log"
    $(declare -f main_script timestamp debug_msg "     Cluster Name: $clusterName" | tee -a "$output_log"
    debug_msg "     jq_or_grep: 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\" | tee -a "$output_log"
    debug_msg "     Detach: $detachable" | tee -a "$output_log"
    debug_msg "     Debug: $debug" | tee -a "$output_log"
    debug_msg "**********************************************************\"$detachable\" \"$debug\" \"${log_levels_string}\" \"${log_level_names_string}\" \"${default_log_levels}\" \"${default_log_levels_name}\" | tee -a \"$output_log\""
        # Convert associative arrays to strings and pass them to 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..." > "$output_log" | tee -a "$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_log> "$temp_script"
#!/bin/bash
-c "$(declare -f main_script timestamp debug_msg format_size format_duration check_jq determine_log_file print_credentials);
main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$detachable\" \"$debug\" \"${log_levels_string}\" \"${log_level_names_string}\}" "${default_log_levels}" "${default_log_levels_name}" | tee \-a "$output_log\"""
rm -f "$temp_script"                  screen  # Remove the script file
tmux kill-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  elif commandtmux has-session -v tmux &>t castor_log_script 2>/dev/null; thendo
        echo -e "Running in ${YELLOW}tmux${RESET} detachable mode..." | tee -a "$output_log"
        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

...