Documentation ¶
Overview ¶
Package log provides structured logging with fine grained control over packages using logger registry
TODO: add convention and usage
Index ¶
- Constants
- Variables
- func DisableSource()
- func EnableSource()
- func SetHandler(handler Handler)
- func SetLevel(level Level)
- func WalkLogger(cb func(l *Logger))
- func WalkRegistry(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 (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{})
- func (l *Logger) WithField(f Field) *Logger
- func (l *Logger) WithFields(fields ...Field) *Logger
- type LoggerType
- type Registry
- type StructLoggerConfig
- type Syncer
- type TestHandler
Examples ¶
Constants ¶
const LevelEnvKey = "GOMMON_LOG_LEVEL"
LevelEnvKey is the environment variable name for setting default log level
const (
MagicStructLoggerFunctionName = "LoggerIdentity"
)
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()
func EnableSource ¶ added in v0.0.8
func EnableSource()
func SetHandler ¶ added in v0.0.8
func SetHandler(handler Handler)
func WalkLogger ¶ added in v0.0.8
func WalkLogger(cb func(l *Logger))
WalkLogger calls WalkRegistry and within each registry, walk in insert order of loggers
func WalkRegistry ¶ added in v0.0.8
func WalkRegistry(cb func(r *Registry))
WalkRegistry walks registry in globalRegistryGroup in sorted order of id (package path)
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 TODO: interface{} is actually not used ...
type FieldType ¶ added in v0.0.3
type FieldType uint8
FieldType avoids doing type assertion or calling reflection TODO: difference between type assertion and reflection
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 TODO: should allow customize default handler like default level, i.e. use json as default handler
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 can be used to inspect logger when traverse and print package hierarchy. NOTE: logger hierarchy is flat instead of tree after https://github.com/dyweb/gommon/issues/110
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 ParseLevel ¶ added in v0.0.11
ParseLevel converts a level string to log level, it is case insensitive. For invalid input, it returns InfoLevel and a non nil error
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 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 nor handler, it is mainly used for benchmark
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 WithField 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 WithFields 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
DisableSource turns off logging source file and line number
func (*Logger) EnableSource ¶ added in v0.0.3
EnableSource turns on logging source file and line number
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 ¶
SetHandler sets handler of logger, it is thread safe
func (*Logger) WithField ¶ added in v0.0.11
WithField is Copy + AddField Use WithField when a common context is shared inside entire func/method Use *F methods if you just want adhoc fields, this won't create copy of entire logger i.e. logger.InfoF(dlog.Str("user", "cat007")) instead of logger.WithField(dlog.Str("user", "cat007")) TODO: there are some optimization here, i.e. the length is known to be + 1 and there is no need to lock
func (*Logger) WithFields ¶ added in v0.0.11
WithFields is Copy + AddFields, see WithField doc on when and when not to use it. It is faster than calling WithField multiple times because of reduced alloc & copy on existing fields
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 default and tracked loggers, it is per package
func NewRegistry ¶ added in v0.0.11
func NewRegistry() *Registry
NewRegistry create a log registry with a default logger for a package. It registers itself in globalRegistryGroup so it can be updated later using WalkRegistries
func (*Registry) NewLogger ¶ added in v0.0.11
NewLogger creates a logger based on default logger and register it in registry. It should be used sparingly, if you need to add more fields as context for a func, you should make copy from default logger using methods like TODO: WithFields? to avoid register them in registry
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 |
---|---|
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 |