# README
Log
Convention
- every package has a log registry and its default logger.
- logger should only register themselves in registry if it's a long lived one, i.e. server
Usage
See examples in handlers
In package, create package level var called log
this saves import and also avoid people importing standard log.
Use dlog
as import alias because log
is already used.
package main
import (
"os"
"time"
dlog "github.com/dyweb/gommon/log"
"github.com/dyweb/gommon/log/handlers/cli"
)
var logReg = dlog.NewRegistry()
var log = logReg.Logger()
func main() {
dlog.SetHandler(cli.New(os.Stderr, true))
if len(os.Args) > 1 {
if os.Args[1] == "nocolor" || os.Args[1] == "no" {
dlog.SetHandler(cli.NewNoColor(os.Stderr))
}
}
log.Info("hi")
log.Infof("open file %s", "foo.yml")
log.InfoF("open",
dlog.Str("file", "foo.yml"),
dlog.Int("mode", 0666),
)
log.Warn("I am yellow")
func() {
defer func() {
if r := recover(); r != nil {
log.Info("recovered", r)
}
}()
log.Panic("I just want to panic")
}()
dlog.SetLevel(dlog.DebugLevel)
log.Debug("I will sleep for a while")
time.Sleep(500 * time.Millisecond)
log.Fatal("I am red")
}
# Functions
DefaultHandler returns the singleton defaultHandler instance, which logs to stderr in text format TODO: should allow customize default handler like default level, i.e.
No description provided by the author
EmptyCaller is mainly used for testing handler, it contains a empty file and line 0.
No description provided by the author
Int creates a field with int value, it uses int64 internally.
MultiHandler creates a handler that duplicates the log to all the provided handlers, it runs in serial and don't handle panic.
No description provided by the author
NewRegistry create a log registry with a default logger for a package.
No description provided by the author
NewTestHandler returns a test handler, it should only be used in test, a concrete type instead of Handler interface is returned to reduce unnecessary type cast in test.
NewTestLogger does NOT have identity nor handler, it is mainly used for benchmark.
NewTextHandler formats log in human readable format without any escape, thus it is NOT machine readable Default handler is a textHandler using os.Stderr.
ParseLevel converts a level string to log level, it is case insensitive.
No description provided by the author
No description provided by the author
Str creates a field with string value.
Stringer calls the String() method and stores return value.
WalkLogger calls WalkRegistry and within each registry, walk in insert order of loggers.
WalkRegistry walks registry in globalRegistryGroup in sorted order of id (package path).
# Constants
DebugLevel log debug message, user should enable DebugLevel logging when report bug.
ErrorLevel log error and do nothing TODO: add integration with errors package.
FatalLevel log error and call `os.Exit(1)` TODO: allow user to add hooks before calling os.Exit?.
No description provided by the author
InfoLevel log info.
No description provided by the author
LevelEnvKey is the environment variable name for setting default log level.
No description provided by the author
No description provided by the author
PackageLogger is normally singleton in entire package We used to have application and library logger but they are replaced by registry.
PanicLevel log error and call `panic`.
PrintLevel is for library/application that requires a Printf based logger interface.
No description provided by the author
No description provided by the author
TraceLevel is very verbose, user should enable it only on packages they are currently investing instead of globally TODO: add compile flag to use empty trace logger implementation to eliminate the call at runtime.
No description provided by the author
No description provided by the author
No description provided by the author
WarnLevel log warning that is often ignored.
# Variables
No description provided by the author
# Structs
Caller is the result from runtime.Caller.
Field is based on uber-go/zap https://github.com/uber-go/zap/blob/master/zapcore/field.go It can be treated as a Union, the value is stored in either Int, Str or Interface TODO: interface{} is actually not used ...
Identity is set based on logger's initialization location, it is close to, but NOT exactly same as location of actual log.
Logger is a concrete type instead of interface because most logic is in handler.
Registry contains default and tracked loggers, it is per package.
StructLoggerConfig is used to generate methods on struct for get identity using runtime, it also generates getter and setter.
TestHandler stores log as entry, its slice is protected by a RWMutex and safe for concurrent use.
# Interfaces
Handler formats log message and writes to underlying storage, stdout, file, remote server etc.
LoggableStruct is used to inject a logger into the struct, the methods for the interface can and should be generated using gommon.
Syncer is implemented by os.File, handler implementation should check this interface and call Sync if they support using file as sink TODO: about sync - in go, both os.Stderr and os.Stdout are not (line) buffered - what would happen if os.Stderr.Close() - os.Stderr.Sync() will there be any different if stderr/stdout is redirected to a file.
# Type aliases
Fields is a slice of Field.
FieldType avoids doing type assertion or calling reflection TODO: difference between type assertion and reflection.
HandlerFunc is an adapter to allow use of ordinary functions as log entry handlers.
Level is log level TODO: allow change default logging level at compile time.
LoggerType can be used for filtering loggers, it is set when creating logger.