summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/mattermost-server/v5/mlog/logr.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mattermost/mattermost-server/v5/mlog/logr.go')
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v5/mlog/logr.go247
1 files changed, 247 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/mlog/logr.go b/vendor/github.com/mattermost/mattermost-server/v5/mlog/logr.go
new file mode 100644
index 00000000..01b39024
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v5/mlog/logr.go
@@ -0,0 +1,247 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package mlog
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/hashicorp/go-multierror"
+ "github.com/mattermost/logr"
+ logrFmt "github.com/mattermost/logr/format"
+ "github.com/mattermost/logr/target"
+ "go.uber.org/zap/zapcore"
+)
+
+const (
+ DefaultMaxTargetQueue = 1000
+ DefaultSysLogPort = 514
+)
+
+type LogLevel struct {
+ ID logr.LevelID
+ Name string
+ Stacktrace bool
+}
+
+type LogTarget struct {
+ Type string // one of "console", "file", "tcp", "syslog", "none".
+ Format string // one of "json", "plain"
+ Levels []LogLevel
+ Options json.RawMessage
+ MaxQueueSize int
+}
+
+type LogTargetCfg map[string]*LogTarget
+type LogrCleanup func() error
+
+func newLogr() *logr.Logger {
+ lgr := &logr.Logr{}
+ lgr.OnExit = func(int) {}
+ lgr.OnPanic = func(interface{}) {}
+ lgr.OnLoggerError = onLoggerError
+ lgr.OnQueueFull = onQueueFull
+ lgr.OnTargetQueueFull = onTargetQueueFull
+
+ logger := lgr.NewLogger()
+ return &logger
+}
+
+func logrAddTargets(logger *logr.Logger, targets LogTargetCfg) error {
+ lgr := logger.Logr()
+ var errs error
+ for name, t := range targets {
+ target, err := NewLogrTarget(name, t)
+ if err != nil {
+ errs = multierror.Append(err)
+ continue
+ }
+ if target != nil {
+ target.SetName(name)
+ lgr.AddTarget(target)
+ }
+ }
+ return errs
+}
+
+// NewLogrTarget creates a `logr.Target` based on a target config.
+// Can be used when parsing custom config files, or when programmatically adding
+// built-in targets. Use `mlog.AddTarget` to add custom targets.
+func NewLogrTarget(name string, t *LogTarget) (logr.Target, error) {
+ formatter, err := newFormatter(name, t.Format)
+ if err != nil {
+ return nil, err
+ }
+ filter, err := newFilter(name, t.Levels)
+ if err != nil {
+ return nil, err
+ }
+
+ if t.MaxQueueSize == 0 {
+ t.MaxQueueSize = DefaultMaxTargetQueue
+ }
+
+ switch t.Type {
+ case "console":
+ return newConsoleTarget(name, t, filter, formatter)
+ case "file":
+ return newFileTarget(name, t, filter, formatter)
+ case "syslog":
+ return newSyslogTarget(name, t, filter, formatter)
+ case "tcp":
+ return newTCPTarget(name, t, filter, formatter)
+ case "none":
+ return nil, nil
+ }
+ return nil, fmt.Errorf("invalid type '%s' for target %s", t.Type, name)
+}
+
+func newFilter(name string, levels []LogLevel) (logr.Filter, error) {
+ filter := &logr.CustomFilter{}
+ for _, lvl := range levels {
+ filter.Add(logr.Level(lvl))
+ }
+ return filter, nil
+}
+
+func newFormatter(name string, format string) (logr.Formatter, error) {
+ switch format {
+ case "json", "":
+ return &logrFmt.JSON{}, nil
+ case "plain":
+ return &logrFmt.Plain{Delim: " | "}, nil
+ default:
+ return nil, fmt.Errorf("invalid format '%s' for target %s", format, name)
+ }
+}
+
+func newConsoleTarget(name string, t *LogTarget, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) {
+ type consoleOptions struct {
+ Out string `json:"Out"`
+ }
+ options := &consoleOptions{}
+ if err := json.Unmarshal(t.Options, options); err != nil {
+ return nil, err
+ }
+
+ var w io.Writer
+ switch options.Out {
+ case "stdout", "":
+ w = os.Stdout
+ case "stderr":
+ w = os.Stderr
+ default:
+ return nil, fmt.Errorf("invalid out '%s' for target %s", options.Out, name)
+ }
+
+ newTarget := target.NewWriterTarget(filter, formatter, w, t.MaxQueueSize)
+ return newTarget, nil
+}
+
+func newFileTarget(name string, t *LogTarget, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) {
+ type fileOptions struct {
+ Filename string `json:"Filename"`
+ MaxSize int `json:"MaxSizeMB"`
+ MaxAge int `json:"MaxAgeDays"`
+ MaxBackups int `json:"MaxBackups"`
+ Compress bool `json:"Compress"`
+ }
+ options := &fileOptions{}
+ if err := json.Unmarshal(t.Options, options); err != nil {
+ return nil, err
+ }
+ return newFileTargetWithOpts(name, t, target.FileOptions(*options), filter, formatter)
+}
+
+func newFileTargetWithOpts(name string, t *LogTarget, opts target.FileOptions, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) {
+ if opts.Filename == "" {
+ return nil, fmt.Errorf("missing 'Filename' option for target %s", name)
+ }
+ if err := checkFileWritable(opts.Filename); err != nil {
+ return nil, fmt.Errorf("error writing to 'Filename' for target %s: %w", name, err)
+ }
+
+ newTarget := target.NewFileTarget(filter, formatter, opts, t.MaxQueueSize)
+ return newTarget, nil
+}
+
+func newSyslogTarget(name string, t *LogTarget, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) {
+ options := &SyslogParams{}
+ if err := json.Unmarshal(t.Options, options); err != nil {
+ return nil, err
+ }
+
+ if options.IP == "" {
+ return nil, fmt.Errorf("missing 'IP' option for target %s", name)
+ }
+ if options.Port == 0 {
+ options.Port = DefaultSysLogPort
+ }
+ return NewSyslogTarget(filter, formatter, options, t.MaxQueueSize)
+}
+
+func newTCPTarget(name string, t *LogTarget, filter logr.Filter, formatter logr.Formatter) (logr.Target, error) {
+ options := &TcpParams{}
+ if err := json.Unmarshal(t.Options, options); err != nil {
+ return nil, err
+ }
+
+ if options.IP == "" {
+ return nil, fmt.Errorf("missing 'IP' option for target %s", name)
+ }
+ if options.Port == 0 {
+ return nil, fmt.Errorf("missing 'Port' option for target %s", name)
+ }
+ return NewTcpTarget(filter, formatter, options, t.MaxQueueSize)
+}
+
+func checkFileWritable(filename string) error {
+ // try opening/creating the file for writing
+ file, err := os.OpenFile(filename, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
+ if err != nil {
+ return err
+ }
+ file.Close()
+ return nil
+}
+
+func isLevelEnabled(logger *logr.Logger, level logr.Level) bool {
+ if logger == nil || logger.Logr() == nil {
+ return false
+ }
+
+ status := logger.Logr().IsLevelEnabled(level)
+ return status.Enabled
+}
+
+// zapToLogr converts Zap fields to Logr fields.
+// This will not be needed once Logr is used for all logging.
+func zapToLogr(zapFields []Field) logr.Fields {
+ encoder := zapcore.NewMapObjectEncoder()
+ for _, zapField := range zapFields {
+ zapField.AddTo(encoder)
+ }
+ return logr.Fields(encoder.Fields)
+}
+
+// mlogLevelToLogrLevel converts a mlog logger level to
+// an array of discrete Logr levels.
+func mlogLevelToLogrLevels(level string) []LogLevel {
+ levels := make([]LogLevel, 0)
+ levels = append(levels, LvlError, LvlPanic, LvlFatal, LvlStdLog)
+
+ switch level {
+ case LevelDebug:
+ levels = append(levels, LvlDebug)
+ fallthrough
+ case LevelInfo:
+ levels = append(levels, LvlInfo)
+ fallthrough
+ case LevelWarn:
+ levels = append(levels, LvlWarn)
+ }
+ return levels
+}