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 Minor bug fix and enhancement.
# v1.3.3 - 2025-03-02 Fixed tmux command to long issue.
# -----------------------------------------------------------------------------------------------------------------------------
# Current Version: 1.3.13
# -----------------------------------------------------------------------------------------------------------------------------
# KB: https://perifery.atlassian.net/wiki/spaces/public/pages/3872161835/Setting+and+Managing+Swarm+Log+Levels+with+script
# -----------------------------------------------------------------------------------------------------------------------------

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

SCRIPT_NAME=$(basename "$0")

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

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

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

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

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

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

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

# Function to Definedisplay 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]"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)  -d, --swarm_ip [DEBUG] ($caller_func:$caller_line) $*"
    fi
}

# Function IPto addresscheck ofif theeither Swarm'screen' API endpoint. Supports single or multiple IPs separated by \",\", \";\" or \" \"."
    echo "or 'tmux' is installed
check_screen_or_tmux() {
    if ! command -v screen &>/dev/null && ! command -v tmux &>/dev/null; then
        echo -e ""
        echo -e "---------------------------------------------------------------------------------------"
    If multiple IPs are provided,echo the-e script" will update the log level for all nodes."
    echo  ${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."
 (Alternatively, set the SCSP_HOST environment variable to theecho Swarm-e IP.)"
    echo "  -p, --credentials        Credentials in the format admin:password"
    echo "  -i, --log.level"---------------------------------------------------------------------------------------"
        detachable=false New cluster# logDisable leveldetachable tosession
set (5, 10, 15, 20, 30, 40, 50, chatter,usage
debug, announce, info, error, critical, default)"fi
}

# Function to echoformat "file  -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 "size
format_size() {
    local size=$1
    if (( size >= 1073741824 )); then
        echo "$(awk "BEGIN {printf \"%.1fGB\", $size/1073741824}")"
    elif (( size >= 1048576 )); then
   **Either -i or -L must be specified, but not both.**"
echo "$(awk "BEGIN {printf \"%.1fMB\", $size/1048576}")"
   echo "elif (( -t, --time   size >= 1024 )); then
        echo "$(awk  (Optional) Duration in seconds to keep the new log level (must be greater than 0)""BEGIN {printf \"%.1fKB\", $size/1024}")"
    else
        echo "  -D, --detach${size}B"
    fi
}

