snippetgoMajor
How to implement level based logging in golang?
Viewed 0 times
logginghowlevelgolangimplementbased
Problem
Is there any good wrapper available for level based logging in golang?
If not, how should I go about implementing one myself?
What I want is pretty simple. I want a few functions e.g.
etc that display their outputs to stdout as well as save these in a log file (based on the level given to the program as commandline argument).
How do I implement this wrapper?
If not, how should I go about implementing one myself?
What I want is pretty simple. I want a few functions e.g.
log.Error()
log.Info()etc that display their outputs to stdout as well as save these in a log file (based on the level given to the program as commandline argument).
How do I implement this wrapper?
Solution
In 2023 today, Go 1.21.0 finally comes with a standard level logger:
No external library is needed anymore for average users.
Last updated: Go 1.26 (2026-02)
1.1 Enable
playground
1.2 Disable Logging
playground
If you want (temporarily) to disable logging, the cleanest solution is to define your own logger (see 4. Create Your Own Logger for the details).
However, this hacky one-liner works:
The name slog is short for structured logging, meaning each log entry can have a structure.
The log functions can optionally receive any number of key-value pairs called attributes:
(You can even nest key-value pairs via
This is useful when you want to print finer-grained timestamps, file names and line numbers:
Basic usage is covered by the top-level functions (e.g.
A created logger can be set as the default logger via
4.1 Standard Loggers
Constructors are provided in
4.2 User-Defined Loggers
By implementing
slog.Info("hello") //=> [INFO] 2023-11-15T22:38:54+09:00 hello
slog.Warn("hello") //=> [WARN] 2023-11-15T22:38:5
log/slog package.No external library is needed anymore for average users.
Last updated: Go 1.26 (2026-02)
- Basic Usage
package main
import "log/slog"
func main() {
slog.Info("hello")
slog.Warn("hello")
slog.Error("hello")
}
2023/08/09 20:05:49 INFO hello
2023/08/09 20:05:49 WARN hello
2023/08/09 20:05:49 ERROR hello1.1 Enable
Debug Log Levelplayground
Debug log level is disabled by default. To enable it, call SetLogLoggerLevel() (available in Go 1.22 or later):slog.SetLogLoggerLevel(slog.LevelDebug)
1.2 Disable Logging
playground
If you want (temporarily) to disable logging, the cleanest solution is to define your own logger (see 4. Create Your Own Logger for the details).
However, this hacky one-liner works:
slog.SetLogLoggerLevel(math.MaxInt)
- Add Context
The name slog is short for structured logging, meaning each log entry can have a structure.
The log functions can optionally receive any number of key-value pairs called attributes:
package main
import "log/slog"
func main() {
slog.Info("hello", "username", "Mike", "age", 18)
//same as above but more type-safe
slog.Info("hello", slog.String("username", "Mike"), slog.Int("age", 18))
}
2023/08/09 20:07:51 INFO hello username=Mike age=18
2023/08/09 20:07:51 INFO hello username=Mike age=18 (same as above)(You can even nest key-value pairs via
Group() or GroupAttrs().)- Customize Format
log package can be used to customize the format of log/slog logger.This is useful when you want to print finer-grained timestamps, file names and line numbers:
package main
import (
"log"
"log/slog"
)
func main() {
slog.Info("hello")
log.SetFlags(log.Ldate | log.Lmicroseconds | log.Llongfile)
slog.Info("hello")
}
2023/08/09 20:15:36 INFO hello
2023/08/09 20:15:36.601583 /home/user/test/a/main.go:9: INFO hello- Create Your Own Logger
Basic usage is covered by the top-level functions (e.g.
slog.Info()) but you can create your own logger for detailed customization.A created logger can be set as the default logger via
slog.SetDefault(). After that, the top-level functions (e.g. slog.Info()) use your logger.4.1 Standard Loggers
Constructors are provided in
log/slog package for some built-in loggers.package main
import (
"log/slog"
"os"
)
func main() {
//text logger
{
//The second argument enables Debug log level.
handler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug})
slog.SetDefault(slog.New(handler))
slog.Debug("hello", "username", "Mike", "age", 18)
}
//JSON logger
{
handler := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug})
slog.SetDefault(slog.New(handler))
slog.Debug("hello", "username", "Mike", "age", 18)
}
}
time=2023-08-09T20:31:05.798+09:00 level=DEBUG msg=hello username=Mike age=18
{"time":"2023-08-09T20:31:05.798984192+09:00","level":"DEBUG","msg":"hello","username":"Mike","age":18}4.2 User-Defined Loggers
By implementing
Handler interface, you can create a fully-customized logger.package main
import (
"context"
"fmt"
"log/slog"
"os"
"time"
)
type MyHandler struct{}
func (h MyHandler) Enabled(context context.Context, level slog.Level) bool {
switch level {
case slog.LevelDebug:
return false
case slog.LevelInfo:
fallthrough
case slog.LevelWarn:
fallthrough
case slog.LevelError:
return true
default:
panic("unreachable")
}
}
func (h MyHandler) Handle(context context.Context, record slog.Record) error {
message := record.Message
//appends each attribute to the message
//An attribute is of the form = and specified as in slog.Error(, , , ...).
record.Attrs(func(attr slog.Attr) bool {
message += fmt.Sprintf(" %v", attr)
return true
})
timestamp := record.Time.Format(time.RFC3339)
switch record.Level {
case slog.LevelDebug:
fallthrough
case slog.LevelInfo:
fallthrough
case slog.LevelWarn:
fmt.Fprintf(os.Stderr, "[%v] %v %v\n", record.Level, timestamp, message)
case slog.LevelError:
fmt.Fprintf(os.Stderr, "!!!ERROR!!! %v %v\n", timestamp, message)
default:
panic("unreachable")
}
return nil
}
// for advanced users
func (h MyHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
panic("unimplemented")
}
// for advanced users
func (h MyHandler) WithGroup(name string) slog.Handler {
panic("unimplemented")
}
func main() {
logger := slog.New(MyHandler{})
slog.SetDefault(logger)
slog.Debug("hello") //=> does nothing (as Enabled() returns false`)slog.Info("hello") //=> [INFO] 2023-11-15T22:38:54+09:00 hello
slog.Warn("hello") //=> [WARN] 2023-11-15T22:38:5
Code Snippets
2023/08/09 20:05:49 INFO hello
2023/08/09 20:05:49 WARN hello
2023/08/09 20:05:49 ERROR hello2023/08/09 20:07:51 INFO hello username=Mike age=18
2023/08/09 20:07:51 INFO hello username=Mike age=18 (same as above)2023/08/09 20:15:36 INFO hello
2023/08/09 20:15:36.601583 /home/user/test/a/main.go:9: INFO hellotime=2023-08-09T20:31:05.798+09:00 level=DEBUG msg=hello username=Mike age=18
{"time":"2023-08-09T20:31:05.798984192+09:00","level":"DEBUG","msg":"hello","username":"Mike","age":18}Context
Stack Overflow Q#16895651, score: 71
Revisions (0)
No revisions yet.