Skip to content

Go Logging

Logging is essential for monitoring your application and debugging errors. Go provides a built-in log package, but many developers use "structured" logging for production.

1. The Standard log Package

This is the simplest way to log. By default, it prints to stderr and includes the date and time.

package main

import (
    "log"
    "os"
)

func main() {
    // 1. Basic logging
    log.Println("Hello, logger!")

    // 2. Fatal - logs the message and calls os.Exit(1)
    // log.Fatal("Critical error! Stopping app.")

    // 3. Panic - logs the message and calls panic()
    // log.Panic("Unexpected state!")

    // 4. Customizing the output
    log.SetFlags(log.LstdFlags | log.Lshortfile)
    log.Println("Log with file name and line number")

    // 5. Custom prefix
    log.SetPrefix("MYAPP: ")
    log.Println("Log with prefix")
}

2. Logging to a File

1
2
3
4
5
f, _ := os.OpenFile("test.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
defer f.Close()

log.SetOutput(f)
log.Println("This message goes to the file")

3. Structured Logging (The Modern Way)

Basic logs are just strings. Structured logs are format-friendly (like JSON), which makes them easy for tools like Datadog or Splunk to search.

While Go's standard library is basic, popular third-party packages include: - slog (Now part of the standard library in Go 1.21+): Recommended for most apps. - zap: High performance. - zerolog: Specialized for high-speed JSON logging.

Example using slog (Standard since 1.21)

1
2
3
4
5
6
import "log/slog"

func main() {
    slog.Info("usage", "user", "alice", "id", 123)
}
// Output: 2023/07/01 12:00:00 INFO usage user=alice id=123

Why use a Logger instead of fmt.Println?

  1. Metadata: Loggers automatically add timestamps and file locations.
  2. Destinations: Easily switch between terminal output, log files, or network streams.
  3. Severity Levels: Use levels like DEBUG, INFO, WARN, and ERROR to filter what you see.