github.com/GuanceCloud/cliutils@v1.1.21/logger/root.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the MIT License. 3 // This product includes software developed at Guance Cloud (https://www.guance.com/). 4 // Copyright 2021-present Guance, Inc. 5 6 // Package logger wrapped zap as a basic logging implement. 7 package logger 8 9 import ( 10 "fmt" 11 "log" 12 "net/url" 13 "os" 14 "path/filepath" 15 "strings" 16 17 "github.com/robfig/cron/v3" 18 "go.uber.org/zap" 19 "gopkg.in/natefinch/lumberjack.v2" 20 ) 21 22 var ( 23 root *zap.Logger 24 defaultOption = &Option{ 25 Level: DEBUG, 26 Flags: OPT_DEFAULT, 27 } 28 29 SchemeTCP = "tcp" 30 SchemeUDP = "udp" 31 ) 32 33 const ( 34 NameKeyMod = "mod" 35 NameKeyMsg = "msg" 36 NameKeyLevel = "lev" 37 NameKeyTime = "ts" 38 NameKeyPos = "pos" 39 ) 40 41 func doSetGlobalRootLogger(fpath, level string, options int) error { 42 if fpath == "" { 43 return fmt.Errorf("fpath should not empty") 44 } 45 46 mtx.Lock() 47 defer mtx.Unlock() 48 49 if root != nil { 50 return nil 51 } 52 53 var err error 54 root, err = newRootLogger(fpath, level, options) 55 if err != nil { 56 return err 57 } 58 59 return nil 60 } 61 62 // SetGlobalRootLogger deprecated, use InitRoot() instead. 63 func SetGlobalRootLogger(fpath, level string, options int) error { 64 return doSetGlobalRootLogger(fpath, level, options) 65 } 66 67 // InitRoot used to setup global root logger, include 68 // - log level 69 // - log path 70 // - set to disk file(with or without rotate) 71 // - set to some remtoe TCP/UDP server 72 // - a bounch of other OPT_XXXs 73 func InitRoot(opt *Option) error { 74 if opt == nil { 75 opt = defaultOption 76 } 77 78 switch opt.Level { 79 case DEBUG, INFO, WARN, ERROR, PANIC, FATAL, DPANIC: 80 case "": // 默认使用 DEBUG 81 opt.Level = DEBUG 82 83 default: 84 return fmt.Errorf("invalid log level `%s'", opt.Level) 85 } 86 87 if opt.Flags == 0 { 88 opt.Flags = OPT_DEFAULT 89 } 90 91 if opt.Path != "" && (opt.Flags&OPT_STDOUT != 0) { 92 return fmt.Errorf("set stdout logging with log path '%s', flag:%b", opt.Path, opt.Flags) 93 } 94 95 switch opt.Path { 96 case "": 97 if v, ok := os.LookupEnv("LOGGER_PATH"); ok { 98 opt.Path = v 99 return setRootLoggerFromEnv(opt) 100 } 101 102 return doSetStdoutLogger(opt) 103 104 default: 105 return doSetGlobalRootLogger(opt.Path, opt.Level, opt.Flags) 106 } 107 } 108 109 func newRootLogger(fpath, level string, options int) (*zap.Logger, error) { 110 if fpath == "" { 111 return newNormalRootLogger(fpath, level, options) 112 } 113 114 u, err := url.Parse(fpath) 115 if err != nil { 116 return nil, err 117 } 118 119 switch strings.ToLower(u.Scheme) { 120 case SchemeTCP, SchemeUDP: // logs sending to some remote TCP/UDP server 121 return newCustomizeRootLogger(level, 122 options, 123 &remoteEndpoint{protocol: u.Scheme, host: u.Host}) 124 125 default: // they must be some disk path file 126 if _, err := os.Stat(fpath); err != nil { // create file if not exists 127 if err := os.MkdirAll(filepath.Dir(fpath), 0o600); err != nil { 128 return nil, fmt.Errorf("MkdirAll(%s): %w", fpath, err) 129 } 130 131 // create empty log file 132 if err := os.WriteFile(fpath, nil, 0o600); err != nil { 133 return nil, fmt.Errorf("WriteFile(%s): %w", fpath, err) 134 } 135 } 136 } 137 138 // auto-rotate disk logging file 139 if options&OPT_ROTATE != 0 && 140 options&OPT_STDOUT == 0 && // can't rotate stdout 141 fpath != os.DevNull { // can't rotate(rename) /dev/null 142 return newCustomizeRootLogger(level, options, &lumberjack.Logger{ 143 Filename: fpath, 144 MaxSize: MaxSize, 145 MaxBackups: MaxBackups, 146 MaxAge: MaxAge, 147 }) 148 } 149 150 return newNormalRootLogger(fpath, level, options) 151 } 152 153 // InitCustomizeRoot used to setup global root logger, include 154 // - log path 155 // - log maxsize 156 // - log compress 157 158 func InitCustomizeRoot(opt *Option) (*zap.Logger, error) { 159 mtx.Lock() 160 defer mtx.Unlock() 161 162 lumberLog := &lumberjack.Logger{ 163 Filename: opt.Path, 164 MaxSize: opt.MaxSize, 165 Compress: opt.Compress, 166 } 167 168 c := cron.New(cron.WithSeconds()) 169 if _, err := c.AddFunc("50 59 * * * *", 170 func() { 171 if err := lumberLog.Rotate(); err != nil { 172 log.Printf("lumberLog.Rotate: %s, ignored", err.Error()) 173 } 174 }); err != nil { 175 return nil, err 176 } 177 c.Start() 178 179 return newOnlyMessageRootLogger(lumberLog) 180 }