Emoji based semantic scoped debuging for Go
Declare a debug zone in a package:
import (
"github.com/teal-finance/emo"
)
var zone = emo.NewZone("myLib")
Create an event for this zone:
zone.Info("An info message")
Output:
[myLib] ℹ️ An info message
Create an error event:
import errors
err := errors.New("PARAM ERROR")
zone.Error("An error has occurred:", err)
Output:
[myLib] 📥 ERROR An error has occurred: PARAM ERROR from main.main in emo/examples/example.go:17
It prints additional information about the file and the line if the event is of type error
See the complete events list
To only print the errors:
var zone = emo.NewZone("api").V(false) // Verbose=false
V(false)
disables the printing for logs that are not errors.
Three possibilities:
zone = zone.V(false) // no verbose: only print when isError
zone = zone.V(true) // default: inherit the global settings
zone = zone.V() // verbose: print all events (except Trace events)
To change all zones at once:
emo.GlobalVerbosity(false) // verbose mode for all zones inheriting the global settings
emo.GlobalVerbosity(true) // only isError for all zones inheriting the global settings
By default emo prints the call stack info only when isError
and in verbose mode.
The call stack info contains the caller function, the source file, and line number.
To always print it, or to never print it, use the third parameter:
const verbose = false // default true
const stack = true // default auto = only when isError
var zone = emo.NewZone("api", verbose, stack)
This can also be later set using a similar function as for zone.SetVerbosity()
:
zone.SetStackInfo(true) // print the call stack info for all events
zone.SetStackInfo(false) // never print the call stack info for any event
zone.SetStackInfo() // inherits from global settings
To control the call stack info for all zones:
emo.GlobalStackInfo(true) // print the call stack info for the zones inheriting global settings
emo.GlobalStackInfo(false) // never print the call stack for the zones inheriting global settings
emo.GlobalStackInfo() // default: only when `isError` and in verbose mode
Sometimes, an non-error event should be still printed, even when the Zone
is configured with Zone.Verbose=false
.
In that case, the P()
helper function can be used:
var prod = true
var verbose = !prod
var zone = emo.NewZone("api", verbose)
func start() {
zone.P().Info("Starting...")
// ...
}
The P(bool)
function accept an optional parameter to explicitly enable/disable the printing of an event:
func foo(n int) error {
if n < 0 {
return zone.P(false).ParamError("Parameter n must be positive, but got:", n).Err()
}
return nil
}
Similarly to P()
, the S()
helper function controls the call stack info of the current event:
zone.S().Debug("v=", v) // always print the call stack info, like S(1)
zone.S(-1).Error("v=", v) // never print the call stack info
zone.S(0).Error("v=", v) // inherits the global settings, usually print when zone.Print=true (default)
zone.S(1).Error("v=", v) // always print the call stack info, like S()
zone.S(2).Error("v=", v) // always print, but use the caller layer at one level up
The N()
helper function sets a temporary name for the current event only:
var zone = emo.NewZone("API")
zone.N("GET").Debug("Received a GET request with v=", v) // replaces [API] -> [GET]
Another example:
var zA = emo.NewZone("A")
var zB = emo.NewZone("B")
zA.Info("this Info event is related to the zone A")
zB.Info("this Info event is related to the zone B")
// previous lines can be replaced by:
emo.DefaultZone.N("A").Info("this Info event is related to the zone A")
emo.DefaultZone.N("B").Info("this Info event is related to the zone B")
To timestamp all event messages:
emo.GlobalTimestamp(true)
By default, emo
does not timestamp the events.
The event messages are by default colorized. But in some cases this is disturbing, especially when testing. To disable the color:
emo.GlobalColoring(false)
Sometimes a function needs to print an error and to return this same string as a Go standard error.
In that case, the function Err()
converts an Event
to a Go standard error:
func foo(n int) error {
if n < 0 {
evt := zone.ParamError("Parameter n must be positive, but got:", n)
return evt.Err()
}
return nil
}
Exported fields of an Event
:
type Event struct {
Emoji string
Zone Zone
IsError bool
Args []any
From string
File string
Line int
}
Note: The fields From
, File
and Line
are always computed when the zone.Hook
is set,
even is stack=false
is set.
A callback can be passed to a zone. It will be executed each time an event is fired:
func hook(evt emo.Event) {
fmt.Println("Event hook", evt.Error)
}
zone := emo.NewZoneWithHook("example", hook)
zone.Debug("Test msg")
All the emo
functions can be used without having to create a custom Zone
.
The emo.DefaultZone
is a pre-configured Zone
ready to use:
var zone = emo.DefaultZone
var ok = true
zone.Info("my event", ok)
The Go implementation of emo
enables the Printf format. Each function has a corresponding function ending with f
:
zone.Info("my event", ok)
zone.Infof("my event %v", ok)
To use emo
as a logger the Go implementation of emo
also implements the standard Go logger functions:
zone.Print("my event", ok) // not an error but always printed
zone.Printf("my event %v", ok)
zone.Fatal("my event", ok) // not an error but always printed
zone.Fatalf("my event %v", ok)
zone.Panic("my event", ok) // not an error but always printed
zone.Panicf("my event %v", ok)
zone.Default()
Moreover, the Go implementation of emo
also implements some of other common functions of loggers like logrus
:
zone.Trace("my event", ok) // not an error but always printed
zone.Tracef("my event %v", ok)
zone.Warn("my event", ok) // not an error but always printed
zone.Warnf("my event %v", ok)
The Trace
events can be very verbose.
Thus a specific function controls its enabling:
emo.GlobalTracing(true)
-
Support structured logging similar to zap:
log.Infow("failed to fetch URL", "url", url, "attempt", 3, "backoff", time.Second, )
-
Improve performance by being inspired by logf:
BenchmarkOneField_WithColor 205.7 ns/op 0 allocs/op BenchmarkThreeFields_WithColor 379.4 ns/op 0 allocs/op BenchmarkErrorField_WithColor 353.6 ns/op 0 allocs/op BenchmarkHugePayload_WithColor 799.5 ns/op 0 allocs/op