# Function to format duration
 format_duration(Optional) Detach{
the script from the currentlocal terminalduration=$1
and run in a detachable session using screen or tmux"local hours=$((duration / 3600))
    local  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=3minutes=$(( (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 #[[ Maximum number of password retries attempts
username="admin"   -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      # Default username
password="" in "/var/log/datacore/castor.log" "/var/log/caringo/castor.log"; do
        if [[ -f "$log" ]]; then
            echo "$log"
           # Defaultreturn
password  # Global associative array for log levelsfi
declare -A log_levels=(   done
 [5]="chatter"   echo -e [10]="debug"
    [15]="audit""${RED}Error: Log file not found.${RESET}"
    [20]="info"
    [30]="warning"
    [40]="error"
    [45]="defect"
    [50]="critical"
    [60]="announceexit 1
}

log_file=$(determine_log_file)

# Function to check if credentials are valid
check_credentials() {
    local CREDENTIALS="$1"
    [30]local SWARM_IP="default$2"
)   # Global associative arraydebug_msg "Credentials: [hidden for logsecurity]"
level names declare -A log_level_names=(
    ["chatter"]=5debug_msg "Swarm IP: $SWARM_IP"

    #  ["debug"]=10
    ["audit"]=15API endpoint for validating user credentials
    local ["info"]=20VALIDATE_URL="http://${SWARM_IP}:91/api/validateUser"
    debug_msg ["warning"]=30
    ["error"]=40Validate URL: $VALIDATE_URL"

    ["defect"]=45
    ["critical"]=50# Make the API request
    debug_msg ["announce"]=60"Validating user credentials..."
    debug_msg ["default"]=30
)

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

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

# Function to check if either 'screen' or 'tmux' is installed
check_screen_or_tmux() {
    if ! command -v screen &>/dev/null && ! command -v tmux &>/dev/nullcurl -s -u \"********\" -X GET \"$VALIDATE_URL\" -H 'Content-Type: application/json'"
    RESPONSE=$(curl -s -u "$CREDENTIALS" -X GET "$VALIDATE_URL" -H 'Content-Type: application/json')
    debug_msg "Validate User Response: $RESPONSE"

    # Check if the response contains "isValid": true
    if echo "$RESPONSE" | "$jq_or_grep" -e '.isValid == true' > /dev/null 2>&1; then
        debug_msg "Authentication successful for user '${CREDENTIALS%%:*}'"
        return 0  # Success
    elif echo "$RESPONSE" | "$jq_or_grep" -e '.isValid == false' > /dev/null 2>&1; then
        echo -edebug_msg ""Authentication failed for       echo -e "---------------------------------------------------------------------------------------"user '${CREDENTIALS%%:*}'"
        return 1  # Failure
    else
        debug_msg "Error: Unable to validate credentials. Please echocheck -eyour inputs."
 ${YELLOW}Warning${RESET}: Neither '${BOLD_GREEN}screen${RESET}' nor '${BOLD_GREEN}tmux${RESET}' is installed. Cannot run in detachable mode."
          return 1  # Failure
    fi
}

# Function to print credentials - hide password
print_credentials() {
    local CREDENTIALS="$1"
    local USERNAME="${CREDENTIALS%%:*}"
    echo -e "  Please install either '${BOLD_GREEN}screen$$USERNAME${RESET}' or '":"${BOLD_GREEN}tmux$********${RESET}' to run the script in a detachable session."
        echo -e "---------------------------------------------------------------------------------------"
}

# Parse input arguments
while [[ "$#" -gt 0 ]]; do
    case $1 in
       echo -e ""
 -d|--swarm_ip) swarm_ip="$2"; debug_msg "Set swarm_ip to $swarm_ip"; shift 2 ;;
      detachable=false  # Disable detachable session-p|--credentials)
           debug_msg "detachable=${YELLOW}false${RESET}credentials="$2"
        debug_msg "Stopping the script..." shift 2 ;;
     exit 1  -i|--log.level)
  fi }  # Function to format file size format_size() {if [[ -n "$new_log_level" ]]; localthen
size=$1     if (( size >= 1073741824 )); then      echo "Error: Options echo-i "$(awkcluster "BEGIN {printf \"%.1fGB\", $size/1073741824}")"
    elif (( size >= 1048576 )); thenlog leve) and -L (node log level) cannot be used together."
            echo "$(awk "BEGIN {printf \"%.1fMB\", $size/1048576}")" usage
     elif (( size >= 1024 )); then fi
       echo "$(awk "BEGIN {printf \"%.1fKB\", $size/1024}") log_level_type="cluster"
    else        if echo[[ "${size}B"log_level_names[$2]} ]]; then
        fi }  # Function to format duration
format_duration() { new_log_level=${log_level_names[$2]}
        local duration=$1   elif [[ local"$2" hours==$((duration / 3600))
 "default" ]]; then
   local minutes=$(( (duration % 3600) / 60 ))     local seconds=$((duration % 60))
new_log_level=${default_log_levels[$log_level_type]}
   printf "%02d:%02d:%02d" $hours $minutes $seconds }  # Function to check if jq is available and set up JSON parsing method
check_jq() { new_log_level_name="default"
            ifelif [[ -x "/usr/local/bin/jq" ${log_levels[$2]} ]]; then
        echo "/usr/local/bin/jq"       elif [[ -x "$(pwd)/jq" ]]; then new_log_level=$2
            echo "$(pwd)/jq"else
     elif command -v jq &>/dev/null; then      echo "Invalid log echolevel: "jq"$2"
         else       exit 1
echo "grep"     fi }  if [[ -f "$JQLOCATION" ]]; thenfi
      jq_or_grep=$JQLOCATION else     jqnew_log_orlevel_grepname=$(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() {{log_levels[$new_log_level]}
            default_log_level=30
        if [[ -f "/var/log/datacore/castor.log" ]]; then
    debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)"
    echo "/var/log/datacore/castor.log"        shift elif2
[[ -f "/var/log/caringo/castor.log" ]]; then        ;;
echo "/var/log/caringo/castor.log"     else  -L|--node.log.level)
      echo "Error: Log file not found in /var/log/datacore/castor.log or /var/log/caringo/castor.log"
 if [[ -n "$new_log_level" ]]; then
      exit 1     fi }  log_file=$(determine_log_file)

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

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

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

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

# If swarm_ip is not provided, try using SCSP_HOST environment echovariable
"Invalidif log level: $2"
 [[ -z "$swarm_ip" ]]; then
    if [[ -n "$SCSP_HOST" ]]; then
    exit 1   swarm_ip="$SCSP_HOST"
         fi
  debug_msg "Using Swarm IP from SCSP_HOST: $swarm_ip"
    else
    new_log_level_name=${log_levels[$new_log_level]}    echo "Error: swarm_ip not provided and SCSP_HOST is  log_level_type="nodenot set."
        usage
   default_log_level=0 fi
fi

