Documentation
¶
Overview ¶
Package multilogger is a thin wrapper around logrus https://github.com/sirupsen/logrus that writes logs simultaneously to many outputs at the same time. Each output (implemented as Hook) have their own logging level. It exposes the same API as a regular logrus logger.
How to use it ¶
So, you can use multilogger to write logs to standard error with a minimal logging level (i.e. WarningLevel) and have the full debug log (i.e. DebugLevel or TraceLevel) written to a file.
import "github.com/coveooss/multilogger"
import "github.com/sirupsen/logrus"
func main() {
log := New("test") // By default, logs are sent to stderr and the logging level is set to WarningLevel
log.AddHooks(NewFileHook("debug.log", logrus.DebugLevel)) // It is possible to add a file as a target for the logs
log.AddHooks(NewFileHook("verbose.log", "trace")) // The logging level could be expressed as string, logrus.Level or int
log.Warning("This is a warning")
log.Infof("This is an information %s", message)
}
Differences with logrus
- The multilogger object is based on a logrus.Entry instead of a logrus.Logger.
- The methods Print, Println and Printf are used to print information directly to stdout without log decoration. Within logrus, these methods are aliases to Info, Infoln and Infof.
- It is not possible to set the global logging level with multilogger, the logging level is determined by hooks that are added to the logging object and the resulting logging level is the highest logging level defined for individual hooks.
- Hooks are fired according to their own logging level while they were fired according to the global logging level with logrus.
- The default formatter used by console and file hook is highly customizable.
Where is it used ¶
This project is used in other Coveo projects to reduce visual clutter in CI systems while keeping debug logs available when errors arise:
gotemplate https://github.com/coveooss/gotemplate terragrunt https://github.com/coveooss/terragrunt tgf https://github.com/coveooss/tgf
Index ¶
- Constants
- func AcceptedLevels() []string
- func AcceptedLevelsString() string
- func FormatDuration(duration time.Duration) string
- func ParseBool(value string) bool
- func ParseLogLevel(level interface{}) logrus.Level
- func TryParseLogLevel(level interface{}) (logrus.Level, error)
- type Formatter
- type Hook
- func (hook *Hook) Fire(entry *logrus.Entry) error
- func (hook *Hook) Formatter() *Formatter
- func (hook *Hook) GetFormatter() logrus.Formatter
- func (hook *Hook) GetInnerHook() logrus.Hook
- func (hook *Hook) Levels() []logrus.Level
- func (hook *Hook) SetColor(color bool) *Hook
- func (hook *Hook) SetFormat(formats ...interface{}) *Hook
- func (hook *Hook) SetFormatter(formatter logrus.Formatter) *Hook
- func (hook *Hook) SetOut(out io.Writer) *Hook
- func (hook *Hook) SetStdout(out io.Writer) *Hook
- type Logger
- func (logger *Logger) AddConsole(name string, level interface{}, format ...interface{}) *Logger
- func (logger *Logger) AddError(err error)
- func (logger *Logger) AddFile(filename string, level interface{}, format ...interface{}) *Logger
- func (logger *Logger) AddHook(name string, level interface{}, hook logrus.Hook) *Logger
- func (logger *Logger) AddHooks(hooks ...*Hook) *Logger
- func (logger *Logger) AddTime(duration time.Duration) *Logger
- func (logger *Logger) Child(child string) *Logger
- func (logger *Logger) ClearError() error
- func (logger *Logger) Close() error
- func (logger *Logger) Copy(module ...string) *Logger
- func (logger *Logger) Formatter() (result *Formatter)
- func (logger *Logger) GetDefaultConsoleHook() *Hook
- func (logger *Logger) GetDefaultConsoleHookLevel() logrus.Level
- func (logger *Logger) GetDefaultInnerHook() (result logrus.Hook)
- func (logger *Logger) GetError() error
- func (logger *Logger) GetFormatter() (result logrus.Formatter)
- func (logger *Logger) GetHookLevel(name string) logrus.Level
- func (logger *Logger) GetLevel() logrus.Level
- func (logger *Logger) GetModule() string
- func (logger *Logger) Hook(name string) *Hook
- func (logger *Logger) IsLevelEnabled(level logrus.Level) bool
- func (logger *Logger) ListHooks() []string
- func (logger *Logger) Print(args ...interface{})
- func (logger *Logger) Printf(format string, args ...interface{})
- func (logger *Logger) Println(args ...interface{})
- func (logger *Logger) RemoveHook(name string) *Logger
- func (logger *Logger) SetAllOutputs(out io.Writer) *Logger
- func (logger *Logger) SetColor(color bool) *Logger
- func (logger *Logger) SetDefaultConsoleHookLevel(level interface{}) error
- func (logger *Logger) SetExitFunc(exitFunc func(int))
- func (logger *Logger) SetFormat(formats ...interface{}) *Logger
- func (logger *Logger) SetFormatter(formatter logrus.Formatter) *Logger
- func (logger *Logger) SetHookLevel(name string, level interface{}) error
- func (logger *Logger) SetModule(module string) *Logger
- func (logger *Logger) SetOut(out io.Writer) *Logger
- func (logger *Logger) SetReportCaller(reportCaller bool) *Logger
- func (logger *Logger) SetStdout(out io.Writer) *Logger
- func (logger *Logger) TryAddHook(name string, level interface{}, hook logrus.Hook) (*Logger, error)
- func (logger *Logger) WithContext(ctx context.Context) *Logger
- func (logger *Logger) WithField(key string, value interface{}) *Logger
- func (logger *Logger) WithFields(fields logrus.Fields) *Logger
- func (logger *Logger) WithTime(time time.Time) *Logger
- func (logger *Logger) Write(writeBuffer []byte) (int, error)
Examples ¶
Constants ¶
const ( // CallerEnvVar is an environment variable that enable the caller stack by default. CallerEnvVar = "MULTILOGGER_CALLER" // FormatEnvVar is an environment variable that allows users to set the default format used for log entry. FormatEnvVar = "MULTILOGGER_FORMAT" // FormatFileEnvVar is an environment variable that allows users to set the default format used for log entry using a file logger. FormatFileEnvVar = "MULTILOGGER_FILE_FORMAT" // DefaultFileFormat is the format used by NewFileHook if neither MULTILOGGER_FORMAT or MULTILOGGER_FILE_FORMAT are set. DefaultFileFormat = "%module:SquareBrackets,IgnoreEmpty,Space%%time% %-8level:upper% %message%" )
const (
// DefaultConsoleFormat is the format used by NewConsoleHook if MULTILOGGER_FORMAT is not set.
DefaultConsoleFormat = "%module:Italic,Green,SquareBrackets,IgnoreEmpty,Space%%time% %-8level:upper,color% %message:color%"
)
const ( // DisabledLevel can be set when one of the logging hooks should be disabled. DisabledLevel logrus.Level = math.MaxUint32 )
Variables ¶
This section is empty.
Functions ¶
func AcceptedLevels ¶
func AcceptedLevels() []string
AcceptedLevels returns all accepted logrus levels.
func AcceptedLevelsString ¶
func AcceptedLevelsString() string
AcceptedLevelsString returns all accepted logrus levels as a comma-separated string.
func FormatDuration ¶ added in v0.2.0
FormatDuration returns a string to represent the duration.
func ParseBool ¶ added in v0.2.0
ParseBool returns true for any value that is set and is not clearly a false. It never returns an error.
True values are: 1, t, true, yes, y, on (of any non false value) False values are: 0, f, false, no, n, off
func ParseLogLevel ¶
ParseLogLevel converts a string or number into a logging level. It panics if the supplied valid cannot be converted into a valid logrus Level.
func TryParseLogLevel ¶ added in v0.2.0
TryParseLogLevel converts a string or number into a logging level.
Types ¶
type Formatter ¶ added in v0.1.1
type Formatter struct {
// Available standard keys: time, delay, globaldelay, delta, message, level, module, file, line, func.
// Also can include custom fields but limited to strings.
// All of fields need to be wrapped inside %% i.e %time% %message%
TimestampFormat string
FormatDuration func(time.Duration) string
FormatCaller func(*runtime.Frame) string
// ColorMap allows user to define the color attributes associated with the error level.
// Attribute names are defined by http://github.com/fatih/color
ColorMap map[logrus.Level][]multicolor.Attribute
// LevelName allows user to rename default level name.
LevelName map[logrus.Level]string
// contains filtered or unexported fields
}
Formatter implements logrus.Formatter interface.
func NewFormatter ¶ added in v0.2.0
NewFormatter creates a new formatter with color setting and takes the first defined format string as the log format.
func (*Formatter) SetLogFormat ¶ added in v0.2.0
SetLogFormat initialize the log format with the first defined format in the list.
type Hook ¶ added in v0.2.0
type Hook struct {
// contains filtered or unexported fields
}
Hook represents a hook that logs at a given level. This struct must be extended to implement the Fire func.
func NewConsoleHook ¶
NewConsoleHook creates a new hook to log information to console (default to stderr).
level: Accept any kind of object, but must be resolvable into a valid logrus level name.
func NewFileHook ¶
NewFileHook creates a new hook to log information into a file.
level: Accept any kind of object, but must be resolvable into a valid logrus level name.
func NewHook ¶ added in v0.2.0
NewHook generates a named hook wrapper that is able the handle its own logging level.
level: Accept any kind of object, but must be resolvable into a valid logrus level name.
func (*Hook) Formatter ¶ added in v0.2.0
Formatter returns the Formatter associated to the hook. The function will panic if called upon a hook that do not support formatter.
func (*Hook) GetFormatter ¶ added in v0.2.0
GetFormatter returns the formater associated to the hook. The function will panic if called upon a hook that do not support formatter.
func (*Hook) GetInnerHook ¶ added in v0.3.0
GetInnerHook returns the inner hook actually used by the leveled hook.
func (*Hook) SetColor ¶ added in v0.2.0
SetColor allows setting color mode on hook that support it. The function will panic if called upon a hook that do not support formatter.
func (*Hook) SetFormat ¶ added in v0.2.0
SetFormat allows setting a format string on hook that support it. The function will panic if called upon a hook that do not support formatter.
func (*Hook) SetFormatter ¶ added in v0.2.0
SetFormatter allows setting a formatter on hook that support it. The function will panic if called upon a hook that do not support formatter.
type Logger ¶ added in v0.2.0
type Logger struct {
*logrus.Entry
PrintLevel logrus.Level
Catcher bool
// contains filtered or unexported fields
}
Logger represents a logger that logs to both a file and the console at different (configurable) levels.
func New ¶
New creates a new Multilogger instance. If no hook is provided, it defaults to standard console logger at warning log level.
Example (Default) ¶
log := getTestLogger("default")
log.Warning("This is a warning")
log.Println("The logging level is set to", log.GetLevel())
log.Printf("Module = %s\n", log.GetModule())
Output: [default] 2018/06/24 12:34:56.789 WARNING This is a warning The logging level is set to warning Module = default
Example (Log_catcher) ¶
log := getTestLogger("catcher", logrus.TraceLevel)
cmd := exec.Command("cat")
stdin, _ := cmd.StdinPipe()
cmd.Stdout, cmd.Stderr = log, log
cmd.Start()
lines := []string{
"Hello,",
"",
"This is a text that contains:",
"[Error] Oops! there is an error",
"This should be considered as a [warning] message",
"This should go directly to output",
}
for _, line := range lines {
io.WriteString(stdin, line+"\n")
}
stdin.Close()
cmd.Wait()
Output: Hello, This is a text that contains: [catcher] 2018/06/24 12:34:56.789 ERROR Oops! there is an error [catcher] 2018/06/24 12:34:56.789 WARNING This should be considered as a warning message This should go directly to output
Example (Log_catcher_disabled) ¶
log := getTestLogger("catcher", logrus.TraceLevel)
// We disable the log catcher.
log.Catcher = false
fmt.Fprintln(log, "Hello,")
fmt.Fprintln(log)
fmt.Fprintln(log, "This is a text that contains:")
fmt.Fprintln(log, "[Error] Oops! there is an error")
fmt.Fprintln(log, "This should be considered as a [warning] message")
fmt.Fprintln(log, "This should go directly to output")
Output: Hello, This is a text that contains: [Error] Oops! there is an error This should be considered as a [warning] message This should go directly to output
Example (Output_sent_to_info) ¶
log := getTestLogger("catcher", logrus.TraceLevel)
// We send all regular text to the InfoLevel.
log.PrintLevel = logrus.InfoLevel
fmt.Fprintln(log, "This is a text that contains:")
fmt.Fprintln(log, "[Error] Oops! there is an error")
fmt.Fprintln(log, "This should be considered as a [warning] message")
fmt.Fprintln(log, "This should go directly to output")
Output: [catcher] 2018/06/24 12:34:56.789 INFO This is a text that contains: [catcher] 2018/06/24 12:34:56.789 ERROR Oops! there is an error [catcher] 2018/06/24 12:34:56.789 WARNING This should be considered as a warning message [catcher] 2018/06/24 12:34:56.789 INFO This should go directly to output
Example (SettingLoggingLevel) ¶
// Logging level could be set by explicitely declaring the hook
log := New("console", NewConsoleHook("", logrus.InfoLevel))
log.Println("The logging level is set to", log.GetLevel())
// Or it can also be set after initializing the logger
// It is possible to use either a logrus.Level or a string to specify the level
log = New("console")
log.SetHookLevel("", "trace")
log.Println("The logging level is set to", log.GetLevel())
Output: The logging level is set to info The logging level is set to trace
func (*Logger) AddConsole ¶ added in v0.2.0
AddConsole adds a console hook to the current logger.
Example ¶
log := getTestLogger("json")
// We add an additional console hook.
log.AddConsole("json", logrus.WarnLevel, new(logrus.JSONFormatter))
log.Warning("New JSON log")
Output: [json] 2018/06/24 12:34:56.789 WARNING New JSON log {"level":"warning","module-field":"json","msg":"New JSON log","time":"2018-06-24T12:34:56Z"}
Example (Overwrite) ¶
log := getTestLogger("json")
// We overwrite the default console hook by not specifying a name to our new console.
// We also set the JSON formatter to pretty format the JSON code.
log.AddConsole("", logrus.WarnLevel, &logrus.JSONFormatter{PrettyPrint: true})
log.Warning("New JSON log")
Output: { "level": "warning", "module-field": "json", "msg": "New JSON log", "time": "2018-06-24T12:34:56Z" }
func (*Logger) AddError ¶ added in v0.2.0
AddError let functions to add error to the current logger indicating that something went wrong in the logging process.
func (*Logger) AddFile ¶ added in v0.2.0
AddFile adds a file hook to the current logger.
Example ¶
log := getTestLogger("file")
var logfile string
if temp, err := ioutil.TempFile("", "example"); err != nil {
log.Fatal(err)
} else {
logfile = temp.Name()
defer os.Remove(logfile)
}
log.AddFile(logfile, logrus.TraceLevel)
log.Info("This is information")
log.Warning("This is a warning")
content, _ := ioutil.ReadFile(logfile)
fmt.Println("Content of the log file is:")
fmt.Println(string(content))
Output: [file] 2018/06/24 12:34:56.789 WARNING This is a warning Content of the log file is: # 2018/06/24 12:34:56.789 [file] 2018/06/24 12:34:56.789 INFO This is information [file] 2018/06/24 12:34:56.789 WARNING This is a warning
func (*Logger) AddHook ¶ added in v0.2.0
AddHook adds a hook to the hook collection and associated it with a name and a level. Can also be used to replace an existing hook.
func (*Logger) AddHooks ¶ added in v0.2.0
AddHooks adds a collection of hook wrapper as hook to the current logger.
func (*Logger) AddTime ¶ added in v0.2.0
AddTime add the specified duration to the current logger if its time has been freezed. Useful for testing.
Example ¶
log := getTestLogger("time", "Trace")
// We can create a logger with a fix moment in time.
t, _ := time.Parse(time.RFC3339, "2020-12-25T00:00:00Z")
log = log.WithTime(t)
log.Info("Log from fixed time")
log.AddTime(5 * time.Second).Trace("Log 5 seconds later")
log.AddTime(8 * time.Millisecond).Warning("Log 8 more milliseconds later")
Output: [time] 2020/12/25 00:00:00.000 INFO Log from fixed time [time] 2020/12/25 00:00:05.000 TRACE Log 5 seconds later [time] 2020/12/25 00:00:05.008 WARNING Log 8 more milliseconds later
func (*Logger) Child ¶ added in v0.2.0
Child clones the logger, appending the child's name to the parent's module name.
Example ¶
log := getTestLogger("original", logrus.TraceLevel)
log.Info("Log from original")
log.Child("1").Trace("Log from first child")
log.Child("2").Trace("Log from second child")
Output: [original] 2018/06/24 12:34:56.789 INFO Log from original [original:1] 2018/06/24 12:34:56.789 TRACE Log from first child [original:2] 2018/06/24 12:34:56.789 TRACE Log from second child
func (*Logger) ClearError ¶ added in v0.2.0
ClearError cleans up the current error state of the logging process. It also returns the current error state.
func (*Logger) Copy ¶ added in v0.2.0
Copy returns a new logger with the same hooks but a different module name. module is optional, if not supplied, the original module name will copied. If many name are supplied, they are joined with a - separator.
Example ¶
log := getTestLogger("original", logrus.TraceLevel)
log.Info("Log from original")
log.Copy("copy").Trace("Log from copy")
log.Copy("").Debug("I have no module")
log.Copy().Debug("I have the same module as the original")
Output: [original] 2018/06/24 12:34:56.789 INFO Log from original [copy] 2018/06/24 12:34:56.789 TRACE Log from copy 2018/06/24 12:34:56.789 DEBUG I have no module [original] 2018/06/24 12:34:56.789 DEBUG I have the same module as the original
func (*Logger) Formatter ¶ added in v0.3.0
Formatter returns the Formatter associated to the default console hook.
func (*Logger) GetDefaultConsoleHook ¶ added in v0.3.0
GetDefaultConsoleHook returns the default console hook.
func (*Logger) GetDefaultConsoleHookLevel ¶ added in v0.3.0
GetDefaultConsoleHookLevel returns the logging level associated to the default console hook.
func (*Logger) GetDefaultInnerHook ¶ added in v0.3.0
GetDefaultInnerHook returns the inner hook actually used by the default console hook.
func (*Logger) GetError ¶ added in v0.2.0
GetError returns the current error state of the logging process.
func (*Logger) GetFormatter ¶ added in v0.3.0
GetFormatter returns the formater associated to the default console hook.
func (*Logger) GetHookLevel ¶ added in v0.2.0
GetHookLevel returns the logging level associated with a specific logger.
func (*Logger) GetLevel ¶ added in v0.2.0
GetLevel returns the highest logger level registered by the hooks.
func (*Logger) GetModule ¶ added in v0.2.0
GetModule returns the module name associated to the current logger.
func (*Logger) IsLevelEnabled ¶ added in v0.2.0
IsLevelEnabled checks if the log level of the logger is greater than the level param
func (*Logger) Print ¶ added in v0.2.0
func (logger *Logger) Print(args ...interface{})
Print acts as fmt.Print but sends the output to a special logging level that allows multiple output support through Hooks.
ATTENTION, default behaviour for logrus.Print is to log at Info level.
func (*Logger) Printf ¶ added in v0.2.0
Printf acts as fmt.Printf but sends the output to a special logging level that allows multiple output support through Hooks.
ATTENTION, default behaviour for logrus.Printf is to log at Info level.
func (*Logger) Println ¶ added in v0.2.0
func (logger *Logger) Println(args ...interface{})
Println acts as fmt.Println but sends the output to a special logging level that allows multiple output support through Hooks.
ATTENTION, default behaviour for logrus.Println is to log at Info level.
func (*Logger) RemoveHook ¶ added in v0.2.0
RemoveHook deletes a hook from the hook collection.
func (*Logger) SetAllOutputs ¶ added in v0.3.0
SetAllOutputs allows configuring the output and the logging stream on the default console hook if there is.
func (*Logger) SetColor ¶ added in v0.3.0
SetColor allows setting color mode on the default console hook if there is.
func (*Logger) SetDefaultConsoleHookLevel ¶ added in v0.3.0
SetDefaultConsoleHookLevel set a new log level for the default console hook.
func (*Logger) SetExitFunc ¶ added in v0.2.0
SetExitFunc let user define what should be executed when a logging call exit (default is call to os.Exit(int)).
func (*Logger) SetFormat ¶ added in v0.3.0
SetFormat allows setting a format string on the default console hook if there is.
func (*Logger) SetFormatter ¶ added in v0.3.0
SetFormatter allows setting a formatter to the default console hook if there is.
func (*Logger) SetHookLevel ¶ added in v0.2.0
SetHookLevel set a new log level for a registered hook.
func (*Logger) SetModule ¶ added in v0.3.0
SetModule sets the module name associated to the current logger.
func (*Logger) SetOut ¶ added in v0.3.0
SetOut allows configuring the logging stream on the default console hook if there is.
func (*Logger) SetReportCaller ¶ added in v0.2.0
SetReportCaller enables caller reporting to be added to each log entry.
func (*Logger) SetStdout ¶ added in v0.3.0
SetStdout allows configuring the output stream on the default console hook if there is.
func (*Logger) TryAddHook ¶ added in v0.2.0
TryAddHook adds a hook to the hook collection and associated it with a name and a level. Can also be used to replace an existing hook.
func (*Logger) WithContext ¶ added in v0.2.0
WithContext return a new logger with a new context.
func (*Logger) WithField ¶ added in v0.2.0
WithField return a new logger with a single additional entry.
Example ¶
log := getTestLogger("field", "Trace")
// We set the format of the log to include fields
log.SetFormat("%module:square% %time% %level:upper% %message% %fields%.")
// We create a new logger with additional context
log2 := log.WithField("hello", "world!").WithField("pi", math.Pi)
log.Info("No additional field")
log2.Info("With additional fields")
Output: [field] 2018/06/24 12:34:56.789 INFO No additional field . [field] 2018/06/24 12:34:56.789 INFO With additional fields hello=world! pi=3.141592653589793.
func (*Logger) WithFields ¶ added in v0.2.0
WithFields return a new logger with a new fields value.
Example ¶
log := getTestLogger("field", "Trace")
// We set the format of the log to include fields
log.SetFormat("%module:square% %time% %level:upper% %message% %fields%.")
// We create a new logger with additional context
log2 := log.WithFields(logrus.Fields{
"hello": "world!",
"pi": math.Pi,
})
log.Info("No additional field")
log2.Info("With additional fields")
Output: [field] 2018/06/24 12:34:56.789 INFO No additional field . [field] 2018/06/24 12:34:56.789 INFO With additional fields hello=world! pi=3.141592653589793.
func (*Logger) WithTime ¶ added in v0.2.0
WithTime return a new logger with a fixed time for log entry (useful for testing).
Example ¶
log := getTestLogger("time", logrus.InfoLevel)
// We can create a logger with a fix moment in time.
t, _ := time.Parse(time.RFC3339, "2020-12-25T00:00:00Z")
log = log.WithTime(t)
log.Info("Log from fixed time")
Output: [time] 2020/12/25 00:00:00.000 INFO Log from fixed time