Логирование в AI Scripting
Карта по логированию скриптов, IFluentLog, логированию через helper-классы и диагностическим breadcrumb-сообщениям.
Навигатор по логированию скриптов
Справочная карта по добавлению полезного диагностического логирования в скрипты и mini-app.
Что обычно нужно пользователю
- Понять, почему скрипт что-то сделал или не сделал.
- Показать выбранные окна, процессы, области, readers и решения по конфигурации.
- Диагностировать отсутствие опциональной настройки SDK, недоступные сервисы и провалившуюся валидацию.
- Сделать так, чтобы вспомогательные классы писали в лог без привязки к глобальным переменным верхнего уровня.
- Избежать шумного спама в лог на каждом кадре или для каждой entity.
Базовая модель
- У кода верхнего уровня в скрипте есть
Log, который предоставляет host. Log— это не глобальный C# API. Обычные классы не получают его автоматически.- Вспомогательным классам лучше передавать
IFluentLogчерез конструктор, параметр метода, property injection или регистрацию в DI. - Код приложения или библиотеки может создать независимый логгер через
typeof(MyType).PrepareLogger(). - Для helper-классов, принадлежащих скрипту, лучше передавать
Logсамого скрипта, чтобы диагностика оставалась привязанной к контексту скрипта и runtime. - Хороший лог — это цепочка понятных следов о решениях и ошибках, а не стенограмма каждой итерации цикла.
Детали API
IFluentLog— интерфейс логирования, который используется в коде EyeAuras/PoeShared.FluentLogLevel—Trace,Debug,Info,Warn,Error.Log.Debug(...)— подробные сообщения, полезные при диагностике.Log.Info(...)— обычные этапы жизненного цикла и важные переходы состояния.Log.Warn(...)— проблемы, после которых можно продолжить работу, отсутствие опциональных данных, fallback-сценарий.Log.Error(...)— неудачная операция или исключение, которое мешает ожидаемой работе.Log.Error(message, exception)— сохраняет информацию об исключении вместе с записью лога.Log.IsDebugEnabled,IsInfoEnabled,IsWarnEnabled,IsErrorEnabled— позволяют защититься от дорогой сборки сообщений.Log.Debug(() => expensiveText)и похожие overload сFunc<string>— ленивое построение сообщения.Log.Write(level, () => message)— запись, когда уровень задаётся динамически.Log.IsEnabled(level)— проверка динамического уровня.Log.WithPrefix(...)/Log.WithSuffix(...)— создают логгеры с контекстом для helper-классов, окон, process readers или выбранных целей.Log.WithMaxLineLength(...)/WithoutMaxLineLength()— управление длиной длинных строк в выводе.Log.WithMinLogLevelOverride(...)— переопределяет минимальный уровень для производного логгера.Log.WithAction(...)/WithLogAction(...)— дублируют записи лога в UI, списки в памяти или собственные sinks.Log.CreateProfiler(...)— создаётIDisposable-таймер для замера именованной операции.TypeExtensions.PrepareLogger()— создаёт логгер из обычного C# типа.
Типовые сценарии
Записать результат работы скрипта
Вставьте в тело Script.csx. Входные данные здесь заданы прямо в примере;
Log предоставляет песочница:
var values = new[] { 12, 7, 19 };
var total = 0;
foreach (var value in values)
{
total += value;
}
Log.Info($"Обработано {values.Length} значений, сумма {total}");
Результат — запись с суммой 38 в журнале скрипта, если уровень Info включён.
Запись подтверждает только достижение этой строки кода, а не успех другой
фоновой операции.
Передача Log во вспомогательный класс
Класс можно разместить в отдельном .cs-файле проекта; вызов остаётся в
Script.csx. Для IFluentLog нужен using PoeShared.Logging;.
using PoeShared.Logging;
using PoeShared.Scaffolding;
var reader = new EntityReader(Log.WithPrefix("EntityReader"));
reader.Refresh();
public sealed class EntityReader
{
private readonly IFluentLog log;
public EntityReader(IFluentLog log)
{
this.log = log;
}
public void Refresh()
{
var values = new[] { 12, 7, 19 };
var total = 0;
foreach (var value in values) total += value;
log.Info($"Сумма {total}");
}
}
После вызова Refresh() в журнале скрипта появится сумма 38 с префиксом EntityReader.
Создание логгера в коде приложения или библиотеки
В обычном проекте со ссылкой на PoeShared импортируйте
PoeShared.Logging и PoeShared.Scaffolding. Это самостоятельный логгер типа,
а не маршрут журнала конкретного скрипта.
using PoeShared.Logging;
using PoeShared.Scaffolding;
public sealed class MyService
{
private static readonly IFluentLog Log = typeof(MyService).PrepareLogger();
public void Start()
{
Log.Info("Service started");
}
}
В коде приложения вызовите new MyService().Start(): сообщение пойдёт в журнал типа, с учётом настроенных уровней и sinks.
Отложить построение подробной диагностики
В Script.csx передайте построение строки в перегрузку с Func<string>:
var values = new[] { 12, 7, 19 };
Log.Debug(() => $"Значения: {string.Join(", ", values)}");
Лямбда позволяет логгеру отложить построение строки до проверки уровня.
Она должна только собирать сообщение: не помещайте туда работу, от которой
зависит результат скрипта. Для уже готовой строки обычный Log.Info(text) проще.
Что имеет смысл логировать
- Запуск и остановку скрипта, запуск и остановку долгоживущих сервисов.
- Настройку опциональных SDK-пакетов и регистрацию container extensions.
- Выбор пользователя: заголовок окна/process id, region, point, color, путь к файлу.
- Выбор process/memory reader и результат валидации.
- Внешние ресурсы: загруженные DLL, модели, шрифты, скрипты, embedded resources.
- Значения конфигурации, которые влияют на поведение.
- Срабатывание fallback-сценариев и пропущенные действия.
- Исключения с контекстом о том, какая именно операция не удалась.
- Отмену операций и сценарии очистки.
Что лучше делать
- Используйте
Infoдля заметных пользователю этапов жизненного цикла. - Используйте
Warn, если скрипт может продолжить работу, но результат будет хуже ожидаемого. - Используйте
Error(message, ex)при перехвате исключений. - Используйте префиксы для повторяющихся helper-классов или нескольких подключённых окон/процессов.
- Используйте ленивые сообщения для таблиц, дампов, скриншотов или memory scan.
- Передавайте
IFluentLogв обычные helper-классы. - В небольших скриптах лучше оставить несколько действительно полезных сообщений вокруг ветвлений и ошибок.
Чего лучше избегать
- Не рассчитывайте, что
Logсуществует вне тела верхнего уровня скрипта. - Не делайте
catchбез лога; как минимум запишите операцию и сообщение исключения. - Не логируйте внутри tight frame loops, memory scans или циклов по entity, если уровень не защищён проверкой или sampling не сделан намеренно.
- Не пишите в лог секреты, auth tokens, license keys и приватные данные пользователя.
- Не превращайте каждое изменение состояния в сообщение уровня
Info. - Не используйте
PrepareLogger()внутри helper-классов скрипта, если передача логгера скрипта сохранит более полезный контекст.
Основные API и точки входа
IFluentLogFluentLogLevelFluentLogExtensionsPrepareLoggerWithPrefixWithSuffixWithActionWithLogActionCreateProfilerAuraScriptSandbox.LogIAuraScriptSandbox.Log
Ключевые слова для поиска
- logging
- diagnostics
- debug log
- script log
- event log
- fluent log
- logger injection
- helper class logging
- log prefix
- log level
- exception logging
- diagnostic breadcrumbs
Связанные карты
scripting/runtime.mdscripting/container-extensions.mdscripting/project-workflow.mdcomputer-vision/profiling.mdauras/entities.mdКонтракты этой карты — EyeAuras20fd3d4, PoeEye0e02c98; точные перегрузки смотрите в SDK/XML своей версии.