Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions configuration/logging.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ stderr_level = ERROR
# Set to true to suppress all console output (useful for daemon scripts)
quiet = false

# Write the INIT message to the log file on initialization (default: true)
# Set to false to suppress "Logger initialized by <name>" from being appended to the
# log file on every init_logger call (useful when multiple scripts share the same log
# file, e.g. a main script and subscripts that all log to the same file)
init_message = true

# Enable verbose/debug logging (default: false)
# When true, sets log level to DEBUG
# Note: If both 'verbose' and 'level' are set, 'level' takes precedence
Expand Down
40 changes: 40 additions & 0 deletions demo-scripts/demo_config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,46 @@ log_error "Error message in JSON format"
# Clean up temporary config file
rm -f "$CONFIG_FILE"

echo -e "\n========== Testing init_message suppression =========="
echo "When multiple scripts share a log file (e.g. a main script and subscripts)"
echo "repeated INIT entries can clutter the log. Use --no-init-message to suppress them."
echo

SHARED_LOG="${LOGS_DIR}/demo_config_shared.log"
true > "$SHARED_LOG"

echo "--- Run 1: default behaviour (INIT message written) ---"
init_logger --log "$SHARED_LOG" || {
echo "Failed to initialize logger" >&2
exit 1
}
log_info "Message from main script"

echo "--- Run 2: subscript using --no-init-message (no extra INIT entry) ---"
init_logger --log "$SHARED_LOG" --no-init-message || {
echo "Failed to initialize logger" >&2
exit 1
}
log_info "Message from subscript"

echo "--- Run 3: same suppression via config file ---"
cat > "$CONFIG_FILE" << 'EOF'
[logging]
init_message = false
EOF
init_logger --config "$CONFIG_FILE" --log "$SHARED_LOG" || {
echo "Failed to initialize logger" >&2
exit 1
}
log_info "Message from another subscript (config-driven)"

echo
echo "Shared log file contents (note: only one INIT entry from run 1):"
cat "$SHARED_LOG"

# Clean up
rm -f "$CONFIG_FILE" "$SHARED_LOG"

echo -e "\n========== Configuration File Demo Complete =========="
echo "Log file: ${LOGGING_FILE}"
echo
Expand Down
3 changes: 3 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ configuration from code.

