Автоматизация сбора логов: пишем скрипт-сборщик за 15 минут

Сбор логов — важная часть мониторинга систем, но делать это вручную неэффективно. В этой статье мы создадим простой, но функциональный скрипт для автоматического сбора и архивации логов. За 15 минут вы получите рабочий инструмент, который будет собирать логи по расписанию.

Зачем нужен автоматический сбор логов?

Ручной сбор логов — трудоемкий процесс, особенно когда у вас много серверов. Автоматизация решает множество проблем:

  • Экономия времени администраторов
  • Регулярность сбора данных
  • Снижение вероятности ошибок
  • Возможность анализа исторических данных

Планирование скрипта

Перед началом напишем список требований к нашему скрипту:

  1. Собирать логи из заданных директорий
  2. Архивировать собранные данные
  3. Удалять старые архивы
  4. Логировать действия самого скрипта
  5. Работать по расписанию (через 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 минут на создание этого скрипта, вы сэкономите намного больше времени в будущем.