Documentation ¶
Overview ¶
Package log provides structured logging with fine grained control over libraries using a tree of logger registry
TODO: add convention and usage
Index ¶
- Constants
- Variables
- func DisableSource(root *Registry)
- func EnableSource(root *Registry)
- func NewApplicationLoggerAndRegistry(project string) (*Logger, *Registry)
- func NewPackageLoggerAndRegistryWithSkip(project string, skip int) (*Logger, *Registry)
- func SetHandler(root *Registry, handler Handler)
- func SetLevel(root *Registry, level Level)
- func WalkLogger(root *Registry, cb func(l *Logger))
- func WalkRegistry(root *Registry, cb func(r *Registry))
- type Caller
- type Field
- type FieldType
- type Fields
- type Handler
- type HandlerFunc
- type Identity
- type Level
- type LoggableStruct
- type Logger
- func NewFunctionLogger(packageLogger *Logger) *Loggerdeprecated
- func NewMethodLogger(structLogger *Logger) *Loggerdeprecated
- func NewPackageLogger() *Logger
- func NewPackageLoggerWithSkip(skip int) *Logger
- func NewStructLogger(packageLogger *Logger, loggable LoggableStruct) *Logger
- func NewTestLogger(level Level) *Logger
- func (l *Logger) AddField(f Field) *Logger
- func (l *Logger) AddFields(fields ...Field) *Logger
- func (l *Logger) Copy() *Logger
- func (l *Logger) Debug(args ...interface{})
- func (l *Logger) DebugF(msg string, fields ...Field)
- func (l *Logger) Debugf(format string, args ...interface{})
- func (l *Logger) DisableSource() *Logger
- func (l *Logger) EnableSource() *Logger
- func (l *Logger) Error(args ...interface{})
- func (l *Logger) ErrorF(msg string, fields ...Field)
- func (l *Logger) Errorf(format string, args ...interface{})
- func (l *Logger) Fatal(args ...interface{})
- func (l *Logger) FatalF(msg string, fields ...Field)
- func (l *Logger) Fatalf(format string, args ...interface{})
- func (l *Logger) Flush()
- func (l *Logger) Identity() Identity
- func (l *Logger) Info(args ...interface{})
- func (l *Logger) InfoF(msg string, fields ...Field)
- func (l *Logger) Infof(format string, args ...interface{})
- func (l *Logger) IsDebugEnabled() bool
- func (l *Logger) IsErrorEnabled() bool
- func (l *Logger) IsInfoEnabled() bool
- func (l *Logger) IsPrintEnabled() bool
- func (l *Logger) IsTraceEnabled() bool
- func (l *Logger) IsWarnEnabled() bool
- func (l *Logger) Level() Level
- func (l *Logger) NoopF(msg string, fields ...Field)
- func (l *Logger) Panic(args ...interface{})
- func (l *Logger) PanicF(msg string, fields ...Field)
- func (l *Logger) Panicf(format string, args ...interface{})
- func (l *Logger) Print(args ...interface{})
- func (l *Logger) PrintF(msg string, fields ...Field)
- func (l *Logger) Printf(format string, args ...interface{})
- func (l *Logger) ResetCallerSkip() *Logger
- func (l *Logger) SetCallerSkip(skip int) *Logger
- func (l *Logger) SetHandler(h Handler) *Logger
- func (l *Logger) SetLevel(level Level) *Logger
- func (l *Logger) Trace(args ...interface{})
- func (l *Logger) TraceF(msg string, fields ...Field)
- func (l *Logger) Tracef(format string, args ...interface{})
- func (l *Logger) Warn(args ...interface{})
- func (l *Logger) WarnF(msg string, fields ...Field)
- func (l *Logger) Warnf(format string, args ...interface{})
- type LoggerType
- type Registry
- type RegistryIdentity
- type RegistryType
- type StructLoggerConfig
- type Syncer
- type TestHandler
Examples ¶
Constants ¶
const ( MagicStructLoggerFunctionName = "LoggerIdentity" MagicPackageLoggerFunctionName = "init" // a hack for new init func name after 1.12 // See https://github.com/dyweb/gommon/issues/108 MagicPackageLoggerFunctionNameGo112 = "init.ializers" )
const PrintLevel = InfoLevel
PrintLevel is for library/application that requires a Printf based logger interface
const UnknownFile = "<?>"
Variables ¶
var UnknownIdentity = Identity{Package: "unk", Type: UnknownLogger}
Functions ¶
func DisableSource ¶ added in v0.0.8
func DisableSource(root *Registry)
func EnableSource ¶ added in v0.0.8
func EnableSource(root *Registry)
func NewApplicationLoggerAndRegistry ¶ added in v0.0.8
TODO: validate skip
func NewPackageLoggerAndRegistryWithSkip ¶ added in v0.0.8
func SetHandler ¶ added in v0.0.8
func WalkLogger ¶ added in v0.0.8
WalkLogger is PreOrderDfs
func WalkRegistry ¶ added in v0.0.8
Types ¶
type Caller ¶ added in v0.0.8
type Caller struct { // File is the full file path without any trimming, it would be UnknownFile if caller is not found File string Line int }
Caller is the result from runtime.Caller
func EmptyCaller ¶ added in v0.0.8
func EmptyCaller() Caller
EmptyCaller is mainly used for testing handler, it contains a empty file and line 0
type Field ¶
type Field struct { Key string Type FieldType // values Int int64 Str string Interface interface{} }
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
type FieldType ¶ added in v0.0.3
type FieldType uint8
FieldType avoids doing type assertion or calling reflection TODO: difference between the two methods above
type Fields ¶
type Fields []Field
Fields is a slice of Field
func CopyFields ¶ added in v0.0.8
CopyFields make a copy of the slice so modifying one won't have effect on another,
type Handler ¶
type Handler interface { // HandleLog requires level, now, msg, all the others are optional // source is Caller which contains full file line TODO: pass frame instead of string so handler can use trace for error handling? // context are fields attached to the logger instance // fields are ad-hoc fields from logger method like DebugF(msg, fields) HandleLog(level Level, now time.Time, msg string, source Caller, context Fields, fields Fields) // Flush writes the buffer to underlying storage Flush() }
Handler formats log message and writes to underlying storage, stdout, file, remote server etc. It MUST be thread safe because logger calls handler concurrently without any locking. There is NO log entry struct in gommon/log, which is used in many logging packages, the reason is if extra field is added to the interface, compiler would throw error on stale handler implementations.
func DefaultHandler ¶
func DefaultHandler() Handler
DefaultHandler returns the singleton defaultHandler instance, which logs to stderr in text format
func MultiHandler ¶ added in v0.0.8
MultiHandler creates a handler that duplicates the log to all the provided handlers, it runs in serial and don't handle panic
func NewTextHandler ¶ added in v0.0.8
NewTextHandler formats log in human readable format without any escape, thus it is NOT machine readable Default handler is a textHandler using os.Stderr
type HandlerFunc ¶
type HandlerFunc func(level Level, now time.Time, msg string, source string, context Fields, fields Fields)
HandlerFunc is an adapter to allow use of ordinary functions as log entry handlers
type Identity ¶
type Identity struct { Package string Function string Struct string File string Line int Type LoggerType }
Identity is set based on logger's initialization location, it is close to, but NOT exactly same as location of actual log. It is used for applying filter rules and print logger hierarchy.
func NewIdentityFromCaller ¶
TODO: document all the black magic here ... https://github.com/dyweb/gommon/issues/32
func (*Identity) Diff ¶
TODO: this is used for print tree like structure ... it's hard to maintain exact parent and child logger due to cycle import
func (*Identity) SourceLocation ¶
type Level ¶
type Level uint8
Level is log level TODO: allow change default logging level at compile time
Example ¶
fmt.Println(FatalLevel.String()) fmt.Println(FatalLevel.AlignedUpperString())
Output: fatal FATA
const ( // FatalLevel log error and call `os.Exit(1)` // TODO: allow user to add hooks before calling os.Exit? FatalLevel Level = iota // PanicLevel log error and call `panic` PanicLevel // ErrorLevel log error and do nothing // TODO: add integration with errors package ErrorLevel // WarnLevel log warning that is often ignored WarnLevel // InfoLevel log info InfoLevel // DebugLevel log debug message, user should enable DebugLevel logging when report bug DebugLevel // 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 TraceLevel )
func (Level) AlignedUpperString ¶ added in v0.0.5
AlignedUpperString returns log level with fixed length of 4 in uppercase, i.e. FATA, WARN
func (Level) ColoredAlignedUpperString ¶ added in v0.0.4
ColoredAlignedUpperString returns fixed length level string in uppercase, wrapped by terminal color characters, only works on *nix
func (Level) ColoredString ¶ added in v0.0.3
TODO: use switch and generate the function ... or just generate it manually ColoredString returns level string wrapped by terminal color characters, only works on *nix
type LoggableStruct ¶
type LoggableStruct interface { GetLogger() *Logger SetLogger(logger *Logger) LoggerIdentity(justCallMe func() Identity) Identity }
LoggableStruct is used to inject a logger into the struct, the methods for the interface can and should be generated using gommon.
In struct initializer call dlog.NewStructLogger(pkgLogger, structInstancePointer)
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
Logger is a concrete type instead of interface because most logic is in handler. There is NO lock when calling logging methods, handlers may have locks. Lock is used when updating logger attributes like Level.
For Printf style logging (Levelf), Logger formats string using fmt.Sprintf before passing it to handlers.
logger.Debugf("id is %d", id)
For structural logging (LevelF), Logger passes fields to handlers without any processing.
logger.DebugF("hi", log.Fields{log.Str("foo", "bar")})
If you want to mix two styles, call fmt.Sprintf before calling DebugF,
logger.DebugF(fmt.Sprintf("id is %d", id), log.Fields{log.Str("foo", "bar")})
func NewFunctionLogger
deprecated
func NewMethodLogger
deprecated
func NewPackageLogger ¶
func NewPackageLogger() *Logger
func NewStructLogger ¶
func NewStructLogger(packageLogger *Logger, loggable LoggableStruct) *Logger
func NewTestLogger ¶ added in v0.0.8
NewTestLogger does not have identity and handler, it is mainly used for benchmark test
func (*Logger) AddField ¶ added in v0.0.8
AddField add field to current logger in place, it does NOT create a copy of logger Use Copy if you want a copy It does NOT check duplication
func (*Logger) AddFields ¶ added in v0.0.8
AddFields add fields to current logger in place, it does NOT create a copy of logger Use Copy if you want a copy It does NOT check duplication
func (*Logger) Copy ¶ added in v0.0.8
Copy create a new logger with different identity, the identity is based on where Copy is called Normally you should call Copy inside func or method on a package/strcut logger
func (*Logger) DisableSource ¶ added in v0.0.3
func (*Logger) EnableSource ¶ added in v0.0.3
func (*Logger) Fatal ¶
func (l *Logger) Fatal(args ...interface{})
Fatal calls os.Exit(1) after it writes and flushes the log
func (*Logger) FatalF ¶ added in v0.0.3
FatalF duplicates instead of calling Fatal to keep source line correct
func (*Logger) Identity ¶
Identity returns the identity set when the logger is created. NOTE: caller can modify the identity because all fields are public, but they should NOT do this
func (*Logger) IsDebugEnabled ¶
func (*Logger) IsErrorEnabled ¶
func (*Logger) IsInfoEnabled ¶
func (*Logger) IsPrintEnabled ¶ added in v0.0.8
func (*Logger) IsTraceEnabled ¶
func (*Logger) IsWarnEnabled ¶
func (*Logger) Panic ¶
func (l *Logger) Panic(args ...interface{})
Panic calls panic after it writes and flushes the log
func (*Logger) PanicF ¶ added in v0.0.3
PanicF duplicates instead of calling Panic to keep source line correct
func (*Logger) ResetCallerSkip ¶ added in v0.0.8
ResetCallerSkip set skip to 0, the default value
func (*Logger) SetCallerSkip ¶ added in v0.0.8
SetCallerSkip is used for util function to log using its caller's location instead of its own Without extra skip, some common util function will keep logging same line and make the real source hard to track.
func echo(w http.ResponseWriter, r *http.Request) { if r.Query().Get("word") == "" { writeError(w, errors.New("word is required") return } w.Write([]byte(r.Query().Get("word"))) }
func writeError(w http.ResponseWriter, err error) { l := pkgLogger.Copy().SetCallerSkip(1) l.Error(err) w.Write([]byte(err.String())) }
func (*Logger) SetHandler ¶
type LoggerType ¶
type LoggerType uint8
LoggerType can be used for filtering loggers, it is set when creating logger
const ( UnknownLogger LoggerType = iota // PackageLogger is normally singleton in entire package // We used to have application and library logger but they are replaced by registry PackageLogger FunctionLogger StructLogger MethodLogger )
func (LoggerType) String ¶
func (tpe LoggerType) String() string
type Registry ¶ added in v0.0.8
type Registry struct {
// contains filtered or unexported fields
}
Registry contains child registry and loggers
func NewLibraryRegistry ¶ added in v0.0.8
func (*Registry) AddLogger ¶ added in v0.0.8
AddLogger is used for registering a logger to package level log registry It skips add if the logger is already there
func (*Registry) AddRegistry ¶ added in v0.0.8
AddRegistry is for adding a package level log registry to a library/application level log registry It skips add if child registry already there
func (*Registry) Identity ¶ added in v0.0.8
func (r *Registry) Identity() RegistryIdentity
type RegistryIdentity ¶ added in v0.0.8
type RegistryIdentity struct { // Project is specified by user, i.e. for all the packages under gommon, they would have github.com/dyweb/gommon Project string // Package is detected base on runtime, i.e. github.com/dyweb/gommon/noodle Package string // Type is specified by user when creating registry Type RegistryType // File is where create registry is called File string // Line is where create registry is called Line int }
type RegistryType ¶ added in v0.0.8
type RegistryType uint8
const ( UnknownRegistry RegistryType = iota ApplicationRegistry LibraryRegistry PackageRegistry )
func (RegistryType) String ¶ added in v0.0.8
func (r RegistryType) String() string
type StructLoggerConfig ¶ added in v0.0.8
type StructLoggerConfig struct { Struct string `yaml:"struct"` Receiver string `yaml:"receiver"` Field string `yaml:"field"` }
StructLoggerConfig is used to generate methods on struct for get identity using runtime, it also generates getter and setter
func (*StructLoggerConfig) Render ¶ added in v0.0.8
func (c *StructLoggerConfig) Render() ([]byte, error)
type Syncer ¶ added in v0.0.3
type Syncer interface {
Sync() error
}
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 TestHandler ¶ added in v0.0.5
type TestHandler struct {
// contains filtered or unexported fields
}
TestHandler stores log as entry, its slice is protected by a RWMutex and safe for concurrent use
func NewTestHandler ¶
func NewTestHandler() *TestHandler
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
func (*TestHandler) Flush ¶ added in v0.0.5
func (h *TestHandler) Flush()
Flush implements Handler interface
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package benchmarks provides benchmark using go test and simulated real environment using pprof
|
Package benchmarks provides benchmark using go test and simulated real environment using pprof |
_examples
|
|
handlers
|
|
cli
Package cli generates human readable text with color and display time in delta.
|
Package cli generates human readable text with color and display time in delta. |
json
Package json writes log in JSON format, it escapes string in json based encoding/json, It does not use encoding/json directly because all the fields have known type
|
Package json writes log in JSON format, it escapes string in json based encoding/json, It does not use encoding/json directly because all the fields have known type |
Package logx is extension for log package
|
Package logx is extension for log package |