mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-23 06:40:23 +00:00
158 lines
8.0 KiB
Go
158 lines
8.0 KiB
Go
|
// Package flume is a logging package, build on top of zap. It's structured and leveled logs, like zap/logrus/etc.
|
||
|
// It adds global, runtime re-configuration of all loggers, via an internal logger registry.
|
||
|
//
|
||
|
// There are two interaction points with flume: code that generates logs, and code that configures logging output.
|
||
|
// Code which generates logs needs to create named logger instances, and call log functions on it, like Info()
|
||
|
// and Debug(). But by default, all these logs will be silently discarded. Flume does not output
|
||
|
// log entries unless explicitly told to do so. This ensures libraries can freely use flume internally, without
|
||
|
// polluting the stdout of the programs importing the library.
|
||
|
//
|
||
|
// The Logger type is a small interface. Libraries should allow replacement of their Logger instances so
|
||
|
// importers can entirely replace flume if they wish. Alternately, importers can use flume to configure
|
||
|
// the library's log output, and/or redirect it into the overall program's log stream.
|
||
|
//
|
||
|
// Logging
|
||
|
//
|
||
|
// This package does not offer package level log functions, so you need to create a logger instance first:
|
||
|
// A common pattern is to create a single, package-wide logger, named after the package:
|
||
|
//
|
||
|
// var log = flume.New("mypkg")
|
||
|
//
|
||
|
// Then, write some logs:
|
||
|
//
|
||
|
// log.Debug("created user", "username", "frank", "role", "admin")
|
||
|
//
|
||
|
// Logs have a message, then matched pairs of key/value properties. Child loggers can be created
|
||
|
// and pre-seeded with a set of properties:
|
||
|
//
|
||
|
// reqLogger := log.With("remoteAddr", req.RemoteAddr)
|
||
|
//
|
||
|
// Expensive log events can be avoid by explicitly checking level:
|
||
|
//
|
||
|
// if log.IsDebug() {
|
||
|
// log.Debug("created resource", "resource", resource.ExpensiveToString())
|
||
|
// }
|
||
|
//
|
||
|
// Loggers can be bound to context.Context, which is convenient for carrying
|
||
|
// per-transaction loggers (pre-seeded with transaction specific context) through layers of request
|
||
|
// processing code:
|
||
|
//
|
||
|
// ctx = flume.WithLogger(ctx, log.With("transactionID", tid))
|
||
|
// // ...later...
|
||
|
// flume.FromContext(ctx).Info("Request handled.")
|
||
|
//
|
||
|
// The standard Logger interface only supports 3 levels of log, DBG, INF, and ERR. This is inspired by
|
||
|
// this article: https://dave.cheney.net/2015/11/05/lets-talk-about-logging. However, you can create
|
||
|
// instances of DeprecatedLogger instead, which support more levels.
|
||
|
//
|
||
|
// Configuration
|
||
|
//
|
||
|
// There are several package level functions which reconfigure logging output. They control which
|
||
|
// levels are discarded, which fields are included in each log entry, and how those fields are rendered,
|
||
|
// and how the overall log entry is rendered (JSON, LTSV, colorized, etc).
|
||
|
//
|
||
|
// To configure logging settings from environment variables, call the configuration function from main():
|
||
|
//
|
||
|
// flume.ConfigFromEnv()
|
||
|
//
|
||
|
// This reads the log configuration from the environment variable "FLUME" (the default, which can be
|
||
|
// overridden). The value is JSON, e.g.:
|
||
|
//
|
||
|
// {"level":"INF","levels":"http=DBG","development"="true"}
|
||
|
//
|
||
|
// The properties of the config string:
|
||
|
//
|
||
|
// - "level": ERR, INF, or DBG. The default level for all loggers.
|
||
|
// - "levels": A string configuring log levels for specific loggers, overriding the default level.
|
||
|
// See note below for syntax.
|
||
|
// - "development": true or false. In development mode, the defaults for the other
|
||
|
// settings change to be more suitable for developers at a terminal (colorized, multiline, human
|
||
|
// readable, etc). See note below for exact defaults.
|
||
|
// - "addCaller": true or false. Adds call site information to log entries (file and line).
|
||
|
// - "encoding": json, ltsv, term, or term-color. Configures how log entries are encoded in the output.
|
||
|
// "term" and "term-color" are multi-line, human-friendly
|
||
|
// formats, intended for terminal output.
|
||
|
// - "encoderConfig": a JSON object which configures advanced encoding settings, like how timestamps
|
||
|
// are formatted. See docs for go.uber.org/zap/zapcore/EncoderConfig
|
||
|
//
|
||
|
// - "messageKey": the label of the message property of the log entry. If empty, message is omitted.
|
||
|
// - "levelKey": the label of the level property of the log entry. If empty, level is omitted.
|
||
|
// - "timeKey": the label of the timestamp of the log entry. If empty, timestamp is omitted.
|
||
|
// - "nameKey": the label of the logger name in the log entry. If empty, logger name is omitted.
|
||
|
// - "callerKey": the label of the logger name in the log entry. If empty, logger name is omitted.
|
||
|
// - "lineEnding": the end of each log output line.
|
||
|
// - "levelEncoder": capital, capitalColor, color, lower, or abbr. Controls how the log entry level
|
||
|
// is rendered. "abbr" renders 3-letter abbreviations, like ERR and INF.
|
||
|
// - "timeEncoder": iso8601, millis, nanos, unix, or justtime. Controls how timestamps are rendered.
|
||
|
// "millis", "nanos", and "unix" are since UNIX epoch. "unix" is in floating point seconds.
|
||
|
// "justtime" omits the date, and just prints the time in the format "15:04:05.000".
|
||
|
// - "durationEncoder": string, nanos, or seconds. Controls how time.Duration values are rendered.
|
||
|
// - "callerEncoder": full or short. Controls how the call site is rendered.
|
||
|
// "full" includes the entire package path, "short" only includes the last folder of the package.
|
||
|
//
|
||
|
// Defaults:
|
||
|
//
|
||
|
// {
|
||
|
// "level":"INF",
|
||
|
// "levels":"",
|
||
|
// "development":false,
|
||
|
// "addCaller":false,
|
||
|
// "encoding":"term-color",
|
||
|
// "encoderConfig":{
|
||
|
// "messageKey":"msg",
|
||
|
// "levelKey":"level",
|
||
|
// "timeKey":"time",
|
||
|
// "nameKey":"name",
|
||
|
// "callerKey":"caller",
|
||
|
// "lineEnding":"\n",
|
||
|
// "levelEncoder":"abbr",
|
||
|
// "timeEncoder":"iso8601",
|
||
|
// "durationEncoder":"seconds",
|
||
|
// "callerEncoder":"short",
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// These defaults are only applied if one of the configuration functions is called, like ConfigFromEnv(), ConfigString(),
|
||
|
// Configure(), or LevelsString(). Initially, all loggers are configured to discard everything, following
|
||
|
// flume's opinion that log packages should be silent unless spoken too. Ancillary to this: library packages
|
||
|
// should *not* call these functions, or configure logging levels or output in anyway. Only program entry points,
|
||
|
// like main() or test code, should configure logging. Libraries should just create loggers and log to them.
|
||
|
//
|
||
|
// Development mode: if "development"=true, the defaults for the rest of the settings change, equivalent to:
|
||
|
//
|
||
|
// {
|
||
|
// "addCaller":true,
|
||
|
// "encoding":"term-color",
|
||
|
// "encodingConfig": {
|
||
|
// "timeEncoder":"justtime",
|
||
|
// "durationEncoder":"string",
|
||
|
// }
|
||
|
// }
|
||
|
//
|
||
|
// The "levels" value is a list of key=value pairs, configuring the level of individual named loggers.
|
||
|
// If the key is "*", it sets the default level. If "level" and "levels" both configure the default
|
||
|
// level, "levels" wins.
|
||
|
// Examples:
|
||
|
//
|
||
|
// * // set the default level to ALL, equivalent to {"level"="ALL"}
|
||
|
// *=INF // same, but set default level to INF
|
||
|
// *,sql=WRN // set default to ALL, set "sql" logger to WRN
|
||
|
// *=INF,http=ALL // set default to INF, set "http" to ALL
|
||
|
// *=INF,http // same as above. If name has no level, level is set to ALL
|
||
|
// *=INF,-http // set default to INF, set "http" to OFF
|
||
|
// http=INF // leave default setting unchanged.
|
||
|
//
|
||
|
// Factories
|
||
|
//
|
||
|
// Most usages of flume will use its package functions. The package functions delegate to an internal
|
||
|
// instance of Factory, which a the logger registry. You can create and manage your own instance of
|
||
|
// Factory, which will be an isolated set of Loggers.
|
||
|
//
|
||
|
// tl;dr
|
||
|
//
|
||
|
// The implementation is a wrapper around zap. zap does levels, structured logs, and is very fast.
|
||
|
// zap doesn't do centralized, global configuration, so this package
|
||
|
// adds that by maintaining an internal registry of all loggers, and using the sync.atomic stuff to swap out
|
||
|
// levels and writers in a thread safe way.
|
||
|
package flume
|