# Check if required arguments are provided
if  debug_msg "Set new_log_level to [[ -z "$credentials" || -z "$new_log_level ($new_log_level_name)" ]]; then
    usage
fi

# Split the shiftswarm_ip 2into an array of IP addresses if it contains     ;;
        -t|--time)
            if [[ -n "$2" && "$2" != -* && "$2" -gt 0delimiters
IFS=';, ' read -r -a ip_array <<< "$swarm_ip"

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

    # Check if credentials shiftcontain 2a colon (username:password format)
    debug_msg "Checking for colon in elsecredentials..."
    if [[ "$CREDENTIALS"          echo "Error: Duration must be a number greater than 0."
 == *":"* ]]; then
              exit 1
            fi
 debug_msg "Credentials contain colon"
        USERNAME="${CREDENTIALS%%:*}"
 ;;       PASSWORD="${CREDENTIALS#*:}"

-D|--detach) detachable=true; debug_msg "Set detachable to true"; shift ;;# Validate credentials
      --debug) debug=true; debugcheck_msgcredentials "Set debug to true with ${YELLOW}--debug${RESET}"; shift ;;$CREDENTIALS" "${ip_array[0]}"
        if [[ $? *)-ne usage0 ]];; then
   esac done  debug_msg "Set log_level_type to ${YELLOW}$log_level_type${RESET}"  # Set default values if not provided
debug_msg "Checking for default log level values..."

# Change the default log level based on Log Level Type
debug_msg "Changing default log level based on Log Level Type: ${YELLOW}$log_level_type${RESET}"
if [[ -n "$new_log_level" ]]; then
    if [[ "$log_level_type" == "node" ]]; then
debug_msg "Invalid credentials. Please check your username and password."
            echo -e ""
            echo -e "${RED}Error${RESET}: Invalid credentials. Please check your username and password."
            echo -e ""
       # new_log_level=0    exit 1
   debug_msg "Checing node default log level"fi
        default_log_level=0
  debug_msg "Validate credentials"
     if [[ $new_log_level credentials==$CREDENTIALS
 30 ]]; then else
        debug_msg "Credentials  new_log_level=$default_log_level
 do not contain password"
        debug_msg  new_log_level_name="default"Username: $(print_credentials "$CREDENTIALS")"
        fiUSERNAME="$CREDENTIALS"
        debug_msg "node - new_log_level: to $new_log_level"# Prompt for password
        while [[ $ATTEMPTS -lt debug_msg "node - new_log_level_name: to $new_log_level_name"$MAX_RETRIES ]]; do
           elif [[echo "$log_level_type"
  == "cluster" ]]; then       read  default_log_level=30
    fi
-sp "Enter password for user $USERNAME: " PASSWORD
   debug_msg "New log level: ${GREEN}$new_log_level${RESET}"     debug_msgecho "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 echo ""
            if [[ -z "$detachable$PASSWORD" == true ]]; then
     check_screen_or_tmux
fi      # If swarm_ip is not provided,echo try using SCSP_HOST environment variable
if [[ -z "$swarm_ip" ]]; then-e "${RED}Error${RESET}: Password cannot be empty."
          if [[ -n "$SCSP_HOST" ]]; then ((ATTEMPTS++))
       swarm_ip="$SCSP_HOST"         debug_msgcontinue
"Using Swarm IP from SCSP_HOST: $swarm_ip"     else  fi
      echo "Error: swarm_ip not provided and SCSP_HOST is not set." CREDENTIALS="$USERNAME:$PASSWORD"
           usage debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"
fi fi  # Check if required arguments are provided if [[ -z check_credentials "$credentials$CREDENTIALS" || -z "$new_log_level" ]]; then"${ip_array[0]}"
     usage fi  # Split the swarm_ip intoif an[[ array$? of-eq IP0 addresses]]; ifthen
it contains delimiters IFS=';, ' read -r -a ip_array <<< "$swarm_ip"  # Validate credentials before proceeding debug_msg "Validating credentials..."
#if [[ "$credentials" =~ ^[^:]+$ ]]; then
if [[ -n "$credentials" ]]; then
    CREDENTIALS="$credentialsCREDENTIALS: $(print_credentials "$CREDENTIALS"))"
                debug_msg "Valid credentials"
    ATTEMPT=$MAX_RETRIES     USERNAME=""     PASSWORD=""  credentials=$CREDENTIALS
  debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS")"     debug_msg "ATTEMPT: $ATTEMPT"     break
# Check if credentials contain a colon (username:password format)    else
debug_msg "Checking for colon in credentials..."     if [[ "$CREDENTIALS" == *":"* ]]; thenecho -e ""
      debug_msg "Credentials contain colon"       echo -e USERNAME="${CREDENTIALS%%:*}"
        PASSWORD="${CREDENTIALS#*:}RED}Error${RESET}: Invalid credentials. Please check your username and password."
         # # Check iffi
