Danro/Assets/Scripts/Utilities/README_LOGGING.md
Danil Iarosh 98d5285b46 feat(logging): add advanced logging example with file output
- Created AdvancedLoggingExample class demonstrating composite and file loggers
- Implemented multi-file logging setup with separate error and full logs
- Added game event and performance logging methods
- Included key input handling for log operations (flush, clear)
- Setup proper resource disposal on application quit
2025-11-07 14:12:50 +03:00

10 KiB
Raw Blame History

Система логирования для Unity

Обзор

Система состоит из трёх компонентов:

  1. CompositeLogger - композитный логгер, пересылающий сообщения на несколько логгеров
  2. FileLogger - логгер для записи в файл
  3. LoggerInitializer - компонент для автоматической инициализации

Быстрый старт

Вариант 1: Использование через LoggerInitializer (рекомендуется)

  1. Создайте пустой GameObject на сцене

  2. Прикрепите компонент LoggerInitializer

  3. Настройте параметры в инспекторе:

    • Enable File Logging - включить запись в файл
    • Custom Log Path - путь к файлу (оставьте пустым для автоматического)
    • Append To Existing Log - добавлять к существующему файлу
    • Clear Log On Start - очищать файл при запуске
  4. Запустите игру - все логи будут автоматически писаться в файл!

Вариант 2: Ручная настройка в коде

using UnityEngine;

public class MyGameManager : MonoBehaviour
{
    private CompositeLogger compositeLogger;
    private FileLogger fileLogger;

    void Awake()
    {
        // Инициализация композитного логгера
        compositeLogger = new CompositeLogger();
        compositeLogger.Initialize();

        // Создание файлового логгера
        fileLogger = new FileLogger(); // Использует путь по умолчанию
        // или
        // fileLogger = new FileLogger("D:/MyGame/logs/game.log", append: true);

        // Добавление файлового логгера в композитный
        compositeLogger.AddLogger(fileLogger);

        // Теперь все логи через compositeLogger будут идти и в консоль, и в файл
        compositeLogger.Log("Игра запущена!");
        compositeLogger.LogWarning("Test", "Тестовое предупреждение");
    }

    void OnApplicationQuit()
    {
        fileLogger?.Dispose();
    }
}

Где находится файл лога?

По умолчанию файл сохраняется в Application.persistentDataPath/game.log:

  • Windows: C:/Users/<Username>/AppData/LocalLow/<CompanyName>/<ProductName>/game.log
  • macOS: ~/Library/Application Support/<CompanyName>/<ProductName>/game.log
  • Linux: ~/.config/unity3d/<CompanyName>/<ProductName>/game.log
  • Android: /storage/emulated/0/Android/data/<PackageName>/files/game.log

Узнать точный путь можно через:

Debug.Log(Application.persistentDataPath);

Примеры использования

Базовое логирование

// Через композитный логгер
compositeLogger.Log("Простое сообщение");
compositeLogger.LogWarning("Tag", "Предупреждение");
compositeLogger.LogError("Tag", "Ошибка");

// Через стандартный Debug (если вы заменили Debug.unityLogger)
Debug.Log("Это тоже пойдёт в файл");

Логирование с контекстом

compositeLogger.Log(LogType.Log, "Игрок спавнится", playerGameObject);
compositeLogger.LogWarning("AI", "Путь не найден", enemyGameObject);

Логирование исключений

try
{
    // Опасный код
}
catch (Exception ex)
{
    compositeLogger.LogException(ex);
}

Форматированное логирование

compositeLogger.LogFormat(LogType.Log, "Игрок {0} имеет {1} очков здоровья", playerName, health);

Добавление нескольких логгеров

var fileLogger1 = new FileLogger("logs/debug.log");
var fileLogger2 = new FileLogger("logs/errors.log");
fileLogger2.filterLogType = LogType.Error; // Только ошибки

compositeLogger.AddLoggers(fileLogger1, fileLogger2);

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

На уровне FileLogger

fileLogger.filterLogType = LogType.Warning; // Логировать только Warning, Error, Exception
fileLogger.logEnabled = false; // Временно отключить

Очистка файла лога

