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_fn → on_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:
При запуске 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 или использовать панель отладки в Настройках, если она доступна.