Привет, Хабр!

Log-файлы систематически записывают хронологию событий, происходящих в системе (или приложение). Это может быть что угодно: от записи о запуске программы до детальной информации об ошибках и предупреждениях. Для нас log-файлы — это не просто дневники событий, а очень хороший инструмент для диагностики и устранения проблем.

Я часто сталкивался с ситуациями, когда правильный анализ этих файлов помогал не только обнаружить и устранить сбои в работе программ, но и предотвратить потенциальные проблемы, еще до того как они проявились.

Log-файлы содержат подробные записи о событиях и ошибках, которые происходят в приложении или системе. Анализируя эти записи, можно точно определить, в какой момент и по какой причине возникла ошибка, также можно отследить последовательность событий, которая привела к ошибке.

Log-файлы

Привет, Хабр!

Форматы log-файлов

Текстовые форматы: распространенные, легки для чтения человечком, но могут быть неэффективны при больших объемах данных. Примеры включают простой текст (.txt), CSV, JSON, XML.

json пример:

{
  "timestamp": "2023-12-19T12:00:00Z",
  "severity": "ERROR",
  "source": "AuthService",
  "message": "Failed to authenticate user",
  "eventId": 1001,
  "user": "user_otus",
  "details": {
    "ipAddress": "192.168.1.10",
    "attempt": 3
  }
}

xml логи выглядят примерно так же, только вместо фигурных скоб - <log>

csv пример:

timestamp,severity,source,message,eventId,user
"2023-12-19T12:00:01Z","INFO","DataService","Data retrieved successfully",1002,"user_otus"
"2023-12-19T12:00:02Z","WARN","DataService","Data retrieval slow",1003,"user_otus"

Бинарные форматы: хороши для хранения и обработки, но требуют специализированных инструментов для чтения. К примеру проприетарные форматы от различных приложений.

В псевдокоде бинарный код может выглядеть таким образом:

Бинарный log-файл:
- Заголовок файла (определяет формат, версию)
- Последовательность записей:
  - Длина записи (фиксированный размер)
  - Метка времени (фиксированный размер)
  - Уровень серьезности (фиксированный размер)
  - Идентификатор события (фиксированный размер)
  - Сообщение (переменный размер, завершается специальным символом)
  - Дополнительные данные (если присутствуют)

Стандартные поля

Дата и время: в целом это самое важное поле, показывающее на точное время события.

Уровень серьезности: Указывает на важность события. Обычно включает уровни, такие как INFO, DEBUG, WARN, ERROR, FATAL.

Источник события: Обычно указывает на компонент системы, откуда произошло событие.

Сообщение: описывает событие или ошибку, предоставляя контекст или детали.

Идентификатор события: уникальный код события, который помогает в классификации и фильтрации.

Пользователь или сессия: информация о пользователе или сессии, связанной с событием.

Дополнительная информация: может включать стек вызовов, значения переменных и другую диагностическую информацию.

Форматирование, стандарты и расширяемость

В текстовых форматах, таких как JSON или XML, данные часто структурированы в форме ключ-значение, что облегчает их парсинг. В бинарных форматах данные могут быть структурированы в определенных форматах, которые оптимизируют скорость чтения и записи.

Некоторые приложения могут следовать специфическим стандартам, например, Syslog в Unix/Linux системах.

syslog используется для отправки сообщений о событиях и ошибках в определенный файл, удаленный сервер или просто выводит их на экран. Сообщения syslog имеют строгую структуру, которая включает в себя метку времени, имя хоста, имя программы, процесс-идентификатор, и само сообщение.

напишем код Python, который отправляет сообщение в syslog на Unix/Linux системе:

import syslog

# открываем соединение с syslog
syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_USER)

# отправка различных уровней сообщений
syslog.syslog(syslog.LOG_INFO, "Информационное сообщение")
syslog.syslog(syslog.LOG_WARNING, "Предупреждение")
syslog.syslog(syslog.LOG_ERR, "Сообщение об ошибке")

# закрываем соединение
syslog.closelog()

syslog.openlog() используется для открытия соединения с syslog. Параметр logoption=syslog.LOG_PID указывает на то, что в каждом сообщении будет указываться ID процесса. facility=syslog.LOG_USER определяет тип программы, отправляющей сообщения. syslog.syslog() используется для отправки сообщений разного уровня серьезности (LOG_INFO, LOG_WARNING, LOG_ERR). syslog.closelog() закрывает соединение с syslog.

Формат сообщения, который в итоге будет записан в журнал syslog, выглядит к примеру так:

