/devlog

A structured log handler for Go, with a human-readable output format designed for development builds.

Primary LanguageGoMIT LicenseMIT

devlog

A structured logging handler for Go, with a human-readable output format designed for development builds.

Run go get hermannm.dev/devlog to add it to your project!

Usage

devlog.Handler implements slog.Handler, so it can handle output for slog's logging functions. It can be configured as follows:

logHandler := devlog.NewHandler(os.Stdout, nil)
slog.SetDefault(slog.New(logHandler))

Logging with slog will now use this handler:

slog.Warn("no value found for 'PORT' in env, defaulting to 8000")
slog.Info("server started", slog.Int("port", 8000), slog.String("environment", "DEV"))
slog.Error(
	"database query failed",
	slog.Group("dbError", slog.Int("code", 60), slog.String("message", "UNKNOWN_TABLE")),
)

...giving the following output (using a gruvbox terminal color scheme):

Screenshot of log messages in a terminal

This output is meant to be easily read by a developer working locally. However, you may want a more structured format for production, such as JSON, to make log analysis easier. You can get both by conditionally choosing the log handler for your application, e.g.:

var logHandler slog.Handler
switch os.Getenv("ENVIRONMENT") {
case "PROD":
	logHandler = slog.NewJSONHandler(os.Stdout, nil)
case "DEV":
	logHandler = devlog.NewHandler(os.Stdout, nil)
}

slog.SetDefault(slog.New(logHandler))

devlog/log

To complement devlog's output handling, the devlog/log subpackage provides input handling. It is a thin wrapper over the slog package, with utility functions for log message formatting.

Example using devlog and devlog/log together:

import (
	"errors"
	"log/slog"
	"os"

	"hermannm.dev/devlog"
	"hermannm.dev/devlog/log"
)

func main() {
	logHandler := devlog.NewHandler(os.Stdout, nil)
	slog.SetDefault(slog.New(logHandler))

	user := map[string]any{"id": 2, "username": "hermannm"}
	err := errors.New("username taken")
	log.ErrorCause(err, "failed to create user", log.JSON("user", user))
}

This gives the following output:

Screenshot of log messages in a terminal

Credits