github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/log.go (about) 1 // Copyright 2012-2020 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package server 15 16 import ( 17 "fmt" 18 "io" 19 "os" 20 "sync/atomic" 21 "time" 22 23 srvlog "github.com/nats-io/nats-server/v2/logger" 24 ) 25 26 // Logger interface of the NATS Server 27 type Logger interface { 28 29 // Log a notice statement 30 Noticef(format string, v ...any) 31 32 // Log a warning statement 33 Warnf(format string, v ...any) 34 35 // Log a fatal error 36 Fatalf(format string, v ...any) 37 38 // Log an error 39 Errorf(format string, v ...any) 40 41 // Log a debug statement 42 Debugf(format string, v ...any) 43 44 // Log a trace statement 45 Tracef(format string, v ...any) 46 } 47 48 // ConfigureLogger configures and sets the logger for the server. 49 func (s *Server) ConfigureLogger() { 50 var ( 51 log Logger 52 53 // Snapshot server options. 54 opts = s.getOpts() 55 ) 56 57 if opts.NoLog { 58 return 59 } 60 61 syslog := opts.Syslog 62 if isWindowsService() && opts.LogFile == "" { 63 // Enable syslog if no log file is specified and we're running as a 64 // Windows service so that logs are written to the Windows event log. 65 syslog = true 66 } 67 68 if opts.LogFile != "" { 69 log = srvlog.NewFileLogger(opts.LogFile, opts.Logtime, opts.Debug, opts.Trace, true, srvlog.LogUTC(opts.LogtimeUTC)) 70 if opts.LogSizeLimit > 0 { 71 if l, ok := log.(*srvlog.Logger); ok { 72 l.SetSizeLimit(opts.LogSizeLimit) 73 } 74 } 75 if opts.LogMaxFiles > 0 { 76 if l, ok := log.(*srvlog.Logger); ok { 77 al := int(opts.LogMaxFiles) 78 if int64(al) != opts.LogMaxFiles { 79 // set to default (no max) on overflow 80 al = 0 81 } 82 l.SetMaxNumFiles(al) 83 } 84 } 85 } else if opts.RemoteSyslog != "" { 86 log = srvlog.NewRemoteSysLogger(opts.RemoteSyslog, opts.Debug, opts.Trace) 87 } else if syslog { 88 log = srvlog.NewSysLogger(opts.Debug, opts.Trace) 89 } else { 90 colors := true 91 // Check to see if stderr is being redirected and if so turn off color 92 // Also turn off colors if we're running on Windows where os.Stderr.Stat() returns an invalid handle-error 93 stat, err := os.Stderr.Stat() 94 if err != nil || (stat.Mode()&os.ModeCharDevice) == 0 { 95 colors = false 96 } 97 log = srvlog.NewStdLogger(opts.Logtime, opts.Debug, opts.Trace, colors, true, srvlog.LogUTC(opts.LogtimeUTC)) 98 } 99 100 s.SetLoggerV2(log, opts.Debug, opts.Trace, opts.TraceVerbose) 101 } 102 103 // Returns our current logger. 104 func (s *Server) Logger() Logger { 105 s.logging.Lock() 106 defer s.logging.Unlock() 107 return s.logging.logger 108 } 109 110 // SetLogger sets the logger of the server 111 func (s *Server) SetLogger(logger Logger, debugFlag, traceFlag bool) { 112 s.SetLoggerV2(logger, debugFlag, traceFlag, false) 113 } 114 115 // SetLogger sets the logger of the server 116 func (s *Server) SetLoggerV2(logger Logger, debugFlag, traceFlag, sysTrace bool) { 117 if debugFlag { 118 atomic.StoreInt32(&s.logging.debug, 1) 119 } else { 120 atomic.StoreInt32(&s.logging.debug, 0) 121 } 122 if traceFlag { 123 atomic.StoreInt32(&s.logging.trace, 1) 124 } else { 125 atomic.StoreInt32(&s.logging.trace, 0) 126 } 127 if sysTrace { 128 atomic.StoreInt32(&s.logging.traceSysAcc, 1) 129 } else { 130 atomic.StoreInt32(&s.logging.traceSysAcc, 0) 131 } 132 s.logging.Lock() 133 if s.logging.logger != nil { 134 // Check to see if the logger implements io.Closer. This could be a 135 // logger from another process embedding the NATS server or a dummy 136 // test logger that may not implement that interface. 137 if l, ok := s.logging.logger.(io.Closer); ok { 138 if err := l.Close(); err != nil { 139 s.Errorf("Error closing logger: %v", err) 140 } 141 } 142 } 143 s.logging.logger = logger 144 s.logging.Unlock() 145 } 146 147 // ReOpenLogFile if the logger is a file based logger, close and re-open the file. 148 // This allows for file rotation by 'mv'ing the file then signaling 149 // the process to trigger this function. 150 func (s *Server) ReOpenLogFile() { 151 // Check to make sure this is a file logger. 152 s.logging.RLock() 153 ll := s.logging.logger 154 s.logging.RUnlock() 155 156 if ll == nil { 157 s.Noticef("File log re-open ignored, no logger") 158 return 159 } 160 161 // Snapshot server options. 162 opts := s.getOpts() 163 164 if opts.LogFile == "" { 165 s.Noticef("File log re-open ignored, not a file logger") 166 } else { 167 fileLog := srvlog.NewFileLogger( 168 opts.LogFile, opts.Logtime, 169 opts.Debug, opts.Trace, true, 170 srvlog.LogUTC(opts.LogtimeUTC), 171 ) 172 s.SetLogger(fileLog, opts.Debug, opts.Trace) 173 if opts.LogSizeLimit > 0 { 174 fileLog.SetSizeLimit(opts.LogSizeLimit) 175 } 176 s.Noticef("File log re-opened") 177 } 178 } 179 180 // Noticef logs a notice statement 181 func (s *Server) Noticef(format string, v ...any) { 182 s.executeLogCall(func(logger Logger, format string, v ...any) { 183 logger.Noticef(format, v...) 184 }, format, v...) 185 } 186 187 // Errorf logs an error 188 func (s *Server) Errorf(format string, v ...any) { 189 s.executeLogCall(func(logger Logger, format string, v ...any) { 190 logger.Errorf(format, v...) 191 }, format, v...) 192 } 193 194 // Error logs an error with a scope 195 func (s *Server) Errors(scope any, e error) { 196 s.executeLogCall(func(logger Logger, format string, v ...any) { 197 logger.Errorf(format, v...) 198 }, "%s - %s", scope, UnpackIfErrorCtx(e)) 199 } 200 201 // Error logs an error with a context 202 func (s *Server) Errorc(ctx string, e error) { 203 s.executeLogCall(func(logger Logger, format string, v ...any) { 204 logger.Errorf(format, v...) 205 }, "%s: %s", ctx, UnpackIfErrorCtx(e)) 206 } 207 208 // Error logs an error with a scope and context 209 func (s *Server) Errorsc(scope any, ctx string, e error) { 210 s.executeLogCall(func(logger Logger, format string, v ...any) { 211 logger.Errorf(format, v...) 212 }, "%s - %s: %s", scope, ctx, UnpackIfErrorCtx(e)) 213 } 214 215 // Warnf logs a warning error 216 func (s *Server) Warnf(format string, v ...any) { 217 s.executeLogCall(func(logger Logger, format string, v ...any) { 218 logger.Warnf(format, v...) 219 }, format, v...) 220 } 221 222 func (s *Server) RateLimitWarnf(format string, v ...any) { 223 statement := fmt.Sprintf(format, v...) 224 if _, loaded := s.rateLimitLogging.LoadOrStore(statement, time.Now()); loaded { 225 return 226 } 227 s.Warnf("%s", statement) 228 } 229 230 func (s *Server) RateLimitDebugf(format string, v ...any) { 231 statement := fmt.Sprintf(format, v...) 232 if _, loaded := s.rateLimitLogging.LoadOrStore(statement, time.Now()); loaded { 233 return 234 } 235 s.Debugf("%s", statement) 236 } 237 238 // Fatalf logs a fatal error 239 func (s *Server) Fatalf(format string, v ...any) { 240 s.executeLogCall(func(logger Logger, format string, v ...any) { 241 logger.Fatalf(format, v...) 242 }, format, v...) 243 } 244 245 // Debugf logs a debug statement 246 func (s *Server) Debugf(format string, v ...any) { 247 if atomic.LoadInt32(&s.logging.debug) == 0 { 248 return 249 } 250 251 s.executeLogCall(func(logger Logger, format string, v ...any) { 252 logger.Debugf(format, v...) 253 }, format, v...) 254 } 255 256 // Tracef logs a trace statement 257 func (s *Server) Tracef(format string, v ...any) { 258 if atomic.LoadInt32(&s.logging.trace) == 0 { 259 return 260 } 261 262 s.executeLogCall(func(logger Logger, format string, v ...any) { 263 logger.Tracef(format, v...) 264 }, format, v...) 265 } 266 267 func (s *Server) executeLogCall(f func(logger Logger, format string, v ...any), format string, args ...any) { 268 s.logging.RLock() 269 defer s.logging.RUnlock() 270 if s.logging.logger == nil { 271 return 272 } 273 274 f(s.logging.logger, format, args...) 275 }