merge: issue/0019-structured-logging — slog-based structured logging (7 fns, 3 tipos)

# Conflicts:
#	registry.db
This commit is contained in:
2026-04-18 17:33:18 +02:00
22 changed files with 935 additions and 0 deletions
+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.