feat(cpp/core): logger + log_window + selectable_text widgets
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>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
---
|
||||
name: logger
|
||||
kind: function
|
||||
lang: cpp
|
||||
domain: core
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "bool fn_log::logger_init(const char* file_path, fn_log::Level min_level = Level::Info); void fn_log::logger_close(); void fn_log::logger_set_level(Level); fn_log::Level fn_log::logger_level(); const char* fn_log::logger_path(); void fn_log::log_debug(const char* fmt, ...); void fn_log::log_info(const char* fmt, ...); void fn_log::log_warn(const char* fmt, ...); void fn_log::log_error(const char* fmt, ...); std::size_t fn_log::buffer_size(); const fn_log::Entry* fn_log::buffer_at(std::size_t); void fn_log::buffer_clear(); const char* fn_log::level_label(fn_log::Level)"
|
||||
description: "Logger global thread-safe para apps C++ del registry. Escribe a archivo (cwd, junto al ejecutable) en modo append y mantiene un ring buffer in-memory de 2000 entradas que el visualizador log_window consume. Formato: [YYYY-MM-DD HH:MM:SS.mmm] [LEVEL] mensaje."
|
||||
tags: [logger, logging, file, infra, thread-safe]
|
||||
uses_functions: []
|
||||
uses_types: [log_level_cpp_core, log_entry_cpp_core]
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [chrono, cstdarg, cstdio, ctime, mutex, string]
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "cpp/functions/core/logger.cpp"
|
||||
framework: ""
|
||||
params:
|
||||
- name: file_path
|
||||
desc: "Ruta del archivo de log relativa al cwd (junto al ejecutable). Modo append. Si vacio o nullptr, no se escribe a disco — solo buffer in-memory"
|
||||
- name: min_level
|
||||
desc: "Nivel minimo a aceptar. Mensajes por debajo se descartan antes de tocar archivo o buffer"
|
||||
- name: fmt
|
||||
desc: "Formato printf-style de log_debug/info/warn/error. Cada llamada produce una linea independiente"
|
||||
- name: i
|
||||
desc: "Indice [0, buffer_size()) en el ring buffer. 0 = entrada mas antigua viva"
|
||||
output: "logger_init retorna true si pudo abrir el archivo (false → solo buffer). logger_close cierra archivo (idempotente). log_* mutan estado global thread-safe. buffer_at retorna puntero valido o nullptr si i fuera de rango"
|
||||
notes: "consumido por cpp/framework/app_base.cpp (init/close automatico via AppConfig.log) y cpp/functions/core/log_window.cpp (lectura del buffer)"
|
||||
---
|
||||
|
||||
# logger
|
||||
|
||||
Logger global, thread-safe, integrado en `fn::run_app`: las apps solo declaran un `AppLogConfig` y emiten con `log_info(...)` etc.
|
||||
|
||||
## Uso desde una app
|
||||
|
||||
```cpp
|
||||
#include "app_base.h"
|
||||
#include "core/logger.h"
|
||||
|
||||
int main() {
|
||||
return fn::run_app({
|
||||
.title = "Mi App",
|
||||
.log = {.file_path = "mi_app.log",
|
||||
.level = static_cast<int>(fn_log::Level::Info)}
|
||||
}, render);
|
||||
}
|
||||
```
|
||||
|
||||
Tras esto, `fn::run_app` llama `logger_init` antes del primer frame y `logger_close` al exit. La app solo necesita usar los emisores:
|
||||
|
||||
```cpp
|
||||
fn_log::log_info ("usuario abrio archivo %s", path);
|
||||
fn_log::log_warn ("retry %d/%d", attempt, max);
|
||||
fn_log::log_error("connection failed: %s", reason);
|
||||
fn_log::log_debug("estado interno: %d items", n);
|
||||
```
|
||||
|
||||
## Uso sin fn::run_app
|
||||
|
||||
Apps que arman su propio main loop deben llamar manualmente:
|
||||
|
||||
```cpp
|
||||
fn_log::logger_init("app.log", fn_log::Level::Info);
|
||||
// ... vida de la app ...
|
||||
fn_log::logger_close();
|
||||
```
|
||||
|
||||
## Reglas
|
||||
|
||||
- Ruta relativa al cwd (igual convencion que `app_settings.ini`).
|
||||
- Modo append: relanzar la app conserva el historico previo en disco.
|
||||
- Thread-safe: un mutex interno protege archivo + buffer + nivel.
|
||||
- Truncacion: cada mensaje cabe en `kEntryTextMax - 64` caracteres formateados; el resto se trunca silenciosamente.
|
||||
- Si `logger_init` no se llama o falla, los `log_*` siguen siendo seguros: solo escriben al ring buffer in-memory (que la ventana `Logs` puede mostrar igualmente).
|
||||
|
||||
## Integracion
|
||||
|
||||
- `fn::AppConfig::log` activa el logger desde el framework.
|
||||
- `fn_ui::log_window` lee el ring buffer y pinta la ventana "Logs..." del menubar.
|
||||
Reference in New Issue
Block a user