From 9e8c0d66bb2fc0e9a8bd722591efa2b7c941a824 Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Sat, 18 Apr 2026 17:14:29 +0200 Subject: [PATCH] feat: log_debug, log_info, log_warn, log_error (infra) Funciones de nivel que delegan al *slog.Logger interno del Logger. Todas son impuras y soportan logger nil sin panic (no-op). Los fields se pasan como pares key-value variadicos estilo slog. Co-Authored-By: Claude Opus 4.7 (1M context) --- functions/infra/log_debug.go | 11 +++++++++ functions/infra/log_debug.md | 41 +++++++++++++++++++++++++++++++++ functions/infra/log_error.go | 11 +++++++++ functions/infra/log_error.md | 44 ++++++++++++++++++++++++++++++++++++ functions/infra/log_info.go | 11 +++++++++ functions/infra/log_info.md | 41 +++++++++++++++++++++++++++++++++ functions/infra/log_warn.go | 11 +++++++++ functions/infra/log_warn.md | 41 +++++++++++++++++++++++++++++++++ 8 files changed, 211 insertions(+) create mode 100644 functions/infra/log_debug.go create mode 100644 functions/infra/log_debug.md create mode 100644 functions/infra/log_error.go create mode 100644 functions/infra/log_error.md create mode 100644 functions/infra/log_info.go create mode 100644 functions/infra/log_info.md create mode 100644 functions/infra/log_warn.go create mode 100644 functions/infra/log_warn.md diff --git a/functions/infra/log_debug.go b/functions/infra/log_debug.go new file mode 100644 index 00000000..8ea2d66b --- /dev/null +++ b/functions/infra/log_debug.go @@ -0,0 +1,11 @@ +package infra + +// LogDebug emite un log a nivel debug en el Logger. +// Los fields son pares key-value variadicos (ej: "port", 8484, "user", "lucas"). +// Si el nivel del logger es mayor que Debug, el mensaje se descarta. +func LogDebug(logger *Logger, msg string, fields ...any) { + if logger == nil || logger.inner == nil { + return + } + logger.inner.Debug(msg, fields...) +} diff --git a/functions/infra/log_debug.md b/functions/infra/log_debug.md new file mode 100644 index 00000000..e5c57bdd --- /dev/null +++ b/functions/infra/log_debug.md @@ -0,0 +1,41 @@ +--- +name: log_debug +kind: function +lang: go +domain: infra +version: "1.0.0" +purity: impure +signature: "func LogDebug(logger *Logger, msg string, fields ...any)" +description: "Emite un log a nivel debug en el Logger. Los fields son pares key-value variadicos. Si el nivel del logger es mayor que Debug, el mensaje se descarta silenciosamente." +tags: [logging, log, debug, slog, infra] +uses_functions: [] +uses_types: [Logger_go_infra] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: logger + desc: "Logger al que emitir el mensaje. Si es nil la funcion no hace nada" + - name: msg + desc: "mensaje principal del log" + - name: fields + desc: "pares key-value variadicos (ej: \"port\", 8484, \"user\", \"lucas\")" +output: "nada (side effect: escribe al Output del Logger)" +tested: true +tests: ["LogDebug emite nivel DEBUG", "campos inline en la llamada aparecen en el JSON", "logger nil no hace panic en las funciones de log"] +test_file_path: "functions/infra/logger_test.go" +file_path: "functions/infra/log_debug.go" +--- + +## Ejemplo + +```go +logger, _ := LoggerNew(LogLevelDebug, os.Stdout, "json") +LogDebug(logger, "parsing body", "content_type", "application/json", "size", 1024) +// {"time":"...","level":"DEBUG","msg":"parsing body","content_type":"application/json","size":1024} +``` + +## Notas + +Funcion impura — delega a `slog.Logger.Debug()`. El filtrado por nivel lo hace el handler de slog internamente (no se evalua el costo de los campos si el nivel esta debajo). Los fields deben venir en pares: si el numero es impar slog lo marca como `!BADKEY`. Usar este nivel para trazas detalladas de desarrollo que normalmente no se ven en produccion. diff --git a/functions/infra/log_error.go b/functions/infra/log_error.go new file mode 100644 index 00000000..d3331721 --- /dev/null +++ b/functions/infra/log_error.go @@ -0,0 +1,11 @@ +package infra + +// LogError emite un log a nivel error en el Logger. +// Los fields son pares key-value variadicos (ej: "err", err, "table", "users"). +// El nivel error siempre se emite (es el mas severo). +func LogError(logger *Logger, msg string, fields ...any) { + if logger == nil || logger.inner == nil { + return + } + logger.inner.Error(msg, fields...) +} diff --git a/functions/infra/log_error.md b/functions/infra/log_error.md new file mode 100644 index 00000000..50d3a5ee --- /dev/null +++ b/functions/infra/log_error.md @@ -0,0 +1,44 @@ +--- +name: log_error +kind: function +lang: go +domain: infra +version: "1.0.0" +purity: impure +signature: "func LogError(logger *Logger, msg string, fields ...any)" +description: "Emite un log a nivel error en el Logger. Los fields son pares key-value variadicos. Nivel maximo de severidad, siempre se emite salvo que el logger tenga un handler que lo filtre explicitamente." +tags: [logging, log, error, slog, infra] +uses_functions: [] +uses_types: [Logger_go_infra] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: logger + desc: "Logger al que emitir el mensaje. Si es nil la funcion no hace nada" + - name: msg + desc: "mensaje principal del log" + - name: fields + desc: "pares key-value variadicos (ej: \"err\", err.Error(), \"table\", \"users\", \"query\", sql)" +output: "nada (side effect: escribe al Output del Logger)" +tested: true +tests: ["LogError emite nivel ERROR", "logger nil no hace panic en las funciones de log"] +test_file_path: "functions/infra/logger_test.go" +file_path: "functions/infra/log_error.go" +--- + +## Ejemplo + +```go +logger, _ := LoggerNew(LogLevelInfo, os.Stdout, "json") +err := db.QueryRow(...).Scan(&x) +if err != nil { + LogError(logger, "db query failed", "err", err.Error(), "table", "users") +} +// {"time":"...","level":"ERROR","msg":"db query failed","err":"connection refused","table":"users"} +``` + +## Notas + +Funcion impura — delega a `slog.Logger.Error()`. Usar para fallos que requieren atencion: panics capturados, errores de I/O, estados invalidos. No aborta el programa por si solo — el caller decide que hacer. Para convertir un `error` en campo se recomienda usar `err.Error()` directamente, aunque slog tambien acepta el tipo `error` como valor (lo serializa con `.Error()` internamente). diff --git a/functions/infra/log_info.go b/functions/infra/log_info.go new file mode 100644 index 00000000..7243f7e0 --- /dev/null +++ b/functions/infra/log_info.go @@ -0,0 +1,11 @@ +package infra + +// LogInfo emite un log a nivel info en el Logger. +// Los fields son pares key-value variadicos (ej: "port", 8484, "user", "lucas"). +// Si el nivel del logger es mayor que Info, el mensaje se descarta. +func LogInfo(logger *Logger, msg string, fields ...any) { + if logger == nil || logger.inner == nil { + return + } + logger.inner.Info(msg, fields...) +} diff --git a/functions/infra/log_info.md b/functions/infra/log_info.md new file mode 100644 index 00000000..28a1f6c0 --- /dev/null +++ b/functions/infra/log_info.md @@ -0,0 +1,41 @@ +--- +name: log_info +kind: function +lang: go +domain: infra +version: "1.0.0" +purity: impure +signature: "func LogInfo(logger *Logger, msg string, fields ...any)" +description: "Emite un log a nivel info en el Logger. Los fields son pares key-value variadicos. Si el nivel del logger es mayor que Info, el mensaje se descarta silenciosamente." +tags: [logging, log, info, slog, infra] +uses_functions: [] +uses_types: [Logger_go_infra] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: logger + desc: "Logger al que emitir el mensaje. Si es nil la funcion no hace nada" + - name: msg + desc: "mensaje principal del log" + - name: fields + desc: "pares key-value variadicos (ej: \"port\", 8484, \"user\", \"lucas\")" +output: "nada (side effect: escribe al Output del Logger)" +tested: true +tests: ["LogInfo emite nivel INFO", "emite JSON valido al escribir", "campos inline en la llamada aparecen en el JSON"] +test_file_path: "functions/infra/logger_test.go" +file_path: "functions/infra/log_info.go" +--- + +## Ejemplo + +```go +logger, _ := LoggerNew(LogLevelInfo, os.Stdout, "json") +LogInfo(logger, "server starting", "port", 8484, "app", "sqlite_api") +// {"time":"...","level":"INFO","msg":"server starting","port":8484,"app":"sqlite_api"} +``` + +## Notas + +Funcion impura — delega a `slog.Logger.Info()`. Nivel por defecto recomendado para eventos normales del ciclo de vida de la app (arranque, conexiones establecidas, requests completadas). Para errores usar `LogError`, para situaciones anomalas no fatales usar `LogWarn`. diff --git a/functions/infra/log_warn.go b/functions/infra/log_warn.go new file mode 100644 index 00000000..2198a3fa --- /dev/null +++ b/functions/infra/log_warn.go @@ -0,0 +1,11 @@ +package infra + +// LogWarn emite un log a nivel warn en el Logger. +// Los fields son pares key-value variadicos (ej: "port", 8484, "user", "lucas"). +// Si el nivel del logger es mayor que Warn, el mensaje se descarta. +func LogWarn(logger *Logger, msg string, fields ...any) { + if logger == nil || logger.inner == nil { + return + } + logger.inner.Warn(msg, fields...) +} diff --git a/functions/infra/log_warn.md b/functions/infra/log_warn.md new file mode 100644 index 00000000..5c290b3d --- /dev/null +++ b/functions/infra/log_warn.md @@ -0,0 +1,41 @@ +--- +name: log_warn +kind: function +lang: go +domain: infra +version: "1.0.0" +purity: impure +signature: "func LogWarn(logger *Logger, msg string, fields ...any)" +description: "Emite un log a nivel warn en el Logger. Los fields son pares key-value variadicos. Indica situaciones anomalas que no impiden el funcionamiento del sistema." +tags: [logging, log, warn, slog, infra] +uses_functions: [] +uses_types: [Logger_go_infra] +returns: [] +returns_optional: false +error_type: "error_go_core" +imports: [] +params: + - name: logger + desc: "Logger al que emitir el mensaje. Si es nil la funcion no hace nada" + - name: msg + desc: "mensaje principal del log" + - name: fields + desc: "pares key-value variadicos (ej: \"retry_count\", 3, \"endpoint\", \"/api/users\")" +output: "nada (side effect: escribe al Output del Logger)" +tested: true +tests: ["LogWarn emite nivel WARN", "filtra mensajes debajo del nivel configurado"] +test_file_path: "functions/infra/logger_test.go" +file_path: "functions/infra/log_warn.go" +--- + +## Ejemplo + +```go +logger, _ := LoggerNew(LogLevelInfo, os.Stdout, "json") +LogWarn(logger, "retry attempt", "attempt", 2, "max", 5, "err", "timeout") +// {"time":"...","level":"WARN","msg":"retry attempt","attempt":2,"max":5,"err":"timeout"} +``` + +## Notas + +Funcion impura — delega a `slog.Logger.Warn()`. Usar para eventos recuperables: reintentos, fallos de cache, deprecaciones, datos inesperados pero no invalidos. Si el evento requiere intervencion humana usar `LogError`.