github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/logconfig/config.go (about) 1 /* 2 * Copyright (C) 2017 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package logconfig 19 20 import ( 21 "fmt" 22 "io" 23 stdlog "log" 24 "os" 25 "strconv" 26 "strings" 27 "time" 28 29 "github.com/mysteriumnetwork/go-openvpn/openvpn" 30 "github.com/mysteriumnetwork/node/logconfig/rollingwriter" 31 "github.com/rs/zerolog" 32 "github.com/rs/zerolog/log" 33 "github.com/rs/zerolog/pkgerrors" 34 ) 35 36 const ( 37 timestampFmt = "2006-01-02T15:04:05.000" 38 ) 39 40 // Bootstrap configures logger defaults (console). 41 func Bootstrap() { 42 var trimPrefixes = []string{ 43 "/github.com/mysteriumnetwork/node", 44 "/vendor", 45 "/go/pkg/mod", 46 } 47 zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack 48 zerolog.TimeFieldFormat = time.RFC3339Nano 49 zerolog.CallerMarshalFunc = func(_ uintptr, file string, line int) string { 50 var ok bool 51 for _, prefix := range trimPrefixes { 52 file, ok = trimLeftInclusive(file, prefix) 53 if ok { 54 break 55 } 56 } 57 return fmt.Sprintf("%-41v", file+":"+strconv.Itoa(line)) 58 } 59 60 openvpn.UseLogger(zerologOpenvpnLogger{}) 61 logger := makeLogger(consoleWriter()) 62 setGlobalLogger(&logger) 63 } 64 65 // SetLogLevel sets global log level to the given one. 66 func SetLogLevel(level zerolog.Level) { 67 CurrentLogOptions.LogLevel = level 68 log.Logger = log.Logger.Level(level) 69 } 70 71 // Configure configures logger using app config (console + file, level). 72 func Configure(opts *LogOptions) { 73 CurrentLogOptions = *opts 74 log.Info().Msgf("Log level: %s", opts.LogLevel) 75 if opts.Filepath != "" { 76 log.Info().Msgf("Log file path: %s", opts.Filepath) 77 rollingWriter, err := rollingwriter.NewRollingWriter(opts.Filepath) 78 if err != nil { 79 log.Err(err).Msg("Failed to configure file logger") 80 } else { 81 multiWriter := io.MultiWriter(consoleWriter(), zeroLogger(rollingWriter.Writer)) 82 logger := makeLogger(multiWriter) 83 setGlobalLogger(&logger) 84 } 85 if err := rollingWriter.CleanObsoleteLogs(); err != nil { 86 log.Err(err).Msg("Failed to cleanup obsolete logs") 87 } 88 } 89 log.Logger = log.Logger.Level(opts.LogLevel) 90 } 91 92 func consoleWriter() io.Writer { 93 return zerolog.ConsoleWriter{ 94 Out: os.Stderr, 95 TimeFormat: timestampFmt, 96 } 97 } 98 99 func zeroLogger(out io.Writer) io.Writer { 100 return zerolog.ConsoleWriter{ 101 Out: out, 102 NoColor: true, 103 TimeFormat: timestampFmt, 104 } 105 } 106 107 func makeLogger(w io.Writer) zerolog.Logger { 108 return log.Output(w). 109 Level(zerolog.DebugLevel). 110 With(). 111 Caller(). 112 Timestamp(). 113 Logger() 114 } 115 116 func setGlobalLogger(logger *zerolog.Logger) { 117 log.Logger = *logger 118 stdlog.SetFlags(0) 119 stdlog.SetOutput(log.Logger) 120 } 121 122 // trimLeftInclusive trims left part of the string up to and including the prefix. 123 func trimLeftInclusive(s string, prefix string) (string, bool) { 124 start := strings.Index(s, prefix) 125 if start != -1 { 126 return s[start+len(prefix):], true 127 } 128 return s, false 129 }