feat: tipos Logger, LogLevel y LogEntry para structured logging (infra)

Tipos base para las funciones de structured logging sobre log/slog:
- LogLevel: suma enum Debug/Info/Warn/Error
- Logger: wrapper producto con nivel, output, formato y fields contextuales
- LogEntry: modelo canonico JSON para tests y pipelines de logs

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-18 17:14:19 +02:00
parent 95826cb14f
commit ab3069ae17
6 changed files with 145 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
package infra
import "time"
// LogEntry representa una entrada de log estructurada serializable a JSON.
// Se usa como modelo canonico para tests y para pipelines que procesan logs.
type LogEntry struct {
Timestamp time.Time `json:"timestamp"`
Level string `json:"level"`
Message string `json:"message"`
Fields map[string]any `json:"fields,omitempty"`
}
+16
View File
@@ -0,0 +1,16 @@
package infra
// LogLevel representa los niveles de log soportados por el Logger.
// El orden implicito es Debug < Info < Warn < Error.
type LogLevel int
const (
// LogLevelDebug es el nivel mas verbose, util para trazas de desarrollo.
LogLevelDebug LogLevel = iota
// LogLevelInfo es el nivel por defecto para eventos normales del sistema.
LogLevelInfo
// LogLevelWarn indica situaciones anomalas que no impiden el funcionamiento.
LogLevelWarn
// LogLevelError indica fallos que requieren atencion.
LogLevelError
)
+16
View File
@@ -0,0 +1,16 @@
package infra
import (
"io"
"log/slog"
)
// Logger wrappea slog.Logger con config del registry (nivel, output, formato, campos contextuales).
// Se crea con LoggerNew y se clona inmutablemente con LoggerWith anadiendo campos.
type Logger struct {
Level LogLevel // nivel minimo filtrado
Output io.Writer // destino de los logs (stdout, stderr, file, buffer)
Format string // "json" | "text"
Fields map[string]any // campos contextuales adjuntos al logger
inner *slog.Logger // handler real de slog
}
+35
View File
@@ -0,0 +1,35 @@
---
name: LogEntry
lang: go
domain: infra
version: "1.0.0"
algebraic: product
definition: |
type LogEntry struct {
Timestamp time.Time `json:"timestamp"`
Level string `json:"level"`
Message string `json:"message"`
Fields map[string]any `json:"fields,omitempty"`
}
description: "Entrada de log estructurada serializable a JSON. Modelo canonico para tests y pipelines de procesamiento de logs."
tags: [logging, log, entry, json, infra]
uses_types: []
file_path: "functions/infra/log_entry.go"
---
## Ejemplo
```go
entry := LogEntry{
Timestamp: time.Now(),
Level: "INFO",
Message: "server starting",
Fields: map[string]any{"port": 8484, "app": "api"},
}
data, _ := json.Marshal(entry)
// {"timestamp":"2026-04-18T10:00:00Z","level":"INFO","message":"server starting","fields":{"app":"api","port":8484}}
```
## Notas
Tipo producto — cuatro campos, todos exportados. El formato JSON de slog usa claves diferentes (`time`, `level`, `msg`) pero este tipo sirve como adaptador cuando se deserializan logs para tests o para pipelines downstream. `Fields` es opcional (omitempty) y permite adjuntar cualquier contexto key-value.
+32
View File
@@ -0,0 +1,32 @@
---
name: LogLevel
lang: go
domain: infra
version: "1.0.0"
algebraic: sum
definition: |
type LogLevel int
const (
LogLevelDebug LogLevel = iota
LogLevelInfo
LogLevelWarn
LogLevelError
)
description: "Nivel de log soportado por el Logger. Los valores ordenados de menor a mayor severidad son Debug, Info, Warn y Error."
tags: [logging, log, level, slog, infra]
uses_types: []
file_path: "functions/infra/log_level.go"
---
## Ejemplo
```go
logger, _ := LoggerNew(LogLevelInfo, os.Stdout, "json")
LogDebug(logger, "no se imprime") // filtrado porque Debug < Info
LogInfo(logger, "server up") // se imprime
```
## Notas
Tipo suma — los cuatro valores son exhaustivos y se corresponden uno a uno con los niveles de `log/slog` (slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, slog.LevelError). El orden de comparacion sigue la convencion clasica: cuanto mas alto, mas severo. Util para configurar filtrado en LoggerNew.
+34
View File
@@ -0,0 +1,34 @@
---
name: Logger
lang: go
domain: infra
version: "1.0.0"
algebraic: product
definition: |
type Logger struct {
Level LogLevel
Output io.Writer
Format string
Fields map[string]any
inner *slog.Logger
}
description: "Wrapper sobre slog.Logger con config del registry: nivel, destino (io.Writer), formato (json/text) y campos contextuales inmutables."
tags: [logging, log, slog, logger, infra]
uses_types: [LogLevel_go_infra]
file_path: "functions/infra/logger.go"
---
## Ejemplo
```go
logger, err := LoggerNew(LogLevelInfo, os.Stdout, "json")
if err != nil {
log.Fatal(err)
}
appLog := LoggerWith(logger, map[string]any{"app": "sqlite_api"})
LogInfo(appLog, "server starting", "port", 8484)
```
## Notas
Tipo producto — los campos publicos describen la config y los fields contextuales. El campo privado `inner` es la instancia real de `slog.Logger` que escribe. Se construye con `LoggerNew` (impuro) y se clona con `LoggerWith` (puro). Nunca se muta despues de creado.