...
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 tojq
otherwise.Detachable Session Execution: Runs in a detachable session using
screen
ortmux
, allowing the script to continue running independently of the terminal session. If bothscreen
andtmux
are installed, the script will prioritizescreen
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 forCSN
andSCS
environments.Log Size Monitoring: Reports the log size generated during the temporary log level change.
Countdown Display: Shows a countdown for the specified duration.
...
jq: 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.
Script Usage
Handling Passwords with Special Characters
If your password contains special characters such as @
, #
, $
, &
or !
, you need to properly escape them or enclose the password in single quote ('
) when passing it as a parameter. Alternatively, use a secure password prompt.
Example 1: Escape special characters in the password
Code Block |
---|
./castor-change-log-level.sh -d <node_ip>192.168.8.84 -p <admin:password> [-i new_log_level | -L new_node_log_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
...
admin:pa\@ss\$word -i 20 -t 600 |
Example 2: Enclose the password in single quotes
Code Block |
---|
./castor-change-log-level.sh -d 192.168.8.84 -p 'admin:pa@ss$word' -i 20 -t 600 |
Example 3: Use the secure password prompt (Recommended)
Code Block |
---|
./castor-change-log-level.sh -p admin -d 192.168.8.84 -i 10 -t 300 |
The script will securely prompt you to enter the password without exposing it in the command line.
Usage of the script as described below:
Code Block |
---|
./castor-change-log-level.sh -d <node_ip> -p '<admin:password>' [-i new_log_level | -L new_node_log_level] [-t <duration_in_seconds>] [-D --detach] [-v] |
Parameter | Description |
---|---|
| IP address of the Swarm API endpoint (or set |
| Admin credentials in the format |
| New log level to set (values: |
| New node log level to set (values: |
| Duration in seconds to keep the new log level (optional). |
| Runs the script in a detachable session using |
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 -D |
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: Secure password prompt if password are not provided
...
Example 4: Secure password prompt if password are not provided
Code Block |
---|
./castor-change-log-level.sh -p admin -d 192.168.8.84 -i 10 -t 300 |
(You will be prompted to enter the password securely.)Example 5: Schedule the script to run at 3:00 AM on 03/02/2025 and collect debug logs for 1 hour
...
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
:
...
Code Block |
---|
./castor-change-log-level.sh -p admin -d 192.168.8.84 -i 10 -t |
...
300 |
...
|
...
Enter |
...
password |
...
for user admin: |
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 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
...
To verify scheduled job:
Code Block atq 7 Sun Mar 02 03:00:00 2025 a root
To remove a scheduled job (replace
JOB_ID
with the actual job number fromatq
output):Code Block atrm 7
Behavior
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.
Countdown: During the specified duration, the script displays a countdown every second.
Revert Log Level: After the countdown, the log level reverts to the initial value.
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.
...
Ensure the at service is installed, enabled and running
Code Block dnf -y install epel-release dnf -y install at systemctl enable --now at
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.
To verify scheduled job:
Code Block atq 7 Sun Mar 02 03:00:00 2025 a root
To remove a scheduled job (replace
JOB_ID
with the actual job number fromatq
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:
List active
screen
session:Code Block screen -ls
Reattach to the session:
Code Block screen -r <session_name>
For tmux
users:
List active
tmux
sessions:Code Block tmux ls
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
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.
Countdown: During the specified duration, the script displays a countdown every second.
Revert Log Level: After the countdown, the log level reverts to the initial value.
Log Size Report: Provides approximately log size generated during the temporary log level change.
Output Messages
Message | Description |
---|---|
| Displays the specified Swarm IP address. |
| Displays the cluster name retrieved from the Swarm API. |
| Shows the new log level requested. |
| Displays the current log level. |
| Indicates the beginning of the log level update process. |
| Confirms that the log level was successfully updated. |
| Shows the temporary period for which the new log level is retained, with a countdown. |
| Indicates that the temporary period has ended and the script is reverting the log level. |
| 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 | ||
---|---|---|
| ||
#!/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. # v1.3.4 - Enhanced password handling to better support password with special characters. # ----------------------------------------------------------------------------------------------------------------------------- # Current Version: 1.3.24 # ----------------------------------------------------------------------------------------------------------------------------- # 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 | --detach]" 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 local caller_line=${BASH_LINENO[0]:-unknown} # Fallback to "unknown" if empty echo -e "$(timestamp) [DEBUG] ($caller_func:$caller_line) $*" fi } # Function to check if either 'screen' or 'tmux' is installed check_screen_or_tmux() { if ! command -v screen &>/dev/null && ! command -v tmux &>/dev/null; then echo -e "" echo -e "---------------------------------------------------------------------------------------" echo -e " ${YELLOW}Warning${RESET}: Neither '${BOLD_GREEN}screen${RESET}' nor '${BOLD_GREEN}tmux${RESET}' is installed. Cannot run in detachable mode." echo -e " Please install either '${BOLD_GREEN}screen${RESET}' or '${BOLD_GREEN}tmux${RESET}' to run the script in a detachable session." echo -e "---------------------------------------------------------------------------------------" detachable=false # Disable detachable session usage fi } # Function to format file size format_size() { local size=$1 if (( size >= 1073741824 )); then echo "$(awk "BEGIN {printf \"%.1fGB\", $size/1073741824}")" elif (( size >= 1048576 )); then echo "$(awk "BEGIN {printf \"%.1fMB\", $size/1048576}")" elif (( size >= 1024 )); then echo "$(awk "BEGIN {printf \"%.1fKB\", $size/1024}")" else echo "${size}B" fi } # Function to format duration format_duration() { local duration=$1 local hours=$((duration / 3600)) local minutes=$(( (duration % 3600) / 60 )) local seconds=$((duration % 60)) printf "%02d:%02d:%02d" $hours $minutes $seconds } # Function to check if jq is available and set up JSON parsing method check_jq() { for jq_path in "/usr/local/bin/jq" "$(pwd)/jq"; do [[ -x "$jq_path" ]] && echo "$jq_path" && return done command -v jq &>/dev/null && echo "jq" || echo "grep" } if [[ -f "$JQLOCATION" ]]; then jq_or_grep=$JQLOCATION else jq_or_grep=$(check_jq) fi debug_msg "jq_or_grep: $jq_or_grep" #jq_or_grep=$(check_jq) # Function to determine the log file path determine_log_file() { for log in "/var/log/datacore/castor.log" "/var/log/caringo/castor.log"; do if [[ -f "$log" ]]; then (Alternatively, setecho the SCSP_HOST environment variable to the Swarm IP.)""$log" echo " return -p, --credentials fi Credentials in the format admin:password"done echo -e "${RED}Error: Log file -i, --log.level New cluster log level to set (5, 10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default)" echo " -L, --node.log.level New node log level to set (0, 5, 10, 15, 20, 30, 40, 50, chatter, debug, announce, info, error, critical, default)" echo not found.${RESET}" exit 1 } log_file=$(determine_log_file) # Function to check if credentials are valid check_credentials() { local CREDENTIALS="$1" local SWARM_IP="$2" debug_msg "Credentials: [hidden for security]" debug_msg "Swarm IP: $SWARM_IP" # API endpoint for validating user credentials local VALIDATE_URL="http://${SWARM_IP}:91/api/validateUser" debug_msg "Validate URL: $VALIDATE_URL" # Make the API request debug_msg "Validating user credentials..." debug_msg "curl -s -u \"**Either -i or -L must be specified, but not both.**" echo " -t, --time ******\" -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" (Optional)# DurationCheck inif secondsthe toresponse keep the new log level (must be greater than 0)" echo " -D, --detachcontains "isValid": true if echo "$RESPONSE" | "$jq_or_grep" -e '.isValid == true' > /dev/null 2>&1; then debug_msg "Authentication successful for (Optional) Detach the script 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 user '${CREDENTIALS%%:*}'" return 0 # Success elif echo "$RESPONSE" | "$jq_or_grep" -e '.isValid == false' > /dev/null 2>&1; then debug_msg "Authentication failed for user '${CREDENTIALS%%:*}'" return 1 # Failure else debug_msg "Error: Unable to validate credentials. Please check your inputs." return 1 # Failure fi } # Function to print credentials - hide password print_credentials() { local #CREDENTIALS="$1" Maximum number of password retrieslocal attempts usernameUSERNAME="admin${CREDENTIALS%%:*}" echo -e "${GREEN}$USERNAME${RESET}":"${GREEN}********${RESET}" } # Parse input arguments while [[ "$#" -gt 0 ]]; do case $1 in # Default username password="" -d|--swarm_ip) swarm_ip="$2"; debug_msg "Set swarm_ip to $swarm_ip"; shift 2 ;; -p|--credentials) credentials="$2" # Defaultshift password2 ;; # Global associative array for log levels declare -A log_levels=(i|--log.level) [5]="chatter" [10]="debug" if [15]="audit" [20]="info" [30]="warning"[[ -n "$new_log_level" ]]; then [40]="error" [45]="defect" echo [50]="critical" [60]="announce" [30]="default" ) # Global associative array for log level names declare -A log_level_names=( ["chatter"]=5 ["debug"]=10 ["audit"]=15 ["info"]=20 ["warning"]=30 ["error"]=40 ["defect"]=45 ["critical"]=50 ["announce"]=60 ["default"]=30 ) # Function to get the current timestamp timestamp() { date -u +"%Y-%m-%dT%H:%M:%S.%3NZ" } # Function to display debug messages if debug mode is enabled debug_msg() { if $debug"Error: Options -i (cluster log leve) and -L (node log level) cannot be used together." usage fi log_level_type="cluster" if [[ ${log_level_names[$2]} ]]; then new_log_level=${log_level_names[$2]} elif [[ "$2" == "default" ]]; then local caller_line new_log_level=${BASHdefault_log_LINENO[0]:-unknownlevels[$log_level_type]} # Fallback to "unknown" if empty echo -e "$(timestamp) [DEBUG] (Line $caller_line) $*"new_log_level_name="default" fi }elif # Function to check if either 'screen' or 'tmux' is installed check_screen_or_tmux() {[[ ${log_levels[$2]} ]]; then if ! command -v screen &>/dev/null && ! command -v tmux &>/dev/null; then new_log_level=$2 else echo -e "" echo -e "---------------------------------------------------------------------------------------""Invalid log level: $2" echo -e " ${YELLOW}Warning${RESET}: Neither '${BOLD_GREEN}screen${RESET}' nor '${BOLD_GREEN}tmux${RESET}' is installed. Cannot run in detachable mode." exit 1 fi echo -e " Please install either '${BOLD_GREEN}screen${RESET}' or '${BOLD_GREEN}tmux${RESET}' to run the script in a detachable session." new_log_level_name=${log_levels[$new_log_level]} default_log_level=30 debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)" echo -e "---------------------------------------------------------------------------------------" shift echo2 -e "" detachable=false #;; Disable detachable session -L|--node.log.level) debug_msg "detachable=${YELLOW}false${RESET}" debug_msg "Stopping the script..." if [[ -n "$new_log_level" ]]; then exit 1 fi } #echo Function"Error: toOptions format-i file(cluster size format_size(log leve) { local size=$1 and -L (node log level) cannot be used together." if (( size >= 1073741824 )); then usage echo "$(awk "BEGIN {printf \"%.1fGB\", $size/1073741824}")" elif ((fi size >= 1048576 )); then echo "$(awk "BEGIN {printf \"%.1fMB\", $size/1048576}")"log_level_type="node" elif (( sizeif >= 1024 ))[[ ${log_level_names[$2]} ]]; then echo "$(awk "BEGIN {printf \"%.1fKB\", $size/1024}")" new_log_level=${log_level_names[$2]} else elif echo[[ "${size}B$2" == "default" ]]; then fi } # Function to format duration format_duration() { local duration=$1new_log_level=${default_log_levels[$log_level_type]} local hours=$((duration / 3600)) local minutes=$(( (duration % 3600) / 60 )) new_log_level_name="default" elif local[[ seconds=$((duration % 60)) ${log_levels[$2]} || $2 -eq 0 ]]; then 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=$2 if [[ -x "/usr/local/bin/jq" ]]; then new_log_level_name="default" else echo "/usr/local/bin/jq" elif [[ -x "$(pwd)/jq" ]]; then echo "Invalid log level: $2" echo "$(pwd)/jq" elif command -v jq &>/dev/null; then exit 1 echo "jq" else fi echo "grep" fi } if [[ -f "$JQLOCATION" ]]; then new_log_level_name=${log_levels[$new_log_level]} jqdefault_orlog_grep=$JQLOCATION elselevel=0 jq_or_grep=$(check_jq) fi debug_msg "jqSet new_or_grep: $jq_or_grep" #jq_or_grep=$(check_jq) # Function to determine the log file path determine_log_file() {log_level to $new_log_level ($new_log_level_name)" shift 2 ;; -t|--time) if [[ -f "/var/log/datacore/castor.log" n "$2" && "$2" != -* && "$2" -gt 0 ]]; then echo "/var/log/datacore/castor.log" duration="$2" elif [[ -f "/var/log/caringo/castor.log" ]]; then debug_msg "Set duration to $duration" shift 2 echo "/var/log/caringo/castor.log" else echo "Error: Log file not found in /var/log/datacore/castor.log or /var/log/caringo/castor.log echo -e "" exit 1 fi }echo log_file=$(determine_log_file) # Function to check if credentials are valid check_credentials() { local CREDENTIALS="$1" local SWARM_IP="$2" debug_msg "Credentials: [hidden for security]" debug_msg "Swarm IP: $SWARM_IP"-e "---------------------------------------------------------------------------------------" echo -e " ${RED}Error${RESET}: Duration must be a number greater than ${BOLD_GREEN}0${RESET}." #echo API-e endpoint" for validating user credentialsPlease specify the duration using local VALIDATE_URL="http://the ${SWARM_IP}:91/api/validateUser" debug_msg "Validate URL: $VALIDATE_URLBOLD_GREEN}-t${RESET} ${GREEN}<seconds>${RESET} or ${BOLD_GREEN}--time${RESET} ${GREEN}<seconds>${RESET} option." # Make the API request debug_msg "Validating user credentials..." debug_msg "curl -s -u \"********\" -X GET \"$VALIDATE_URL\" -H 'Content-Type: application/json'" RESPONSE=$(curl -s -u "$CREDENTIALS" -X GET "$VALIDATE_URL" -H 'Content-Type: application/json') debug_msg "Validate User Response: $RESPONSE" # Check if the response contains "isValid": true if echo "$RESPONSE" | "$jq_or_grep" -e '.isValid == true' > /dev/null 2>&1; thenecho -e "---------------------------------------------------------------------------------------" usage fi ;; -D|--detach) detachable=true; debug_msg "Authentication successful for user '${CREDENTIALS%%:*}'"Set detachable to true"; shift ;; return 0 # Success elif echo "$RESPONSE" | "$jq_or_grep" -e '.isValid == false' > /dev/null 2>&1; then--debug) debug=true; debug_msg "Set debug to true with ${YELLOW}--debug${RESET}"; shift ;; *) usage ;; esac done debug_msg "Authentication failed for user '${CREDENTIALS%%:*}'Set log_level_type to ${YELLOW}$log_level_type${RESET}" # Check if 'screen' or 'tmux' is returninstalled 1if [[ # Failure else"$detachable" == true ]]; then if [[ -z "$duration" debug_msg "Error: Unable to validate credentials. Please check your inputs." ]]; then echo -e "" return 1 # Failureecho -e "---------------------------------------------------------------------------------------" fi } # Function to printecho credentials-e -" hide password print_credentials() { local CREDENTIALS="$1" local USERNAME="${CREDENTIALS%%:*}" ${RED}Error${RESET}: Duration must be specified when running in detachable mode." echo -e " Please specify the duration using the ${BOLD_GREEN}$USERNAME$-t${RESET}":" or ${BOLD_GREEN}********${RESET}" } # Parse input arguments while [[ "$#" -gt 0 ]]; do case $1 in -d|--swarm_ip) swarm_ip="$2"; debug_msg "Set swarm_ip to $swarm_ip"; shift 2 ;; -p|--credentials) --time${RESET} option." echo -e "---------------------------------------------------------------------------------------" usage fi check_screen_or_tmux fi # If swarm_ip is not provided, try using SCSP_HOST environment variable if [[ -z "$swarm_ip" ]]; then if [[ -n "$SCSP_HOST" ]]; then credentialsswarm_ip="$2$SCSP_HOST" debug_msg "Using Swarm IP shift 2 ;; from SCSP_HOST: $swarm_ip" -i|--log.level) else echo "Error: swarm_ip ifnot [[provided -nand "$new_log_level" ]]; thenSCSP_HOST is not set." usage fi fi # Check echo "Error: Options -i (cluster log leve) and -L (node log level) cannot be used together." usage fi if [[ ${log_level_names[$2]}if required arguments are provided if [[ -z "$credentials" || -z "$new_log_level" ]]; then usage fi # Split the swarm_ip into an array of IP addresses if it contains delimiters IFS=';, ' read -r -a ip_array <<< "$swarm_ip" # Validate credentials before proceeding debug_msg "Validating credentials..." #if [[ "$credentials" =~ ^[^:]+$ ]]; then if [[ -n "$credentials" ]]; then CREDENTIALS="$credentials" ATTEMPT=$MAX_RETRIES USERNAME="" new_log_level=${log_level_names[$2]} PASSWORD="" debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS")" elif [[ ${log_levels[$2]} ]]; thendebug_msg "ATTEMPT: $ATTEMPT" # # Capture the original command as executed by the user new_log_level=$2 # ORIGINAL_INPUT=$(ps -o args= -p $$) else# debug_msg "ORIGINAL_INPUT: $ORIGINAL_INPUT" # Check if credentials contain a colon echo "Invalid log level: $2" (username:password format) if [[ "$CREDENTIALS" == *":"* ]]; then debug_msg exit"Checking 1for colon in credentials..." debug_msg fi"Credentials contain colon" new_log_level_name=${log_levels[$new_log_level]}USERNAME="${CREDENTIALS%%:*}" log_level_type="clusterPASSWORD="${CREDENTIALS#*:}" default_log_level=30 debug_msg "Username: $USERNAME" debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)"Password: $PASSWORD" # Define special characters that shiftmay 2cause issues debug_msg "Defining ;;special characters..." -L|--node.log.level)SPECIAL_CHARS="!@#\$%^&*()_+{}|:<>?~\`-=[]\\;',./\"" debug_msg "Special characters: $SPECIAL_CHARS" if [[ -n "$new_log_level" ]]; then # Debug: Show the final regex pattern echodebug_msg "Error:Special Optionscharacters -i (cluster log leve) and -L (node log level) cannot be used together." regex: $SPECIAL_REGEX" # Check if password start with '$' # usageWhen credentials contains ":" and password is empty fi # it will be treated as environment variable if [[ ${log_level_names[$2]} ]]; then # Bash will try to expand the variable and new_log_level=${log_level_names[$2]} if it starts with '$' if elif [[ ${log_levels[$2]} || $2 -eq 0-z "$PASSWORD" ]]; then new_log_level=$2 new_log_level_name="default"debug_msg "Password is empty, bash may interpret the password as an environment variable." elseecho -e "" echo echo "Invalid log level: $2" -e "${RED}Error${RESET}: Password cannot start with '${BOLD_YELLOW}\$'${RESET}." exitecho 1-e "Bash may interpret the password as an environment variable." fi echo -e "To new_log_level_name=${log_levels[$new_log_level]} log_level_type="nodeprevent issues, enclose the password in single quotes (${BOLD_YELLOW}'${RESET})." default_log_level=0 echo -e "" debug_msg "Set new_log_level to $new_log_level ($new_log_level_name)echo -e "${GREEN}Example${RESET}:" shiftecho 2-e " -p ${BOLD_YELLOW}'${RESET}${GREEN}admin:\$password123${RESET}${BOLD_YELLOW}'${RESET}" ;; echo -e -t|--time)"" exit 1 if [[ -n "$2" &&fi "$2" != -* && "$2" -gt 0 ]]; then # Validate credentials duration="$2" check_credentials "$CREDENTIALS" "${ip_array[0]}" if [[ debug_msg "Set duration to $duration"$? -ne 0 ]]; then debug_msg "Invalid credentials. Please check shiftyour 2username and password." else echo -e "" echo -e "Error${RED}Error${RESET}: DurationInvalid mustcredentials. bePlease acheck numberyour greaterusername thanand 0password." echo -e "If your password exitcontains 1special characters, enclose it in single quotes (${BOLD_YELLOW}'${RESET}) to prevent misinterpretation by the fisystem." ;;echo -e "${GREEN}Special characters include${RESET}: ${YELLOW}$SPECIAL_CHARS${RESET}" -D|--detach) detachable=true; debug_msg "Set detachable to true"; shift ;;echo -e "" --debug) debug=true; debug_msg "Set debug to trueecho with-e "${YELLOWGREEN}--debug$Example${RESET}:"; shift ;; *) usage ;;echo -e " esac done debug_msg "Set log_level_type to ${YELLOW}$log_level_type$-p ${BOLD_YELLOW}'${RESET}${GREEN}admin:password!@#${RESET}${BOLD_YELLOW}'${RESET}" # Set default values if not provided debug_msg "Checking for default logecho level values..." # Change the default log level based on Log Level Type debug_msg "Changing default log level based on Log Level Type: ${YELLOW}$log_level_type${RESET}" if [[ -n "$new_log_level" ]]; then-e "" exit 1 fi debug_msg "Validate credentials" if [[ "$log_level_type" credentials==$CREDENTIALS "node" ]]; then else # new_log_level=0debug_msg "Credentials do not contain password" debug_msg "Checing node default log level "Username: $(print_credentials "$CREDENTIALS")" USERNAME="$CREDENTIALS" default_log_level=0# Prompt for password ifwhile [[ $new_log_level == 30$ATTEMPTS -lt $MAX_RETRIES ]]; do then echo "" new_log_level=$default_log_level read -sp "Enter password for new_log_level_name="default" user $USERNAME: " PASSWORD fi echo "" debug_msg "node - new_log_level: to $new_log_level" echo "" debug_msg "node - new_log_level_name: to $new_log_level_name" elifif [[ "$log_level_type" == "cluster-z "$PASSWORD" ]]; then default_log_level=30 fi debug_msg "New log level: ${GREEN}$new_log_level${RESET}echo -e "${RED}Error${RESET}: Password cannot be empty." debug_msg "New log level name: ${GREEN}$new_log_level_name${RESET}" debug_msg "Set default_log_level to: $default_log_level" fi # Check if 'screen' or 'tmux' is installed if [[ "$detachable" == true ]]; then((ATTEMPTS++)) continue check_screen_or_tmux fi # Iffi swarm_ip is not provided, try using SCSP_HOST environment variable if [[ -z "$swarm_ip" ]]; thenCREDENTIALS="$USERNAME:$PASSWORD" if [[ -n "$SCSP_HOST" ]]; then debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))" swarm_ip="$SCSP_HOSTcheck_credentials "$CREDENTIALS" "${ip_array[0]}" debug_msg "Using Swarm IPif from SCSP_HOST: $swarm_ip" else[[ $? -eq 0 ]]; then echo "Error: swarm_ip not provided and SCSPdebug_HOSTmsg is not set."CREDENTIALS: $(print_credentials "$CREDENTIALS"))" usage fi fidebug_msg "Valid #credentials" Check if required arguments are provided if [[ -z "$credentials" || -z "$new_log_level" ]]; then credentials=$CREDENTIALS usage fi # Split the swarm_ip into an array of IP addresses ifbreak it contains delimiters IFS=';, ' read -r -a ip_array <<< "$swarm_ip" #else Validate credentials before proceeding debug_msg "Validating credentials..." #if [[ "$credentials" =~ ^[^:]+$ ]]; then if [[ -n "$credentials" ]]; then echo -e "" CREDENTIALS="$credentials" ATTEMPT=$MAX_RETRIES echo -e USERNAME=""${RED}Error${RESET}: Invalid credentials. Please check your username and password." PASSWORD="" debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS")" echo debug_msg-e "ATTEMPT: $ATTEMPT" # Check if credentials contain a colon (username:password format)fi debug_msg "Checking for colon in credentials..." ((ATTEMPTS++)) if [[ "$CREDENTIALS" == *":"* ]]; thendone debug_msg "Credentials contain colon" if [[ $ATTEMPTS -ge $MAX_RETRIES ]]; then USERNAME="${CREDENTIALS%%:*}" echo -e PASSWORD="${CREDENTIALS#*:}" # Validate credentials echo -e "${RED}Error${RESET}: Maximum number of password check_credentials "$CREDENTIALS" "${ip_array[0]}"attempts reached. Exiting script." if [[ $? -neexit 01 ]]; then fi fi debug_msgelse "Invalid credentials. Please check yourif username! and password." check_credentials "$credentials" "${ip_array[0]}"; then echo -e "" echo -e "${REDYELLOW}Error$Warning${RESET}: Invalid credentials. Please check your username and password." ${RED}Invalid credentials${RESET}." echo -e "" exit 1 exit 1 fi fi # Retrieve cluster name and fihandle JSON parsing using the first IP address debug_msg "ValidateRetrieving credentials"the cluster name from Swarm API using IP: credentials=$CREDENTIALS else ${ip_array[0]}" if [[ "$jq_or_grep" == "grep" ]]; then clusterName=$(curl --user debug_msg "Credentials do not contain password" debug_msg "Username: $(print_credentials "$CREDENTIALS")" "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | grep -oP '"name":\s*"\K[^"]+') else clusterName=$(curl --user USERNAME="$CREDENTIALS$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | "$jq_or_grep" -r '._embedded.clusters[0].name') fi # Prompt for password while if [[ $ATTEMPTS -lt $MAX_RETRIESz "$clusterName" ]]; do then echo ""Failed to retrieve the cluster name. Please check read -sp "Enter password for user $USERNAME: " PASSWORDyour inputs." exit 1 echo "" echo ""fi debug_msg "Cluster Name: $clusterName" # Main logic function to run the script tasks main_script() { local swarm_ip="$1" local CREDENTIALScredentials="$USERNAME:$PASSWORD$2" local new_log_level="$3" local debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))"new_log_level_name="$4" local duration="$5" local check_credentials "$CREDENTIALS" "${ip_array[0]}"log_level_type="$6" #local log_file="/var/log/datacore/castor.log" if [[ $? -eq 0z "$log_file" ]]; then log_file=$(determine_log_file) fi local debug_msg "CREDENTIALS: $(print_credentials "$CREDENTIALS"))" initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0) local current_log_level debug_msg "Valid credentialslocal clusterName="$7" local jq_or_grep="$8" credentials=$CREDENTIALSlocal detachable="$9" if [[ "$detachable" ]]; then break local debug="${10}" eval else "$(echo "${11}" | sed 's/declare -A/declare -A/')" eval "$(echo -e ""${12}" | sed 's/declare -A/declare -A/')" fi echo -e "${RED}Error${RESET}: Invalid credentials. Please check your username and password.local default_log_levels="$13" local default_log_levels_name="$14" debug_msg "**********************************************************" debug_msg "local fivariables" debug_msg "Log Level Type: ((ATTEMPTS++))${GREEN}$log_level_type${RESET}" debug_msg "Default Log Level: ${GREEN}$default_log_level${RESET}" done debug_msg "Swarm fi elseIP: $swarm_ip" if ! checkdebug_msg "Credentials: $(print_credentials "$credentials")" "${ip_array[0]}"; then debug_msg "New Log Level: $new_log_level" debug_msg "New log Level echo -e ""Name: $new_log_level_name" debug_msg "Duration: $duration" echo -e "${YELLOW}Warning${RESET}: ${RED}Invalid credentials${RESET}.debug_msg "Log File: $log_file" debug_msg "Initial Log File echo -e ""Size: $initial_size" debug_msg "Current Log exit 1Level: $current_log_level" debug_msg fi"Cluster fiName: $clusterName" # Retrieve cluster name and handle JSON parsing using the first IP addressdebug_msg "jq_or_grep: $jq_or_grep" debug_msg "RetrievingDetach: the$detachable" cluster name from Swarm API using IP: ${ip_array[0]}" if [[ "$jq_or_grep" == "grep" ]]; then clusterName=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | grep -oP '"name":\s*"\K[^"]+') else clusterName=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters" | "$jq_or_grep" -r '._embedded.clusters[0].name') fi if [[ -z "$clusterName" ]]; then echo "Failed to retrieve the cluster name. Please check your inputs." exit 1 fi debug_msg "Cluster Name: $clusterName" # Main logic function to run the script tasks main_script() { local swarm_ip="$1" local credentials="$2" local new_log_level="$3" local new_log_level_name="$4" local duration="$5" local log_level_type="$6" #local log_file="/var/log/datacore/castor.log" if [[ -z "$log_file" ]]; then log_file=$(determine_log_file) fi local initial_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0) local current_log_level local clusterName="$7" local jq_or_grep="$8" local detachable="$9" if [[ "$detachable" ]]; then local debug="${10}" eval "$(echo "${11}" | sed 's/declare -A/declare -A/')" eval "$(echo "${12}" | sed 's/declare -A/declare -A/')" fi debug_msg "**********************************************************" debug_msg "local variables" debug_msg "Log Level Type: ${GREEN}$log_level_type${RESET}" debug_msg "Default Log Level: ${GREEN}$default_log_level${RESET}" debug_msg "Swarm IP: $swarm_ip" debug_msg "Credentials: $(print_credentials "$credentials")" debug_msg "New Log Level: $new_log_level" debug_msg "New log Level Name: $new_log_level_name" debug_msg "Duration: $duration" debug_msg "Log File: $log_file" debug_msg "Initial Log File Size: $initial_size" debug_msg "Current Log Level: $current_log_level" debug_msg "Cluster Name: $clusterName" debug_msg "jq_or_grep: $jq_or_grep" debug_msg "Detach: $detachable" debug_msg "Debug: $debug" debug_msg "**********************************************************" # Split the swarm_ip into an array of IP addresses IFS=';, ' read -r -a ip_array <<< "$swarm_ip" debug_msg "IP Array: ${ip_array[*]}" # Display initial information if [[ "$log_level_type" == "cluster" ]]; then echo -e "Swarm IP: ${GREEN}${ip_array[0]}${RESET}" elsedebug_msg "Debug: $debug" debug_msg "**********************************************************" # Split the swarm_ip into an array of IP addresses IFS=';, ' read -r -a ip_array <<< "$swarm_ip" debug_msg "IP Array: ${ip_array[*]}" # Display initial information if [[ "$log_level_type" == "cluster" ]]; then echo -e "Swarm IP: ${GREEN}${ip_array[0]}${RESET}" else echo -e "Swarm IPs: ${GREEN}${ip_array[*]}${RESET}" fi # echo -e "Swarm IP: ${GREEN}$swarm_ip${RESET}" debug_msg "Credentials: ${GREEN}[hidden for security]${RESET}" echo -e "Cluster Name: ${GREEN}$clusterName${RESET}" debug_msg "Starting main_script function..." debug_msg "Log level type: $log_level_type" # Store the original log levels declare -A original_log_levels declare -A original_log_level_names default_log_level=${default_log_levels[$log_level_type]} default_log_level_name=${default_log_level_names[$log_level_type]} debug_msg "Default log level: $default_log_level" debug_msg "Default log level name: $default_log_level_name" if [[ $log_level_type == "cluster" ]]; then debug_msg "Setting cluster log level to $new_log_level ($new_log_level_name)" # Retrieve current log level if [[ "$jq_or_grep" == "grep" ]]; then current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | grep -oP '"value":\s*\K[0-9]+') else current_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | "$jq_or_grep" -r '.value') fi current_log_level_name=${log_levels[$current_log_level]} if [[ $current_log_level == 30 ]]; then current_log_level_name="default" fi if [[ $new_log_level == 30 ]]; then new_log_level_name="default" fi debug_msg "Current cluster log level: ${BOLD_GREEN}$current_log_level${RESET}" debug_msg "Current log level name: ${BOLD_GREEN}$current_log_level_name${RESET}" echo -e "Swarm IPs: ${GREEN}${ip_array[*]}${RESET}" fi # echo -e "Swarm IPNew cluster log level: ${BOLD_GREEN}$swarm_ip$$new_log_level_name${RESET}" debug_msg "Credentials: (${BOLD_GREEN}[hidden for security]$$new_log_level${RESET})" echo -e "Cluster Name: ${GREEN}$clusterName${RESET}Current cluster log level is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})." debug_msg "Starting main_script function..." # Skip update if debug_msg "Log level type: $log_level_type" # Store the original log levels declare -A original_log_levels declare -A original_log_level_namesnew level matches the current level if [[ "$current_log_level" -eq "$new_log_level" ]]; then if [[ $log_level_type == "cluster" ]]; then echo "" echo debug_msg-e "SettingCluster cluster log level is already set to ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level_name)"level${RESET}). No changes made." return # fi Retrieve current log level # Update the ifcluster [[ "$jq_or_grep" == "grep" ]]; thenlog level using PUT debug_msg "Updating cluster log level to current$new_log_level=$(curl --user "$credentials" -sS "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" | grep -oP '"value":\s*\K[0-9]+') _name" debug_msg "Cluster Name: $clusterName" else debug_msg "Credentials: $(print_credentials "$credentials")" current_log_level=$(curl --user "$credentials" -sS debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -H \"Content-Type: application/json\" \"http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level\" |-d "$jq_or_grep" -r '.value') fi\"{\\\"value\\\": $new_log_level}\"" response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ current_log_level_name="http://${logip_levels[$current_log_level]}array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \ debug_msg "Current cluster log level: ${BOLD_GREEN}$current_log_level${RESET}"-d "{\"value\": $new_log_level}") debug_msg "CurrentResponse: log$response" level name: ${BOLD_GREEN}$current_log_level_name${RESET}" if echo -e[[ "$jq_or_grep" == "grep" ]]; then echo -e "New cluster log level: ${BOLD_GREEN}$new updated_log_level_name${RESET}"=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+') echo -e "Current cluster log level is ${GREEN}$currentelse updated_log_level_name.${RESET}"=$(echo "$response" | "$jq_or_grep" -r '.value') fi # Skip update if new level matches the current leveldebug_msg "Updated cluster log level: $updated_log_level" if [[ "$current$updated_log_level" -eq "$new_log_level" ]]; then echo "" echo -e "Cluster log${GREEN}$(timestamp)${RESET} Log level ischanged alreadysuccessfully setfrom to ${BOLD_GREEN}$new$current_log_level_name${RESET}. No changes made." return fi (${BOLD_GREEN}$current_log_level${RESET}) -> ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})." else # Update the cluster log level using PUT echo -e "${GREEN}$(timestamp)${RESET} Failed debug_msg "Updating clusterto update log level to $new_log_level_name" debug_msg "Cluster Name: $clusterName. Response: ${RED}$response${RESET}" debug_msg "Credentials: $(print_credentials "$credentials")" exit 1 debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -H \"Content-Type: application/json\" \"http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level\" -d \"{\\\"value\\\": $new_log_level}\"" response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \ fi # Countdown and revert log level if [[ -n "$duration" && "$duration" -gt 0 ]]; then echo -e "Keeping log level at ${YELLOW}$new_log_level_name${RESET} (${YELLOW}$new_log_level${RESET}) for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..." echo -de "{\"value\": $new_log_level}") debug_msg "Response: $response" for ((i=duration; i>0; i--)); do if [[ "$jq_or_grep" == "grep" ]]; then printf -v countdown updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+') "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) else updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value')-ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r" fi sleep debug_msg1 "Updated cluster log level: $updated_log_level" done if [[ "$updated_log_level" -eq "$new_log_level" ]]; then echo -e "${GREEN}$(timestamp)${RESET} Log\n\nTime's up! Reverting log level changedback successfullyto from ${GREEN}$current_log_level_level$name${RESET} -> (${BOLD_GREEN}$new$current_log_level${RESET}) ..." else # Revert the log level back to echothe -e "${GREEN}$(timestamp)${RESET} Failed to update log level. Response: ${RED}$response${RESET}"original value # echo -e "Level log revert on exit$(timestamp)" 1 fi response=$(curl --user "$credentials" -sS -X PUT # Countdown and revert log level-H "Content-Type: application/json" \ if [[ -n "$duration" && "$duration" -gt 0 ]]; then "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \ echo -e "Keeping log level at ${YELLOW}$newd "{\"value\": $current_log_level_name${RESET}") for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..." debug_msg "Response: $response" echo -e "" if [[ "$jq_or_grep" == for ((i=duration; i>0; i--)); do"grep" ]]; then reverted_log_level=$(echo "$response" | printfgrep -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60))oP '"value":\s*\K[0-9]+') else reverted_log_level=$(echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r""$response" | "$jq_or_grep" -r '.value') fi sleep 1 debug_msg "Reverted cluster log donelevel: $reverted_log_level" echofinal_size=$(stat -e "\n\nTime's up! Reverting log level back to ${GREEN}$current_log_level${RESET}..."c%s "$log_file" 2>/dev/null || echo 0) debug_msg "Initial log file size: $initial_size" # Revert the log level back to the original value debug_msg "Final log file size: $final_size" # echo -e "Level log revert on size_diff=$(timestamp)"( final_size - initial_size )) responsesize_diff_formatted=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ format_size "$size_diff") duration_formatted=$(format_duration "$duration") if (( size_diff < 0 )); then echo "http://${ip_array[0]}:91/api/storage/clusters/$clusterName/settings/log.level" \ -e "castor.log file was rotated." else echo -de "{\"value\": $current_log_level}") echo debug_msg-e "Response: $response" if [[ "$jq_or_grep" == "grep" ]]; then Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})." reverted_log_level=$(echo "$response" | grep -oPe '"value":\s*\K[0-9]+') fi else if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then reverted_log_level=$(echo "$response" | "$jq_or_grep" echo -r '.value') e "${GREEN}$(timestamp)${RESET} Log level reverted successfully back to ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})." fi echo -e "" debug_msg "Reverted cluster log level: $reverted_log_level" else final_size=$(statecho -c%s "$log_file" 2>/dev/null || echo 0) e "${GREEN}$(timestamp)${RESET} Failed to revert log level. Response: ${RED}$response${RESET}" debug_msg "Initial log fileecho size: $initial_size-e "" debug_msg "Final log file size: $final_size"exit 1 fi size_diff=$(( final_size - initial_size )) else echo size_diff_formatted=$(format_size "$size_diff")-e "${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified." fi elif duration_formatted=$(format_duration "$duration") [[ "$log_level_type" == "node" ]]; then if (( size_diff <# 0 )); then echo -e "castor.log file was rotated." First loop: Change the node log level else local same_log_level=false for echoip -ein "${ip_array[@]}"; do # Retrieve current node echo -e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level${RESET}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})."log level debug_msg "Retrieving current node log level for IP: $ip" debug_msg "curl -s echo -e "" -u \"$(print_credentials "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\"" fi current_log_level=$(curl -s if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then-u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value') echo -e "${GREEN}$(timestamp)${RESET} Logdebug_msg "Current log level revertedfor successfullyIP back to ${BOLD_GREEN}$ip: $current_log_level${RESET}.level" echo -e ""original_log_levels["$ip"]=$current_log_level else echo -e "${GREEN}$(timestamp)${RESET} Failed to revertdebug_msg "Original log level. Response: ${RED}$response${RESET}" echo -e "for IP $ip: ${original_log_levels["$ip"]}" exitif 1 [[ "$current_log_level" == "0" ]]; then fi else current_log_level_name="default" echo "$(timestamp) Log level change iselse permanent until manually modified." fi elif [[ "$logcurrent_log_level_type" == "node" ]]; thenname=${log_levels[$current_log_level]} # First loop: Changefi the node log level local sameoriginal_log_level=false_names["$ip"]=$current_log_level_name for ip indebug_msg "Original log level name: ${ip_array[@original_log_level_names["$ip"]}"; do if # Retrieve current node log level[[ "$new_log_level" == "0" ]]; then debug_msg "Retrieving current node new_log level for IP: $ip_level_name="default" debug_msgelse "curl -s -u \"$(print_credentials "$credentials")\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel\"" currentnew_log_level_name=$(curl -s -u "$credentials" "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel" | $jq_or_grep -r '.value'){log_levels[$new_log_level]} fi debug_msg "Current log level for IP $ip: $current_log_level ($current_log_level_name)" original_log_levels["$ip"]=$current_log_levelecho "" echo -e "New node log level: ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})" debug_msgecho -e "OriginalCurrent node log level for IP $ip: ${original_log_levels["$ip"]}"${BOLD_GREEN}$ip${RESET} is ${BOLD_GREEN}$current_log_level_name${RESET} (${BOLD_GREEN}$current_log_level${RESET})." # Skip update if [[ "$current_log_level" == "0" ]]; thennew level matches the current level if [[ "$current_log_level" -eq current"$new_log_level_name="default" ]]; then else currentsame_log_level_name=${log_levels[$current_log_level]}=true fi original_log_level_names["$ip"]=$current_log_level_nameecho "" debug_msg "Original log level name: ${original_log_level_names["$ip"]}" echo -e "Node log level for IP ${BOLD_GREEN}$ip${RESET} is if [[ "already set to ${BOLD_GREEN}$new_log_level" == "0" ]]; then_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}). No changes made." new_log_level_name="default"continue else newsame_log_level_name=${log_levels[$new_log_level]}=false fi debug_msg "Currentif log level for IP $ip: $current[[ "$same_log_level ($current_log_level_name)" == false ]]; then echo "" echo -e "New# Update the node log level: ${BOLD_GREEN}$new_log_level_name${RESET}" using PUT echo -edebug_msg "CurrentUpdating node log level for IP ${BOLD_GREEN}$ip${RESET} is ${GREEN}$currentto $new_log_level_name.${RESET}" for IP $ip..." # Skip update if new level matches the current level if [[ "$current_log_level" -eq "debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level\"" ]]; then same_log_level=true echo "" response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ echo -e "Node log level for IP ${BOLD_GREEN}$ip${RESET} is already set to ${BOLD_GREEN} "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level_name${RESET}. No changes made."") continue debug_msg "Response: $response" else if [[ same"$jq_log_level=false or_grep" == "grep" ]]; then fi if [[ "$sameupdated_log_level=$(echo " == false ]]; then$response" | grep -oP '"value":\s*\K[0-9]+') else # Update the node log level using PUT updated_log_level=$(echo "$response" | "$jq_or_grep" debug_msg "Updating node log level to $new_log_level_name for IP $ip..."-r '.value') fi debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -Hdebug_msg \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level\"""Updated log level for IP $ip: $updated_log_level" response=$(curl --user "$credentialsif [[ "$updated_log_level" -sS -X PUT -H "Content-Type: application/json" \eq "$new_log_level" ]]; then echo "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$new_log_level") debug_msg "Response: $response"-e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} changed successfully from ${BOLD_GREEN}$current_log_level_name${RESET} (${GREEN}$current_log_level${RESET}) -> ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET})." if [[ "$jq_or_grep" == "grep" ]]; thenelse updated_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+') -e "${GREEN}$(timestamp)${RESET} Failed to update node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}" else exit 1 updated_log_level=$(echo "$response" | "$jq_or_grep" -r '.value') fi fi fi done debug_msg "Updated log level for# IPSecond $iploop: $updated_log_level" Countdown if duration is provided if [[ "$updated$same_log_level" -eq "$new_log_level"== false ]]; then echo -e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} changed successfully from ${GREEN}$current_log_level_name${RESET} -> ${BOLD_GREEN}$new_log_level_name${RESET}." \ if [[ -n "$duration" && "$duration" -gt 0 ]]; then else echo -e "" echo -e "${GREEN}$(timestamp)${RESET} Failed to update node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}Keeping node(s) log level at ${YELLOW}$new_log_level_name${RESET} (${YELLOW}$new_log_level${RESET}) for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) ..." echo -e "" exit 1 for ((i=duration; fii>0; i--)); do fi printf done-v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) # Second loop: Countdown if duration is provided if [[ "$same_log_level" == false ]]; then\ echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r" if [[ -n "$duration" && "$duration" -gt 0 ]]; then sleep 1 echo -e ""done echo -e "Keeping node(s) log level at ${YELLOW}$new_log_level_name${RESET} for ${YELLOW}$duration${RESET} seconds (${YELLOW}$(format_duration $duration)${RESET}) \n\nTime's up! Reverting node log level back to original levels..." echo -e# ""Third loop: Revert the node log level for ((i=duration; i>0; i--)); do for ip in "${ip_array[@]}"; do printf -v countdown "%02d:%02d:%02d" $((i/3600)) $(( (i%3600) / 60 )) $((i%60)) current_log_level=${original_log_levels["$ip"]} echo -ne "Countdown: ${YELLOW}$countdown${RESET} remaining...\r"current_log_level_name=${original_log_level_names["$ip"]} debug_msg sleep"Reverting 1node log level back to $current_log_level_name for IP $ip..." done debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X echoPUT -eH \"\n\nTime's up! Reverting node log level back to original levels..."Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\"" # Thirdecho loop: Revert the node log level -e "Node level log revert on $(timestamp) for IP $ip" for ip in "${ip_array[@]}"; do response=$(curl --user "$credentials" -sS -X PUT -H "Content-Type: application/json" \ current_log_level=${original_log_levels["$ip"]} current_log_level_name=${original"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level_names["$ip"]}") debug_msg "RevertingResponse: node$response" log level back to $current_log_level_name for IP $ip..." if [[ "$jq_or_grep" == "grep" debug_msg "curl --user \"$(print_credentials "$credentials")\" -sS -X PUT -H \"Content-Type: application/json\" \"http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level\"" ]]; then reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+') # echo -e "Node level logelse revert on $(timestamp) for IP $ip" responsereverted_log_level=$(curlecho --user "$credentials$response" -sS -X PUT -H "Content-Type: application/json" \ | "$jq_or_grep" -r '.value') fi "http://$ip:91/api/storage/nodes/_self/settings/log.nodeLogLevel?value=$current_log_level") final_size=$(stat -c%s debug"$log_msg file"Response: $response" 2>/dev/null || echo 0) if [[ "$jq_or_grep" == "grep" ]]; then size_diff=$(( final_size - initial_size )) reverted_log_level=$(echo "$response" | grep -oP '"value":\s*\K[0-9]+')debug_msg "Initial log file size: $initial_size" debug_msg else"Final log file size: $final_size" revertedsize_logdiff_levelformatted=$(echoformat_size "$response$size_diff") | "$jq_or_grep" -r '.value') duration_formatted=$(format_duration "$duration") fi if final_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)[[ "$reverted_log_level" -eq "$current_log_level" ]]; then echo size_diff=$(( final_size - initial_size ))-e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} reverted successfully back to ${BOLD_GREEN}${current_log_level_name}${RESET} (${BOLD_GREEN}$current_log_level${RESET})." debug_msgelse "Initial log file size: $initial_size" echo debug_msg "Final log file size: $final_size-e "${GREEN}$(timestamp)${RESET} Failed to revert node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}" size_diff_formatted=$(format_size "$size_diff") exit 1 duration_formatted=$(format_duration "$duration") fi done if [[ "$reverted_log_level" -eq "$current_log_level" ]]; then # Combine the log output for multiple IP addresses into a single summary echo -e "${GREEN}$(timestamp)${RESET} Node log level for IP ${BOLD_GREEN}$ip${RESET} reverted successfullyif back to ${BOLD_GREEN}${current_log_level_name}${RESET}." (( size_diff < 0 )); then else echo -e "castor.log file was rotated." else echo -e "${GREEN}$(timestamp)${RESET} Failed to revert node log level for IP ${BOLD_GREEN}$ip${RESET}. Response: ${RED}$response${RESET}" echo -e "" exit 1 echo -e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} (${BOLD_GREEN}$new_log_level${RESET}) for IP ${ip_array[*]}. Current castor.log fisize is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})." done echo -e "" # Combine the log output for multiple IP addresses into afi single summary else if (( size_diff < 0 )); then echo -e "castor.log file was rotated." ${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified." else fi fi fi } echo -e# ""Run in detachable or directly if $detachable; then # Pass the main_script function to echo -e "Approximate ${BOLD_GREEN}$size_diff_formatted${RESET} new logs were generated at log level ${BOLD_GREEN}$new_log_level_name${RESET} for IP ${ip_array[*]}. Current castor.log size is ${BOLD_GREEN}$(format_size "$final_size")${RESET} after ${YELLOW}$duration${RESET} seconds (${YELLOW}$duration_formatted${RESET})." echo -e "" fi else echo "${GREEN}$(timestamp)${RESET} Log level change is permanent until manually modified." fi fi fi } # Run in detachable or directly if $detachable; then # Pass the main_script function to the screen session and store the output in a file debug_msg "**********************************************************the screen session and store the output in a file debug_msg "**********************************************************" | tee -a "$output_log" debug_msg "Detach mode - Parameters passed to main_script:" | tee -a "$output_log" debug_msg " Swarm IP: $swarm_ip" | tee -a "$output_log" debug_msg " Credentials: $(print_credentials "$credentials")" | tee -a "$output_log" debug_msg " New Log Level: $new_log_level" | tee -a "$output_log" debug_msg " New log Level Name: $new_log_level_name" | tee -a "$output_log" debug_msg " Duration: $duration" | tee -a "$output_log" debug_msg " Log Level Type: $log_level_type" | tee -a "$output_log" debug_msg " Log File: $log_file" | tee -a "$output_log" debug_msg " Initial Log File Size: $initial_size" | tee -a "$output_log" debug_msg "Detach mode - ParametersCurrent passedLog to main_script:Level: $current_log_level" | tee -a "$output_log" debug_msg " SwarmCluster IPName: $swarm_ip$clusterName" | tee -a "$output_log" debug_msg " Credentialsjq_or_grep: $(print_credentials "$credentials")" $jq_or_grep" | tee -a "$output_log" debug_msg " New Log LevelDetach: $new_log_level$detachable" | tee -a "$output_log" debug_msg " Debug: $debug" | New log Level Name: $new_log_level_nametee -a "$output_log" debug_msg "**********************************************************" | tee -a "$output_log" debug_msg "# Convert associative arrays to Duration:strings $duration"and |pass teethem -a "$output_log" to the screen session debug_msg " Log Level Type: $log_level_type" | tee -a "$output_log"log_levels_string=$(declare -p log_levels) debug_msg " Log File: $log_file" | tee -a "$output_log"log_level_names_string=$(declare -p log_level_names) debug_msg " Initial Log File Size: $initial_sizelog_levels_string: $log_levels_string" | tee -a "$output_log" debug_msg " Current Log Level: $current_log_levellog_level_names_string: $log_level_names_string" | tee -a "$output_log" debug_msg " Cluster Name: $clusterName if command -v screen &>/dev/null; then echo -e "Running in ${YELLOW}screen${RESET} detachable mode..." | tee -a "$output_log" debug_msg " screen -dmS jqcastor_orlog_grep: $jq_or_grep" | tee -a "$output_log" script bash -c "$(declare -f main_script timestamp debug_msg " Detach: $detachable" | tee -a "$output_log" debug_msg " Debug: $debug" | tee -a "$output_log" debug_msg "**********************************************************" | tee -a "$output_log" # Convert associative arrays to strings and pass them toformat_size format_duration check_jq determine_log_file print_credentials); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$detachable\" \"$debug\" \"${log_levels_string}\" \"${log_level_names_string}\" \"${default_log_levels}\" \"${default_log_levels_name}\" | tee \"$output_log\"" screen -r castor_log_script # Wait for the screen session to complete and then log_levels_string=$(declare -p log_levels) log_level_names_string=$(declare -p log_level_names) debug_msg "log_levels_string: $log_levels_string" | tee -a "$output_log" debug_msg "log_level_names_string: $log_level_names_string" | tee -a "$output_log" ifdisplay the output log sleep 1 while screen -list | grep -q "castor_log_script"; do sleep 1 done elif command -v screentmux &>/dev/null; then echo -e "Running in ${YELLOW}screen$tmux${RESET} detachable mode..." | tee -a "$output_log"" > "$output_log" # Truncate log file to remove old entries # Create a temp script file temp_script="$SCRIPTDIR/castor_log_script.sh" # Write the script to a file to avoid printing function definitions cat screen<<EOF -dmS> castor"$temp_log_script" #!/bin/bash -c "$(declare -f main_script timestamp debug_msg format_size format_duration check_jq determine_log_file print_credentials); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$detachable\" \"$debug\" \"${log_levels_string}\" \"${log_level_names_string}\" "${default_log_levels}" "${default_log_levels_name}" | tee \-a "$output_log\""" rm -f "$temp_script" # Remove the script file tmux screenkill-session -rt castor_log_script EOF # Wait for the screen session to complete and then display the output log sleep 1 Ensure the script is executable chmod +x "$temp_script" # Start tmux session and execute the script inside while screentmux new-listsession |-d grep -qs "castor_log_script "; dobash $temp_script" # Attach session sleeponly 1if it's still running done while tmux elifhas-session command -v tmux &>t castor_log_script 2>/dev/null; then echo -e "Running in ${YELLOW}tmux${RESET} detachable mode..." | tee -a "$output_log"do tmux newattach-session -dt -s castor_log_script "$(declare -f main_script timestamp debug_msg format_size format_duration check_jq determine_log_file print_credentials); main_script \"$swarm_ip\" \"$credentials\" \"$new_log_level\" \"$new_log_level_name\" \"$duration\" \"$log_level_type\" \"$clusterName\" \"$jq_or_grep\" \"$detachable\" \"$debug\" \"${log_levels_string}\" \"${log_level_names_string}\" | tee \"$output_log\"" done # if tmux has-session -t castor_log_script 2>/dev/null; then # tmux attach-session -t castor_log_script # fi else echo "Error: Neither screen nor tmux available. Run without --detachable." exit 1 fi echo "" cat "$output_log" else # main_script "$swarm_ip" "$credentials" "$new_log_level" "$duration" "$clusterName" "$jq_or_grep" | tee "$output_log" debug_msg "**********************************************************" debug_msg "Parameters passed to main_script:" debug_msg "Swarm IP: $swarm_ip" debug_msg "Credentials: $(print_credentials "$credentials")" debug_msg "New Log Level: $new_log_level" debug_msg "Duration: $duration" debug_msg "Cluster Name: $clusterName" debug_msg "jq_or_grep: $jq_or_grep" debug_msg "**********************************************************" debug_msg "Running main_script function..." main_script "$swarm_ip" "$credentials" "$new_log_level" "$new_log_level_name" "$duration" "$log_level_type" "$clusterName" "$jq_or_grep" | tee "$output_log" fi |
...