Log Script Output to a File
Table of Contents
- [Introduction](#introduction) - [Basic Concepts](#basic-concepts) - [Redirection Operators](#redirection-operators) - [Logging Methods](#logging-methods) - [Advanced Logging Techniques](#advanced-logging-techniques) - [Log Management](#log-management) - [Best Practices](#best-practices) - [Common Use Cases](#common-use-cases) - [Troubleshooting](#troubleshooting)Introduction
Logging script output to a file is a fundamental practice in system administration, software development, and automation. It allows you to capture, store, and analyze the execution details of scripts and commands for debugging, auditing, monitoring, and compliance purposes. This comprehensive guide covers various methods and techniques for effectively logging script output in different environments.
Basic Concepts
What is Script Output Logging
Script output logging refers to the process of capturing and redirecting the standard output (stdout), standard error (stderr), and sometimes standard input (stdin) of a script or command to a file instead of displaying it on the terminal. This enables persistent storage of execution results, error messages, and diagnostic information.
File Descriptors
Understanding file descriptors is crucial for effective output logging:
| File Descriptor | Name | Description | Default Destination | |-----------------|------|-------------|-------------------| | 0 | stdin | Standard Input | Keyboard | | 1 | stdout | Standard Output | Terminal/Screen | | 2 | stderr | Standard Error | Terminal/Screen |
Stream Types
| Stream Type | Purpose | Typical Content | |-------------|---------|-----------------| | Standard Output | Normal program output | Results, data, success messages | | Standard Error | Error messages and diagnostics | Warnings, errors, debug information | | Combined | Both stdout and stderr | Complete execution log |
Redirection Operators
Basic Redirection Operators
| Operator | Description | Example | Result |
|----------|-------------|---------|--------|
| > | Redirect stdout, overwrite file | command > file.log | Overwrites file.log with command output |
| >> | Redirect stdout, append to file | command >> file.log | Appends command output to file.log |
| 2> | Redirect stderr, overwrite file | command 2> error.log | Overwrites error.log with error output |
| 2>> | Redirect stderr, append to file | command 2>> error.log | Appends error output to error.log |
| &> | Redirect both stdout and stderr | command &> all.log | Redirects all output to all.log |
| &>> | Append both stdout and stderr | command &>> all.log | Appends all output to all.log |
Advanced Redirection Techniques
`bash
Redirect stdout to file and stderr to another file
command > output.log 2> error.logRedirect stderr to stdout, then both to file
command > combined.log 2>&1Redirect stdout to file and stderr to stdout
command 2>&1 > output.logDiscard output while keeping errors
command > /dev/null 2> error.logDiscard errors while keeping output
command > output.log 2> /dev/null`Logging Methods
Method 1: Simple Output Redirection
The most straightforward approach uses basic redirection operators:
`bash
#!/bin/bash
Basic logging example
Create a simple script
cat << 'EOF' > sample_script.sh #!/bin/bash echo "Script started at $(date)" echo "Processing data..." ls /nonexistent 2>&1 # This will generate an error echo "Script completed at $(date)" EOFchmod +x sample_script.sh
Log output to file
./sample_script.sh > script_output.log 2>&1`Method 2: Using tee Command
The tee command allows you to both display output on the terminal and save it to a file:
`bash
Display output and save to file
./sample_script.sh 2>&1 | tee script_output.logAppend to existing file
./sample_script.sh 2>&1 | tee -a script_output.logSave to multiple files
./sample_script.sh 2>&1 | tee output1.log output2.log`Method 3: Exec Command for Script-wide Logging
Use exec to redirect all subsequent output within a script:
`bash
#!/bin/bash
Script with built-in logging
Redirect all output to log file
exec > script.log 2>&1echo "This goes to the log file"
date
ls /some/directory
echo "Script execution completed"
`
Method 4: Function-based Logging
Create logging functions for better control:
`bash
#!/bin/bash
LOG_FILE="application.log"
Logging function
log_message() { local level="$1" shift echo "$(date '+%Y-%m-%d %H:%M:%S') [$level] $*" >> "$LOG_FILE" }Usage examples
log_message "INFO" "Application started" log_message "ERROR" "Failed to connect to database" log_message "DEBUG" "Processing user ID: 12345"`Advanced Logging Techniques
Timestamped Logging
Add timestamps to log entries for better tracking:
`bash
#!/bin/bash
Function to add timestamps
log_with_timestamp() { while IFS= read -r line; do echo "$(date '+%Y-%m-%d %H:%M:%S') $line" done }Usage
./sample_script.sh 2>&1 | log_with_timestamp >> timestamped.log`Rotating Logs
Implement log rotation to manage file sizes:
`bash
#!/bin/bash
LOG_FILE="application.log" MAX_SIZE=1048576 # 1MB in bytes
rotate_log() { if [[ -f "$LOG_FILE" && $(stat -f%z "$LOG_FILE" 2>/dev/null || stat -c%s "$LOG_FILE" 2>/dev/null) -gt $MAX_SIZE ]]; then mv "$LOG_FILE" "${LOG_FILE}.$(date +%Y%m%d_%H%M%S)" touch "$LOG_FILE" fi }
Check and rotate before logging
rotate_log ./sample_script.sh >> "$LOG_FILE" 2>&1`Conditional Logging
Log only specific types of messages:
`bash
#!/bin/bash
DEBUG=true VERBOSE=false
debug_log() { if [[ "$DEBUG" == "true" ]]; then echo "DEBUG: $*" >> debug.log fi }
verbose_log() { if [[ "$VERBOSE" == "true" ]]; then echo "VERBOSE: $*" >> verbose.log fi }
Usage
debug_log "Variable X has value: $X" verbose_log "Processing step 1 of 10"`Log Management
Log File Organization
| Log Type | Filename Convention | Example | Purpose |
|----------|-------------------|---------|---------|
| Application | app_YYYYMMDD.log | myapp_20231215.log | Daily application logs |
| Error | error_YYYYMMDD.log | error_20231215.log | Error-specific logs |
| Debug | debug_YYYYMMDD.log | debug_20231215.log | Debugging information |
| Access | access_YYYYMMDD.log | access_20231215.log | Access/audit logs |
Log Levels
| Level | Numeric Value | Description | Use Case | |-------|---------------|-------------|----------| | FATAL | 0 | System unusable | Critical system failures | | ERROR | 1 | Error conditions | Application errors | | WARN | 2 | Warning conditions | Potential issues | | INFO | 3 | Informational | General information | | DEBUG | 4 | Debug messages | Development/troubleshooting |
Log Format Standards
`bash
Standard log format function
format_log() { local level="$1" local component="$2" shift 2 local message="$*" printf "[%s] %s %s: %s\n" \ "$(date '+%Y-%m-%d %H:%M:%S')" \ "$level" \ "$component" \ "$message" }Examples
format_log "INFO" "AUTH" "User login successful" format_log "ERROR" "DB" "Connection timeout after 30 seconds"`Best Practices
1. Consistent Naming Conventions
`bash
Good naming examples
APPLICATION_LOG="/var/log/myapp/application.log" ERROR_LOG="/var/log/myapp/error.log" ACCESS_LOG="/var/log/myapp/access.log"Include date in filename for daily logs
DAILY_LOG="/var/log/myapp/app_$(date +%Y%m%d).log"`2. Proper File Permissions
`bash
Set appropriate permissions for log files
touch "$LOG_FILE" chmod 644 "$LOG_FILE" chown user:group "$LOG_FILE"For sensitive logs
chmod 600 "$SENSITIVE_LOG"`3. Error Handling in Logging
`bash
#!/bin/bash
LOG_FILE="/var/log/myapp/application.log"
safe_log() {
local message="$*"
local log_dir=$(dirname "$LOG_FILE")
# Ensure log directory exists
if [[ ! -d "$log_dir" ]]; then
mkdir -p "$log_dir" || {
echo "Failed to create log directory: $log_dir" >&2
return 1
}
fi
# Check if log file is writable
if [[ ! -w "$LOG_FILE" ]] && [[ -e "$LOG_FILE" ]]; then
echo "Cannot write to log file: $LOG_FILE" >&2
return 1
fi
# Write to log
echo "$(date '+%Y-%m-%d %H:%M:%S') $message" >> "$LOG_FILE" || {
echo "Failed to write to log file" >&2
return 1
}
}
`
4. Log Cleanup and Maintenance
`bash
#!/bin/bash
Log cleanup script
LOG_DIR="/var/log/myapp" RETENTION_DAYS=30cleanup_logs() { find "$LOG_DIR" -name "*.log" -type f -mtime +$RETENTION_DAYS -delete find "$LOG_DIR" -name ".log." -type f -mtime +$RETENTION_DAYS -delete }
Compress old logs
compress_old_logs() { find "$LOG_DIR" -name ".log" -type f -mtime +7 ! -name ".gz" -exec gzip {} \; }cleanup_logs
compress_old_logs
`
Common Use Cases
Database Script Logging
`bash
#!/bin/bash
DB_LOG="/var/log/database/maintenance.log" ERROR_LOG="/var/log/database/errors.log"
Database maintenance script with logging
{ echo "Starting database maintenance at $(date)" # Backup database if mysqldump -u user -p database > backup.sql 2>> "$ERROR_LOG"; then echo "Database backup completed successfully" else echo "Database backup failed - check error log" fi # Optimize tables mysql -u user -p -e "OPTIMIZE TABLE table1, table2;" database 2>> "$ERROR_LOG" echo "Database maintenance completed at $(date)" } >> "$DB_LOG" 2>&1`System Monitoring Script
`bash
#!/bin/bash
MONITOR_LOG="/var/log/system/monitor.log"
System monitoring with structured logging
monitor_system() { { echo "=== System Monitor Report - $(date) ===" echo "CPU Usage:" top -l 1 | head -n 10 echo "" echo "Memory Usage:" free -h echo "" echo "Disk Usage:" df -h echo "" echo "Network Connections:" netstat -tuln | head -20 echo "=== End Report ===" echo "" } >> "$MONITOR_LOG" }monitor_system
`
Application Deployment Logging
`bash
#!/bin/bash
DEPLOY_LOG="/var/log/deployment/app_deploy.log" ERROR_LOG="/var/log/deployment/deploy_errors.log"
deploy_application() {
local app_version="$1"
exec 1> >(tee -a "$DEPLOY_LOG")
exec 2> >(tee -a "$ERROR_LOG" >&2)
echo "Starting deployment of version $app_version at $(date)"
# Stop application
echo "Stopping application service..."
systemctl stop myapp
# Backup current version
echo "Creating backup..."
cp -r /opt/myapp "/opt/myapp.backup.$(date +%Y%m%d_%H%M%S)"
# Deploy new version
echo "Deploying new version..."
tar -xzf "myapp-${app_version}.tar.gz" -C /opt/
# Start application
echo "Starting application service..."
systemctl start myapp
# Verify deployment
if systemctl is-active --quiet myapp; then
echo "Deployment successful at $(date)"
return 0
else
echo "Deployment failed - service not running" >&2
return 1
fi
}
`
Troubleshooting
Common Issues and Solutions
| Issue | Symptom | Solution | |-------|---------|----------| | Permission Denied | Cannot write to log file | Check file/directory permissions, ensure user has write access | | Disk Space Full | Logging stops working | Implement log rotation, clean up old logs | | Log File Corruption | Garbled or incomplete entries | Use proper file locking, avoid concurrent writes | | Missing Timestamps | Cannot determine when events occurred | Add timestamp functions to logging | | Large Log Files | Performance degradation | Implement log rotation and compression |
Debugging Log Issues
`bash
#!/bin/bash
Debug logging function
debug_logging() { local log_file="$1" echo "Debugging log file: $log_file" # Check if file exists if [[ ! -e "$log_file" ]]; then echo "Log file does not exist" return 1 fi # Check permissions echo "File permissions: $(ls -l "$log_file")" # Check disk space echo "Disk space on $(dirname "$log_file"):" df -h "$(dirname "$log_file")" # Check file size echo "Log file size: $(du -h "$log_file")" # Check if file is being written to echo "Recent entries:" tail -5 "$log_file" }`Log Analysis Commands
`bash
Count log entries by level
grep -c "ERROR" application.log grep -c "INFO" application.logFind errors in the last hour
grep "$(date '+%Y-%m-%d %H:')" application.log | grep "ERROR"Monitor logs in real-time
tail -f application.logSearch for specific patterns
grep -i "database connection" application.logAnalyze log file statistics
wc -l application.log # Count lines du -h application.log # File size`This comprehensive guide provides the foundation for implementing robust logging mechanisms in your scripts and applications. Proper logging is essential for maintaining, debugging, and monitoring systems effectively. Remember to regularly review and maintain your logging practices to ensure they continue to meet your operational needs.