Привет, Хабр! Меня зовут Владлен Кузнецов, я QA Lead в компании, которая разрабатывает мобильные игры. Однажды я потратил более 2 часов, разбирая логи, чтобы локализовать весьма коварный баг с начислением ресурсов. Это был сигнал: пора что‑то менять. В этой статье я расскажу, как мой конвертер логов на Python ускорил для нашей команды анализ логов в разы, и поделюсь советами, как вы можете сделать то же самое.

Проблема: утонуть в логах

У нас в игре клиентские логи содержат аналитические события (например CurrencyChanged, KeysChanged) и технические записи (инициализация Unity, вызовы Firebase). Один лог может достигать 100 тысяч строк и более, но QA нужны только 1–2% — ключевые события и их параметры. Найти их вручную — это как искать иголку в стоге сена. Например:

[24.01.2025 16:59:27] Log : NDA.EventName: CurrencyChanged [eventType | sink][currencyName | Energy][balance | 50]

Эта строка окружена сотнями записей вроде UnityEngine.Debug:Log. или UIWindow. Construct. Started....

Огромные логи — это просто кошмар. Как QA, мне не нужны детали внедрения зависимостей или внутренние вызовы методов — мне нужны ключевые события, такие как списания, начисления, открытие окон, расхождения геймстета и параметры этих событий. Находить их в полном логе — весьма неудобно и не особо быстро.

Решение: конвертер логов

Я написал скрипт на Python, который:

  1. Фильтрует шум: Удаляет технические записи (Unity, Firebase и др.)

  2. Извлекает события: Фокусируется на аналитических событиях и специфичных логах, важных для QA

  3. Форматирует вывод: Преобразует строки в читаемый вид с временными метками и параметрами.

  4. Добавляет удобство: Подсвечивает события цветами в терминале для быстрой визуальной оценки и сохраняет результат в _cleaned.txt.

Вот пример кода (упрощённый, чтобы соответствовать NDA. Полный код содержит около 800 строк):

import re
def process_log_line(line):
    if "EventName:" in line:
        timestamp = re.search(r'\[(.*?)]', line).group(1)
        event_name = re.search(r'EventName:\s*(\w+)', line).group(1)
        params = re.findall(r'\[([^|]+)\s*\|\s*([^]]+)]', line)
        params_str = ",\n".join(f"[key: {k}, value: {v}]" for k, v in params)
        return f"{timestamp} | EventName: {event_name} | Params:\n{params_str}"
    return None

  
  Этот фрагмент:
- ищет в строке логов ключевое слово `EventName`;
- извлекает временную метку, название события и параметры;
- форматирует вывод, делая его читабельным для QA и прочих заинтересованных лиц.

Пример вывода конвертера:

Вывод конвертера логов
Вывод конвертера логов

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

Блок-схема
+-----------------------+
|   Входной файл логов  |
+-----------------------+
            |
            v
+-----------------------+
|   Чтение файла        |
|   (open, readlines)   |
+-----------------------+
            |
            v
+-----------------------+
|   Фильтрация строк    |
|   (удаление шума:     |
|   Unity, Firebase)    |
+-----------------------+
            |
            v
+-----------------------+
|   Извлечение событий  |
|   (EventName,         |
|   SeasonsRules и др.) |
+-----------------------+
            |
            v
+-----------------------+
|   Форматирование      |
|   (временные метки,   |
|   параметры, цвета)   |
+-----------------------+
            |
            v
+-----------------------+
|   Вывод в терминал    |
|   и сохранение в файл |
|   (_cleaned.txt)      |
+-----------------------+

Результаты: больше времени на важное

До появления этого инструмента анализ логов был настоящей рутиной.

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

Теперь мы можем быстро проверить, такие кейсы как: проверять, были ли ресурсы начислены или списаны, или это только визуальный эффект.

Подытожим

Конвертер логов — это необходимый инструмент для QA, как минимум в геймдеве. Рекомендую взять его на вооружение. Для старта воспользуйтесь блок‑схемой выше. Даже если ваши QA сами не пишут код, выделите некоторое время разработчика чтобы помочь с этим, и оно определённо окупится.

Что дальше?

Этот инструмент уже изменил процесс анализа логов в нашей компании, но я не остановился на достигнутом. Я разработал программу для сравнения очищенных логов с чек‑листом, что ещё больше автоматизирует проверку событий. Представьте, что вы можете находить расхождения в логах за секунды (при условии, что вы написали чек лист и прошлись по нему)! Если эта статья вам понравится, то возможно я расскажу об этой программе в следующей статье.

Спасибо за чтение! Буду рад узнать, как вы решаете подобные задачи в ваших компания!

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


  1. economist75
    13.05.2025 06:33

    Полезный пример кода, но python в данных умеет больше. Такие логи стандартизованы и немногословны, там не увидишь разное число токенов/полей, а значит вместо readlines и re-регулярок кмк лучше использовать pandas/fireducks или polars - будет работать быстрее кратно и проще в кодинге, а главное есть сразу куда расти дальше.

    Ведь сразу становится доступна туча однострочных EDA-инструментов для поиска аномалий, статистики, построения черновых графиков bamboolib, dabl, dataprep, dtale, sweetwiz, ydata_profiling итд. Разработку можно вести всей командой, согласно последнему писку моды, в формате jupyterlab-блокнота в jupyterhub в 4-6 рук (разные курсоры правят разные ячейки). Блокнот сам зеркалится в py-файл, который дергать теперь принято не ручками и cron, а с помощью dagster/airflow с шикарными GUI, от которых так и веет надежностью.

    А разобравшись с визуализациями и добавив еще пару десятков строк можно вывалить в LAN/web готовый дэшборд с streamlit/panel/shiny ну или в grafana итд. Юзеры тут другие, поэтому очень пригодится готовая авторизация (oauth/ldap итд), все данные компактно кэшированы в RAM и пару десятков аналитиков выдержат даже без разворачивания отдельного web-сервера (хватит tornado + nginx reverse proxy).

    Впрочем, если лень делать полноценный BI и ваш одностраничный дэшборд "выфрезерован в граните" (т.е. он статический или просто нужна навигация, TOC и десяток спойлеров) - можно в Блокнот точечно впечатать в теги JS-код и тупо экспортировать блокнот в HTML, который (файл + папка с рендеренными png-графиками) можно кидать даже на дохлый web-сервер (все кэширование будут делать жирные ПК и смартфоны юзеров). JS-код будет выполняться только в браузерах, а не в блокноте, и даже месяц офлайн все будет работать как живое.


    1. OcMaRUS
      13.05.2025 06:33

      Тот случай, когда комент полезнее топика ;)


    1. VladlenQA Автор
      13.05.2025 06:33

      Спасибо, изучу


  1. yaroslavp
    13.05.2025 06:33

    Cat | Grep вышел из чата


    1. domix32
      13.05.2025 06:33

      fzf


  1. Alex32ru
    13.05.2025 06:33

    Спасибо, было познавательно


  1. adrozhzhov
    13.05.2025 06:33

    filebeat + Logstash grok?