Um pacote de logging estruturado e flexível para Go que utiliza o padrão Adapter para permitir integração com diferentes bibliotecas de logging, com suporte completo a observabilidade e conformidade LGPD.
- Interface fluente com method chaining para construção de logs
- Logging estruturado com campos tipados
- Padrão Adapter para integração com diferentes bibliotecas de logging
- Níveis de log padrão (DEBUG, INFO, WARN, ERROR, FATAL)
- Propagação de contexto para rastreamento de requisições
- Campos pré-definidos por instância do logger
- Otimização de performance com verificação de nível habilitado
- Observabilidade integrada com Datadog e ELK Stack
- Middlewares HTTP para Gin, Fiber e Chi
- Integração com PostgreSQL via PGX
- Sanitização LGPD automática de dados sensíveis
- Correlation IDs automáticos para rastreamento
- Distributed tracing com Datadog
- Métricas automáticas e dashboards
- Adapter Zerolog incluído para uso imediato
go get github.com/victorximenis/loggerpackage main
import (
"context"
"github.com/victorximenis/logger"
)
func main() {
// Inicialização para produção (Datadog + ELK habilitados)
err := logger.InitWithProfile("production", "my-service")
if err != nil {
panic(err)
}
ctx := context.Background()
// Usar o logger global
logger.Info(ctx).
Str("user_id", "123").
Int("attempt", 1).
Msg("User login successful")
}package main
import (
"context"
"github.com/victorximenis/logger"
)
func main() {
// Configuração personalizada
config := logger.NewConfig()
config.ServiceName = "auth-service"
config.Environment = "production"
config.LogLevel = core.INFO
// Habilitar observabilidade
config.Observability.Enabled = true
config.Observability.EnableDatadog = true
config.Observability.EnableELK = true
config.Observability.EnableCorrelationID = true
err := logger.Init(config)
if err != nil {
panic(err)
}
ctx := context.Background()
logger.Info(ctx).Msg("Service started")
}package main
import (
"github.com/gin-gonic/gin"
"github.com/victorximenis/logger"
"github.com/victorximenis/logger/middlewares"
)
func main() {
logger.InitWithProfile("production", "api-service")
r := gin.New()
// Adicionar middleware de logging
r.Use(middlewares.GinLogger())
r.GET("/users/:id", func(c *gin.Context) {
// O contexto já contém correlation_id, request_id, etc.
logger.Info(c.Request.Context()).
Str("user_id", c.Param("id")).
Msg("User requested")
c.JSON(200, gin.H{"status": "ok"})
})
r.Run(":8080")
}package main
import (
"github.com/gofiber/fiber/v2"
"github.com/victorximenis/logger"
"github.com/victorximenis/logger/middlewares"
)
func main() {
logger.InitWithProfile("production", "api-service")
app := fiber.New()
// Adicionar middleware de logging
app.Use(middlewares.FiberLogger())
app.Get("/users/:id", func(c *fiber.Ctx) error {
// O contexto já contém correlation_id, request_id, etc.
logger.Info(c.Context()).
Str("user_id", c.Params("id")).
Msg("User requested")
return c.JSON(fiber.Map{"status": "ok"})
})
app.Listen(":8080")
}package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/victorximenis/logger"
"github.com/victorximenis/logger/middlewares"
)
func main() {
logger.InitWithProfile("production", "api-service")
r := chi.NewRouter()
// Adicionar middleware de logging
r.Use(middlewares.ChiLogger())
r.Get("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
// O contexto já contém correlation_id, request_id, etc.
logger.Info(r.Context()).
Str("user_id", chi.URLParam(r, "id")).
Msg("User requested")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "ok"}`))
})
http.ListenAndServe(":8080", r)
}package main
import (
"context"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/victorximenis/logger"
"github.com/victorximenis/logger/integrations"
)
func main() {
logger.InitWithProfile("production", "db-service")
// Configurar pool de conexões com logging
config, err := pgxpool.ParseConfig("postgres://user:pass@localhost/db")
if err != nil {
panic(err)
}
// Adicionar tracer de logging
config.ConnConfig.Tracer = integrations.NewPGXTracer()
pool, err := pgxpool.NewWithConfig(context.Background(), config)
if err != nil {
panic(err)
}
defer pool.Close()
// Todas as queries serão automaticamente logadas
rows, err := pool.Query(context.Background(), "SELECT id, name FROM users WHERE active = $1", true)
if err != nil {
logger.Error(context.Background()).Err(err).Msg("Query failed")
return
}
defer rows.Close()
logger.Info(context.Background()).Msg("Query executed successfully")
}package main
import (
"context"
"github.com/victorximenis/logger"
)
func main() {
logger.InitWithProfile("production", "user-service")
ctx := context.Background()
// Dados sensíveis são automaticamente sanitizados
logger.Info(ctx).
Str("email", "user@example.com"). // Será sanitizado: u***@e***.com
Str("cpf", "123.456.789-00"). // Será sanitizado: 123.***.***-**
Str("phone", "+55 11 99999-9999"). // Será sanitizado: +55 11 9****-****
Str("credit_card", "4111 1111 1111 1111"). // Será sanitizado: 4111 **** **** ****
Str("password", "mypassword"). // Será sanitizado: [REDACTED]
Msg("User data processed")
}package main
import (
"context"
"github.com/victorximenis/logger"
"github.com/victorximenis/logger/observability"
)
func main() {
logger.InitWithProfile("production", "order-service")
ctx := context.Background()
// Adicionar correlation ID manualmente
ctx = observability.ContextWithCorrelationID(ctx, "order-123")
// Iniciar span do Datadog
span := observability.StartSpan("process.order")
defer span.Finish()
ctx = observability.ContextWithSpan(ctx, span)
// Logs incluirão automaticamente trace_id, span_id, correlation_id
logger.Info(ctx).
Str("order_id", "123").
Float64("amount", 99.99).
Msg("Processing order")
// Registrar métricas
observability.IncrementCounter("orders.processed", []string{"status:success"})
observability.RecordDuration("orders.processing_time", span.Duration(), []string{"service:order"})
}# Habilitar observabilidade
LOGGER_OBSERVABILITY_ENABLED=true
OBSERVABILITY_ENABLED=true
OBSERVABILITY_DATADOG=true
OBSERVABILITY_ELK=true
OBSERVABILITY_CORRELATION_ID=true# Configurações básicas
DD_ENABLED=true
DD_SERVICE=my-service
DD_ENV=production
DD_VERSION=1.0.0
DD_AGENT_HOST=localhost:8126
# Tracing e métricas
DD_TRACING_ENABLED=true
DD_METRICS_ENABLED=true
DD_TRACE_SAMPLE_RATE=0.1
# Tags globais
DD_TAGS=team:backend,region:us-east-1# Configurações básicas
ELK_ENABLED=true
ELK_SERVICE=my-service
ELK_ENV=production
ELK_SERVICE_VERSION=1.0.0
# Elasticsearch
ELK_INDEX_PREFIX=logs
ELK_ECS_MAPPING=true
ELK_HOSTNAME=my-host
ELK_DATACENTER=us-east-1
# Campos personalizados
ELK_CUSTOM_FIELDS=team=backend,region=us-east-1// Configuração automática para produção
config := logger.NewProductionConfig("my-service")
// - LogLevel: INFO
// - PrettyPrint: false
// - CallerEnabled: false
// - Datadog: habilitado (sampling 10%)
// - ELK: habilitado (ECS mapping)
// - CorrelationID: habilitado// Configuração automática para desenvolvimento
config := logger.NewDevelopmentConfig("my-service")
// - LogLevel: DEBUG
// - PrettyPrint: true
// - CallerEnabled: true
// - Datadog: desabilitado
// - ELK: habilitado (formato simples)
// - CorrelationID: habilitado// Configuração automática para staging
config := logger.NewStagingConfig("my-service")
// - LogLevel: DEBUG
// - PrettyPrint: false
// - CallerEnabled: true
// - Datadog: habilitado
// - ELK: habilitado (ECS mapping)
// - CorrelationID: habilitadopackage main
import (
"os"
"github.com/victorximenis/logger"
"github.com/victorximenis/logger/adapters"
"github.com/victorximenis/logger/core"
)
func main() {
// Configuração avançada do Zerolog
config := &adapters.ZerologConfig{
Writer: os.Stdout,
Level: core.INFO,
TimeFormat: "", // Unix timestamp
PrettyPrint: false,
CallerEnabled: false,
}
// Criar adapter e logger
adapter := adapters.NewZerologAdapter(config)
log := logger.New(adapter)
// Logger com campos pré-definidos
serviceLogger := log.WithFields(map[string]interface{}{
"service": "auth",
"version": "1.0.0",
})
ctx := context.Background()
serviceLogger.Info(ctx).
Str("user_id", "123").
Int("attempt", 1).
Msg("User login successful")
}log.Info(ctx).
Str("string_field", "value"). // Campo string
Int("int_field", 42). // Campo inteiro
Float64("float_field", 3.14). // Campo float64
Bool("bool_field", true). // Campo booleano
Err(errors.New("example error")). // Campo de erro
Any("any_field", customStruct). // Campo de qualquer tipo
Fields(map[string]interface{}{ // Múltiplos campos
"key1": "value1",
"key2": "value2",
}).
Msg("Log with various field types")// Mensagem simples
log.Info(ctx).Msg("Simple message")
// Mensagem formatada
log.Info(ctx).Msgf("User %s has %d points", "John", 100)
// Apenas campos sem mensagem
log.Info(ctx).Str("event", "user_action").Send()O pacote suporta os seguintes níveis de log:
DEBUG: Informações detalhadas de depuraçãoINFO: Mensagens informativas geraisWARN: Situações que merecem atençãoERROR: Erros que não impedem a execuçãoFATAL: Erros críticos que impedem a execução
Interface que deve ser implementada por diferentes bibliotecas de logging:
type LoggerAdapter interface {
Log(ctx context.Context, level Level, msg string, fields map[string]interface{})
WithContext(ctx context.Context) LoggerAdapter
IsLevelEnabled(level Level) bool
}Interface pública para operações de logging:
type Logger interface {
Debug(ctx context.Context) LogEvent
Info(ctx context.Context) LogEvent
Warn(ctx context.Context) LogEvent
Error(ctx context.Context) LogEvent
Fatal(ctx context.Context) LogEvent
WithContext(ctx context.Context) Logger
WithFields(fields map[string]interface{}) Logger
}Interface para construção fluente de entradas de log:
type LogEvent interface {
Str(key, val string) LogEvent
Int(key string, val int) LogEvent
Float64(key string, val float64) LogEvent
Bool(key string, val bool) LogEvent
Err(err error) LogEvent
Any(key string, val interface{}) LogEvent
Fields(fields map[string]interface{}) LogEvent
Msg(msg string)
Msgf(format string, args ...interface{})
Send()
}- ZerologAdapter: Implementação completa usando zerolog
- DatadogLoggerAdapter: Wrapper para integração com Datadog
- ELKLoggerAdapter: Wrapper para integração com ELK Stack
- MultiObservabilityAdapter: Combina múltiplos adapters
- CorrelationIDAdapter: Adiciona correlation IDs automáticos
- GinLogger: Middleware para framework Gin
- FiberLogger: Middleware para framework Fiber
- ChiLogger: Middleware para framework Chi
- PGXTracer: Tracer para logging de queries PostgreSQL via PGX
- LGPDSanitizer: Sanitização automática de dados sensíveis conforme LGPD
- Datadog: Distributed tracing, métricas e dashboards
- ELK Stack: Logs estruturados com Elastic Common Schema (ECS)
- Correlation IDs: Rastreamento de requisições entre serviços
import "github.com/sirupsen/logrus"
type LogrusAdapter struct {
logger *logrus.Logger
}
func (l *LogrusAdapter) Log(ctx context.Context, level core.Level, msg string, fields map[string]interface{}) {
entry := l.logger.WithFields(logrus.Fields(fields))
switch level {
case core.DEBUG:
entry.Debug(msg)
case core.INFO:
entry.Info(msg)
case core.WARN:
entry.Warn(msg)
case core.ERROR:
entry.Error(msg)
case core.FATAL:
entry.Fatal(msg)
}
}import "go.uber.org/zap"
type ZapAdapter struct {
logger *zap.Logger
}
func (z *ZapAdapter) Log(ctx context.Context, level core.Level, msg string, fields map[string]interface{}) {
zapFields := make([]zap.Field, 0, len(fields))
for k, v := range fields {
zapFields = append(zapFields, zap.Any(k, v))
}
switch level {
case core.DEBUG:
z.logger.Debug(msg, zapFields...)
case core.INFO:
z.logger.Info(msg, zapFields...)
// ... outros níveis
}
}O sistema automaticamente envia métricas para Datadog:
logger.log_count: Contador de logs por nívellogger.error_count: Contador de erroshttp.request.duration: Duração de requisições HTTPhttp.request.count: Contador de requisições HTTPdb.query.duration: Duração de queries de bancodb.query.count: Contador de queries de banco
Logs são enviados para Elasticsearch seguindo o padrão ECS:
{
"@timestamp": "2024-01-15T10:30:00.000Z",
"ecs.version": "8.0",
"message": "User login successful",
"log.level": "info",
"service.name": "auth-service",
"service.version": "1.0.0",
"service.environment": "production",
"host.name": "api-server-01",
"user.id": "123",
"trace.id": "abc123",
"span.id": "def456",
"http.request.method": "POST",
"http.response.status_code": 200,
"event.duration": 150000000
}Execute os testes com:
go test ./...Para executar com cobertura:
go test ./... -coverPara executar exemplos:
go run examples/basic_usage.go
go run examples/middleware_example.go
go run examples/observability_example.gologger/
├── logger/
│ ├── core/ # Interfaces principais e tipos
│ │ ├── adapter.go # Interface LoggerAdapter
│ │ ├── event.go # Interface LogEvent
│ │ ├── level.go # Níveis de log
│ │ └── output.go # Gerenciamento de saída
│ ├── adapters/ # Implementações de adapters
│ │ └── zerolog.go # Adapter para zerolog
│ ├── middlewares/ # Middlewares HTTP
│ │ ├── gin.go # Middleware para Gin
│ │ ├── fiber.go # Middleware para Fiber
│ │ └── chi.go # Middleware para Chi
│ ├── integrations/ # Integrações com bancos de dados
│ │ └── pgx.go # Integração com PostgreSQL via PGX
│ ├── observability/ # Sistema de observabilidade
│ │ ├── adapter.go # Adapters de observabilidade
│ │ ├── datadog.go # Integração com Datadog
│ │ └── elk.go # Integração com ELK Stack
│ ├── sanitize/ # Sistema de sanitização LGPD
│ │ └── lgpd.go # Sanitizador LGPD
│ ├── config.go # Configuração do sistema
│ ├── logger.go # Interface Logger principal
│ └── doc.go # Documentação do pacote
├── examples/ # Exemplos de uso
│ ├── basic_usage.go
│ ├── middleware_example.go
│ └── observability_example.go
├── scripts/ # Scripts de configuração
├── tasks/ # Documentação de tarefas
├── go.mod
└── README.md
github.com/rs/zerolog- Biblioteca de logging principalgithub.com/google/uuid- Geração de UUIDs para correlation IDs
github.com/gin-gonic/gin- Framework web Gingithub.com/gofiber/fiber/v2- Framework web Fibergithub.com/go-chi/chi/v5- Framework web Chi
github.com/jackc/pgx/v5- Driver PostgreSQL
github.com/DataDog/datadog-go/v5/statsd- Cliente de métricas Datadoggopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer- Distributed tracing Datadog
gopkg.in/natefinch/lumberjack.v2- Rotação automática de arquivos de log
- Faça um fork do projeto
- Crie uma branch para sua feature (
git checkout -b feature/nova-feature) - Commit suas mudanças (
git commit -am 'Adiciona nova feature') - Push para a branch (
git push origin feature/nova-feature) - Abra um Pull Request
Este projeto está licenciado sob a licença MIT - veja o arquivo LICENSE para detalhes.