Cómo crear un sistema de logs en Go
Clase 27 de 30 • Curso de Ciberseguridad para Desarrollo Web
Contenido del curso
Funciona en mi local
Introducción a DevSecOps
Seguridad en la arquitectura
- 11

Arquitectura AWS para métricas de Git
02:24 min - 12

Configuración de AWS CLI para Terraform
09:34 min - 13

Terraform IAM: roles y policies automáticos
17:44 min - 14

Modificando main.tf para enlazar módulos IAM en Terraform
06:02 min - 15

Bucket S3 para Lambdas con Terraform
16:44 min - 16

Configuración de Postgres RDS con VPC y seguridad
14:10 min - 17

Configurando VPC para AWS Lambda con Terraform
12:29 min - 18

Cómo configurar API Gateway para Lambdas
05:42 min
Evitando vulnerabilidades en el código
- 19

Configuración completa de Auth0 para tokens
07:14 min - 20

Authorizer Lambda con Auth0 y JWT
16:56 min - 21

Conecta Go a Postgres usando AWS Secrets
13:35 min - 22

Conexión segura de Lambdas a Secrets con VPC
11:27 min - 23

Validación de webhooks desde GitHub con user-agent
12:08 min - 24

Cómo validar integridad de webhooks con HMAC
14:32 min
Controles de seguridad sobre datos
Monitoring y alertas
CORS y cierre
Crear logs útiles no es opcional: es la base de la observabilidad. Con un sistema de logs consistente en Go, podrás medir con precisión en CloudWatch (y herramientas como New Relic, Datadog o Kibana) lo que de verdad importa. Aquí verás cómo estructurar niveles de log, mensajes claros y atributos ricos en JSON para monitorear tu servicio con confianza.
¿Por qué crear un sistema de logs escalable en Go?
Los logs permiten saber qué sucede en el sistema y, sobre todo, medir. Porque lo que no se loguea no se puede medir. El objetivo: logs consistentes, claros, encontrables y accionables.
- Consistentes: mismo formato y campos en todos los servicios.
- Claros: sin ambigüedad en el mensaje.
- Encontrables: con event name estable y service name explícito.
- Accionables: suficientes datos en attributes para tomar decisiones.
Este enfoque facilita filtrar y analizar en plataformas como CloudWatch.
¿Cómo estructurar el logger con niveles y JSON?
Se crea una carpeta Logger con un paquete logger que expone una estructura Logger, un constructor y métodos por nivel de log. El mensaje se serializa a JSON para que sea encontrable y filtrable en diferentes plataformas.
¿Qué niveles de log usar?
Se define un "enum" (constantes de tipo string) llamado LogLevel con: fatal, error, warning e info. Cada nivel sirve para comunicar gravedad y guiar acciones.
package logger
import (
"context"
"encoding/json"
"fmt"
)
type LogLevel string
const (
LevelFatal LogLevel = "fatal"
LevelError LogLevel = "error"
LevelWarning LogLevel = "warning"
LevelInfo LogLevel = "info"
)
type Logger struct {
serviceName string
}
func NewLogger(serviceName string) *Logger {
return &Logger{serviceName: serviceName}
}
func (l *Logger) log(ctx context.Context, event string, level LogLevel, attrs map[string]interface{}) {
out := map[string]interface{}{
"event": event,
"level": level,
"service": l.serviceName,
"properties": attrs,
}
b, _ := json.Marshal(out)
fmt.Println(string(b))
}
func (l *Logger) Info(ctx context.Context, event string, attrs map[string]interface{}) {
l.log(ctx, event, LevelInfo, attrs)
}
func (l *Logger) Warning(ctx context.Context, event string, attrs map[string]interface{}) {
l.log(ctx, event, LevelWarning, attrs)
}
func (l *Logger) Error(ctx context.Context, event string, err error, attrs map[string]interface{}) {
if attrs == nil {
attrs = map[string]interface{}{}
}
attrs["error"] = err.Error()
l.log(ctx, event, LevelError, attrs)
}
func (l *Logger) Fatal(ctx context.Context, event string, attrs map[string]interface{}) {
l.log(ctx, event, LevelFatal, attrs)
}
- Logger: incluye el service name para identificar el origen del log.
- log: método base que imprime un objeto JSON con
event,level,serviceyproperties. - Info/Warning/Error/Fatal: métodos convenientes que estandarizan el
level. En Error, el error se añade aattributes.
¿Cómo definir el event name y los atributos?
- Usa un event name estable y buscable: no pongas el detalle dinámico del error ahí.
- Enriquécelo con attributes: datos clave como
head_commitpara contexto. - Beneficio: rápido filtrado y métricas confiables por evento.
¿Cómo integrarlo en una Lambda y monitorear en CloudWatch?
Se inicializa el logger al inicio de la lambda handleGitHubWebhook con su service name. Luego se reemplazan los fmt.Print por logger.Info usando un event name estándar y un mapa de attributes.
// Dentro de la Lambda handleGitHubWebhook
log := logger.NewLogger("handleGitHubWebhook")
attrs := map[string]interface{}{
"head_commit": /* dato del evento */ nil,
}
log.Info(ctx, "validGitHubWebhookReceived", attrs)
log.Info(ctx, "commitCreated", attrs)
- validGitHubWebhookReceived: permite medir cuántos webhooks válidos llegan.
- commitCreated: confirma la creación del commit y su traza asociada.
¿Cómo desplegar y verificar en CloudWatch?
- Publica el artefacto en S3:
make publish. - Revisa el plan:
terraform plan. - Aplica cambios:
terraform applyy confirma conyes. - Genera tráfico: git commit, push y usa “redeliver” en el webhook de GitHub.
- Observa en AWS Lambda > Monitor > CloudWatch > log stream: verás logs con
event,level,propertiesyserviceen formato JSON legible.
¿Qué habilidades y keywords refuerzas?
- Diseño de observabilidad con logs consistentes y accionables.
- Modelado de LogLevel y mensajes en JSON.
- Uso de event name estable y attributes enriquecidos.
- Implementación de Logger reutilizable en Go con
NewLoggery métodosInfo/Warning/Error/Fatal. - Integración en AWS Lambda y lectura en CloudWatch.
- Despliegue con Terraform y prueba con GitHub Webhook y “redeliver”.
¿Te gustaría comentar cómo nombrarías tus eventos y qué atributos añadirías para mejorar la observabilidad de tu servicio?