Перейти к содержанию

App Debug Log

AppDebugLog — общий кольцевой буфер, принимающий строки журнала от всех трёх подсистем (C++, Rust, TypeScript) и эмитирующий их в виде Tauri-событий для встроенной консоли.

Исходники: src-tauri/src/torrent_stream/debug_log.rs, src-tauri/src/torrent_stream/debug_api.rs


Структура AppDebugLog

pub struct AppDebugLog {
    app: AppHandle,
    enabled: AtomicBool,
    lines: Mutex<VecDeque<DebugLine>>,
    max_lines: usize,           // 2500 (DEFAULT_MAX_LINES)
}

DebugLine

#[derive(Clone, Serialize)]
pub struct DebugLine {
    pub ts_ms: u64,             // Unix timestamp в миллисекундах
    pub category: String,       // "vozduxan" | "soulseek" | "stream" | …
    pub message: String,
    pub detail: Option<serde_json::Value>,  // опциональные структурированные данные
}

detail сериализуется в JSON и не включается в Tauri-событие если равен None (через skip_serializing_if).


Shared Arc — критическое соединение

AppDebugLog создаётся один раз в lib.rs и разделяется через Arc::clone между тремя Tauri-состояниями:

let debug_log = Arc::new(AppDebugLog::new(app.handle().clone()));
app.manage(VozduxanStreamState::new(&app, debug_log.clone()));
app.manage(TorrentImageState::new(&app, debug_log.clone()));
app.manage(TorrentStreamState::new(&app, debug_log.clone()));

Все три должны разделять один и тот же Arc. Отдельный Arc для любого из них направит его логи в другой кольцевой буфер и сделает их невидимыми в консоли (см. Обзор архитектуры — критический инвариант).

C++-логгер также подключён к этому же sink-у: VozduxanConfig.log_fn — это указатель на функцию, вызывающую on_vozduxan_log(), который вызывает AppDebugLog.push("vozduxan", …). Указатель log_userdata для C++ ссылается на Arc<AppDebugLog>, который удерживается VozduxanSessionInner._debug_log_arc.


push — всегда активен

pub fn push(&self, category: impl Into<String>, message: impl Into<String>, detail: Option<serde_json::Value>) {
    // ... строит DebugLine с текущей временной меткой ...
    {
        let mut q = self.lines.lock().unwrap();
        while q.len() >= self.max_lines { q.pop_front(); }
        q.push_back(line.clone());
    }
    let _ = self.app.emit("app-debug-line", &line);
}

is_enabled больше не блокирует запись. Каждый вызов журналирования всегда записывает в кольцевой буфер и эмитирует app-debug-line. Это гарантирует захват ошибок, даже если отладочное окно никогда не открывалось. set_enabled теперь управляет только тем, дублируется ли вывод в stderr (eprintln!) на некоторых путях — сохранено для миграции legacy-файла настроек.


Источники логов

Источник Как логи попадают в sink
C++ vozduxan VozduxanConfig.log_fnon_vozduxan_log()push("vozduxan", …)
Rust vozduxan_stream self.dlog(msg) / замыкание dlog в spawn_blocking
Rust torrent_image self.dlog(msg)
Rust soulseek session.slog(msg)push("soulseek", …)
TypeScript (фронтенд) appDebugLog(category, msg) → Tauri-команда app_debug_push

appDebugLog на фронтенде пакетирует вызовы в команду app_debug_push, которая вызывает push на общем логе. Так src/torrent/api.ts логирует события потока (см. Prefetch).

stderr всегда получает все логи от Rust и C++ (eprintln! / C++ stderr). Кольцевой буфер — дополнение к stderr, а не замена.


Tauri-команды

Команда Назначение
get_app_debug_enabled Возвращает is_enabled()
set_app_debug_enabled(enabled) Устанавливает флаг enabled + сохраняет в app_debug.json
get_app_debug_log Возвращает snapshot() — полный буфер от старейшей записи к новейшей
clear_app_debug_log Очищает буфер в памяти
app_debug_push(category, message, detail) Мост: фронтенд → кольцевой буфер

Хранение

enabled сохраняется в {exe_dir}/app_debug.json:

{ "enabled": true }

При запуске apply_app_debug_from_disk читает этот файл и вызывает set_enabled. Legacy-путь (streaming_debug.json в app_data_dir) считывается как запасной вариант для однократной миграции.


Встроенная консоль

AppDebugConsole.vue отображает кольцевой буфер. Она подписывается на Tauri-события app-debug-line для дополнения строк в реальном времени без polling-а. Консоль показывается в AppDebugWindow.vue, который монтируется при открытии окна с URL ?app-debug.

В dev-сборках App.vue открывает отладочное окно автоматически. В production нет UI для его открытия — необходимо явно перейти по URL ?app-debug или использовать панель отладки в Настройках, если она доступна.