Saiba como iniciar sessão no Go
Os logs desempenham um papel significativo em um programa porque eles se tornam uma fonte de informações que você pode verificar quando algo dá errado. Normalmente, quando um erro acontece, os usuários finais apenas veem uma mensagem que indica um problema com o programa. Do ponto de vista de um desenvolvedor, precisamos de mais informações do que uma simples mensagem de erro. Isso ocorre principalmente porque queremos reproduzir o problema para escrever uma correção adequada. Neste módulo, você aprenderá como o registro em log funciona no Go. Você também aprenderá algumas práticas que você deve sempre implementar.
o pacote log
Para começar, o Go oferece um pacote padrão simples para trabalhar com logs. Você pode usá-lo de uma maneira que é como você usa o fmt
pacote. O pacote padrão não fornece níveis de log e não permite configurar registradores separados para cada pacote. Se você precisar escrever configurações de log mais complexas, poderá fazê-lo usando uma estrutura de log. Abordaremos as estruturas de registro mais tarde.
Aqui está a maneira mais fácil de usar logs:
import (
"log"
)
func main() {
log.Print("Hey, I'm a log!")
}
Quando você executa o código anterior, você obtém esta saída:
2020/12/19 13:39:17 Hey, I'm a log!
Por padrão, a log.Print()
função inclui a data e a hora como o prefixo da mensagem de log. Você pode obter o mesmo comportamento usando fmt.Print()
o , mas pode fazer outras coisas com o log
pacote, como enviar logs para um arquivo. Veremos mais log
informações sobre a funcionalidade do pacote mais tarde.
Você pode usar a log.Fatal()
função para registrar um erro e terminar o programa como se tivesse usado os.Exit(1)
o . Para experimentar, vamos usar este trecho de código:
package main
import (
"fmt"
"log"
)
func main() {
log.Fatal("Hey, I'm an error log!")
fmt.Print("Can you see me?")
}
Quando você executa o código anterior, você obtém esta saída:
2020/12/19 13:53:19 Hey, I'm an error log!
exit status 1
Observe como a última linha, fmt.Print("Can you see me?")
, não é executada. Isso porque a chamada de log.Fatal()
função interrompe o programa. Você obtém um comportamento semelhante quando usa a log.Panic()
função, que também chama a panic()
função, assim:
package main
import (
"fmt"
"log"
)
func main() {
log.Panic("Hey, I'm an error log!")
fmt.Print("Can you see me?")
}
Quando você executa o código anterior, você obtém esta saída:
2020/12/19 13:53:19 Hey, I'm an error log!
panic: Hey, I'm an error log!
goroutine 1 [running]:
log.Panic(0xc000060f58, 0x1, 0x1)
/usr/local/Cellar/go/1.15.5/libexec/src/log/log.go:351 +0xae
main.main()
/Users/christian/go/src/helloworld/logs.go:9 +0x65
exit status 2
Você ainda está recebendo a mensagem de log, mas agora você também recebe o rastreamento da pilha de erros.
Outra função essencial é log.SetPrefix()
. Você pode usá-lo para adicionar um prefixo às mensagens de log do seu programa. Por exemplo, você pode usar este trecho de código:
package main
import (
"log"
)
func main() {
log.SetPrefix("main(): ")
log.Print("Hey, I'm a log!")
log.Fatal("Hey, I'm an error log!")
}
Quando você executa o código anterior, você obtém esta saída:
main(): 2021/01/05 13:59:58 Hey, I'm a log!
main(): 2021/01/05 13:59:58 Hey, I'm an error log!
exit status 1
Você define o prefixo uma vez e seus logs incluirão informações como o nome da função da qual o log veio.
Você pode explorar outras funções no site Go.
Registrando em um arquivo
Além de imprimir logs para o console, você pode querer enviar logs para um arquivo para que possa processá-los mais tarde ou em tempo real.
Por que você gostaria de enviar logs para um arquivo? Primeiro, talvez você queira ocultar informações específicas de seus usuários finais. Eles podem não estar interessados ou você pode estar expondo informações confidenciais. Quando você tiver arquivos de login, poderá centralizar todos os logs em um único local e correlacioná-los com outros eventos. Este padrão é típico: ter aplicações distribuídas que podem ser efémeras, como contentores.
Vamos usar o código a seguir para testar o envio de logs para um arquivo:
package main
import (
"log"
"os"
)
func main() {
file, err := os.OpenFile("info.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
log.SetOutput(file)
log.Print("Hey, I'm a log!")
}
Quando você executa o código anterior, não vê nada no console. No diretório, você verá um novo arquivo chamado info.log que contém os logs enviados usando a log.Print()
função. Observe que você precisa começar criando ou abrindo um arquivo e, em seguida, configurando o log
pacote para enviar toda a saída para um arquivo. Em seguida, você pode continuar usando a log.Print()
função como faria normalmente.
Arquiteturas de registo
Finalmente, pode haver momentos em que as log
funções do pacote não sejam suficientes. Você pode achar útil usar uma estrutura de registro em log em vez de escrever suas próprias bibliotecas. Algumas estruturas de log para Go são Logrus, zerolog, zap e Apex.
Vamos explorar o que podemos fazer com zerolog.
Primeiro, você precisa instalar o pacote. Se você tem trabalhado nesta série, você provavelmente já está usando módulos Go, então você não precisa fazer nada. Apenas no caso, você pode executar este comando em sua estação de trabalho para instalar as bibliotecas zerolog:
go get -u github.com/rs/zerolog/log
Agora, use este trecho de código para experimentar:
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Print("Hey! I'm a log message!")
}
Quando você executa o código anterior, você obtém esta saída:
{"level":"debug","time":1609855453,"message":"Hey! I'm a log message!"}
Observe como você só precisa incluir os nomes de importação corretos e, em seguida, você pode continuar usando a log.Print()
função como normalmente faz. Além disso, observe como a saída muda para o formato JSON. JSON é um formato útil para logs quando você executa pesquisas em um local centralizado.
Outro recurso útil é que você pode incluir dados de contexto rapidamente, como este:
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Debug().
Int("EmployeeID", 1001).
Msg("Getting employee information")
log.Debug().
Str("Name", "John").
Send()
}
Quando você executa o código anterior, você obtém esta saída:
{"level":"debug","EmployeeID":1001,"time":1609855731,"message":"Getting employee information"}
{"level":"debug","Name":"John","time":1609855731}
Observe como adicionamos como contexto o ID do funcionário. Torna-se parte do logline como outra propriedade. Além disso, é importante destacar que os campos incluídos são fortemente digitados.
Você pode implementar outros recursos com zerolog, como usar log nivelado, usar rastreamentos de pilha formatados e usar mais de uma instância de logger para gerenciar saídas diferentes. Para obter mais informações, consulte o site do GitHub.