f1a5e04d4f
Logger global thread-safe con ring buffer in-memory de 2000 entradas + escritura opcional a archivo. log_window flotante consume el ring buffer con filtros por nivel, busqueda y autoscroll; se abre desde Settings -> Logs en la menubar. selectable_text cubre el patron drag-to-select + Ctrl+C en cualquier ventana. app_menubar y framework run_app integran log_window_render() en el frame loop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
82 lines
2.8 KiB
C++
82 lines
2.8 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
|
|
// Logger global thread-safe para apps del registry. Escribe a archivo (cwd
|
|
// junto al ejecutable, igual que app_settings.ini) y mantiene un ring buffer
|
|
// in-memory que el visualizador (log_window) consume.
|
|
//
|
|
// Lifecycle:
|
|
// - run_app llama logger_init(cfg.log_file, cfg.log_level) si log_file != nullptr
|
|
// - app llama log_info / log_warn / ... durante su ciclo de vida
|
|
// - run_app llama logger_close() al exit
|
|
//
|
|
// Apps que NO usan fn::run_app deben llamar logger_init/close manualmente.
|
|
// Si nunca se llama logger_init, los log_* siguen funcionando contra el ring
|
|
// buffer in-memory pero no escriben a disco.
|
|
//
|
|
// Formato de cada linea:
|
|
// [YYYY-MM-DD HH:MM:SS.mmm] [LEVEL] mensaje
|
|
namespace fn_log {
|
|
|
|
enum class Level : int {
|
|
Debug = 0,
|
|
Info = 1,
|
|
Warn = 2,
|
|
Error = 3,
|
|
};
|
|
|
|
// Inicializa el logger global. file_path se interpreta relativo al cwd
|
|
// (donde la app ya escribe app_settings.ini). Crea/trunca el archivo si no
|
|
// existe; si existe, abre en modo append.
|
|
//
|
|
// Idempotente: si ya hay un archivo abierto, lo cierra y reabre el nuevo.
|
|
// Returns true si pudo abrir el archivo (false → solo buffer in-memory).
|
|
bool logger_init(const char* file_path, Level min_level = Level::Info);
|
|
|
|
// Cierra el archivo. log_* siguen funcionando contra el buffer in-memory.
|
|
void logger_close();
|
|
|
|
// Nivel minimo. Mensajes por debajo se descartan silenciosamente (no van ni
|
|
// al archivo ni al buffer).
|
|
void logger_set_level(Level level);
|
|
Level logger_level();
|
|
|
|
// Path del archivo activo. Vacio si no inicializado o cerrado.
|
|
const char* logger_path();
|
|
|
|
// Emisores. Formato printf-style. Cada llamada escribe una linea completa.
|
|
// Thread-safe (mutex interno).
|
|
void log_debug(const char* fmt, ...);
|
|
void log_info (const char* fmt, ...);
|
|
void log_warn (const char* fmt, ...);
|
|
void log_error(const char* fmt, ...);
|
|
|
|
// === Ring buffer in-memory (para log_window) ===
|
|
|
|
constexpr std::size_t kBufferCapacity = 2000;
|
|
constexpr std::size_t kEntryTextMax = 480; // deja sitio para timestamp + level
|
|
|
|
struct Entry {
|
|
Level level;
|
|
long long ts_ms; // unix epoch en milisegundos
|
|
char text[kEntryTextMax];
|
|
};
|
|
|
|
// Numero de entradas vivas en el buffer (≤ kBufferCapacity).
|
|
std::size_t buffer_size();
|
|
|
|
// Acceso por indice [0, buffer_size()). i==0 es la entrada mas antigua viva.
|
|
// Nullptr si i fuera de rango. Snapshot — el caller debe asumir que la
|
|
// entrada puede ser sobrescrita en la siguiente llamada thread-unsafe; para
|
|
// el viewer esto no es problema porque ImGui es single-threaded.
|
|
const Entry* buffer_at(std::size_t i);
|
|
|
|
// Limpia el ring buffer. No toca el archivo en disco.
|
|
void buffer_clear();
|
|
|
|
// Helper para el viewer: nombre corto del nivel ("DEBUG"/"INFO"/...).
|
|
const char* level_label(Level level);
|
|
|
|
} // namespace fn_log
|