Sanitized mirror from private repository - 2026-04-18 11:19:59 UTC
This commit is contained in:
347
ansible/automation/playbooks/log_rotation.yml
Normal file
347
ansible/automation/playbooks/log_rotation.yml
Normal file
@@ -0,0 +1,347 @@
|
||||
---
|
||||
# Log Rotation and Cleanup Playbook
|
||||
# Manage log files across all services and system components
|
||||
# Usage: ansible-playbook playbooks/log_rotation.yml
|
||||
# Usage: ansible-playbook playbooks/log_rotation.yml -e "aggressive_cleanup=true"
|
||||
# Usage: ansible-playbook playbooks/log_rotation.yml -e "dry_run=true"
|
||||
|
||||
- name: Log Rotation and Cleanup
|
||||
hosts: "{{ host_target | default('all') }}"
|
||||
gather_facts: yes
|
||||
vars:
|
||||
_dry_run: "{{ dry_run | default(false) }}"
|
||||
_aggressive_cleanup: "{{ aggressive_cleanup | default(false) }}"
|
||||
_max_log_age_days: "{{ max_log_age_days | default(30) }}"
|
||||
_max_log_size: "{{ max_log_size | default('100M') }}"
|
||||
_keep_compressed_logs: "{{ keep_compressed_logs | default(true) }}"
|
||||
_compress_old_logs: "{{ compress_old_logs | default(true) }}"
|
||||
|
||||
tasks:
|
||||
- name: Create log cleanup report directory
|
||||
file:
|
||||
path: "/tmp/log_cleanup/{{ ansible_date_time.date }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Display log cleanup plan
|
||||
debug:
|
||||
msg: |
|
||||
LOG ROTATION AND CLEANUP PLAN
|
||||
================================
|
||||
Host: {{ inventory_hostname }}
|
||||
Date: {{ ansible_date_time.date }}
|
||||
Dry Run: {{ _dry_run }}
|
||||
Aggressive: {{ _aggressive_cleanup }}
|
||||
Max Age: {{ _max_log_age_days }} days
|
||||
Max Size: {{ _max_log_size }}
|
||||
Compress: {{ _compress_old_logs }}
|
||||
|
||||
- name: Analyze current log usage
|
||||
shell: |
|
||||
echo "=== LOG USAGE ANALYSIS ==="
|
||||
|
||||
echo "--- SYSTEM LOGS ---"
|
||||
if [ -d "/var/log" ]; then
|
||||
system_log_size=$(du -sh /var/log 2>/dev/null | cut -f1 || echo "0")
|
||||
system_log_count=$(find /var/log -type f -name "*.log" 2>/dev/null | wc -l)
|
||||
echo "System logs: $system_log_size ($system_log_count files)"
|
||||
echo "Largest system logs:"
|
||||
find /var/log -type f -name "*.log" -exec du -h {} \; 2>/dev/null | sort -hr | head -10 || echo "No system logs found"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- DOCKER CONTAINER LOGS ---"
|
||||
if [ -d "/var/lib/docker/containers" ]; then
|
||||
docker_log_size=$(du -sh /var/lib/docker/containers 2>/dev/null | cut -f1 || echo "0")
|
||||
docker_log_count=$(find /var/lib/docker/containers -name "*-json.log" 2>/dev/null | wc -l)
|
||||
echo "Docker logs: $docker_log_size ($docker_log_count files)"
|
||||
echo "Largest container logs:"
|
||||
find /var/lib/docker/containers -name "*-json.log" -exec du -h {} \; 2>/dev/null | sort -hr | head -10 || echo "No Docker logs found"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- APPLICATION LOGS ---"
|
||||
for log_dir in /volume1/docker /opt/docker; do
|
||||
if [ -d "$log_dir" ]; then
|
||||
app_logs=$(timeout 15 find "$log_dir" -maxdepth 4 -name "*.log" -type f 2>/dev/null | head -20)
|
||||
if [ -n "$app_logs" ]; then
|
||||
echo "Application logs in $log_dir:"
|
||||
echo "$app_logs" | while read log_file; do
|
||||
if [ -f "$log_file" ]; then
|
||||
du -h "$log_file" 2>/dev/null || echo "Cannot access $log_file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "--- LARGE LOG FILES (>{{ _max_log_size }}) ---"
|
||||
timeout 15 find /var/log /var/lib/docker/containers -name "*.log" -size +{{ _max_log_size }} -type f 2>/dev/null | head -20 | while read large_log; do
|
||||
du -h "$large_log" 2>/dev/null || echo "? $large_log"
|
||||
done || echo "No large log files found"
|
||||
|
||||
echo ""
|
||||
echo "--- OLD LOG FILES (>{{ _max_log_age_days }} days) ---"
|
||||
old_logs=$(timeout 15 find /var/log /var/lib/docker/containers -name "*.log" -mtime +{{ _max_log_age_days }} -type f 2>/dev/null | wc -l)
|
||||
echo "Old log files found: $old_logs"
|
||||
register: log_analysis
|
||||
changed_when: false
|
||||
|
||||
- name: Rotate system logs
|
||||
shell: |
|
||||
echo "=== SYSTEM LOG ROTATION ==="
|
||||
rotated_list=""
|
||||
|
||||
{% if _dry_run %}
|
||||
echo "DRY RUN: System log rotation simulation"
|
||||
if command -v logrotate >/dev/null 2>&1; then
|
||||
echo "Would run: logrotate -d /etc/logrotate.conf"
|
||||
logrotate -d /etc/logrotate.conf 2>/dev/null | head -20 || echo "Logrotate config not found"
|
||||
fi
|
||||
{% else %}
|
||||
if command -v logrotate >/dev/null 2>&1; then
|
||||
echo "Running logrotate..."
|
||||
logrotate -f /etc/logrotate.conf 2>/dev/null && echo "System log rotation completed" || echo "Logrotate had issues"
|
||||
rotated_list="system_logs"
|
||||
else
|
||||
echo "Logrotate not available"
|
||||
fi
|
||||
|
||||
for log_file in /var/log/syslog /var/log/auth.log /var/log/kern.log; do
|
||||
if [ -f "$log_file" ]; then
|
||||
file_size=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
|
||||
if [ "$file_size" -gt 104857600 ]; then
|
||||
echo "Rotating large log: $log_file"
|
||||
{% if _compress_old_logs %}
|
||||
gzip -c "$log_file" > "$log_file.$(date +%Y%m%d).gz" && > "$log_file"
|
||||
{% else %}
|
||||
cp "$log_file" "$log_file.$(date +%Y%m%d)" && > "$log_file"
|
||||
{% endif %}
|
||||
rotated_list="$rotated_list $(basename $log_file)"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
{% endif %}
|
||||
|
||||
echo "ROTATION SUMMARY: $rotated_list"
|
||||
if [ -z "$rotated_list" ]; then
|
||||
echo "No logs needed rotation"
|
||||
fi
|
||||
register: system_log_rotation
|
||||
|
||||
- name: Manage Docker container logs
|
||||
shell: |
|
||||
echo "=== DOCKER LOG MANAGEMENT ==="
|
||||
managed_count=0
|
||||
total_space_saved=0
|
||||
|
||||
{% if _dry_run %}
|
||||
echo "DRY RUN: Docker log management simulation"
|
||||
large_logs=$(find /var/lib/docker/containers -name "*-json.log" -size +{{ _max_log_size }} 2>/dev/null)
|
||||
if [ -n "$large_logs" ]; then
|
||||
echo "Would truncate large container logs:"
|
||||
echo "$large_logs" | while read log_file; do
|
||||
size=$(du -h "$log_file" 2>/dev/null | cut -f1)
|
||||
container_id=$(basename $(dirname "$log_file"))
|
||||
container_name=$(docker ps -a --filter "id=$container_id" --format '{% raw %}{{.Names}}{% endraw %}' 2>/dev/null || echo "unknown")
|
||||
echo " - $container_name: $size"
|
||||
done
|
||||
else
|
||||
echo "No large container logs found"
|
||||
fi
|
||||
{% else %}
|
||||
find /var/lib/docker/containers -name "*-json.log" -size +{{ _max_log_size }} 2>/dev/null | while read log_file; do
|
||||
if [ -f "$log_file" ]; then
|
||||
container_id=$(basename $(dirname "$log_file"))
|
||||
container_name=$(docker ps -a --filter "id=$container_id" --format '{% raw %}{{.Names}}{% endraw %}' 2>/dev/null || echo "unknown")
|
||||
size_before=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
|
||||
echo "Truncating log for container: $container_name"
|
||||
tail -1000 "$log_file" > "$log_file.tmp" && mv "$log_file.tmp" "$log_file"
|
||||
size_after=$(stat -c%s "$log_file" 2>/dev/null || echo 0)
|
||||
space_saved=$((size_before - size_after))
|
||||
echo " Truncated: $(echo $space_saved | numfmt --to=iec 2>/dev/null || echo ${space_saved}B) saved"
|
||||
fi
|
||||
done
|
||||
|
||||
{% if _aggressive_cleanup %}
|
||||
echo "Cleaning old Docker log files..."
|
||||
find /var/lib/docker/containers -name "*.log.*" -mtime +{{ _max_log_age_days }} -delete 2>/dev/null
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
echo "DOCKER LOG SUMMARY: done"
|
||||
register: docker_log_management
|
||||
|
||||
- name: Clean up application logs
|
||||
shell: |
|
||||
echo "=== APPLICATION LOG CLEANUP ==="
|
||||
cleaned_count=0
|
||||
|
||||
{% if _dry_run %}
|
||||
echo "DRY RUN: Application log cleanup simulation"
|
||||
for log_dir in /volume1/docker /opt/docker; do
|
||||
if [ -d "$log_dir" ]; then
|
||||
old_app_logs=$(timeout 15 find "$log_dir" -maxdepth 4 -name "*.log" -mtime +{{ _max_log_age_days }} -type f 2>/dev/null)
|
||||
if [ -n "$old_app_logs" ]; then
|
||||
echo "Would clean logs in $log_dir:"
|
||||
echo "$old_app_logs" | head -10
|
||||
fi
|
||||
fi
|
||||
done
|
||||
{% else %}
|
||||
for log_dir in /volume1/docker /opt/docker; do
|
||||
if [ -d "$log_dir" ]; then
|
||||
echo "Cleaning logs in $log_dir..."
|
||||
|
||||
{% if _compress_old_logs %}
|
||||
find "$log_dir" -name "*.log" -mtime +7 -mtime -{{ _max_log_age_days }} -type f 2>/dev/null | while read log_file; do
|
||||
if [ -f "$log_file" ]; then
|
||||
gzip "$log_file" 2>/dev/null && echo " Compressed: $(basename $log_file)"
|
||||
fi
|
||||
done
|
||||
{% endif %}
|
||||
|
||||
old_logs_removed=$(find "$log_dir" -name "*.log" -mtime +{{ _max_log_age_days }} -type f -delete -print 2>/dev/null | wc -l)
|
||||
{% if _keep_compressed_logs %}
|
||||
max_gz_age=$(({{ _max_log_age_days }} * 2))
|
||||
old_gz_removed=$(find "$log_dir" -name "*.log.gz" -mtime +$max_gz_age -type f -delete -print 2>/dev/null | wc -l)
|
||||
{% else %}
|
||||
old_gz_removed=$(find "$log_dir" -name "*.log.gz" -mtime +{{ _max_log_age_days }} -type f -delete -print 2>/dev/null | wc -l)
|
||||
{% endif %}
|
||||
|
||||
if [ "$old_logs_removed" -gt 0 ] || [ "$old_gz_removed" -gt 0 ]; then
|
||||
echo " Cleaned $old_logs_removed logs, $old_gz_removed compressed logs"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
{% endif %}
|
||||
|
||||
echo "APPLICATION CLEANUP SUMMARY: done"
|
||||
register: app_log_cleanup
|
||||
|
||||
- name: Configure log rotation for services
|
||||
shell: |
|
||||
echo "=== LOG ROTATION CONFIGURATION ==="
|
||||
config_changed="no"
|
||||
|
||||
{% if _dry_run %}
|
||||
echo "DRY RUN: Would configure log rotation"
|
||||
{% else %}
|
||||
logrotate_config="/etc/logrotate.d/docker-containers"
|
||||
|
||||
if [ ! -f "$logrotate_config" ]; then
|
||||
echo "Creating Docker container log rotation config..."
|
||||
printf '%s\n' '/var/lib/docker/containers/*/*.log {' ' rotate 7' ' daily' ' compress' ' size 100M' ' missingok' ' delaycompress' ' copytruncate' '}' > "$logrotate_config"
|
||||
config_changed="yes"
|
||||
echo " Docker container log rotation configured"
|
||||
fi
|
||||
|
||||
docker_config="/etc/docker/daemon.json"
|
||||
if [ -f "$docker_config" ]; then
|
||||
if ! grep -q "log-driver" "$docker_config" 2>/dev/null; then
|
||||
echo "Docker daemon log configuration recommended"
|
||||
cp "$docker_config" "$docker_config.backup.$(date +%Y%m%d)"
|
||||
echo " Manual Docker daemon config update recommended"
|
||||
echo ' Add: "log-driver": "json-file", "log-opts": {"max-size": "{{ _max_log_size }}", "max-file": "3"}'
|
||||
fi
|
||||
fi
|
||||
{% endif %}
|
||||
|
||||
echo "CONFIGURATION SUMMARY: config_changed=$config_changed"
|
||||
register: log_rotation_config
|
||||
|
||||
- name: Generate log cleanup report
|
||||
copy:
|
||||
content: |
|
||||
LOG ROTATION AND CLEANUP REPORT - {{ inventory_hostname }}
|
||||
==========================================================
|
||||
|
||||
Cleanup Date: {{ ansible_date_time.iso8601 }}
|
||||
Host: {{ inventory_hostname }}
|
||||
Dry Run: {{ _dry_run }}
|
||||
Aggressive Mode: {{ _aggressive_cleanup }}
|
||||
Max Age: {{ _max_log_age_days }} days
|
||||
Max Size: {{ _max_log_size }}
|
||||
|
||||
LOG USAGE ANALYSIS:
|
||||
{{ log_analysis.stdout }}
|
||||
|
||||
SYSTEM LOG ROTATION:
|
||||
{{ system_log_rotation.stdout }}
|
||||
|
||||
DOCKER LOG MANAGEMENT:
|
||||
{{ docker_log_management.stdout }}
|
||||
|
||||
APPLICATION LOG CLEANUP:
|
||||
{{ app_log_cleanup.stdout }}
|
||||
|
||||
CONFIGURATION UPDATES:
|
||||
{{ log_rotation_config.stdout }}
|
||||
|
||||
RECOMMENDATIONS:
|
||||
- Schedule regular log rotation via cron
|
||||
- Monitor disk usage: ansible-playbook playbooks/disk_usage_report.yml
|
||||
- Configure application-specific log rotation
|
||||
- Set up log monitoring and alerting
|
||||
{% if not _dry_run %}
|
||||
- Verify services are functioning after log cleanup
|
||||
{% endif %}
|
||||
|
||||
CLEANUP COMPLETE
|
||||
|
||||
dest: "/tmp/log_cleanup/{{ ansible_date_time.date }}/{{ inventory_hostname }}_log_cleanup_report.txt"
|
||||
|
||||
- name: Display log cleanup summary
|
||||
debug:
|
||||
msg: |
|
||||
|
||||
LOG CLEANUP COMPLETE - {{ inventory_hostname }}
|
||||
==========================================
|
||||
|
||||
Date: {{ ansible_date_time.date }}
|
||||
Mode: {{ 'Dry Run' if _dry_run else 'Live Cleanup' }}
|
||||
Aggressive: {{ _aggressive_cleanup }}
|
||||
|
||||
ACTIONS TAKEN:
|
||||
{{ system_log_rotation.stdout | regex_replace('\n.*', '') }}
|
||||
{{ docker_log_management.stdout | regex_replace('\n.*', '') }}
|
||||
{{ app_log_cleanup.stdout | regex_replace('\n.*', '') }}
|
||||
|
||||
Full report: /tmp/log_cleanup/{{ ansible_date_time.date }}/{{ inventory_hostname }}_log_cleanup_report.txt
|
||||
|
||||
Next Steps:
|
||||
{% if _dry_run %}
|
||||
- Run without dry_run to perform actual cleanup
|
||||
{% endif %}
|
||||
- Monitor disk usage improvements
|
||||
- Schedule regular log rotation
|
||||
- Verify service functionality
|
||||
|
||||
==========================================
|
||||
|
||||
- name: Restart services if needed
|
||||
shell: |
|
||||
echo "=== SERVICE RESTART CHECK ==="
|
||||
restart_needed="no"
|
||||
|
||||
if systemctl is-active --quiet rsyslog 2>/dev/null && echo "{{ system_log_rotation.stdout }}" | grep -q "system_logs"; then
|
||||
restart_needed="yes"
|
||||
{% if not _dry_run %}
|
||||
echo "Restarting rsyslog..."
|
||||
systemctl restart rsyslog && echo " rsyslog restarted" || echo " Failed to restart rsyslog"
|
||||
{% else %}
|
||||
echo "DRY RUN: Would restart rsyslog"
|
||||
{% endif %}
|
||||
fi
|
||||
|
||||
if echo "{{ log_rotation_config.stdout }}" | grep -q "docker"; then
|
||||
echo "Docker daemon config changed - manual restart may be needed"
|
||||
echo " Run: sudo systemctl restart docker"
|
||||
fi
|
||||
|
||||
if [ "$restart_needed" = "no" ]; then
|
||||
echo "No services need restarting"
|
||||
fi
|
||||
register: service_restart
|
||||
when: restart_services | default(true) | bool
|
||||
Reference in New Issue
Block a user