fileLogger.Clear(); // Очистить файл и записать новый заголовок

Принудительная запись на диск

fileLogger.Flush(); // Сбросить буфер на диск

Формат записи в файле

================================================================================
Новая сессия логирования начата: 2025-11-07 14:30:15
Unity версия: 2022.3.5f1
Платформа: WindowsEditor
Путь к логу: C:/Users/User/AppData/LocalLow/DefaultCompany/MyGame/game.log
================================================================================

[14:30:15.123] [INFO] Игра запущена!
[14:30:16.456] [WARNING] [AI] Путь не найден
[14:30:17.789] [ERROR] [Network] Соединение потеряно
[14:30:18.012] [EXCEPTION] NullReferenceException: Object reference not set to an instance of an object
StackTrace:
  at MyScript.MyMethod () [0x00000] in <filename>:0

Важные замечания

Потокобезопасность

FileLogger потокобезопасен - использует lock для синхронизации записи.

Производительность

  • AutoFlush = true гарантирует сохранность данных при крашах, но снижает производительность
  • Если нужна максимальная производительность, установите AutoFlush = false и вызывайте Flush() вручную

Освобождение ресурсов

ВАЖНО: Всегда вызывайте Dispose() при завершении работы:

void OnApplicationQuit()
{
    fileLogger?.Dispose();
}

Ротация логов

Для больших проектов можно реализовать ротацию:

string timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
string logPath = $"logs/game_{timestamp}.log";
var fileLogger = new FileLogger(logPath, append: false);

Расширенные сценарии

Отдельные логи для разных систем

// Общий лог
var mainLogger = new FileLogger("logs/game.log");

// Лог только для сетевой подсистемы
var networkLogger = new FileLogger("logs/network.log");
networkLogger.filterLogType = LogType.Log;

// Лог только для ошибок
var errorLogger = new FileLogger("logs/errors.log");
errorLogger.filterLogType = LogType.Error;

compositeLogger.AddLoggers(mainLogger, networkLogger, errorLogger);

Условное логирование

#if UNITY_EDITOR
    // В редакторе не пишем в файл, только в консоль
#else
    compositeLogger.AddLogger(new FileLogger());
#endif

Логирование с метками времени

public class TimestampLogger
{
    private CompositeLogger logger;
    
    public void LogWithTimestamp(string message)
    {
        logger.Log($"[{Time.time:F2}s] {message}");
    }
}

Troubleshooting

Файл не создаётся

  • Проверьте права доступа к папке
  • Проверьте путь через Debug.Log(Application.persistentDataPath)
  • Убедитесь, что вызвали Initialize() на CompositeLogger

Логи не пишутся в файл

  • Убедитесь, что logEnabled = true
  • Проверьте filterLogType - возможно фильтр слишком строгий
  • Проверьте, что логгер добавлен через AddLogger()

Файл заблокирован

  • Убедитесь, что вызвали Dispose() перед закрытием приложения
  • Закройте все программы, которые могут держать файл открытым

Производительность низкая

  • Установите AutoFlush = false в конструкторе FileLogger
  • Вызывайте Flush() периодически (например, раз в секунду)
  • Используйте более строгий filterLogType

API Reference

FileLogger

Конструктор

FileLogger(string filePath = null, bool append = true)

Свойства

  • bool logEnabled - включено ли логирование
  • LogType filterLogType - минимальный уровень логирования
  • ILogHandler logHandler - обработчик логов (для совместимости)

Методы

  • void Flush() - принудительно сбросить буфер на диск
  • void Clear() - очистить файл лога
  • void Dispose() - закрыть файл и освободить ресурсы
  • bool IsLogTypeAllowed(LogType) - проверка фильтра

CompositeLogger

Методы управления

  • void Initialize(ILogger additiveLogger = null) - инициализация
  • void AddLogger(ILogger) - добавить логгер
  • void AddLoggers(params ILogger[]) - добавить несколько логгеров
  • void RemoveLogger(ILogger) - удалить логгер
  • void RemoveLoggers(params ILogger[]) - удалить несколько логгеров

Лицензия

Свободное использование в ваших проектах.