38/100 Dias de Golang - Logging
Table of Contents
#
Logging
Outro biblioteca padrão da linguagem Go! Muito simples de usar e cobre a maior parte dos casos de uso comuns — sem precisar instalar nada! Vamos ver o nosso primeiro log
package main
import (
"log"
)
func main() {
log.Println("Olá, mundo!")
}
Veja que a saída é automaticamente formatada com o timestamp atual
2025/04/19 15:36:27 Olá, mundo!
Uma funcionalidade muito legal que eu encontrei é o log para no caso de um erro. A função log.Fatal
imprime a mensagem e depois chama os.Exit(1) — ou seja, o programa termina imediatamente
if err != nil {
log.Fatal("Algo deu errado:", err)
}
Podemos fazer várias customizações no formato do log
log.SetPrefix("[meuapp] ")
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.Println("Rodando...")
[meuapp] 2025/04/19 15:56:27 main.go:10: Rodando...
Vamos ver um exemplo de como imprimir o log em um arquivo. Veja como é simples, criamos um arquivo nesse caso o app.log
. E quando criarmos o log com a função New
passamos esse arquivo, e depois é tudo igual. A função log.New
cria um novo logger personalizado.
package main
import (
"log"
"os"
)
func main() {
file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatal("Erro ao abrir arquivo de log:", err)
}
defer file.Close()
logger := log.New(file, "[APP] ", log.LstdFlags|log.Lshortfile)
logger.Println("Aplicação iniciada")
}
Uma das grandes vantagens da biblioteca padrão log em Go é que todos os métodos do tipo *log.Logger
são seguros para uso simultâneo por múltiplas goroutines.
Isso significa que você pode chamar logger.Println
, de várias goroutines ao mesmo tempo sem precisar de mutexes ou canais para sincronização.
Veja esse exemplo:
package main
import (
"log"
"os"
"sync"
)
func main() {
logger := log.New(os.Stdout, "[LOG] ", log.LstdFlags|log.Lmicroseconds)
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for j := 0; j < 3; j++ {
logger.Printf("Goroutine %d - Mensagem %d", id, j)
}
}(i)
}
wg.Wait()
}
[LOG] 2025/04/19 23:46:42.831649 Goroutine 4 - Mensagem 0
[LOG] 2025/04/19 23:46:42.831831 Goroutine 4 - Mensagem 1
[LOG] 2025/04/19 23:46:42.831837 Goroutine 4 - Mensagem 2
[LOG] 2025/04/19 23:46:42.831683 Goroutine 1 - Mensagem 0
[LOG] 2025/04/19 23:46:42.831849 Goroutine 1 - Mensagem 1
[LOG] 2025/04/19 23:46:42.831852 Goroutine 1 - Mensagem 2
[LOG] 2025/04/19 23:46:42.831697 Goroutine 0 - Mensagem 0
[LOG] 2025/04/19 23:46:42.831860 Goroutine 0 - Mensagem 1
[LOG] 2025/04/19 23:46:42.831864 Goroutine 0 - Mensagem 2
[LOG] 2025/04/19 23:46:42.831691 Goroutine 2 - Mensagem 0
[LOG] 2025/04/19 23:46:42.831875 Goroutine 2 - Mensagem 1
[LOG] 2025/04/19 23:46:42.831880 Goroutine 2 - Mensagem 2
[LOG] 2025/04/19 23:46:42.831713 Goroutine 3 - Mensagem 0
[LOG] 2025/04/19 23:46:42.831911 Goroutine 3 - Mensagem 1
[LOG] 2025/04/19 23:46:42.831916 Goroutine 3 - Mensagem 2
Internamente, o pacote log protege o acesso ao writer com um mutex. Sempre que chamamos Println
, Printf
, Fatal
, o logger adquire esse mutex, escreve, e libera. Isso evita o race condition e não precisamos nos preocupar em chamar mutex.