Documentation ¶
Overview ¶
Package logging provides a precise logging framework.
LogRecord ¶
A LogRecord can be sent by the application. It contains a level, message, timestamp, target (which subsystem the message came from) and PC information (file, line number).
Filter ¶
A Filter can determine whether a LogRecord should be accepted or not.
Handler ¶
A Handler can persist a LogRecord as it deems fit. Each Handler can have a (set of) Filters configured. The Handler will log a record iff all Filters accept it. The lifecycle of a Handler is: init, open, log OR flush ..., close.
Multiple Handles can be configured on a running system.
All Handles will write to an in-memory buffer which can typically hold up to 20 log records. When the buffer cannot add another log record, it is flushed.
Once a Handler has been created for a given name, it cannot be replaced.
This allows you to have different Handles who can log based on different criteria e.g. stackdriver only logs error and severe messages from web container at night.
NOTE: The framework *tries* to ensure that only one handler is writing to standard error or output streams. This allows us to handle backtraces, as we can ensure that the Handler writing to the standard error stream is flushed first.
Formatter ¶
A Formatter can take a LogRecord and convert it to a string for easy persisting.
A Handler *may* have a Formatter determine how the LogRecord should be persisted.
Logger ¶
A Logger can be retrieved for any subsystem (target). This can be retrieved explicitly by name or implicitly (where we use the package path to infer the subsystem).
Note that a Logger is only lazily initialized on first use, not on declaration/assignment. This ensures that the logging framework is initialized before the first log message is called.
A Logger can also have a Filter attached to it, which determines whether to send the LogRecord to the Handlers to persist.
To allow short-circuiting creating a LogRecord, a Logger has a minimum log level defined, so it can bypass logging quickly.
There is no hierachy of Loggers.
Once a Logger has been retrieved for a given subsystem, it cannot be replaced.
Customizing Target Subsystem name in Record ¶
By default, the target subsystem is named according to the name of the package, or whatever name is explicitly specified by calling NamedLogger.
However, it is possible and sometimes necessary to customize it. For example, you have a proxy that handles many different domain names, and you want each to have their own grouping of log records. You can specify a function that will take the package name and give a richer Target name in the Record.
For simplicity, this "extra" information can be passed into the context by the running application using the key: `logging.SubsystemExtraContextKey`. The value retrieved from the key, by default, will be a string, or a func() string, or a func(string) string, or a value which can be coerced to a string via fmt.Sprintf.
Backtraces ¶
A Logger can be configured to write a backtrace to standard error stream at the point that a Log is being generated on a given line in a given go file, and at a Level >= the Level for populating the file/line PC info in the Record.
File and Line PC information in logs ¶
Each log Record will contain File and Line PC information if the Level == DEBUG or if Level >= populatePCLevel (which is WARNING by default but can be configured).
Flushing ¶
The framework has a timer that will flush each Handler when triggered. By default, the timer is triggered every 5 seconds. This can be configured.
Each Handle is expected to use a buffer to cache its output. When the buffer is full, it is flushed. Also, the framework timer will flush so that you always see log persisted within the timer schedule duration.
Whenever a Record with level NOTICE or higher is logged, the system flushes immediately.
Framework Initialization ¶
The logging framework is typically initialized by the running application ie early in its main method.
To make this easier, the logging framework provides an initialization function taking Config objects that can be configured via json.
The first time that a LogRecord is to be published, it will ensure that the logging framework is initialized. If it was not initialized apriori, then it is initialized to have a single Handler that writes a single human readable line for each log record with minimum level of NOTICE (can be configured).
Note that this affect the whole process.
Framework Runtime ¶
At startup, logging is closed.
It must be started explicitly by calling logging.Open().
Default Configuration ¶
By default, the logging framework is configured with:
- FlushInterval: 5 seconds - BufferSize: 32KB (max of 1MB) - PopulatePCLevel: WARNING - MinLevel: NOTICE - SubsystemFunc: func(context.Context, string)
Levels based on syslog ¶
The levels are roughly model'ed after syslog. We however omit ALERT and EMERGENCY, as we expect these are just finer forms of a SEVERE issue, and developers typically cannot separate the two.
We include ALWAYS and OFF for configuration of MinimumLogLevel only. This way, it is easy to configure that ALL records should be logged, or no records should be logged.
Context ¶
All the logging methods (.Trace, .Debug, .Info, etc) take a Context as the first parameter.
This allows us grab information from the context where appropriate e.g. App Engine, HTTP Request, etc.
Debugging ¶
By default, we include the program counter file/line info when logging at DEBUG level and at >= WARNING level. The WARNING level can be configured.
Typical Usage ¶
Initialization:
logging.Addhandler(...)... logging.Addhandler("", ...) logging.AddLogger("", ...) logging.Open(...) // ... logging.Close()
Usage:
// make log a package-level variable var log = logging.PkgLogger() // Use these within your function calls log.Info(ctx, formatString, params...) log.Info(nil, formatString, params...)
Index ¶
- Variables
- func AddHandler(name string, f Handler) (err error)
- func AddLogger(name string, minLevel Level, backtraces []Backtrace, handlerNames []string)
- func BasicInit(names []string, c Config) (err error)
- func Close() error
- func Flush() error
- func NewHandlerFile(fname string, fmter Formatter, ff Filter) (h *handlerWriter)
- func NewHandlerWriter(w io.Writer, fmter Formatter, ff Filter) (h *handlerWriter)
- func Open(c Config) error
- func Reopen() error
- type Backtrace
- type CSVFormatter
- type Config
- type Filter
- type FilterFunc
- type Flags
- type Formatter
- type Handler
- type HandlerFunc
- type HumanFormatter
- type JSONFormatter
- type Level
- type Logger
- func (l *Logger) Debug(ctx context.Context, message string, params ...interface{})
- func (l *Logger) Error(ctx context.Context, message string, params ...interface{})
- func (l *Logger) IfError(ctx context.Context, err error, message string, params ...interface{}) error
- func (l *Logger) Info(ctx context.Context, message string, params ...interface{})
- func (l *Logger) Log(ctx context.Context, calldepth uint8, level Level, message string, ...) error
- func (l *Logger) Notice(ctx context.Context, message string, params ...interface{})
- func (l *Logger) Severe(ctx context.Context, message string, params ...interface{})
- func (l *Logger) Warning(ctx context.Context, message string, params ...interface{})
- type Noop
- type Record
Constants ¶
This section is empty.
Variables ¶
var ( FilterRejectedErr = errorutil.String("logging: log level lower than logger threshold") EmptyMessageErr = errorutil.String("logging: empty message") NoWriterForHandlerErr = errorutil.String("logging: no writer for handler") OnlyOneStderrHandlerErr = errorutil.String("logging: only one stderr handler can exist") OnlyOneStdoutHandlerErr = errorutil.String("logging: only one stdout handler can exist") )
var AppContextKey = new(int)
AppContextKey is the context.Context key used to store an app.Context
var CorrelationIDContextKey = new(int)
CorrelationIDContextKey is the context.Context key used to track multiple records as part of a request flow
var ErrorContextKey = new(int)
ErrorContextKey is the context.Context key used to store an error
var HTTPRequestContextKey = new(int)
HTTPRequestKey is the context.Context key used to store a http.Request (clone)
var SubsystemExtraContextKey = new(int)
SubsystemExtraContextKey is the context.Context key used to obtain a subsystem prefix.
Different SubsystemFunc can handle it differently. By default, the value retrieved is a value which can be coerced to a string. e.g. func() string, func(string) string, a string, or any value passed to fmt.Sprintf("%v", v)
Functions ¶
func AddHandler ¶
AddHandler will bind a handler to a given name, iff no handler is bound to that name.
Note that a Handler is bound one time only.
func AddLogger ¶
AddLogger will register a Logger for a given name if not existing.
If name="" and it is not bound to any logger, it is created and will serve as default for minLevel and handlerNames for loggers not explicitly added.
func BasicInit ¶
BasicInit is used to simply initialize the logging subsystem.
It creates a Handler for each name, logging using the HumanFormatter.
- If the name is "" or <stderr>, then it logs to standard error stream
- Else If the name is <stdout>, then it logs to standard output stream
- Else it logs to a file with the name given
func NewHandlerFile ¶
NewHandlerFile returns an un-opened handler.
func NewHandlerWriter ¶
NewHandlerWriter returns an un-opened handler.
Types ¶
type CSVFormatter ¶
type CSVFormatter struct{}
type Config ¶
type Config struct { FlushInterval time.Duration BufferSize int MinLevel Level PopulatePCLevel Level SubsystemFunc func(ctx context.Context, name string) string }
func (*Config) CopySanitize ¶
type FilterFunc ¶
func FilterByLevel ¶
func FilterByLevel(level Level) FilterFunc
type Formatter ¶
type Formatter interface { // Format will write the record into the writer. // // It ensures that a new record can be written right after. // Consequently, where appropriate, new lines or other record separators may be written // after each record. Format(ctx context.Context, r *Record, seqId string, w io.Writer) error }
type HandlerFunc ¶
func (HandlerFunc) Close ¶
func (f HandlerFunc) Close() error
func (HandlerFunc) Filter ¶
func (f HandlerFunc) Filter() Filter
func (HandlerFunc) Flush ¶
func (f HandlerFunc) Flush() error
func (HandlerFunc) Open ¶
func (f HandlerFunc) Open(buffer uint16) error
type HumanFormatter ¶
type HumanFormatter struct {
ANSIColor bool
}
type JSONFormatter ¶
type JSONFormatter struct{}
type Level ¶
type Level uint8
Level is an int representing the log levels.
The levels are roughly model'ed around syslog.
const ( DEBUG Level = 100 + iota // Debug or trace information. INFO // Routine information, such as ongoing status or performance NOTICE // Normal but significant events, such as start up, shut down, config WARNING // Warning events might cause problems ERROR // Error events are likely to cause problems SEVERE // Critical events cause more severe problems or brief outages ALWAYS Level = 1 // Config only: specify that ALL messages are logged OFF Level = math.MaxUint8 // Config only: specify that NO messages are logged )
func ParseLevel ¶
func (*Level) CodecDecodeSelf ¶
func (Level) CodecEncodeSelf ¶
func (Level) ShortString ¶
type Logger ¶
type Logger struct {
// contains filtered or unexported fields
}
func NamedLogger ¶
func (*Logger) Error ¶
Error will log a message at ERROR level.
If the last parameter is a non-nil error value, it will be presented specially to the Handlers for possible special consideration.
func (*Logger) IfError ¶
func (l *Logger) IfError(ctx context.Context, err error, message string, params ...interface{}) error
IfError logs at ERROR level iff err IS NOT nil. It is a no-op if err is nil.
func (*Logger) Log ¶
func (l *Logger) Log(ctx context.Context, calldepth uint8, level Level, message string, params ...interface{}) error
Log is the all-encompassing function that can be used by helper log functions in packages without losing caller positon.
A nil *Logger does nothing - equivalent to a no-op.
Example:
func logT(message string, params ...interface{}) { logging.Log(nil, 1, level.TRACE, message, params...) }