Lançado recentemente, o Go 1.21 trouxe um novo package padrão na linguagem, o log/slog
. Embora Go tenha um package de logs desde seu lançamento, ao longo dos anos, ficou claro que as aplicações Go precisavam de logs estruturados.
Diferente do formato padrão em texto puro, logs estruturados utilizam o formato chave=valor
, facilitando muito na hora de fazer parse, buscar e analisar os logs.
Embora existam vários packages open source que desempenham esse papel, sendo o logrus um dos mais famosos, todos os anos, a comunidade continuava pedindo ao time do Go que essa funcionalidade fosse adicionada ao package oficial da linguagem.
Nesse post, vou explorar um pouco desse package, mostrando as principais funções e formas de utilização.
Logger padrão
Assim como o package log
, o package log/slog
vem com um logger padrão.
logger := slog.Default() logger.Info("servidor iniciado com sucesso") logger.Warn("variável com valor vazio", "var", "teste") logger.Debug("usuário logado com sucesso", "user", os.Getenv("USER")) logger.Error("falha ao tentar executar servidor")
No entanto, para facilitar ainda mais, o package log/slog
também conta com algumas funções auxiliares que, internamente, utilizam o logger padrão.
slog.Info("servidor iniciado com sucesso") slog.Warn("variável com valor vazio", "var", "teste") slog.Debug("usuário logado com sucesso", "user", os.Getenv("USER")) slog.Error("falha ao tentar executar servidor")
Em outras palavras, você não precisa recuperar a instância do logger padrão para utilizar seus métodos, as funções auxiliares farão isso por você.
Embora eu tenha colocado no exemplo a função Warn, como o level do log padrão é Info, os logs que utilizam esse método não serão exibidos.
Para que ele “funcione”, é preciso criar um novo logger configurando o level como Debug.
Abaixo mostro como fazer.
Level Debug
Como eu disse acima, o logger padrão do package log/slog
vem configurado para exibir logs com level Info. Em outras palavras, ele exibirá somente logs do tipo INFO, WARNING, ERROR.
Para que os logs do tipo DEBUG sejam exibidos, precisamos criar um logger customizado definindo esse level.
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ Level: slog.LevelDebug, })) logger.Debug("usuário logado com sucesso", "user", os.Getenv("USER"))
Função WithGroup
Caso você queira adicionar um prefixo aos valores do log, a função WithGroup
é o que você procura.
Por exemplo, imagine que você queira adicionar o nome do package de onde o log foi originado.
logger := slog.Default().WithGroup("user") logger.Info("logado com sucesso", "id", u.ID, "username", u.Username)
Como passamos o valor user como nome do grupo, a saída do log seria assim:
2023/09/04 08:07:24 INFO logado com sucesso user.id=1 user.username=tiago
Logger em JSON
Não tem como falar em log estruturado sem falar em logs no formato JSON.
Para que o logger construa os logs em formato JSON, precisamos iniciar um novo logger, configurando seu handler com o JSONHandler
.
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
A chamada dos métodos continua sendo a mesma do primeiro exemplo, no entanto, o output do log será em formato JSON.
{"time":"2023-09-04T08:07:24.048433-03:00","level":"INFO","msg":"servidor iniciado com sucesso","port":"8080"}
Definindo logger padrão
Uma funcionalidade que gostei muito desse novo package, é a função SetDefault
. Com ela, podemos customizar um novo logger e depois utilizá-lo como o logger padrão do package.
logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ Level: slog.LevelDebug, })) slog.SetDefault(logger)
Agora, ao chamar as funções auxiliares do package log/slog
, o logger utilizado internamente será o que configuramos.
slog.Info("servidor iniciado com sucesso", "port", os.Getenv("SERVER_PORT")) slog.Debug("usuário logado com sucesso", "user", os.Getenv("USER")) slog.Error("falha ao tentar iniciar servidor")
Dessa forma, podemos configurar um logger na função main
da aplicação e, sem necessidade de injections, facilmente utilizá-lo em qualquer lugar.
Conclusão
Depois de brincar um pouco com log/slog
, não restam dúvidas do quão poderoso e fácil de usar é esse novo package.
Embora ainda não seja possível mudar o level dos logs facilmente, gostei e recomendo muito a utilização do package log/slog
.
Se você quiser ver um benchmark entre o log/slog
e algum outro package de logs, deixe nos comentários o nome do package que em breve farei um post.
Não deixe de se inscrever na nossa newsletter para receber os novos posts e promoções.
Até a próxima.