Dec 19 12:00:00 hostname myprogram[1234]: Информационное сообщение

Dec 19 12:00:00 — это метка времени, hostname — имя хоста, myprogram — имя программы, [1234] — ID процесса, и Информационное сообщение — это текст самого сообщения.

Формат log-файла должен позволять добавление пользовательских полей без нарушения существующей структуры.

Инструменты для анализа log-файлов

ELK Stack

Элементы

  • Elasticsearch: Распределенный поисковый движок, служит для хранения всех собранных логов. Обеспечивает хорошей масштабируемостью

  • Logstash: Потоковый процессор данных, который собирает, преобразует и перенаправляет данные в Elasticsearch. Подерживает широкий спектр входных и выходных данных, включая файлы, базы данных и облачные хранилища.

  • Kibana: Веб-интерфейс для визуализации и анализа данных из Elasticsearch. Предлагает инструменты для создания дашбордов, графиков и карт, позволяя глубоко анализировать данные.

Elastic stack

Splunk

Splunk автоматически собирает и индексирует данные из различных источников, включая логи, конфигурационные файлы и метрики. Предлагает язык запросов для поиска, анализа и визуализации лог-данных.

Splunk - мой любимый.

Graylog

Собирает логи из различных источников в единое место для анализа. Позволяет фильтровать, сортировать и анализировать данные.

Предлагает инструменты для визуализации данных и настройки оповещений о событиях.

Graylog

Сравним эти инструменты в табличке:

Критерий

ELK Stack

Splunk

Graylog

Основная функция

Сбор, агрегация и анализ логов

Сбор, анализ и визуалиация больших данных

Централизованный сбор и анализ логов

Масштабируемость

Высокая

Высокая

Средняя

Удобство использования

Средняя (требуется настройка)

Высокая (простой интерфейс)

Высокая (простота настройки)

Поиск и анализ данных

Мощные возможности поиска в Elasticsearch

Сложные поисковые запросы и алерты

Эффективный поиск и алерты

Визуализация

Гибкие дашборды в Kibana

Гибкая визуализация и отчетность

Стандартные дашборды и графики

Расширяемость

Высокая (множество плагинов и интеграций)

Модульная система плагинов

Поддержка плагинов и интеграций

Безопасность

Настройки доступа и шифрования

Расширенные функции управления и безопасности

Настройки доступа и фильтрации

Лицензирование

Open Source (с платными дополнениями)

Проприетарный (с бесплатным ограниченным использованием)

Open Source (с коммерческими опциями)

Принципы анализа лог файлов

Сбор и агрегация данных

Сбор данных включается в себя:

Определение всех источников log-данных, таких как серверы, приложения, сетевые устройства. Приведение данных к единому формату для упрощения последующего анализа. Использование агентов или служб сбора данных (например, Filebeat).

Агрегация данных вкл. в себя:

Перенаправление собранных данных в централизованное хранилище (например, Elasticsearch). Обеспечение единообразия данных, например, через схемы или шаблоны. Подготовка данных для быстрого поиска и анализа.

