IgdrasilLogging — Система логирования
IgdrasilLogging — простая и гибкая система логирования для отладки и мониторинга игры. Поддерживает различные уровни логирования, множественные выводы (консоль, файлы), цветное форматирование и контексты.
Использование в движке
При работе с Igdrasil Engine вам не нужно создавать LoggingContext вручную — движок автоматически инициализирует систему логирования при запуске.
Получение логгера
Используйте статический метод Igdrasil.GetLogger():
using IgdrasilEngine.Engine;
// Получаем логгер для своей системы
var logger = Igdrasil.GetLogger("MyGameSystem");
logger.Info("Система инициализирована");
logger.Warning("Что-то пошло не так");
Каждый вызов GetLogger создает новый логгер с указанным тегом, но все логгеры используют один общий контекст движка.
Настройка уровня логирования
Управляйте уровнем через свойство Igdrasil.LogLevel:
// По умолчанию: LoggingLevel.Default (Info, Warning, Error, Fatal, Wtf)
Igdrasil.LogLevel = LoggingLevel.All; // включить Debug
#if DEBUG
Igdrasil.LogLevel = LoggingLevel.All;
#else
Igdrasil.LogLevel = LoggingLevel.OnlyErrors;
#endif
Автоматическое логирование в файлы
При инициализации движок автоматически:
- Создает директорию
logs/в корне проекта - Логирует в
logs/latest.log(по умолчанию) — файл перезаписывается при каждом запуске - Архивирует старые логи — когда накапливается 25+ файлов, создается ZIP-архив
logs/archive_<дата>.zip
// Создавать новый файл при каждом запуске (вместо latest.log)
Igdrasil.InitializeWindow(options, onlyLatestLog: false);
// Создаст logs/<дата и время>.log
Все логи автоматически пишутся в консоль и файл одновременно.
Добавление своих писателей
Если нужен дополнительный вывод (например, GUI-консоль):
var customWriter = new StringWriter();
Igdrasil.ModifyLoggerContext(customWriter);
// Теперь все логи идут в Console.Out, logs/latest.log и customWriter
Внутренние логгеры движка
Движок использует логгеры для своих систем:
// Главный логгер движка
var engineLogger = Igdrasil.Logger; // тег: "Igdrasil Engine"
engineLogger.Info("Ad astra abyssosque!"); // выводится при старте
// Логгеры автоматически назначаются разным модулям
ResourceHelper.Logger = Igdrasil.Logger;
AbstractGameEvent.Logger = Igdrasil.Logger;
Автоматическая обработка исключений
При вызове Igdrasil.Start(sendExceptions: true) движок автоматически:
- Логирует все необработанные исключения
- Записывает состояние движка в лог
- Отправляет отчет на сервер разработчиков движка для автономной регистрации проблем (если исключение из модулей Igdrasil)
Igdrasil.Start(
hideConsole: false, // показать консоль
sendExceptions: true // отправлять отчеты об ошибках
);
// При падении в logs/latest.log будет полный стек + состояние движка
Быстрый старт: логирование в консоль (без движка)
using IgdrasilLogging.Engine.Logging;
// Создаём контекст (куда писать логи)
using var context = new LoggingContext(Console.Out);
// Создаём логгер с тегом
var logger = LoggerFactory.CreateLogger("Game", context);
// Логируем
logger.Info("Игра запущена");
logger.Warning("Низкий FPS: {0}", 30);
logger.Error("Не удалось загрузить текстуру");
Вывод в консоли:
25-01-2026 14:32:15.123 - (Main Thread) [Game] INFO: Игра запущена
25-01-2026 14:32:16.456 - (Main Thread) [Game] WARN: Низкий FPS: 30
25-01-2026 14:32:17.789 - (Main Thread) [Game] ERROR: Не удалось загрузить текстуру
Создание логгеров для разных систем
Используйте теги для разделения логов разных систем:
// Контекст общий
var context = new LoggingContext(Console.Out);
// Логгеры для разных подсистем
var physicsLogger = LoggerFactory.CreateLogger("Physics", context);
var audioLogger = LoggerFactory.CreateLogger("Audio", context);
var networkLogger = LoggerFactory.CreateLogger("Network", context);
physicsLogger.Info("Collision detected");
audioLogger.Warning("Sound clip missing");
networkLogger.Error("Connection timeout");
Вывод:
[Physics] INFO: Collision detected
[Audio] WARN: Sound clip missing
[Network] ERROR: Connection timeout
Логирование в файл
Используйте StreamWriter для записи логов в файл:
var fileWriter = new StreamWriter("game.log", append: true);
var context = new LoggingContext(Console.Out, fileWriter);
var logger = LoggerFactory.CreateLogger("Game", context);
logger.Info("Игра запущена");
// Логи идут и в консоль, и в файл game.log
Добавление писателя после создания контекста:
var context = new LoggingContext(Console.Out);
var logger = LoggerFactory.CreateLogger("Game", context);
// Позже добавляем файл
var fileWriter = new StreamWriter("errors.log");
context.AddWriter(fileWriter);
logger.Error("Критическая ошибка"); // запишется в консоль + файл
Уровни логирования
Фильтруйте логи по важности через LoggingLevel:
var context = new LoggingContext(Console.Out);
// По умолчанию: Info, Warning, Error, Fatal, Wtf
context.Level = LoggingLevel.Default;
// Только критические
context.Level = LoggingLevel.OnlyCritical; // Warning, Error, Fatal
// Только ошибки
context.Level = LoggingLevel.OnlyErrors; // Error, Fatal
// Всё включая Debug
context.Level = LoggingLevel.All; // Debug, Info, Warning, Error, Fatal, Wtf
// Вообще ничего
context.Level = LoggingLevel.None;
Пример настройки для релизной сборки:
var context = new LoggingContext(Console.Out);
#if DEBUG
context.Level = LoggingLevel.All; // в отладке всё
#else
context.Level = LoggingLevel.OnlyErrors; // в релизе только ошибки
#endif
Методы логирования
Все уровни имеют одинаковый интерфейс:
// Простое сообщение
logger.Info("Сообщение");
// С форматированием (string.Format)
logger.Warning("FPS: {0}, Objects: {1}", fps, objectCount);
// Без сообщения (пустая строка)
logger.Debug();
Уровни:
| Метод | Описание | Цвет | Когда использовать |
|---|---|---|---|
Debug |
Отладочная информация | Синий | Детальная трассировка, проверка значений |
Info |
Информационные сообщения | Белый | Нормальные события (загрузка уровня, старт игры) |
Warning |
Предупреждения | Оранжевый | Неоптимальные ситуации (низкий FPS, отсутствующий ресурс) |
Error |
Ошибки | Красный | Ошибки с возможностью продолжения (не удалось загрузить текстуру) |
Fatal |
Фатальные ошибки | Тёмно-красный | Критические ошибки (невозможно продолжить) |
Wtf |
"Что за чёрт?" | Фиолетовый | Невозможные ситуации (проверка на всякий случай) |
Форматирование сообщений
Поддерживается string.Format с произвольным числом параметров:
// Переменные
logger.Info("Player {0} joined", playerName);
// Несколько параметров
logger.Debug("Position: ({0}, {1}, {2})", x, y, z);
// Объекты (будет вызван ToString())
logger.Info("Loaded asset: {0}", assetObject);
// Числа с форматированием
logger.Info("Health: {0:0.00}%", health);
Когда что использовать
LoggingContext
Используйте: Один раз при инициализации игры, создайте глобальный контекст.
Не делайте: Не создавайте новый контекст для каждого логгера — используйте один на всё приложение.
LoggerFactory.CreateLogger
Используйте: Для каждой подсистемы создайте свой логгер с уникальным тегом.
Не делайте: Не создавайте логгеры в методах, вызываемых часто — кешируйте их в полях класса.
Уровень Debug
Используйте: Для трассировки алгоритмов, проверки значений в процессе разработки.
Не делайте: Не оставляйте Debug в production — они замедляют игру и захламляют логи.
Уровень Info
Используйте: Для важных событий игры (загрузка уровня, подключение к серверу, сохранение).
Не делайте: Не логируйте Info каждый кадр или в Update() — используйте Debug или вообще не логируйте.
Уровень Warning
Используйте: Когда что-то не так, но игра может продолжаться (fallback на дефолтные значения).
Не делайте: Не используйте Warning для нормальных ситуаций.
Уровень Error
Используйте: Когда операция не удалась (не загрузился файл, не установилось соединение).
Не делайте: Не используйте Error для предупреждений — они фильтруются отдельно.
Уровень Fatal
Используйте: Перед вылетом/закрытием игры при критической ошибке.
Не делайте: Не используйте Fatal для обычных ошибок — он предполагает невозможность продолжения.
Уровень Wtf
Используйте: В коде, который "никогда не должен выполниться" (например, default в switch с полным перечислением).
Не делайте: Не используйте Wtf вместо Error — это уровень для логической невозможности.
Типичные сценарии
Централизованная система логирования
public static class GameLogger
{
private static LoggingContext? _context;
public static ILogger Physics { get; private set; } = null!;
public static ILogger Audio { get; private set; } = null!;
public static ILogger Network { get; private set; } = null!;
public static ILogger UI { get; private set; } = null!;
public static void Initialize()
{
var fileWriter = new StreamWriter("game.log", append: true);
_context = new LoggingContext(Console.Out, fileWriter);
#if DEBUG
_context.Level = LoggingLevel.All;
#else
_context.Level = LoggingLevel.OnlyCritical;
#endif
Physics = LoggerFactory.CreateLogger("Physics", _context);
Audio = LoggerFactory.CreateLogger("Audio", _context);
Network = LoggerFactory.CreateLogger("Network", _context);
UI = LoggerFactory.CreateLogger("UI", _context);
}
public static void Shutdown()
{
_context?.Dispose();
}
}
// Использование в игре
GameLogger.Initialize();
GameLogger.Physics.Info("Physics engine initialized");
GameLogger.Audio.Warning("Sound device not found, using default");
GameLogger.Shutdown();
Логирование ошибок с fallback
var logger = LoggerFactory.CreateLogger("AssetLoader", context);
Texture? LoadTexture(string path)
{
try
{
var texture = Texture.Load(path);
logger.Info("Loaded texture: {0}", path);
return texture;
}
catch (FileNotFoundException ex)
{
logger.Warning("Texture not found: {0}, using default", path);
return Texture.DefaultTexture;
}
catch (Exception ex)
{
logger.Error("Failed to load texture {0}: {1}", path, ex.Message);
return null;
}
}
Раздельные логи для разных этапов
// Лог загрузки
using var bootContext = new LoggingContext(new StreamWriter("boot.log"));
var bootLogger = LoggerFactory.CreateLogger("Boot", bootContext);
bootLogger.Info("Starting game...");
// Лог игровой сессии
using var gameContext = new LoggingContext(Console.Out, new StreamWriter("session.log"));
gameContext.Level = LoggingLevel.Default;
var gameLogger = LoggerFactory.CreateLogger("Game", gameContext);
gameLogger.Info("Player joined");
Отладочные утверждения
void ProcessEntity(Entity entity)
{
if (entity == null)
{
logger.Wtf("Entity is null in ProcessEntity — should never happen!");
return;
}
if (entity.Health < 0)
{
logger.Warning("Entity {0} has negative health: {1}", entity.Name, entity.Health);
entity.Health = 0;
}
logger.Debug("Processing entity {0}", entity.Name);
}
Архитектура
- ILogger — интерфейс логгера с методами Info, Warning, Error, Fatal, Debug, Wtf
- LoggerFactory — создаёт экземпляры логгеров (
CreateLogger(tag, context)) - LoggingContext — контекст логирования с писателями (
TextWriter[]) и уровнем (LoggingLevel) - LoggingLevel — перечисление уровней (Debug | Info | Warning | Error | Wtf | Fatal)
- SimpleContextLogger — внутренняя реализация с форматированием и цветным выводом (Pastel)
Проект: Igdrasil Engine
Автор: Alexander Izmailov
Собственность: Igdrasil Project
Версия: 1.0
Лицензия: Proprietary License
© 2026 Alexander Izmailov. Все права защищены.
Этот программный продукт является собственностью студии Igdrasil Project.