Awesome
✒️ golog
golog is a zero-dependency simple, fast and easy-to-use level-based logger written in Go Programming Language.
<!-- ## 🥇 Features * Focus on high performance and agile perspective of things * Easy API and a default package-level instance, i.e `golog#Fatalf/Errorf/Warnf/Infof/Debugf` * Fully compatible with the standard library * Thanks to the [pio library](https://github.com/kataras/pio) it supports any type of structure, gives you the ability to `Hijack` and `Handle` or `Intercept` the on-going logs too * Set or even Add unlimited number of output targets, `io.Writer` * Scan from any `io.Reader` and log to the defined output target(s) * Levels such as `fatal`,`error`, `warn`, `info`, `debug`, or `disable` * Beautiful (**customizable**) colors for leveled logs, automatically omit colors when output does not support colors (i.e files) * Incredible high-performant, 3 times faster than your favourite logger * Never-Panics Navigate through [_examples](_examples/) and [integrations](_examples/integrations/) to learn if that fair solution suits your needs. -->🚀 Installation
The only requirement is the Go Programming Language*.
<details> <summary>Go modules</summary>$ go get github.com/kataras/golog@latest
Or edit your project's go.mod file and execute $ go build.
module your_project_name
go 1.22
require (
github.com/kataras/golog v0.1.12
)
</details>
$ go build
$ go get github.com/kataras/golog@latest
package main
import (
"github.com/kataras/golog"
)
func main() {
// Default Output is `os.Stdout`,
// but you can change it:
// golog.SetOutput(os.Stderr)
// Time Format defaults to: "2006/01/02 15:04"
// you can change it to something else or disable it with:
// golog.SetTimeFormat("")
// Level defaults to "info",
// but you can change it:
golog.SetLevel("debug")
golog.Println("This is a raw message, no levels, no colors.")
golog.Info("This is an info message, with colors (if the output is terminal)")
golog.Warn("This is a warning message")
golog.Error("This is an error message")
golog.Debug("This is a debug message")
golog.Fatal(`Fatal will exit no matter what,
but it will also print the log message if logger's Level is >=FatalLevel`)
// Use any other supported logger through golog, e.g. the new "log/slog":
// golog.Install(slog.Default())
}
Log Levels
Name | Method | Text | Color |
---|---|---|---|
"fatal" | Fatal, Fatalf | [FTAL] | Red background |
"error" | Error, Errorf | [ERRO] | Red foreground |
"warn" | Warn, Warnf, Warningf | [WARN] | Magenta foreground |
"info" | Info, Infof | [INFO] | Cyan foreground |
"debug" | Debug, Debugf | [DBUG] | Yellow foreground |
On debug level the logger will store stacktrace information to the log instance, which is not printed but can be accessed through a
Handler
(see below).
Helpers
// GetTextForLevel returns the level's (rich) text.
fatalRichText := golog.GetTextForLevel(golog.FatalLevel, true)
// fatalRichText == "\x1b[41m[FTAL]\x1b[0m"
// ParseLevel returns a Level based on its string name.
level := golog.ParseLevel("debug")
// level == golog.DebugLevel
Customization
You can customize the log level attributes.
func init() {
// Levels contains a map of the log levels and their attributes.
errorAttrs := golog.Levels[golog.ErrorLevel]
// Change a log level's text.
customColorCode := 156
errorAttrs.SetText("custom text", customColorCode)
// Get (rich) text per log level.
enableColors := true
errorRichText := errorAttrs.Text(enableColors)
}
Alternatively, to change a specific text on a known log level, you can just call:
golog.ErrorText("custom text", 156)
Integration
The golog.Logger
is using common, expected log methods, therefore you can integrate it with ease.
Take for example the badger database. You want to add a prefix of [badger]
in your logs when badger wants to print something.
- Create a child logger with a prefix text using the
Child
function, - disable new lines (because they are managed by badger itself) and you are ready to GO:
opts := badger.DefaultOptions("./data")
opts.Logger = golog.Child("[badger]").DisableNewLine()
db, err := badger.Open(opts)
// [...]
Level-based and standard Loggers
You can put golog
in front of your existing loggers using the Install method.
Supporte loggers:
- log
- slog
- logrus
Example for log/slog
standard package:
// Simulate an slog.Logger preparation.
var myLogger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
}))
func main() {
golog.SetLevel("error")
golog.Install(myLogger)
golog.Error("error message")
}
Example for log
standard package:
// Simulate a log.Logger preparation.
myLogger := log.New(os.Stdout, "", 0)
golog.SetLevel("error")
golog.Install(myLogger)
golog.Error("error message")
Example for sirupsen/logrus:
// Simulate a logrus logger preparation.
logrus.SetLevel(logrus.InfoLevel)
logrus.SetFormatter(&logrus.JSONFormatter{})
golog.Install(logrus.StandardLogger())
golog.Debug(`this debug message will not be shown,
because the logrus level is InfoLevel`)
golog.Error(`this error message will be visible as JSON,
because of logrus.JSONFormatter`)
Output Format
Any value that completes the Formatter interface can be used to write to the (leveled) output writer. By default the "json"
formatter is available.
JSON
import "github.com/kataras/golog"
func main() {
golog.SetLevel("debug")
golog.SetFormat("json", " ") // < --
// main.go#29
golog.Debugf("This is a %s with data (debug prints the stacktrace too)", "message", golog.Fields{
"username": "kataras",
})
}
Output
{
"timestamp": 1591423477,
"level": "debug",
"message": "This is a message with data (debug prints the stacktrace too)",
"fields": {
"username": "kataras"
},
"stacktrace": [
{
"function": "main.main",
"source": "C:/example/main.go:29"
}
]
}
Register custom Formatter
golog.RegisterFormatter(new(myFormatter))
golog.SetFormat("myformat", options...)
The Formatter
interface looks like this:
// Formatter is responsible to print a log to the logger's writer.
type Formatter interface {
// The name of the formatter.
String() string
// Set any options and return a clone,
// generic. See `Logger.SetFormat`.
Options(opts ...interface{}) Formatter
// Writes the "log" to "dest" logger.
Format(dest io.Writer, log *Log) bool
}
Custom Format using Handler
The Logger can accept functions to handle (and print) each Log through its Handle method. The Handle method accepts a Handler.
type Handler func(value *Log) (handled bool)
This method can be used to alter Log's fields based on custom logic or to change the output destination and its output format.
Create a JSON handler
import "encoding/json"
func jsonOutput(l *golog.Log) bool {
enc := json.NewEncoder(l.Logger.GetLevelOutput(l.Level.String()))
enc.SetIndent("", " ")
err := enc.Encode(l)
return err == nil
}
Register the handler and log something
import "github.com/kataras/golog"
func main() {
golog.SetLevel("debug")
golog.Handle(jsonOutput)
// main.go#29
golog.Debugf("This is a %s with data (debug prints the stacktrace too)", "message", golog.Fields{
"username": "kataras",
})
}
Examples
- basic
- output per level
- child
- add new level
- change text and color
- customize output
- multi output
- scan
- logurs integration
- log.Logger std integration
- ngrok integration NEW
- postgres integration NEW
- new instance
🔥 Benchmarks
test | times ran (large is better) | ns/op (small is better) | B/op (small is better) | allocs/op (small is better) |
---|---|---|---|---|
BenchmarkGologPrint | 10000000 | 3749 ns/op | 890 B/op | 28 allocs/op |
BenchmarkLogrusPrint | 3000000 | 9609 ns/op | 1611 B/op | 64 allocs/op |
Click here for details.
👥 Contributing
If you find that something is not working as expected please open an issue.