Go за Прикладом: Logging

Стандартна бібліотека Go надає як простиі засоби виводити логи програм за допомогою пакету log для довільної форми логів так і пакет log/slog для стуктурованого логування.

package main
import (
    "bytes"
    "fmt"
    "log"
    "log/slog"
    "os"
)
func main() {

Просто викликаючи функції типу Println пакету log використає standard логгер, який вже попередньо сконфігуровано виводити до os.Stderr. Такі додаткові методи як Fatal* або Panic* припинять роботу програми після логування.

    log.Println("standard logger")

Логгер можливо сконфігуровати прапорцями для встановленння формату виводу. По-замовчуванню, стандартний логер має log.Ldate та log.Ltime прапорці встановлено, вони збираються log.LstdFlags. Ми можемо змінити ці прапорці, щоб, напряклад, виводити час з мікросекундною акуратністю.

    log.SetFlags(log.LstdFlags | log.Lmicroseconds)
    log.Println("with micro")

Або виводити імя файлу з якого функція log виклиана.

    log.SetFlags(log.LstdFlags | log.Lshortfile)
    log.Println("with file/line")

Може бути корисним створити власний логер, та передавати його куди треба. Коли створбємо власний логер, краще задавати префікс щоб відрізняти його від інших.

    mylog := log.New(os.Stdout, "my:", log.LstdFlags)
    mylog.Println("from mylog")

Ми можемо задати префікс і для існуючих логерів (включно з стандартним) скориставшись методом SetPrefix.

    mylog.SetPrefix("ohmy:")
    mylog.Println("from mylog")

Логерри можуть мати власні цілі логування; будь-який io.Writer підійде.

    var buf bytes.Buffer
    buflog := log.New(&buf, "buf:", log.LstdFlags)

Цей виклик запише лог до buf.

    buflog.Println("hello")

Виведемо наш лог вже у стандартний потік виводу.

    fmt.Print("from buflog:", buf.String())

Пакет slog надає структурований вивід логу. Наприклад, форматування JSON для логів.

    jsonHandler := slog.NewJSONHandler(os.Stderr, nil)
    myslog := slog.New(jsonHandler)
    myslog.Info("hi there")

На додачу до логів, slog може містити довільну кількість пар ключ=значення.

    myslog.Info("hello again", "key", "val", "age", 25)
}

Простий вивід; дата і час будуь залежати від того коли приклад запускався.

$ go run logging.go
2023/12/17 18:22:25 standard logger
2023/12/17 18:22:25.121928 with micro
2023/12/17 18:22:25 logging.go:33: with file/line
my:2023/12/17 18:22:25 from mylog
ohmy:2023/12/17 18:22:25 from mylog
from buflog:buf:2023/12/17 18:22:25 hello

Ми додали перенос для зручності, в реальності воно будуть виведені однією лінією.

{"time":"2023-12-17T18:22:25.121979+02:00",
"level":"INFO","msg":"hi there"}
{"time":"2023-12-17T18:22:25.121996+02:00",
"level":"INFO","msg":"hello again","key":"val",
"age":25}

Наступний приклад: HTTP Клієнт.