credentials contains special characters         # debug_msg "Checking for special characters in credentials..."
 ((ATTEMPTS++))
        done
      #  if [[ "$PASSWORD" == *['!@#\$%^\&*()_+''-']* $ATTEMPTS -ge $MAX_RETRIES ]]; then
        #    echo debug_msg-e ""Credentials
     contain special characters"     echo -e "${RED}Error${RESET}: Maximum #number of password attempts reached. debug_msgExiting script."Username:
 $USERNAME"         #  exit 1
 debug_msg "Password: $PASSWORD"     fi
   # fi
else
  echo -e ""if ! check_credentials "$credentials" "${ip_array[0]}"; then
   #     echo -e "${YELLOW}Warning${RESET}: Password contains special characters. Please enclose the credentials in single quotes. ('username:password')"
 "
        echo -e "${YELLOW}Warning${RESET}: ${RED}Invalid credentials${RESET}."
      #     echo -e ""
   
    #     exit 1
    fi
 fi

# fiRetrieve cluster name and handle JSON parsing using the #first ValidateIP credentialsaddress
debug_msg "Retrieving the cluster name from Swarm API check_credentials "$CREDENTIALS" "using IP: ${ip_array[0]}"

       if [[ $? -ne 0"$jq_or_grep" == "grep" ]]; then
    clusterName=$(curl        debug_msg "Invalid credentials. Please check your username and password."
            echo -e ""
--user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | grep -oP '"name":\s*"\K[^"]+')
else
    clusterName=$(curl       echo--user "$credentials" -esS "http://${RED}Error${RESET}: Invalid credentials. Please check your username and password."
 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 echoname. -ePlease ""check your inputs."
    exit 1
fi
debug_msg "Cluster  exit 1Name: $clusterName"

# Main logic function to run the fiscript tasks
main_script() {
    local debugswarm_msg "Validate credentialsip="$1"
    local    credentials=$CREDENTIALS"$2"
    else
local new_log_level="$3"
    local new_log_level_name="$4"
 debug_msg "Credentials do not contain passwordlocal duration="$5"
    local log_level_type="$6"
  debug_msg "Username: $(print_credentials "$CREDENTIALS")"  #local log_file="/var/log/datacore/castor.log"
    if [[ -z  USERNAME="$CREDENTIALS"$log_file" ]]; then
      # Prompt for password log_file=$(determine_log_file)
    fi
    while [[ $ATTEMPTS -lt $MAX_RETRIES ]]; do
 local initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
    local current_log_level
    echolocal clusterName="$7"
    local jq_or_grep="$8"
      read -sp "Enter password for user $USERNAME: " PASSWORD
local detachable="$9"
    if [[ "$detachable" ]]; then
           echo "local debug="${10}"
            eval "$(echo "${11}" | sed 's/declare -A/declare -A/')"
       CREDENTIALS="$USERNAME:$PASSWORD"
       eval "$(echo "${12}" | sed 's/declare -A/declare -A/')"
    fi
    local debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"default_log_levels="$13"
    local default_log_levels_name="$14"
      checkdebug_credentials "$CREDENTIALS" "${ip_array[0]}"
     msg "**********************************************************"
    debug_msg "local variables"
    debug_msg "Log ifLevel [[Type: $? -eq 0 ]]; then
   {GREEN}$log_level_type${RESET}"
    debug_msg "Default Log Level: ${GREEN}$default_log_level${RESET}"
    debug_msg "Swarm IP: $swarm_ip"
    debug_msg "CREDENTIALSCredentials: $(print_credentials "$CREDENTIALS$credentials"))"
    debug_msg "New Log Level: $new_log_level"
       debug_msg "ValidNew credentials"log Level Name: $new_log_level_name"
    debug_msg "Duration: $duration"
    debug_msg  credentials=$CREDENTIALS
"Log File: $log_file"
    debug_msg "Initial Log File Size: $initial_size"
    debug_msg break"Current Log Level: $current_log_level"
    debug_msg "Cluster Name: $clusterName"
 else   debug_msg "jq_or_grep: $jq_or_grep"
       debug_msg "Detach: $detachable"
   echo -edebug_msg "Debug: $debug"
    debug_msg "**********************************************************"

    # Split the swarm_ip into echoan -e "${RED}Error${RESET}: Invalid credentials. Please check your username and password."
     array of IP addresses
    IFS=';, ' read -r -a ip_array <<< "$swarm_ip"
    debug_msg "IP fi
   Array: ${ip_array[*]}"

    # Display  ((ATTEMPTS++))initial information
    if [[ "$log_level_type" == done
 "cluster" ]]; then
  fi else     ifecho ! check_credentials "$credentials" "-e "Swarm IP: ${GREEN}${ip_array[0]}${RESET}";
then     else
   echo -e ""         echo -e "Swarm IPs: ${YELLOWGREEN}Warning${RESET}: ${RED}Invalid credentials$${ip_array[*]}${RESET}."
    fi
    # echo -e ""Swarm IP: ${GREEN}$swarm_ip${RESET}"
    debug_msg  exit 1
"Credentials: ${GREEN}[hidden for security]${RESET}"
   fi
fi

# Retrieve cluster name and handle JSON parsing using the first IP address echo -e "Cluster Name: ${GREEN}$clusterName${RESET}"

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

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

# Main logic function to run the script tasks
main_script() {
    local swarm_ip="$1"
    local credentials="$2"
    local new_log_level="$3"
    local new_log_level_name="$4"
    local duration="$5"
    local log_level_type="$6"
    #local log_file="/var/log/datacore/castor.log"
    if [[ -z "$log_file" ]]; thenmain_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_filelevel=$(determine_log_filecurl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | grep -oP '"value":\s*\K[0-9]+')
    fi    else
local initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)     local current_log_level=$(curl --user "$credentials"   local clusterName="$7"
    local jq-sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | "$jq_or_grep="$8" -r '.value')
  local detachable="$9"     if [[ "$detachable" ]]; thenfi
          local debug="${10}"current_log_level_name=${log_levels[$current_log_level]}
        eval "$(echo "${11}" | sed 's/declare -A/declare -A/')"
        eval "$(echo "${12}" | sed 's/declare -A/declare -A/')"if [[ $current_log_level == 30 ]]; then
       fi     debug_msg "**********************************************************current_log_level_name="default"
    debug_msg "local variables"    fi
      debug_msg "Log Levelif Type: ${GREEN}$log_level_type${RESET}"[[ $new_log_level == 30 ]]; then
        debug_msg "Default Log Level: ${GREEN}$default new_log_level${RESET}level_name="default"
    debug_msg "Swarm IP: $swarm_ip"    fi
debug_msg "Credentials: $(print_credentials "$credentials")"     debug_msg "NewCurrent cluster Loglog Levellevel: $new${BOLD_GREEN}$current_log_levellevel${RESET}"
        debug_msg "NewCurrent log Levellevel Namename: $new${BOLD_GREEN}$current_log_level_namename${RESET}"
    debug_msg "Duration: $duration"
    debug_msg "Log File: $log_file"    echo -e ""
        echo debug_msg-e "InitialNew Logcluster Filelog Sizelevel: $initial_size"
    debug_msg "Current Log Level: $current_log_level"${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})"
       debug_msg "Cluster Name: $clusterName"
    debug_msg "jq_or_grep: $jq_or_grep"
    debug_msg "Detach: $detachable"echo -e "Current cluster log level is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."

    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[*]}  # Skip update if new level matches the current level
        if [[ "$current_log_level" -eq "$new_log_level" ]]; then
            echo ""
            echo -e "Cluster log level is already set to ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). No changes made."
     # Display initial information    return
if [[ "$log_level_type" == "cluster" ]]; then  fi

     echo -e "Swarm IP: ${GREEN}${ip_array[0]}${RESET}"
    else
# Update the cluster log level using PUT
       echo -edebug_msg "SwarmUpdating IPs: ${GREEN}${ip_array[*]}${RESET}"
    ficluster log level to $new_log_level_name"
      # echo -edebug_msg "SwarmCluster IPName: ${GREEN}$swarm_ip${RESET}"$clusterName"
        debug_msg "Credentials: ${GREEN}[hidden for security]${RESET}"
    echo -e "Cluster Name: ${GREEN}$clusterName${RESET}"(print_credentials "$credentials")"
        debug_msg "Starting main_script function..."
    debug_msg "Log level type: $log_level_typecurl --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}\""
     # Store the original log levels
    declare -A original_log_levels
    declare -A original_log_level_namesresponse=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
          if [[ $log_level_type == "cluster" ]]; then "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
         debug_msg "Setting cluster log level to -d "{\"value\": $new_log_level ($new_log_level_name)"}")
        # Retrieve current log leveldebug_msg "Response: $response"

         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   updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
        else
            currentupdated_log_level=$(curlecho --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level"$response" | "$jq_or_grep" -r '.value')
        fi
        currentdebug_msg "Updated cluster log level: $updated_log_level_name=${log_levels[$current_log_level]}
        debug_msg "Current cluster log level: "

        if [[ "$updated_log_level" -eq "$new_log_level" ]]; then
            echo -e "${GREEN}$(timestamp)${RESET} Log level changed successfully from ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET}")         debug_msg "Current log level name: -> ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$current$new_log_level_name$level${RESET})."
        echoelse
  -e ""         echo -e "New cluster${GREEN}$(timestamp)${RESET} Failed to update log level. Response: ${BOLD_GREEN}$new_log_level_name${RESET}"RED}$response${RESET}"
            exit 1
        fi

        echo# -eCountdown "Currentand clusterrevert log level
is ${GREEN}$current_log_level_name.${RESET}"        if [[ -n "$duration" # Skip update if new level matches the current level&& "$duration" -gt 0 ]]; then
            ifecho [[-e "$currentKeeping log level at ${YELLOW}$new_log_level" -eq "_name${RESET} (${YELLOW}$new_log_level" ]]; then
   level${RESET}) for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."
        echo ""   echo -e ""
       echo -e "Cluster log level is already set to ${BOLD_GREEN}$new_log_level_name${RESET}. No changes made."for ((i=duration; i>0; i--)); do
               return printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / fi60 )) $((i%60))
       # Update the cluster log level using PUT  echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"
  debug_msg "Updating cluster log level to $new_log_level_name"        sleep debug_msg1
