Home

Awesome

✒️ golog

golog is a zero-dependency simple, fast and easy-to-use level-based logger written in Go Programming Language.

Output from win terminal

build status report card godocs github issues

<!-- ## 🥇 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
)

$ go build

</details>
$ 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

NameMethodTextColor
"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.

  1. Create a child logger with a prefix text using the Child function,
  2. 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:

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

🔥 Benchmarks

testtimes ran (large is better)ns/op (small is better)B/op (small is better)allocs/op (small is better)
BenchmarkGologPrint100000003749 ns/op890 B/op28 allocs/op
BenchmarkLogrusPrint  30000009609 ns/op1611 B/op64 allocs/op

Click here for details.

👥 Contributing

If you find that something is not working as expected please open an issue.