Автоматизация сбора логов: пишем скрипт-сборщик за 15 минут
Сбор логов — важная часть мониторинга систем, но делать это вручную неэффективно. В этой статье мы создадим простой, но функциональный скрипт для автоматического сбора и архивации логов. За 15 минут вы получите рабочий инструмент, который будет собирать логи по расписанию.
Зачем нужен автоматический сбор логов?
Ручной сбор логов — трудоемкий процесс, особенно когда у вас много серверов. Автоматизация решает множество проблем:
- Экономия времени администраторов
- Регулярность сбора данных
- Снижение вероятности ошибок
- Возможность анализа исторических данных
Планирование скрипта
Перед началом напишем список требований к нашему скрипту:
- Собирать логи из заданных директорий
- Архивировать собранные данные
- Удалять старые архивы
- Логировать действия самого скрипта
- Работать по расписанию (через cron)
Bash-скрипт для сбора логов
Начнем с простого bash-скрипта, который будет работать в Linux:
```bash
!/bin/bash
Скрипт автоматического сбора логов
Автор: Log Analyzer Team
Версия: 1.0
Конфигурация
LOG_DIR="/var/log" BACKUP_DIR="/backup/logs" DATE=$(date +%Y%m%d_%H%M%S) ARCHIVE_NAME="logs_$DATE.tar.gz" MAX_AGE_DAYS=30
Создание директории для бэкапов, если она не существует
mkdir -p "$BACKUP_DIR"
Логирование действий скрипта
exec >> "$BACKUP_DIR/script_log.txt" 2>&1 echo "$(date '+%Y-%m-%d %H:%M:%S') - Начало сбора логов"
Сбор логов из различных директорий
echo "$(date '+%Y-%m-%d %H:%M:%S') - Сбор логов из $LOG_DIR" tar -czf "$BACKUP_DIR/$ARCHIVE_NAME" -C "$LOG_DIR" --exclude='.gz' --exclude='.bz2' .
Проверка успешности архивации
if [ $? -eq 0 ]; then echo "$(date '+%Y-%m-%d %H:%M:%S') - Архив $ARCHIVE_NAME создан успешно" else echo "$(date '+%Y-%m-%d %H:%M:%S') - Ошибка при создании архива" fi
Удаление архивов старше MAX_AGE_DAYS дней
echo "$(date '+%Y-%m-%d %H:%M:%S') - Удаление архивов старше $MAX_AGE_DAYS дней" find "$BACKUP_DIR" -name "logs_*.tar.gz" -mtime +$MAX_AGE_DAYS -delete
echo "$(date '+%Y-%m-%d %H:%M:%S') - Завершение сбора логов" echo "----------------------------------------" ```
Сохраните этот скрипт в файл log_collector.sh и сделайте его исполняемым:
bash
chmod +x log_collector.sh
Python-скрипт для продвинутого сбора
Для более сложных сценариев используем Python:
```python
!/usr/bin/env python3
""" Скрипт автоматического сбора логов Версия: 1.0 """
import os import tarfile import shutil import logging from datetime import datetime, timedelta from pathlib import Path import argparse import json
class LogCollector: def init(self, config_file=None): """Инициализация сборщика логов""" self.config = self.load_config(config_file) self.setup_logging()
def load_config(self, config_file):
"""Загрузка конфигурации из файла"""
default_config = {
"log_directories": ["/var/log"],
"backup_directory": "/backup/logs",
"archive_prefix": "logs",
"max_age_days": 30,
"exclude_patterns": [".gz", ".bz2", ".zip"],
"include_subdirs": True
}
if config_file and os.path.exists(config_file):
with open(config_file, 'r') as f:
user_config = json.load(f)
default_config.update(user_config)
return default_config
def setup_logging(self):
"""Настройка логирования для скрипта"""
log_dir = self.config['backup_directory']
os.makedirs(log_dir, exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(os.path.join(log_dir, 'collector.log')),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
def collect_logs(self):
"""Основной метод сбора логов"""
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
archive_name = f"{self.config['archive_prefix']}_{timestamp}.tar.gz"
archive_path = os.path.join(self.config['backup_directory'], archive_name)
self.logger.info(f"Начало сбора логов в {archive_path}")
try:
with tarfile.open(archive_path, "w:gz") as tar:
for log_dir in self.config['log_directories']:
self.add_directory_to_archive(tar, log_dir)
self.logger.info(f"Архив {archive_name} создан успешно")
return archive_path
except Exception as e:
self.logger.error(f"Ошибка при создании архива: {str(e)}")
return None
def add_directory_to_archive(self, tar, directory):
"""Добавление директории в архив"""
if not os.path.exists(directory):
self.logger.warning(f"Директория {directory} не существует")
return
for root, dirs, files in os.walk(directory):
for file in files:
# Проверяем, не нужно ли исключить файл
if self.should_exclude(file):
continue
file_path = os.path.join(root, file)
arc_path = os.path.relpath(file_path, os.path.dirname(directory))
tar.add(file_path, arcname=arc_path)
self.logger.debug(f"Добавлен файл: {file_path}")
def should_exclude(self, filename):
"""Проверка, нужно ли исключить файл из архива"""
for pattern in self.config['exclude_patterns']:
if pattern in filename:
return True
return False
def cleanup_old_archives(self):
"""Удаление старых архивов"""
backup_dir = self.config['backup_directory']
cutoff_date = datetime.now() - timedelta(days=self.config['max_age_days'])
self.logger.info(f"Удаление архивов старше {self.config['max_age_days']} дней")
for file in os.listdir(backup_dir):
if file.startswith(self.config['archive_prefix']) and file.endswith('.tar.gz'):
file_path = os.path.join(backup_dir, file)
file_time = datetime.fromtimestamp(os.path.getctime(file_path))
if file_time < cutoff_date:
os.remove(file_path)
self.logger.info(f"Удален старый архив: {file}")
def run(self):
"""Запуск процесса сбора логов"""
self.logger.info("Запуск сбора логов")
# Сбор логов
archive_path = self.collect_logs()
if archive_path:
# Очистка старых архивов
self.cleanup_old_archives()
self.logger.info("Процесс сбора логов завершен")
else:
self.logger.error("Процесс сбора логов завершился с ошибкой")
def main(): parser = argparse.ArgumentParser(description='Сборщик логов') parser.add_argument('-c', '--config', help='Путь к конфигурационному файлу') args = parser.parse_args()
collector = LogCollector(args.config)
collector.run()
if name == "main": main() ```
Создадим также конфигурационный файл log_collector_config.json:
json
{
"log_directories": [
"/var/log",
"/opt/myapp/logs",
"/home/user/app/logs"
],
"backup_directory": "/backup/logs",
"archive_prefix": "system_logs",
"max_age_days": 30,
"exclude_patterns": [".gz", ".bz2", ".zip", "tmp", "cache"],
"include_subdirs": true
}
Настройка автоматического запуска
Для автоматического запуска скрипта используем cron. Добавьте в crontab строку:
```bash
Сбор логов каждую ночь в 2:00
0 2 * * * /path/to/log_collector.sh
Или для Python-скрипта:
0 2 * * * /usr/bin/python3 /path/to/log_collector.py ```
Для редактирования crontab:
bash
crontab -e
Скрипт для Windows
Для Windows создадим PowerShell-скрипт log_collector.ps1:
```powershell
Скрипт автоматического сбора логов для Windows
Автор: Log Analyzer Team
Версия: 1.0
Конфигурация
$LogDirectories = @("C:\Windows\Logs", "C:\ProgramData\Application\Logs") $BackupDirectory = "D:\Backup\Logs" $Date = Get-Date -Format "yyyyMMdd_HHmmss" $ArchiveName = "logs_$Date.zip" $MaxAgeDays = 30
Создание директории для бэкапов
if (!(Test-Path $BackupDirectory)) { New-Item -ItemType Directory -Path $BackupDirectory }
Логирование действий
$LogFile = Join-Path $BackupDirectory "script_log.txt" "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Начало сбора логов" | Out-File -Append -FilePath $LogFile
try { # Создание временной директории для сбора $TempDir = Join-Path $env:TEMP "log_collection_$Date" New-Item -ItemType Directory -Path $TempDir
# Копирование логов из указанных директорий
foreach ($LogDir in $LogDirectories) {
if (Test-Path $LogDir) {
$DestDir = Join-Path $TempDir (Split-Path $LogDir -Leaf)
Copy-Item -Path $LogDir -Destination $DestDir -Recurse -Force
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Скопированы логи из $LogDir" | Out-File -Append -FilePath $LogFile
} else {
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Директория $LogDir не найдена" | Out-File -Append -FilePath $LogFile
}
}
# Архивация
$ArchivePath = Join-Path $BackupDirectory $ArchiveName
Compress-Archive -Path $TempDir\* -DestinationPath $ArchivePath -Force
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Архив $ArchiveName создан успешно" | Out-File -Append -FilePath $LogFile
# Удаление временной директории
Remove-Item -Path $TempDir -Recurse -Force
} catch { "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Ошибка: $($_.Exception.Message)" | Out-File -Append -FilePath $LogFile }
Удаление старых архивов
$CutoffDate = (Get-Date).AddDays(-$MaxAgeDays) Get-ChildItem -Path $BackupDirectory -Filter "logs_*.zip" | Where-Object { $_.CreationTime -lt $CutoffDate } | Remove-Item -Force "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Удалены архивы старше $MaxAgeDays дней" | Out-File -Append -FilePath $LogFile
"$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Завершение сбора логов" | Out-File -Append -FilePath $LogFile Write-Host "Сбор логов завершен. Архив: $ArchivePath" ```
Для автоматического запуска в Windows используйте Task Scheduler:
```powershell
Создание задачи в Task Scheduler
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-ExecutionPolicy Bypass -File C:\Scripts\log_collector.ps1" $trigger = New-ScheduledTaskTrigger -Daily -At 2am $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries Register-ScheduledTask -TaskName "Log Collector" -Action $action -Trigger $trigger -Settings $settings -Description "Автоматический сбор логов" ```
Мониторинг и уведомления
Для улучшения скрипта добавим отправку уведомлений о результатах:
```bash
Добавим в конец bash-скрипта
NOTIFICATION_EMAIL="admin@example.com" if [ $? -eq 0 ]; then echo "Сбор логов успешно завершен: $(hostname) - $ARCHIVE_NAME" | mail -s "Логи собраны" $NOTIFICATION_EMAIL else echo "Ошибка при сборе логов: $(hostname)" | mail -s "Ошибка сбора логов" $NOTIFICATION_EMAIL fi ```
Заключение
Мы создали простой, но эффективный скрипт для автоматического сбора логов. В зависимости от ваших потребностей, вы можете:
- Добавить шифрование архивов
- Интегрировать с облачным хранилищем
- Добавить проверку целостности архивов
- Настроить расширенные фильтры
- Добавить отправку метрик в систему мониторинга
Автоматизация сбора логов — важный шаг к эффективному управлению инфраструктурой. Потратив всего 15 минут на создание этого скрипта, вы сэкономите намного больше времени в будущем.