4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-07-04 08:57:44 +00:00

Update vendor

This commit is contained in:
Wim
2021-10-16 23:11:32 +02:00
parent 57fce93af7
commit 20f6c05ec5
588 changed files with 119386 additions and 3424 deletions

View File

@ -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
}

View File

@ -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...)
}

View File

@ -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}
)

View File

@ -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")

View File

@ -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...)
}

View File

@ -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()
}