# debug_config — Runtime-система отладочного логирования ## 1. Назначение Модуль обеспечивает гибкое управление отладочным выводом без перекомпиляции. Позволяет: - Задавать **глобальный уровень** логирования (error/warn/info/debug/trace). - **Покатегорийно** включать/выключать или переопределять уровень (26 категорий: etcp, crypto, tun, routing, bgp, bbr, …). - Вести **двойной вывод**: в консоль (stdout) и/или в файл. - Настраивать формат сообщений (временные метки с микросекундами, имя функции, файл:строка). - Парсить конфигурационную строку вида `"etcp=trace,config=info"` из конфиг-файла. Логика вывода: итоговый уровень = **max(глобальный уровень, уровень категории)**. Сообщение печатается, если его уровень ≤ итогового. ## 2. Как пользоваться ### 2.1. Инициализация ```c #include "debug_config.h" debug_config_init(); // уровень по умолчанию: ERROR, консоль включена debug_set_level(DEBUG_LEVEL_INFO); // поднять глобальный уровень до INFO debug_enable_file_output("/tmp/utun.log", 1); // писать в файл (truncate=1) debug_apply_category_config("etcp", "trace"); // для ETCP-категории — всё ``` ### 2.2. Макросы логирования ```c DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "Decrypt failed: len=%d", len); DEBUG_WARN(DEBUG_CATEGORY_ETCP, "Retransmit timeout, seq=%u", seq); DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Socket created on port %d", port); DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Route added: %s -> %s", dst, gw); DEBUG_TRACE(DEBUG_CATEGORY_TUN, "Packet recv: %zu bytes", n); ``` Макросы делают проверку `debug_should_output()` **перед** вызовом `debug_output()`, поэтому дорогой `vsnprintf` не вызывается, если вывод не нужен. ### 2.3. Конфигурационная строка Формат: `"категория=уровень,категория=уровень,..."`. Парсится вызовом `debug_parse_config()`. Пример из конфиг-файла: ```ini debug = etcp=trace,config=info,crypto=error ``` Категории: `none, uasync, ll_queue, connection, etcp, crypto, memory, timing, config, tun, routing, timers, normalizer, bgp, socket, control, dump, traffic, debug, general, nat, keepalive, etcp_route, bbr, etcp_dump, connectivity, all`. Уровни: `disabled, none, error, warn, info, debug, trace`. **Важно:** старый формат `ll_queue:debug` (двоеточие) тоже работает через `debug_parse_config`, но в конфиге рекомендуется `=`. ### 2.4. Двойной вывод (консоль + файл) - По умолчанию вывод в **stdout**. - `debug_enable_file_output(path, truncate)` — перенаправляет вывод в файл, консоль отключается. - `debug_disable_file_output()` — закрывает файл. - `debug_reopen_log()` — переоткрывает лог-файл (используется по SIGHUP для ротации). - `debug_enable_console(1/0)` — ручное управление консольным выводом. ### 2.5. Вспомогательные утилиты ```c log_dump(DEBUG_LEVEL_TRACE, DEBUG_CATEGORY_DUMP, "payload", data, len); // hex-дамп (до 128 байт) ip_str_t s = sockaddr_storage_to_str(&addr); // "192.168.1.1:8080" или "[::1]:443" ip_str_t s = ip_to_str(&addr, AF_INET); // "192.168.1.1" (без порта) ``` ### 2.6. Нюансы - **Потокобезопасность:** модуль не потокобезопасен. Несколько потоков, одновременно вызывающих макросы, могут перемешать вывод (но не упадут). Файловый вывод использует `fflush()` после каждой строки. - **Буфер:** размер строки лога ограничен 4096 байт (`BUFFER_SIZE`), длинные сообщения обрезаются. - **`debug_set_output_file`** против `debug_enable_file_output`: первая вызывается один раз (кто первый — того и тапки), вторая позволяет переоткрыть файл. - **Флаг `-f` (foreground):** в foreground-режиме вывод идёт в stdout, в daemon-режиме — в файл. ## 3. API | Функция/макрос | Назначение | |---|---| | `debug_config_init()` | Инициализация: глобальный уровень ERROR, консоль включена, метки времени/функций/файлов — да | | `debug_set_level(level)` | Задать глобальный уровень (ERROR..TRACE) | | `debug_set_category_level(cat, level)` | Задать уровень конкретной категории (0 = использовать глобальный) | | `debug_set_category_level_by_name("etcp", "trace")` | То же, но именами строк | | `debug_apply_category_config("etcp", "trace")` | Установить уровень категории с логированием результата | | `debug_apply_global_level("info")` | Установить глобальный уровень по имени строки | | `debug_parse_config("etcp=trace,config=info")` | Разобрать конфигурационную строку | | `debug_should_output(level, cat)` | Проверить, нужно ли выводить сообщение данного уровня/категории | | `debug_output(level, cat, func, file, line, fmt, ...)` | Форматировать и вывести сообщение (вызывается макросами) | | `debug_enable_file_output(path, truncate)` | Включить вывод в файл (консоль отключается) | | `debug_disable_file_output()` | Закрыть файл вывода | | `debug_reopen_log()` | Переоткрыть лог-файл (для SIGHUP/ротации) | | `debug_enable_console(1/0)` | Включить/выключить консольный вывод | | `debug_get_level()` | Получить текущий глобальный уровень | | `get_category_by_name("etcp")` | Получить ID категории по имени строки | | `debug_level_from_name("trace")` | Получить уровень по имени строки | | `debug_get_category_name(cat)` | Получить имя категории по ID | | `log_dump(level, cat, prefix, data, len)` | Hex-дамп данных (первые 128 байт) в лог | | `ip_to_str(addr, family)` | IP-адрес → строка (без порта). Статический буфер | | `sockaddr_storage_to_str(addr)` | sockaddr_storage → "ip:port" (IPv6 в скобках). Статический буфер | | `DEBUG_ERROR/WARN/INFO/DEBUG/TRACE(cat, fmt, ...)` | Макросы логирования с проверкой `debug_should_output()` | | `DEBUG_OUTPUT(fmt, ...)` | Устаревший макрос совместимости (ERROR, категория ALL) | **Глобальная переменная:** `g_debug_config` (тип `debug_config_t`) — хранит всё состояние системы логирования. **Структура `debug_config_t`:** - `level` — глобальный уровень (по умолчанию ERROR) - `category_levels[26]` — уровни по категориям (NONE = использовать глобальный, DISABLED = никогда не выводить) - `timestamp_enabled` / `function_name_enabled` / `file_line_enabled` — формат вывода - `file_output` — FILE* файла (NULL если вывод в консоль) - `console_enabled` — вывод в stdout - `thread_marker` — числовой маркер потока (0 = нет)