Logging em Go: melhores práticas para iniciantes

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Logging em aplicações Go: melhores práticas para iniciantes



Logging não é apenas registrar mensagens no console. Em produção, os logs ajudam a rastrear erros, analisar desempenho e entender o comportamento do sistema. Neste artigo, abordaremos as melhores práticas de logging em Go (Golang) para iniciantes: desde a biblioteca padrão até abordagens estruturadas modernas.



Por que o logging é importante em Go?



Go é uma linguagem para criar aplicações server-side de alta carga. Sem um logging de qualidade, você não conseguirá:

  • Localizar rapidamente bugs em ambiente de produção
  • Entender a sequência de eventos durante uma falha
  • Realizar auditoria de segurança
  • Otimizar o desempenho


Um bom logging deve ser: estruturado, por nível (debug, info, warn, error), contextual (conter ID da requisição, nome da função) e gerenciável (rotação, saída para arquivo).



1. Começando com a biblioteca padrão log



Go fornece o pacote embutido log — simples e suficiente para projetos pequenos. Veja como ele funciona:



package main

import ( "log" "os")

func main() { // Configuração básica: saída para stderr log.SetOutput(os.Stderr) log.SetPrefix("INFO: ") log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

log.Println("Aplicação iniciada") log.Printf("Usuário %s autenticado", "admin") log.Fatal("Erro crítico") // encerra o programa com código 1}


Principais recursos do log:

  • log.Println() — saída de string
  • log.Printf() — saída formatada
  • log.Fatal() — saída + encerramento do programa
  • log.Panic() — saída + pânico


Mas o logger padrão tem desvantagens: não possui níveis (debug, info, error), não tem saída estruturada (JSON), nem rotação de arquivos.



2. Adicionando níveis de logging



Para aplicações em produção, é crucial separar os logs por níveis. Aqui está uma implementação mínima usando o pacote padrão:



package main

import ( "log" "os")

type Logger struct { debug *log.Logger info *log.Logger warn *log.Logger error *log.Logger}

func NewLogger() *Logger { flags := log.Ldate | log.Ltime | log.Lshortfile return &Logger{ debug: log.New(os.Stdout, "DEBUG: ", flags), info: log.New(os.Stdout, "INFO: ", flags), warn: log.New(os.Stderr, "WARN: ", flags), error: log.New(os.Stderr, "ERROR: ", flags), }}

func (l *Logger) Debug(msg string, args ...interface{}) { l.debug.Printf(msg, args...)}

func (l *Logger) Info(msg string, args ...interface{}) { l.info.Printf(msg, args...)}

func (l *Logger) Error(msg string, args ...interface{}) { l.error.Printf(msg, args...)}

func main() { log := NewLogger() log.Info("Servidor iniciado na porta %d", 8080) log.Debug("Requisição de %s", "192.168.1.1") log.Error("Falha ao conectar ao BD: %v", "timeout")}


Dica: Em produção, use os.Stderr para erros e os.Stdout para logs normais — isso simplifica a coleta de logs via systemd ou Docker.



3. Logging estruturado (JSON)



Em sistemas modernos, os logs são frequentemente coletados em armazenamentos centralizados (Elasticsearch, Loki). Para isso, é necessária uma saída estruturada, por exemplo em JSON. Bibliotecas populares:

  • logrus — flexível, com suporte a formatadores
  • zap — ultrarrápido, da Uber
  • zerolog — leve e rápido


Exemplo com logrus:



package main

import ( "os" "gi

Blogs

Book Recommendations