"Cluster Name: $clusterName"         debug_msg "Credentials: $(print_credentials "$credentials")" done
           debug_msg "curlecho --usere \"$(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" \"\n\nTime's up! Reverting log level back to ${GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET}) ..."

            # Revert the log level back to the original value
            # echo -de "{\"value\": $new_log_level}")
  Level log revert on $(timestamp)"
     debug_msg "Response: $response"     response=$(curl --user "$credentials" -sS -X ifPUT [[-H "$jq_or_grep" == "grep" ]]; thenContent-Type: application/json" \
             updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \
       else         -d    updated"{\"value\": $current_log_level=$(echo "$response" | "$jq_or_grep" -r '.value'}")
        fi         debug_msg "Response: $response"Updated
cluster
log level: $updated_log_level"          if [[ "$updated$jq_logor_levelgrep" -eq== "$new_log_levelgrep" ]]; then
            echo -e "Log level changed successfully from ${GREEN}$current_log_level${RESET} -> ${BOLD_GREEN}$new_log_level${RESET}." reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
        else    else
        echo -e "Failed to update log level. Response: ${RED}$response${RESET}"
    reverted_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
        exit  1  fi
      fi      debug_msg "Reverted cluster log # Countdown and revert log levellevel: $reverted_log_level"

           if [[ final_size=$(stat -nc%s "$duration$log_file" && "$duration" -gt 0 ]]; then2>/dev/null || echo 0)
            echo -edebug_msg "KeepingInitial log levelfile at ${YELLOW}$new_log_level_name${RESET} for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."size: $initial_size"
            debug_msg "Final log file echo -e ""size: $final_size"
            for size_diff=$((i=duration; i>0; i--)); do final_size - initial_size ))
            size_diff_formatted=$(format_size "$size_diff")
   printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))    duration_formatted=$(format_duration "$duration")
	    if (( size_diff < 0 )); then
		echo -nee "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"
