15. Log - логирование
Лёгкий логгер ядра. Уровень проверяется до форматирования (отключённый уровень не тратит такты на разбор строки формата). Вывод идёт в платформенный бэкенд плюс опциональный приёмник строк.
enum class log::Level : uint8_t
{
Verbose = 0, Debug = 1, Info = 2, Warning = 3, Error = 4, Off = 5
};
using log::Sink = void (*)(void *user, Level level, const char *line) noexcept;
| Функция | Описание |
|---|---|
void log::setLevel(Level level) |
Установить порог уровня в рантайме |
Level log::level() |
Текущий порог |
bool log::enabled(Level level) |
Пройдёт ли сообщение такого уровня через фильтр - полезно, чтобы не готовить дорогие аргументы |
void log::setSink(Sink sink, void *user) |
Дополнительный приёмник отформатированных строк (nullptr - отключить) |
void log::print(Level level, const char *fmt, ...) |
Вывод с printf-форматированием |
void log::vprint(Level level, const char *fmt, std::va_list args) |
То же с va_list |
log::verbose/debug/info/warning/error(const char *fmt, ...) |
Сокращения для соответствующего уровня |
- Стартовый уровень -
PIPCORE_LOG_LEVEL(по умолчанию Info). Сообщения ниже порога не форматируются вообще. - На ESP32 вывод идёт через логгер IDF (метка
pipcore, с меткой времени и уровнем) - виден вidf.py monitor; в симуляторе - в консоль. setSink()передаёт каждую уже отформатированную строку вашему колбэку. Так симулятор показывает логи в своей консоли; так же логи можно пересылать куда угодно (по сети, в файл).
log::info("heap: internal %u KB", unsigned(plat->freeHeapInternal() / 1024));
log::error("display: %s", plat->lastErrorText());
if (log::enabled(log::Level::Debug))
log::debug("state dump: %s", buildExpensiveDump());
16. Debug - профайлер и трекер аллокаций
Включается PIPCORE_ENABLE_DEBUG. В production-сборке (выключено) макросы профайлера превращаются в пустышки - нулевая цена.
Профайлер
void hotPath()
{
PIP_PROFILE_FUNCTION(); // зона на всю функцию (имя из __PRETTY_FUNCTION__)
PIP_PROFILE_ZONE("parse"); // именованная зона в любом scope
// ...
}
Макросы строят дерево узлов: суммарное и собственное время (в тактах CPU), число вызовов, максимальная длительность зоны. Точность измерения - до такта (debug::profileCycles()). Каждая зона - одна строка кода: не ставьте две PIP_PROFILE_ZONE на одной строке.
Данные читает PipCore Inspector (GET_PROFILE) или вы вручную:
auto &prof = debug::Profiler::instance();
prof.calculateSelfCycles(); // пересчёт собственного времени
for (debug::ProfileNode *n = prof._head; n; n = n->next)
log::info("%s: %u cycles x%u", n->name, unsigned(n->totalCycles), unsigned(n->callCount));
prof.clear(); // обнулить счётчики
Трекер аллокаций
Все глобальные operator new/delete идут через трекер: он ведёт текущие и пиковые байты, теги точек выделения и полный список живых аллокаций (виден в Inspector).
debug::AllocStats st = debug::allocStats();
log::info("heap now %u, peak %u", unsigned(st.currentBytes), unsigned(st.peakBytes));
debug::allocStats() и AllocStats доступны только при PIPCORE_ENABLE_DEBUG, поэтому при использовании оберните вызовы в #if PIPCORE_ENABLE_DEBUG.
Отладочная консоль (PipCore Inspector)
PIPCORE_DEBUG_CONSOLE поднимает ASCII-консоль (таск PipCoreConsole, транспорт - USB-Serial/JTAG или UART0) для десктопного инспектора.
| Команда | Действие |
|---|---|
GET_ALLOCS |
Список живых аллокаций |
GET_FLASH |
Информация о флеш-памяти |
GET_NVS |
Содержимое NVS |
GET_CPU |
Загрузка CPU |
GET_PROFILE / RESET_PROFILE |
Данные профайлера / сброс |
GET_FS |
Содержимое файловой системы |
GET_FILE:<path> |
Скачать файл |
WRITE_START:<path> → WRITE_CHUNK:<hex> → WRITE_END |
Загрузить файл по частям |
DELETE_FILE:<path> |
Удалить файл |
GET_PARTITIONS |
Таблица разделов |
READ_FLASH:<offset>,<size> |
Прочитать флеш (до 1 КБ за запрос) |
GET_BOOT_SECURITY |
Состояние защиты загрузки |
Любой, у кого есть доступ к порту, может прочитать всю флеш-память и NVS, а также скачать, перезаписать и удалить файлы в разделе хранилища. Используйте только при разработке. Ядро не соберётся, пока не включён PIPCORE_DEBUG_CONSOLE_ACCEPT_RISK. Никогда не включайте консоль в релизной прошивке.