Filebeat - это легковесный сборщик логов, который может перенаправлять данные в Elasticsearch или Logstash. Пример конфигурационного файла Filebeat для сбора логов Apache может выгдядеть так:

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/apache2/*.log

output.elasticsearch:
  hosts: ["localhost:9200"]
  index: "apache-logs-%{+yyyy.MM.dd}"

Logstash может принимать данные от Filebeat, преобразовывать их и отправлять в Elasticsearch. Пример конфигурации Logstash для обработки Apache логов:

input {
  beats {
    port => 5044
  }
}

filter {
  if [fileset][module] == "apache" {
    grok {
      match => { "message" => "%{COMBINEDAPACHELOG}" }
    }
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "apache-logs-%{+YYYY.MM.dd}"
  }
}

На нашем любимом питоне к примеру этот процесс может выглядеть так:

напишем код, который читает строки из log-файла и извлекает определенные данные:

import re

# Открываем log-файл
with open('/path/to/logfile.log', 'r') as file:
    for line in file:
        # Используем регулярное выражение для извлечения данных
        match = re.search(r'ERROR: (.*) - at (\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})', line)
        if match:
            error_message = match.group(1)
            timestamp = match.group(2)
            print(f'Timestamp: {timestamp}, Error: {error_message}')

напишем скрипт, который собирает данные из нескольких log-файлов и агрегирует их в одном списке:

import glob

# Список для хранения агрегированных данных
aggregated_logs = []

# Собираем все log-файлы в директории
log_files = glob.glob('/path/to/logs/*.log')

# Читаем каждый файл и добавляем данные в список
for log_file in log_files:
    with open(log_file, 'r') as file:
        for line in file:
            aggregated_logs.append(line.strip())

Преобразуем данные из log-файлов перед анализом, например, преобразуем формат времени:

from datetime import datetime
import re

def preprocess_log_line(line):
    # Извлекаем метку времени и преобразуем ее
    timestamp_regex = r'\[(\d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2})'
    match = re.search(timestamp_regex, line)
    if match:
        timestamp_str = match.group(1)
        timestamp = datetime.strptime(timestamp_str, '%d/%b/%Y:%H:%M:%S')
        return timestamp, line
    return None, line

# Чтение и обработка log-файла
with open('/path/to/apache.log', 'r') as file:
    for line in file:
        timestamp, processed_line = preprocess_log_line(line)
        print(f'Timestamp: {timestamp}, Log Line: {processed_line}')

Фильтрация и сортировка данных

Фильтрация в контексте log-файлов означает извлечение записей, соответствующих определенным критериям//

Можно использовать регулярные выражения для извлечения определенных шаблонов из текста log-файлов.

Условную логику можно использловать для отбора записей по определенным критериям, например, дата, уровень ошибки и т.д

Пример фильтрации по уровню ошибки:

import re

log_file_path = '/path/to/logfile.log'
error_level = 'ERROR'

with open(log_file_path, 'r') as file:
    for line in file:
        if re.search(f'{error_level}:', line):
            print(line.strip())

Сортировка данных

Сортировка данных помогает организовать записи в порядке, который упрощает анализ, например, по времени или уровню серьезности.

Сортировка по временной метке:

from datetime import datetime
import re

def extract_timestamp(line):
    match = re.search(r'\[(.*?)\]', line)
    if match:
        return datetime.strptime(match.group(1), '%d/%b/%Y:%H:%M:%S')
    return None

log_entries = []
with open('/path/to/apache.log', 'r') as file:
    for line in file:
        timestamp = extract_timestamp(line)
        if timestamp:
            log_entries.append((timestamp, line.strip()))

# Сортировка по временной метке
log_entries.sort(key=lambda x: x[0])

for entry in log_entries:
    print(entry[1])

Сначала извлекаем временные метки из каждой строки log-файла, затем сортируем записи по этим меткам.

ml для автоматического выявления аномалий

Для выявления аномалий часто используются методы обучения без учителя, так как реальные аномалии редко бывают заранее известны. Используются алгоритмы, такие как изолирующий лес (Isolation Forest), одноклассовый SVM, автоэнкодеры.

Для примера попробуем изол.форест:

import pandas as pd
from sklearn.ensemble import IsolationForest
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Создание примера датафрейма
# Предположим, у нас есть логи с тремя параметрами: CPU Usage, Memory Usage и Number of Requests
np.random.seed(42)
data = {
    'cpu_usage': np.random.normal(loc=50, scale=5, size=100),   # Нормальное распределение вокруг 50 с отклонением 5
    'memory_usage': np.random.normal(loc=70, scale=10, size=100), # Нормальное распределение вокруг 70 с отклонением 10
    'num_requests': np.random.normal(loc=100, scale=20, size=100) # Нормальное распределение вокруг 100 с отклонением 20
}

# Добавление аномалий в данные
data['cpu_usage'][::10] = np.random.normal(loc=80, scale=5, size=10)   # Аномально высокое использование CPU
data['memory_usage'][::10] = np.random.normal(loc=30, scale=5, size=10) # Аномально низкое использование памяти
data['num_requests'][::10] = np.random.normal(loc=150, scale=30, size=10) # Аномально высокое количество запросов

# Создание DataFrame
df = pd.DataFrame(data)

# Инициализация и обучение модели Isolation Forest
iso_forest = IsolationForest(n_estimators=100, contamination=0.1)
predictions = iso_forest.fit_predict(df)

# Добавление результатов в датафрейм
df['anomaly'] = predictions

# Визуализация данных с аномалиями
sns.pairplot(df, hue='anomaly', palette={-1:'red', 1:'blue'})
plt.title('Isolation forest в аномалиях')
plt.show()

Анализ log-файлов – это большая техническая необходимость для каждого проекта.

Всем необходимым инструментам аналитики можно научиться на онлайн-курсах OTUS, в рамках которых каждый день проходят открытые уроки — календарь занятий доступен по ссылке.

Комментарии (0)