diff options
Diffstat (limited to 'vendor/github.com/mattermost/mattermost-server/v6/shared/mlog')
6 files changed, 806 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/default.go b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/default.go new file mode 100644 index 00000000..0567c016 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/default.go @@ -0,0 +1,63 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package mlog + +import ( + "bytes" + "encoding/json" + "fmt" + "os" +) + +// defaultLog manually encodes the log to STDERR, providing a basic, default logging implementation +// before mlog is fully configured. +func defaultLog(level Level, msg string, fields ...Field) { + mFields := make(map[string]string) + buf := &bytes.Buffer{} + + for _, fld := range fields { + buf.Reset() + fld.ValueString(buf, shouldQuote) + mFields[fld.Key] = buf.String() + } + + log := struct { + Level string `json:"level"` + Message string `json:"msg"` + Fields map[string]string `json:"fields,omitempty"` + }{ + level.Name, + msg, + mFields, + } + + if b, err := json.Marshal(log); err != nil { + fmt.Fprintf(os.Stderr, `{"level":"error","msg":"failed to encode log message"}%s`, "\n") + } else { + fmt.Fprintf(os.Stderr, "%s\n", b) + } +} + +func defaultIsLevelEnabled(level Level) bool { + return true +} + +func defaultCustomMultiLog(lvl []Level, msg string, fields ...Field) { + for _, level := range lvl { + defaultLog(level, msg, fields...) + } +} + +// shouldQuote returns true if val contains any characters that require quotations. +func shouldQuote(val string) bool { + for _, c := range val { + if !((c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + c == '-' || c == '.' || c == '_' || c == '/' || c == '@' || c == '^' || c == '+') { + return true + } + } + return false +} diff --git a/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/global.go b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/global.go new file mode 100644 index 00000000..de346123 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/global.go @@ -0,0 +1,132 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package mlog + +import ( + "sync" +) + +var ( + globalLogger *Logger + muxGlobalLogger sync.RWMutex +) + +func InitGlobalLogger(logger *Logger) { + muxGlobalLogger.Lock() + defer muxGlobalLogger.Unlock() + + globalLogger = logger +} + +func getGlobalLogger() *Logger { + muxGlobalLogger.RLock() + defer muxGlobalLogger.RUnlock() + + return globalLogger +} + +// IsLevelEnabled returns true only if at least one log target is +// configured to emit the specified log level. Use this check when +// gathering the log info may be expensive. +// +// Note, transformations and serializations done via fields are already +// lazily evaluated and don't require this check beforehand. +func IsLevelEnabled(level Level) bool { + logger := getGlobalLogger() + if logger == nil { + return defaultIsLevelEnabled(level) + } + return logger.IsLevelEnabled(level) +} + +// Log emits the log record for any targets configured for the specified level. +func Log(level Level, msg string, fields ...Field) { + logger := getGlobalLogger() + if logger == nil { + defaultLog(level, msg, fields...) + return + } + logger.Log(level, msg, fields...) +} + +// LogM emits the log record for any targets configured for the specified levels. +// Equivalent to calling `Log` once for each level. +func LogM(levels []Level, msg string, fields ...Field) { + logger := getGlobalLogger() + if logger == nil { + defaultCustomMultiLog(levels, msg, fields...) + return + } + logger.LogM(levels, msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Trace` level. +func Trace(msg string, fields ...Field) { + logger := getGlobalLogger() + if logger == nil { + defaultLog(LvlTrace, msg, fields...) + return + } + logger.Trace(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Debug` level. +func Debug(msg string, fields ...Field) { + logger := getGlobalLogger() + if logger == nil { + defaultLog(LvlDebug, msg, fields...) + return + } + logger.Debug(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Info` level. +func Info(msg string, fields ...Field) { + logger := getGlobalLogger() + if logger == nil { + defaultLog(LvlInfo, msg, fields...) + return + } + logger.Info(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Warn` level. +func Warn(msg string, fields ...Field) { + logger := getGlobalLogger() + if logger == nil { + defaultLog(LvlWarn, msg, fields...) + return + } + logger.Warn(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Error` level. +func Error(msg string, fields ...Field) { + logger := getGlobalLogger() + if logger == nil { + defaultLog(LvlError, msg, fields...) + return + } + logger.Error(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Critical` level. +// DEPRECATED: Either use Error or Fatal. +func Critical(msg string, fields ...Field) { + logger := getGlobalLogger() + if logger == nil { + defaultLog(LvlCritical, msg, fields...) + return + } + logger.Critical(msg, fields...) +} + +func Fatal(msg string, fields ...Field) { + logger := getGlobalLogger() + if logger == nil { + defaultLog(LvlFatal, msg, fields...) + return + } + logger.Fatal(msg, fields...) +} diff --git a/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/levels.go b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/levels.go new file mode 100644 index 00000000..c0b30996 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/levels.go @@ -0,0 +1,58 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package mlog + +import "github.com/mattermost/logr/v2" + +// Standard levels. +var ( + LvlPanic = logr.Panic // ID = 0 + LvlFatal = logr.Fatal // ID = 1 + LvlError = logr.Error // ID = 2 + LvlWarn = logr.Warn // ID = 3 + LvlInfo = logr.Info // ID = 4 + LvlDebug = logr.Debug // ID = 5 + LvlTrace = logr.Trace // ID = 6 + StdAll = []Level{LvlPanic, LvlFatal, LvlError, LvlWarn, LvlInfo, LvlDebug, LvlTrace} + // non-standard "critical" level + LvlCritical = Level{ID: 7, Name: "critical"} + // used by redirected standard logger + LvlStdLog = Level{ID: 10, Name: "stdlog"} + // used only by the logger + LvlLogError = Level{ID: 11, Name: "logerror", Stacktrace: true} +) + +// Register custom (discrete) levels here. +// !!!!! Custom ID's must be between 20 and 32,768 !!!!!! +var ( + // used by the audit system + LvlAuditAPI = Level{ID: 100, Name: "audit-api"} + LvlAuditContent = Level{ID: 101, Name: "audit-content"} + LvlAuditPerms = Level{ID: 102, Name: "audit-permissions"} + LvlAuditCLI = Level{ID: 103, Name: "audit-cli"} + + // used by the TCP log target + LvlTCPLogTarget = Level{ID: 120, Name: "TcpLogTarget"} + + // used by Remote Cluster Service + LvlRemoteClusterServiceDebug = Level{ID: 130, Name: "RemoteClusterServiceDebug"} + LvlRemoteClusterServiceError = Level{ID: 131, Name: "RemoteClusterServiceError"} + LvlRemoteClusterServiceWarn = Level{ID: 132, Name: "RemoteClusterServiceWarn"} + + // used by Shared Channel Sync Service + LvlSharedChannelServiceDebug = Level{ID: 200, Name: "SharedChannelServiceDebug"} + LvlSharedChannelServiceError = Level{ID: 201, Name: "SharedChannelServiceError"} + LvlSharedChannelServiceWarn = Level{ID: 202, Name: "SharedChannelServiceWarn"} + LvlSharedChannelServiceMessagesInbound = Level{ID: 203, Name: "SharedChannelServiceMsgInbound"} + LvlSharedChannelServiceMessagesOutbound = Level{ID: 204, Name: "SharedChannelServiceMsgOutbound"} + + // Focalboard + LvlFBTelemetry = Level{ID: 9000, Name: "telemetry"} + LvlFBMetrics = Level{ID: 9001, Name: "metrics"} +) + +// Combinations for LogM (log multi). +var ( + MLvlAuditAll = []Level{LvlAuditAPI, LvlAuditContent, LvlAuditPerms, LvlAuditCLI} +) diff --git a/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/mlog.go b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/mlog.go new file mode 100644 index 00000000..ac56362c --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/mlog.go @@ -0,0 +1,419 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +// Package mlog provides a simple wrapper around Logr. +package mlog + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "strings" + "sync/atomic" + "time" + + "github.com/mattermost/logr/v2" + logrcfg "github.com/mattermost/logr/v2/config" +) + +const ( + ShutdownTimeout = time.Second * 15 + FlushTimeout = time.Second * 15 + DefaultMaxQueueSize = 1000 + DefaultMetricsUpdateFreqMillis = 15000 +) + +type LoggerIFace interface { + IsLevelEnabled(Level) bool + Debug(string, ...Field) + Info(string, ...Field) + Warn(string, ...Field) + Error(string, ...Field) + Critical(string, ...Field) + Log(Level, string, ...Field) + LogM([]Level, string, ...Field) +} + +// Type and function aliases from Logr to limit the spread of dependencies. +type Field = logr.Field +type Level = logr.Level +type Option = logr.Option +type Target = logr.Target +type TargetInfo = logr.TargetInfo +type LogRec = logr.LogRec +type LogCloner = logr.LogCloner +type MetricsCollector = logr.MetricsCollector +type TargetCfg = logrcfg.TargetCfg +type Sugar = logr.Sugar + +// LoggerConfiguration is a map of LogTarget configurations. +type LoggerConfiguration map[string]TargetCfg + +func (lc LoggerConfiguration) Append(cfg LoggerConfiguration) { + for k, v := range cfg { + lc[k] = v + } +} + +func (lc LoggerConfiguration) toTargetCfg() map[string]logrcfg.TargetCfg { + tcfg := make(map[string]logrcfg.TargetCfg) + for k, v := range lc { + tcfg[k] = v + } + return tcfg +} + +// Any picks the best supported field type based on type of val. +// For best performance when passing a struct (or struct pointer), +// implement `logr.LogWriter` on the struct, otherwise reflection +// will be used to generate a string representation. +var Any = logr.Any + +// Int64 constructs a field containing a key and Int64 value. +var Int64 = logr.Int64 + +// Int32 constructs a field containing a key and Int32 value. +var Int32 = logr.Int32 + +// Int constructs a field containing a key and Int value. +var Int = logr.Int + +// Uint64 constructs a field containing a key and Uint64 value. +var Uint64 = logr.Uint64 + +// Uint32 constructs a field containing a key and Uint32 value. +var Uint32 = logr.Uint32 + +// Uint constructs a field containing a key and Uint value. +var Uint = logr.Uint + +// Float64 constructs a field containing a key and Float64 value. +var Float64 = logr.Float64 + +// Float32 constructs a field containing a key and Float32 value. +var Float32 = logr.Float32 + +// String constructs a field containing a key and String value. +var String = logr.String + +// Stringer constructs a field containing a key and a fmt.Stringer value. +// The fmt.Stringer's `String` method is called lazily. +var Stringer = func(key string, s fmt.Stringer) logr.Field { + if s == nil { + return Field{Key: key, Type: logr.StringType, String: ""} + } + return Field{Key: key, Type: logr.StringType, String: s.String()} +} + +// Err constructs a field containing a default key ("error") and error value. +var Err = func(err error) logr.Field { + return NamedErr("error", err) +} + +// NamedErr constructs a field containing a key and error value. +var NamedErr = func(key string, err error) logr.Field { + if err == nil { + return Field{Key: key, Type: logr.StringType, String: ""} + } + return Field{Key: key, Type: logr.StringType, String: err.Error()} +} + +// Bool constructs a field containing a key and bool value. +var Bool = logr.Bool + +// Time constructs a field containing a key and time.Time value. +var Time = logr.Time + +// Duration constructs a field containing a key and time.Duration value. +var Duration = logr.Duration + +// Millis constructs a field containing a key and timestamp value. +// The timestamp is expected to be milliseconds since Jan 1, 1970 UTC. +var Millis = logr.Millis + +// Array constructs a field containing a key and array value. +var Array = logr.Array + +// Map constructs a field containing a key and map value. +var Map = logr.Map + +// Logger provides a thin wrapper around a Logr instance. This is a struct instead of an interface +// so that there are no allocations on the heap each interface method invocation. Normally not +// something to be concerned about, but logging calls for disabled levels should have as little CPU +// and memory impact as possible. Most of these wrapper calls will be inlined as well. +type Logger struct { + log *logr.Logger + lockConfig *int32 +} + +// NewLogger creates a new Logger instance which can be configured via `(*Logger).Configure`. +// Some options with invalid values can cause an error to be returned, however `NewLogger()` +// using just defaults never errors. +func NewLogger(options ...Option) (*Logger, error) { + options = append(options, logr.StackFilter(logr.GetPackageName("NewLogger"))) + + lgr, err := logr.New(options...) + if err != nil { + return nil, err + } + + log := lgr.NewLogger() + var lockConfig int32 + + return &Logger{ + log: &log, + lockConfig: &lockConfig, + }, nil +} + +// Configure provides a new configuration for this logger. +// Zero or more sources of config can be provided: +// cfgFile - path to file containing JSON +// cfgEscaped - JSON string probably from ENV var +// +// For each case JSON containing log targets is provided. Target name collisions are resolved +// using the following precedence: +// cfgFile > cfgEscaped +func (l *Logger) Configure(cfgFile string, cfgEscaped string) error { + if atomic.LoadInt32(l.lockConfig) != 0 { + return ErrConfigurationLock + } + + cfgMap := make(LoggerConfiguration) + + // Add config from file + if cfgFile != "" { + b, err := ioutil.ReadFile(cfgFile) + if err != nil { + return fmt.Errorf("error reading logger config file %s: %w", cfgFile, err) + } + + var mapCfgFile LoggerConfiguration + if err := json.Unmarshal(b, &mapCfgFile); err != nil { + return fmt.Errorf("error decoding logger config file %s: %w", cfgFile, err) + } + cfgMap.Append(mapCfgFile) + } + + // Add config from escaped json string + if cfgEscaped != "" { + var mapCfgEscaped LoggerConfiguration + if err := json.Unmarshal([]byte(cfgEscaped), &mapCfgEscaped); err != nil { + return fmt.Errorf("error decoding logger config as escaped json: %w", err) + } + cfgMap.Append(mapCfgEscaped) + } + + if len(cfgMap) == 0 { + return nil + } + + return logrcfg.ConfigureTargets(l.log.Logr(), cfgMap.toTargetCfg(), nil) +} + +// ConfigureTargets provides a new configuration for this logger via a `LoggerConfig` map. +// Typically `mlog.Configure` is used instead which accepts JSON formatted configuration. +func (l *Logger) ConfigureTargets(cfg LoggerConfiguration) error { + if atomic.LoadInt32(l.lockConfig) != 0 { + return ErrConfigurationLock + } + return logrcfg.ConfigureTargets(l.log.Logr(), cfg.toTargetCfg(), nil) +} + +// LockConfiguration disallows further configuration changes until `UnlockConfiguration` +// is called. The previous locked stated is returned. +func (l *Logger) LockConfiguration() bool { + old := atomic.SwapInt32(l.lockConfig, 1) + return old != 0 +} + +// UnlockConfiguration allows configuration changes. The previous locked stated is returned. +func (l *Logger) UnlockConfiguration() bool { + old := atomic.SwapInt32(l.lockConfig, 0) + return old != 0 +} + +// IsConfigurationLocked returns the current state of the configuration lock. +func (l *Logger) IsConfigurationLocked() bool { + return atomic.LoadInt32(l.lockConfig) != 0 +} + +// With creates a new Logger with the specified fields. This is a light-weight +// operation and can be called on demand. +func (l *Logger) With(fields ...Field) *Logger { + logWith := l.log.With(fields...) + return &Logger{ + log: &logWith, + lockConfig: l.lockConfig, + } +} + +// IsLevelEnabled returns true only if at least one log target is +// configured to emit the specified log level. Use this check when +// gathering the log info may be expensive. +// +// Note, transformations and serializations done via fields are already +// lazily evaluated and don't require this check beforehand. +func (l *Logger) IsLevelEnabled(level Level) bool { + return l.log.IsLevelEnabled(level) +} + +// Log emits the log record for any targets configured for the specified level. +func (l *Logger) Log(level Level, msg string, fields ...Field) { + l.log.Log(level, msg, fields...) +} + +// LogM emits the log record for any targets configured for the specified levels. +// Equivalent to calling `Log` once for each level. +func (l *Logger) LogM(levels []Level, msg string, fields ...Field) { + l.log.LogM(levels, msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Trace` level. +func (l *Logger) Trace(msg string, fields ...Field) { + l.log.Trace(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Debug` level. +func (l *Logger) Debug(msg string, fields ...Field) { + l.log.Debug(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Info` level. +func (l *Logger) Info(msg string, fields ...Field) { + l.log.Info(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Warn` level. +func (l *Logger) Warn(msg string, fields ...Field) { + l.log.Warn(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Error` level. +func (l *Logger) Error(msg string, fields ...Field) { + l.log.Error(msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Critical` level. +func (l *Logger) Critical(msg string, fields ...Field) { + l.log.Log(LvlCritical, msg, fields...) +} + +// Convenience method equivalent to calling `Log` with the `Fatal` level, +// followed by `os.Exit(1)`. +func (l *Logger) Fatal(msg string, fields ...Field) { + l.log.Log(logr.Fatal, msg, fields...) + _ = l.Shutdown() + os.Exit(1) +} + +// HasTargets returns true if at least one log target has been added. +func (l *Logger) HasTargets() bool { + return l.log.Logr().HasTargets() +} + +// StdLogger creates a standard logger backed by this logger. +// All log records are output with the specified level. +func (l *Logger) StdLogger(level Level) *log.Logger { + return l.log.StdLogger(level) +} + +// StdLogWriter returns a writer that can be hooked up to the output of a golang standard logger +// anything written will be interpreted as log entries and passed to this logger. +func (l *Logger) StdLogWriter() io.Writer { + return &logWriter{ + logger: l, + } +} + +// RedirectStdLog redirects output from the standard library's package-global logger +// to this logger at the specified level and with zero or more Field's. Since this logger already +// handles caller annotations, timestamps, etc., it automatically disables the standard +// library's annotations and prefixing. +// A function is returned that restores the original prefix and flags and resets the standard +// library's output to os.Stdout. +func (l *Logger) RedirectStdLog(level Level, fields ...Field) func() { + return l.log.Logr().RedirectStdLog(level, fields...) +} + +// RemoveTargets safely removes one or more targets based on the filtering method. +// `f` should return true to delete the target, false to keep it. +// When removing a target, best effort is made to write any queued log records before +// closing, with cxt determining how much time can be spent in total. +// Note, keep the timeout short since this method blocks certain logging operations. +func (l *Logger) RemoveTargets(ctx context.Context, f func(ti TargetInfo) bool) error { + return l.log.Logr().RemoveTargets(ctx, f) +} + +// SetMetricsCollector sets (or resets) the metrics collector to be used for gathering +// metrics for all targets. Only targets added after this call will use the collector. +// +// To ensure all targets use a collector, use the `SetMetricsCollector` option when +// creating the Logger instead, or configure/reconfigure the Logger after calling this method. +func (l *Logger) SetMetricsCollector(collector MetricsCollector, updateFrequencyMillis int64) { + l.log.Logr().SetMetricsCollector(collector, updateFrequencyMillis) +} + +// Sugar creates a new `Logger` with a less structured API. Any fields are preserved. +func (l *Logger) Sugar(fields ...Field) Sugar { + return l.log.Sugar(fields...) +} + +// Flush forces all targets to write out any queued log records with a default timeout. +func (l *Logger) Flush() error { + ctx, cancel := context.WithTimeout(context.Background(), FlushTimeout) + defer cancel() + return l.log.Logr().FlushWithTimeout(ctx) +} + +// Flush forces all targets to write out any queued log records with the specfified timeout. +func (l *Logger) FlushWithTimeout(ctx context.Context) error { + return l.log.Logr().FlushWithTimeout(ctx) +} + +// Shutdown shuts down the logger after making best efforts to flush any +// remaining records. +func (l *Logger) Shutdown() error { + ctx, cancel := context.WithTimeout(context.Background(), ShutdownTimeout) + defer cancel() + return l.log.Logr().ShutdownWithTimeout(ctx) +} + +// Shutdown shuts down the logger after making best efforts to flush any +// remaining records. +func (l *Logger) ShutdownWithTimeout(ctx context.Context) error { + return l.log.Logr().ShutdownWithTimeout(ctx) +} + +// GetPackageName reduces a fully qualified function name to the package name +// By sirupsen: https://github.com/sirupsen/logrus/blob/master/entry.go +func GetPackageName(f string) string { + for { + lastPeriod := strings.LastIndex(f, ".") + lastSlash := strings.LastIndex(f, "/") + if lastPeriod > lastSlash { + f = f[:lastPeriod] + } else { + break + } + } + return f +} + +type logWriter struct { + logger *Logger +} + +func (lw *logWriter) Write(p []byte) (int, error) { + lw.logger.Info(string(p)) + return len(p), nil +} + +// ErrConfigurationLock is returned when one of a logger's configuration APIs is called +// while the configuration is locked. +var ErrConfigurationLock = errors.New("configuration is locked") diff --git a/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/options.go b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/options.go new file mode 100644 index 00000000..3a98b480 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/options.go @@ -0,0 +1,55 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package mlog + +import "github.com/mattermost/logr/v2" + +// MaxQueueSize is the maximum number of log records that can be queued. +// If exceeded, `OnQueueFull` is called which determines if the log +// record will be dropped or block until add is successful. +// Defaults to DefaultMaxQueueSize. +func MaxQueueSize(size int) Option { + return logr.MaxQueueSize(size) +} + +// OnLoggerError, when not nil, is called any time an internal +// logging error occurs. For example, this can happen when a +// target cannot connect to its data sink. +func OnLoggerError(f func(error)) Option { + return logr.OnLoggerError(f) +} + +// OnQueueFull, when not nil, is called on an attempt to add +// a log record to a full Logr queue. +// `MaxQueueSize` can be used to modify the maximum queue size. +// This function should return quickly, with a bool indicating whether +// the log record should be dropped (true) or block until the log record +// is successfully added (false). If nil then blocking (false) is assumed. +func OnQueueFull(f func(rec *LogRec, maxQueueSize int) bool) Option { + return logr.OnQueueFull(f) +} + +// OnTargetQueueFull, when not nil, is called on an attempt to add +// a log record to a full target queue provided the target supports reporting +// this condition. +// This function should return quickly, with a bool indicating whether +// the log record should be dropped (true) or block until the log record +// is successfully added (false). If nil then blocking (false) is assumed. +func OnTargetQueueFull(f func(target Target, rec *LogRec, maxQueueSize int) bool) Option { + return logr.OnTargetQueueFull(f) +} + +// SetMetricsCollector enables metrics collection by supplying a MetricsCollector. +// The MetricsCollector provides counters and gauges that are updated by log targets. +// `updateFreqMillis` determines how often polled metrics are updated. Defaults to 15000 (15 seconds) +// and must be at least 250 so we don't peg the CPU. +func SetMetricsCollector(collector MetricsCollector, updateFreqMillis int64) Option { + return logr.SetMetricsCollector(collector, updateFreqMillis) +} + +// StackFilter provides a list of package names to exclude from the top of +// stack traces. The Logr packages are automatically filtered. +func StackFilter(pkg ...string) Option { + return logr.StackFilter(pkg...) +} diff --git a/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/tlog.go b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/tlog.go new file mode 100644 index 00000000..ef8f6016 --- /dev/null +++ b/vendor/github.com/mattermost/mattermost-server/v6/shared/mlog/tlog.go @@ -0,0 +1,79 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package mlog + +import ( + "bytes" + "io" + "os" + "sync" + + "github.com/mattermost/logr/v2" + "github.com/mattermost/logr/v2/formatters" + "github.com/mattermost/logr/v2/targets" +) + +// AddWriterTarget adds a simple io.Writer target to an existing Logger. +// The `io.Writer` can be a buffer which is useful for testing. +// When adding a buffer to collect logs make sure to use `mlog.Buffer` which is +// a thread safe version of `bytes.Buffer`. +func AddWriterTarget(logger *Logger, w io.Writer, useJSON bool, levels ...Level) error { + filter := logr.NewCustomFilter(levels...) + + var formatter logr.Formatter + if useJSON { + formatter = &formatters.JSON{EnableCaller: true} + } else { + formatter = &formatters.Plain{EnableCaller: true} + } + + target := targets.NewWriterTarget(w) + return logger.log.Logr().AddTarget(target, "_testWriter", filter, formatter, 1000) +} + +// CreateConsoleTestLogger creates a logger for unit tests. Log records are output to `os.Stdout`. +// Logs can also be mirrored to the optional `io.Writer`. +func CreateConsoleTestLogger(useJSON bool, level Level) *Logger { + logger, _ := NewLogger() + + filter := logr.StdFilter{ + Lvl: level, + Stacktrace: LvlPanic, + } + + var formatter logr.Formatter + if useJSON { + formatter = &formatters.JSON{EnableCaller: true} + } else { + formatter = &formatters.Plain{EnableCaller: true} + } + + target := targets.NewWriterTarget(os.Stdout) + if err := logger.log.Logr().AddTarget(target, "_testcon", filter, formatter, 1000); err != nil { + panic(err) + } + return logger +} + +// Buffer provides a thread-safe buffer useful for logging to memory in unit tests. +type Buffer struct { + buf bytes.Buffer + mux sync.Mutex +} + +func (b *Buffer) Read(p []byte) (n int, err error) { + b.mux.Lock() + defer b.mux.Unlock() + return b.buf.Read(p) +} +func (b *Buffer) Write(p []byte) (n int, err error) { + b.mux.Lock() + defer b.mux.Unlock() + return b.buf.Write(p) +} +func (b *Buffer) String() string { + b.mux.Lock() + defer b.mux.Unlock() + return b.buf.String() +} |