castor.log file was rotated."
	    else
           sleep 1echo -e ""
          done  echo -e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log  echo -e "\n\nTime's up! Reverting log level back to ${GREEN}$current_log_level${RESET}..."

  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})."
         # Revert the logecho level-e back""
to	 the original value fi
        if [[  response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \"$reverted_log_level" -eq "$current_log_level" ]]; then
            echo -e "${GREEN}$(timestamp)${RESET} Log level reverted successfully back  "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \to ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."
             echo   -de "{\"value\":
$current_log_level}")        else
    debug_msg "Response: $response"      echo -e "${GREEN}$(timestamp)${RESET} Failed to revert log  if [[ "$jq_or_grep" == "grep" ]]; thenlevel. Response: ${RED}$response${RESET}"
            echo -e ""
        reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')exit 1
        fi
    else    else
            reverted_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
   echo -e "${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified."
        fi
    elif [[ "$log_level_type" == "node" ]]; then
  debug_msg "Reverted cluster log level: $reverted_log_level"      # First loop: Change the node log level
        local same_log_level=false
        final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)for ip in "${ip_array[@]}"; do
            # Retrieve debug_msg "Initialcurrent node log file size: $initial_size"level
            debug_msg "FinalRetrieving current node log filelevel for sizeIP: $final_size$ip"
            size_diff=$(( final_size - initial_size ))debug_msg "curl -s -u \"$(print_credentials "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\""
            sizecurrent_difflog_formattedlevel=$(format_size "$size_diff"curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value')
            duration_formatted=$(format_duration "$duration")
	    if (( size_diff < 0 )); then
		echo -e "castor.log file was rotated."
	debug_msg "Current log level for IP $ip: $current_log_level"
    else             echo -e ""original_log_levels["$ip"]=$current_log_level
            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})."debug_msg "Original log level for IP $ip: ${original_log_levels["$ip"]}"
            if [[ "$current_log_level" == "0" ]]; then
              echo -e ""
	 current_log_level_name="default"
            fielse
              if [[ "$revertedcurrent_log_level" -eq "_name=${log_levels[$current_log_level" ]];}
