github.com/cs3org/reva/v2@v2.27.7/pkg/logger/logger.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package logger 20 21 import ( 22 "fmt" 23 "io" 24 "os" 25 "time" 26 27 "github.com/mitchellh/mapstructure" 28 "github.com/pkg/errors" 29 "github.com/rs/zerolog" 30 ) 31 32 func init() { 33 zerolog.CallerSkipFrameCount = 2 34 zerolog.TimeFieldFormat = time.RFC3339Nano 35 } 36 37 // Mode changes the logging format. 38 type Mode string 39 40 const ( 41 // JSONMode outputs JSON. 42 JSONMode Mode = "json" 43 // ConsoleMode outputs human-readable logs. 44 ConsoleMode Mode = "console" 45 ) 46 47 // Option is the option to use to configure the logger. 48 type Option func(l *zerolog.Logger) 49 50 // New creates a new logger. 51 func New(opts ...Option) *zerolog.Logger { 52 // create a default logger 53 zl := zerolog.New(os.Stderr).With().Timestamp().Caller().Logger() 54 for _, opt := range opts { 55 opt(&zl) 56 } 57 return &zl 58 } 59 60 // WithLevel is an option to configure the logging level. 61 func WithLevel(lvl string) Option { 62 return func(l *zerolog.Logger) { 63 zlvl := parseLevel(lvl) 64 *l = l.Level(zlvl) 65 } 66 } 67 68 // WithWriter is an option to configure the logging output. 69 func WithWriter(w io.Writer, m Mode) Option { 70 return func(l *zerolog.Logger) { 71 if m == ConsoleMode { 72 *l = l.Output(zerolog.ConsoleWriter{Out: w, TimeFormat: "2006-01-02 15:04:05.999"}) 73 } else { 74 *l = l.Output(w) 75 } 76 } 77 } 78 79 func parseLevel(v string) zerolog.Level { 80 if v == "" { 81 return zerolog.InfoLevel 82 } 83 84 lvl, err := zerolog.ParseLevel(v) 85 if err != nil { 86 return zerolog.InfoLevel 87 } 88 89 return lvl 90 } 91 92 func InitLoggerOrDie(v interface{}, logLevel string) *zerolog.Logger { 93 conf := ParseLogConfOrDie(v, logLevel) 94 log, err := fromConfig(conf) 95 if err != nil { 96 fmt.Fprintf(os.Stderr, "error creating logger, exiting ...") 97 os.Exit(1) 98 } 99 return log 100 } 101 102 func ParseLogConfOrDie(v interface{}, logLevel string) *LogConf { 103 c := &LogConf{} 104 if err := mapstructure.Decode(v, c); err != nil { 105 fmt.Fprintf(os.Stderr, "error decoding log config: %s\n", err.Error()) 106 os.Exit(1) 107 } 108 109 // if mode is not set, we use console mode, easier for devs 110 if c.Mode == "" { 111 c.Mode = "console" 112 } 113 114 // Give priority to the log level passed through the command line. 115 if logLevel != "" { 116 c.Level = logLevel 117 } 118 119 return c 120 } 121 122 type LogConf struct { 123 Output string `mapstructure:"output"` 124 Mode string `mapstructure:"mode"` 125 Level string `mapstructure:"level"` 126 } 127 128 func fromConfig(conf *LogConf) (*zerolog.Logger, error) { 129 if conf.Level == "" { 130 conf.Level = zerolog.DebugLevel.String() 131 } 132 133 var opts []Option 134 opts = append(opts, WithLevel(conf.Level)) 135 136 w, err := getWriter(conf.Output) 137 if err != nil { 138 return nil, err 139 } 140 141 opts = append(opts, WithWriter(w, Mode(conf.Mode))) 142 143 l := New(opts...) 144 sub := l.With().Int("pid", os.Getpid()).Logger() 145 return &sub, nil 146 } 147 148 func getWriter(out string) (io.Writer, error) { 149 if out == "stderr" || out == "" { 150 return os.Stderr, nil 151 } 152 153 if out == "stdout" { 154 return os.Stdout, nil 155 } 156 157 fd, err := os.OpenFile(out, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) 158 if err != nil { 159 err = errors.Wrap(err, "error creating log file: "+out) 160 return nil, err 161 } 162 163 return fd, nil 164 }