* [Configuration File Format](#configuration-file-format)
* [Configuration Keys](#configuration-keys)
* [Syslog Facility Key](#syslog-facility-key)
* [Configuration Value Limits](#configuration-value-limits)
* [Boolean Values](#boolean-values)
* [Key Aliases](#key-aliases)
* [Using Configuration Files](#using-configuration-files)
Expand Down Expand Up @@ -120,6 +122,7 @@ max_journal_length = 4096
| `unsafe_allow_ansi_codes` | `unsafe-allow-ansi-codes` | true/false, yes/no, on/off, 1/0 | `false` | Allow ANSI codes in log messages (unsafe) |
| `max_line_length` | `max-line-length`, `log_max_line_length` | Non-negative integer (0 = unlimited) | `4096` | Max message length before formatting |
| `max_journal_length` | `max-journal-length`, `journal_max_length` | Non-negative integer (0 = unlimited) | `4096` | Max message length for journal |
| `init_message` | `log_init_message` | true/false, yes/no, on/off, 1/0 | `true` | Write INIT entry to log file on startup |

### Syslog Facility Key

Expand Down
1 change: 1 addition & 0 deletions docs/initialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ The `init_logger` function accepts the following options:
| `-F, --facility FACILITY` | Set syslog facility for journal logs (default: daemon) |
| `--color, --colour` | Explicitly enable color output (default: auto-detect) |
| `--no-color, --no-colour` | Disable color output |
| `--no-init-message` | Suppress the INIT entry written to the log file on initialization |
| `-U, --unsafe-allow-newlines` | Allow newlines in log messages (not recommended; disables sanitization) |
| `-A, --unsafe-allow-ansi-codes` | Allow ANSI escape codes in log messages (not recommended; disables sanitization) |
| `--max-line-length LENGTH` | Max message length before formatting for console/file output (0 = unlimited) |
Expand Down
38 changes: 30 additions & 8 deletions logging.sh
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ LOG_FILE=""
VERBOSE="false"
CURRENT_LOG_LEVEL=$LOG_LEVEL_INFO
USE_UTC="false" # Set to true to use UTC time in logs
LOG_INIT_MESSAGE="true" # Set to false to suppress the INIT message written to the log file on init_logger

# Journal logging settings
USE_JOURNAL="false"
Expand Down Expand Up @@ -703,11 +704,25 @@ _parse_config_file() {
echo " Hint: Using default value of 4096" >&2
fi
;;
init_message|log_init_message)
case "${value,,}" in
true|yes|1|on)
LOG_INIT_MESSAGE="true"
;;
false|no|0|off)
LOG_INIT_MESSAGE="false"
;;
*)
echo "Warning: Invalid init_message value '$value' at line $line_num, expected true/false" >&2
;;
esac
;;
*)
echo "Warning: Unknown configuration key '$key' at line $line_num" >&2
echo " Hint: Valid keys are: level, format, log_file, journal, tag, utc, color," >&2
echo " stderr_level, quiet, console_log, script_name, verbose," >&2
echo " unsafe_allow_newlines, unsafe_allow_ansi_codes, max_line_length, max_journal_length" >&2
echo " unsafe_allow_newlines, unsafe_allow_ansi_codes, max_line_length, max_journal_length," >&2
echo " init_message" >&2
;;
esac
else
Expand Down Expand Up @@ -1210,6 +1225,10 @@ init_logger() {
fi
shift 2
;;
--no-init-message)
LOG_INIT_MESSAGE="false"
shift
;;
*)
echo "Unknown parameter for logger: $1" >&2
return 1
Expand Down Expand Up @@ -1288,13 +1307,16 @@ init_logger() {
fi

# Write the initialization message using the same format
local init_message
init_message=$(_format_log_message "INIT" "Logger initialized by $SCRIPT_NAME")
echo "$init_message" >> "$LOG_FILE" 2>/dev/null || {
echo "Error: Failed to write test message to log file" >&2
echo " Hint: Verify the file is writable and disk space is available" >&2
return 1
}
# Can be suppressed with --no-init-message (or init_message=false in config)
if [[ "$LOG_INIT_MESSAGE" == "true" ]]; then
local init_message
init_message=$(_format_log_message "INIT" "Logger initialized by $SCRIPT_NAME")
echo "$init_message" >> "$LOG_FILE" 2>/dev/null || {
echo "Error: Failed to write initialization message to log file" >&2
echo " Hint: Verify the file is writable and disk space is available" >&2
return 1
}
fi

echo "Logger: Successfully initialized with log file enabled" >&2
fi
Expand Down
51 changes: 51 additions & 0 deletions tests/test_initialization.sh
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,54 @@ EOF
pass_test
}

# Test: INIT message written to log file by default
test_init_message_default() {
start_test "INIT message is written to log file by default"

local log_file="$TEST_DIR/init_default.log"
init_logger --log "$log_file"

assert_file_contains "$log_file" "INIT" || return
assert_file_contains "$log_file" "Logger initialized" || return
assert_equals "true" "$LOG_INIT_MESSAGE" || return

pass_test
}

# Test: --no-init-message suppresses the INIT log file entry
test_no_init_message_flag() {
start_test "--no-init-message suppresses INIT entry in log file"

local log_file="$TEST_DIR/no_init_flag.log"
init_logger --log "$log_file" --no-init-message

assert_file_not_contains "$log_file" "Logger initialized" || return
assert_file_not_contains "$log_file" " INIT " || return
assert_equals "false" "$LOG_INIT_MESSAGE" || return
Comment on lines +408 to +410
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suppression tests only assert that "Logger initialized" is absent. Since the feature is specifically about suppressing the INIT log entry, it would be stronger to also assert that the INIT marker/level (e.g., "INIT") is not written, so the test fails if the message text changes but the INIT entry still appears.

Copilot uses AI. Check for mistakes.

pass_test
}

# Test: init_message = false in config suppresses the INIT log file entry
test_no_init_message_config() {
start_test "init_message=false in config suppresses INIT entry in log file"

local config_file="$TEST_DIR/no_init.conf"
cat > "$config_file" << 'EOF'
[logging]
init_message = false
EOF

local log_file="$TEST_DIR/no_init_config.log"
init_logger --config "$config_file" --log "$log_file"

assert_file_not_contains "$log_file" "Logger initialized" || return
assert_file_not_contains "$log_file" " INIT " || return
assert_equals "false" "$LOG_INIT_MESSAGE" || return

pass_test
}

# Run all tests
test_default_initialization
test_quiet_option
Expand Down Expand Up @@ -413,3 +461,6 @@ test_script_name_short_option
test_script_name_in_output
test_script_name_from_config
test_script_name_cli_overrides_config
test_init_message_default
test_no_init_message_flag
test_no_init_message_config
Loading