then            fi
    echo -e "Log level reverted successfully back to ${BOLD_GREEN} original_log_level_names["$ip"]=$current_log_level${RESET}."level_name
            debug_msg "Original log level echo -e ""name: ${original_log_level_names["$ip"]}"
            if  else
 [[ "$new_log_level" == "0" ]]; then
              echo -e "Failed to revert log level. Response: ${RED}$response${RESET}" new_log_level_name="default"
            else
         echo -e ""     new_log_level_name=${log_levels[$new_log_level]}
           exit fi
1             fi
        elsedebug_msg "Current log level for IP $ip: $current_log_level ($current_log_level_name)"
             echo "Log"
level change is permanent until manually modified."      echo -e "New finode log    elif [[ "$log_level_type" == "node" ]]; thenlevel: ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})"
          # First loop:echo Change-e the"Current node log level for IP ${BOLD_GREEN}$ip${RESET}      local sameis ${BOLD_GREEN}$current_log_level=false
        for ip in "${ip_array[@]}"; do_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})."

            # RetrieveSkip currentupdate nodeif lognew level             debug_msg "Retrieving current node logmatches the current level
for IP: $ip"           if [[ debug_msg "curl -s -u \"$(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')"$current_log_level" -eq "$new_log_level" ]]; then
              debug_msg "Current same_log_level=true
level for IP $ip: $current_log_level"            echo original_log_levels["$ip"]=$current_log_level"
                echo debug_msg-e "OriginalNode log level for IP $ip: ${original_log_levels["$ip"]}"${BOLD_GREEN}$ip${RESET} is already set to ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). No changes made."
             if [[ "$current_log_level" == "0" ]]; then   continue
            else
                currentsame_log_level_name="default"false
            elsefi

            if [[  current"$same_log_level_name=${log_levels[$current_log_level]}" == false ]]; then
              fi  # Update the node log level using PUT
   original_log_level_names["$ip"]=$current_log_level_name             debug_msg "OriginalUpdating node log level name: ${originalto $new_log_level_names["$ip"]}"
  name for IP $ip..."
         if [[ "$new_log_level" == "0" ]]; then debug_msg "curl --user              new_log_level_name="default\"$(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\""
            else                 new_log_level_name=${log_levels[$new_log_level]}
        response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \
   fi             debug_msg "Current log level for IP $ip: $current_log_level ($current "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level_name)"")
                echodebug_msg "Response: $response"

            echo -e "New node logif level: ${BOLD_GREEN}$new_log_level_name${RESET}"
 [[ "$jq_or_grep" == "grep" ]]; then
          echo -e "Current node log level for IP $ip is ${GREEN}$currentupdated_log_level_name.${RESET}=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
            #  Skip update ifelse
