A Brief History of Logging in Go

Márk Sági-Kazár


2023-10-27 @ Go Budapest meetup

Standard library

(Prior to 1.21)

log package

package main

import "log"

func main() {
    log.Print("Hello world!")
}


go run main.go

2009/11/10 23:00:00 Hello world!

log package

  • No structured logging
  • No levels
  • No way to change the output format or destination 1
  • No context propagation

log.Fatal

package main

import "log"

func main() {
    log.Fatal("Hello world!")

    log.Print("Bye")
}


go run main.go

2009/11/10 23:00:00 Hello world!

Logger interface???

Userland

Awesome Go 1

  • 62 logging related libraries
  • 6 of them called go-log(ger)
  • 7 of them called log(ger)

Challenges

  • Interoperability between libraries
  • Dependency hell purgatory
  • Dozens of interfaces (gRPC, mysql, etc)

log/slog package

  • First proposed in 2022 October
  • Released in Go 1.21

Levels

package main

import "log/slog"

func main() {
    slog.Info("Hello world!")
}


2009/11/10 23:00:00 INFO Hello world!

Structured logging

package main

import (
    "log/slog"
    "os"
)

func main() {
    slog.Info("Hello world!", "user", os.Getenv("USER"))
    // OR
    slog.Info("Hello world!", slog.String("user", os.Getenv("USER")))
}


2009/11/10 23:00:00 INFO Hello world! user="user"

Custom handlers

package main

import (
    "log/slog"
    "os"
)

func main() {
    logger := slog.New(slog.NewTextHandler(os.Stdout, nil))

    logger.Info("Hello world!", slog.String("user", os.Getenv("USER")))
}


time=2009-11-10T23:00:00.000Z level=INFO msg="Hello world!" user="user"

Other features

  • Context propagation
  • Attach common attributes to logger
  • No more log.Fatal BS!

Further reading

Final thoughts

Questions?