new level matches the current level             if [[ "$currentupdated_log_level=$(echo "$response" -eq| "$new$jq_logor_levelgrep" ]]; then-r '.value')
                same_log_level=truefi
                echodebug_msg ""Updated log level for IP $ip: $updated_log_level"

         echo -e "Node log level for IP $ipif is already set to ${BOLD_GREEN}[[ "$updated_log_level" -eq "$new_log_level_name${RESET}. No changes made." ]]; then
              continue      echo -e "${GREEN}$(timestamp)${RESET} Node log level for else
                same_log_level=false
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})."
           fi     else
        if [[ "$same_log_level" == false ]]; then      echo -e "${GREEN}$(timestamp)${RESET} Failed        # Update the to update node log level usingfor PUT
  IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"
             debug_msg "Updating node log level to $new_log_level_name for IP $ip..."         exit 1
      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\"" fi
            fi
     response=$(curl --user "$credentials" -sSdone
-X
PUT -H "Content-Type: application/json" \    # Second loop: Countdown if duration is provided
         "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$newif [[ "$same_log_level") == false ]]; then\
            if  debug_msg "Response: $response"

 [[ -n "$duration" && "$duration" -gt 0 ]]; then
              if [[ "$jq_or_grep" == echo -e "grep"
]]; then               echo -e "Keeping node(s) log  updatedlevel at ${YELLOW}$new_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')
_name${RESET} (${YELLOW}$new_log_level${RESET}) for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."
               else echo -e ""
                 updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')for ((i=duration; i>0; i--)); do
                    printf -v countdown  fi"%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))
                debug_msg "Updated log level forecho IP-ne $ip: $updated_log_level"Countdown: ${YELLOW}$countdown${RESET} remaining...\r"
                 if   [[ "$updated_log_level" -eq "$new_log_level" ]]; thensleep 1
                done
         echo -e "Node log level for IP $ipecho changed successfully from ${GREEN}$current_log_level_name${RESET} -> ${BOLD_GREEN}$new_log_level_name${RESET}."
   -e "\n\nTime's up! Reverting node log level back to original levels..."

           else     # Third loop: Revert the node log level
        echo -e "Failed to update node log level for IPip $ip. Response: ${RED}$response${RESET}"
in "${ip_array[@]}"; do
                   exit 1
    current_log_level=${original_log_levels["$ip"]}
            fi        current_log_level_name=${original_log_level_names["$ip"]}
    fi         done       debug_msg "Reverting node #log Secondlevel loop:back Countdown if duration is providedto $current_log_level_name for IP $ip..."
        if [[ "$same_log_level" == false ]]; then\      debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X ifPUT [[ -n "$duration" && "$duration" -gt 0 ]]; then-H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\""
                    echo -e ""
               # echo -e "Keeping node(s)Node level log levelrevert aton ${YELLOW}$new_log_level_name${RESET} for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..."(timestamp) for IP $ip"
                    echoresponse=$(curl -e-user "$credentials" -sS -X PUT -H             for ((i=duration; i>0; i--)); do"Content-Type: application/json" \
                     printf -v countdown "%02dhttp:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))//$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level")
                     echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\rdebug_msg "Response: $response"

                   sleep 1if [[ "$jq_or_grep" == "grep" ]]; then
          done              reverted_log_level=$(echo "$response" | echogrep -eoP '"value":\n\nTime's up! Reverting node log level back to original levels..."s*\K[0-9]+')
                    else
   # Third loop: Revert the node log level              reverted_log_level=$(echo   for ip in "${ip_array[@]}"; do"$response" | "$jq_or_grep" -r '.value')
                     current_log_level=${original_log_levels["$ip"]}fi

                    current_log_level_name=${original_log_level_names["$ip"]}
   final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
                debug_msg "Reverting node log level back to $current_log_level_name for IP $ip..." size_diff=$(( final_size - initial_size ))
                    debug_msg "curlInitial --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\"log file size: $initial_size"
                    response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \debug_msg "Final log file size: $final_size"
                         "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_levelsize_diff_formatted=$(format_size "$size_diff")
                    debug_msg "Response: $response"duration_formatted=$(format_duration "$duration")

                    if [[ "$jq$reverted_orlog_greplevel" ==-eq "grep$current_log_level" ]]; then
                        echo  reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')-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})."
                    else
                        reverted_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')
          -e "${GREEN}$(timestamp)${RESET} Failed to revert node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}"
         fi               exit 1
     final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
                    size_diff=$(( final_size - initial_size ))           fi
         debug_msg "Initial log file size: $initial_size"  done

                # debug_msg "FinalCombine the log fileoutput size: $final_size"
     for multiple IP addresses into a single summary
            if (( size_diff_formatted=$(format_size "$size_diff")
 < 0 )); then
            echo -e "castor.log file was rotated."
 duration_formatted=$(format_duration "$duration")           else
            if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then  echo -e ""
                    echo -e "Node log level for IP $ip reverted successfully back toApproximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}${current$new_log_level_namename${RESET} (${BOLD_GREEN}$new_log_level${RESET}.") for IP ${ip_array[*]}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET}          else
 seconds (${YELLOW}$duration_formatted${RESET})."
                      echo -e "Failed"
to revert node log level for IP $ip. Response: ${RED}$response${RESET}"   fi
            else
        exit 1       echo              fi
   -e "${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified."
            donefi
        fi
    fi
 }

# CombineRun thein logdetachable outputor fordirectly
multipleif IP addresses into a single summary
            if (( size_diff < 0 )); then
       $detachable; then
    # Pass the main_script function to the screen session and store the output in a file
    echo -e "castor.log file was rotated."
   debug_msg "**********************************************************" | tee -a "$output_log"
    debug_msg "Detach mode - elseParameters passed to main_script:"                  echo -e "| tee -a "$output_log"
    debug_msg "     Swarm IP: $swarm_ip" | tee      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 "-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   "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

...