github.com/Cloud-Foundations/Dominator@v0.3.4/lib/log/serverlogger/impl.go (about) 1 package serverlogger 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "log" 8 "os" 9 "regexp" 10 "runtime" 11 "strings" 12 "sync" 13 "time" 14 15 "github.com/Cloud-Foundations/Dominator/lib/logbuf" 16 "github.com/Cloud-Foundations/Dominator/lib/srpc" 17 "github.com/Cloud-Foundations/Dominator/lib/srpc/serverutil" 18 proto "github.com/Cloud-Foundations/Dominator/proto/logger" 19 ) 20 21 type loggerMapT struct { 22 *serverutil.PerUserMethodLimiter 23 sync.Mutex 24 loggerMap map[string]*Logger 25 } 26 27 type grabWriter struct { 28 data []byte 29 } 30 31 var loggerMap *loggerMapT = &loggerMapT{ 32 loggerMap: make(map[string]*Logger), 33 PerUserMethodLimiter: serverutil.NewPerUserMethodLimiter( 34 map[string]uint{ 35 "Debug": 1, 36 "GetStackTrace": 1, 37 "Print": 1, 38 "SetDebugLevel": 1, 39 "Watch": 1, 40 }), 41 } 42 43 func init() { 44 srpc.RegisterName("Logger", loggerMap) 45 } 46 47 func getCallerName(depth int) string { 48 if pc, _, _, ok := runtime.Caller(depth); !ok { 49 return "UNKNOWN" 50 } else if fi := runtime.FuncForPC(pc); fi == nil { 51 return "UNKNOWN" 52 } else if splitName := strings.Split(fi.Name(), "."); len(splitName) < 1 { 53 return "UNKNOWN" 54 } else { 55 return splitName[len(splitName)-1] 56 } 57 } 58 59 func (w *grabWriter) Write(p []byte) (int, error) { 60 w.data = p 61 return len(p), nil 62 } 63 64 func newLogger(name string, options logbuf.Options, flags int) *Logger { 65 if name == "" && !options.AlsoLogToStderr { 66 options.RedirectStderr = true 67 } 68 loggerMap.Lock() 69 defer loggerMap.Unlock() 70 if _, ok := loggerMap.loggerMap[name]; ok { 71 panic("logger already exists: " + name) 72 } 73 circularBuffer := logbuf.NewWithOptions(options) 74 logger := &Logger{ 75 circularBuffer: circularBuffer, 76 flags: flags, 77 level: int16(*initialLogDebugLevel), 78 streamers: make(map[*streamerType]struct{}), 79 } 80 if logger.level < -1 { 81 logger.level = -1 82 } 83 logger.maxLevel = logger.level 84 loggerMap.loggerMap[name] = logger 85 if circularBuffer.CheckNeverLogged() { 86 logger.Println("New log directory") 87 } 88 if *logAtStartup { 89 logger.Println("Startup") 90 } 91 return logger 92 } 93 94 func (l *Logger) checkAuth(authInfo *srpc.AuthInformation) error { 95 if authInfo.HaveMethodAccess { 96 return nil 97 } 98 if accessChecker := l.accessChecker; accessChecker == nil { 99 return errors.New("no access to resource") 100 } else if accessChecker(getCallerName(3), authInfo) { 101 return nil 102 } else { 103 return errors.New("no access to resource") 104 } 105 } 106 107 func (l *Logger) debug(level int16, v ...interface{}) { 108 if l.maxLevel >= level { 109 l.log(level, fmt.Sprint(v...), false) 110 } 111 } 112 113 func (l *Logger) debugf(level int16, format string, v ...interface{}) { 114 if l.maxLevel >= level { 115 l.log(level, fmt.Sprintf(format, v...), false) 116 } 117 } 118 119 func (l *Logger) debugln(level int16, v ...interface{}) { 120 if l.maxLevel >= level { 121 l.log(level, fmt.Sprintln(v...), false) 122 } 123 } 124 125 func (l *Logger) fatals(msg string) { 126 l.log(-1, msg, true) 127 os.Exit(1) 128 } 129 130 func (l *Logger) log(level int16, msg string, dying bool) { 131 buffer := &grabWriter{} 132 rawLogger := log.New(buffer, "", l.flags) 133 rawLogger.Output(4, msg) 134 if l.level >= level { 135 l.circularBuffer.Write(buffer.data) 136 } 137 recalculateLevels := false 138 l.mutex.Lock() 139 defer l.mutex.Unlock() 140 for streamer := range l.streamers { 141 if streamer.debugLevel >= level && 142 (streamer.includeRegex == nil || 143 streamer.includeRegex.Match(buffer.data)) && 144 (streamer.excludeRegex == nil || 145 !streamer.excludeRegex.Match(buffer.data)) { 146 select { 147 case streamer.output <- buffer.data: 148 default: 149 delete(l.streamers, streamer) 150 close(streamer.output) 151 recalculateLevels = true 152 } 153 } 154 } 155 if dying { 156 for streamer := range l.streamers { 157 delete(l.streamers, streamer) 158 close(streamer.output) 159 } 160 l.circularBuffer.Flush() 161 time.Sleep(time.Millisecond * 10) 162 } else if recalculateLevels { 163 l.updateMaxLevel() 164 } 165 } 166 167 func (l *Logger) makeStreamer(request proto.WatchRequest) ( 168 *streamerType, error) { 169 if request.DebugLevel < -1 { 170 request.DebugLevel = -1 171 } 172 streamer := &streamerType{debugLevel: request.DebugLevel} 173 if request.ExcludeRegex != "" { 174 var err error 175 streamer.excludeRegex, err = regexp.Compile(request.ExcludeRegex) 176 if err != nil { 177 return nil, err 178 } 179 } 180 if request.IncludeRegex != "" { 181 var err error 182 streamer.includeRegex, err = regexp.Compile(request.IncludeRegex) 183 if err != nil { 184 return nil, err 185 } 186 } 187 return streamer, nil 188 } 189 190 func (l *Logger) panics(msg string) { 191 l.log(-1, msg, true) 192 panic(msg) 193 } 194 195 func (l *Logger) prints(msg string) { 196 l.log(-1, msg, false) 197 } 198 199 func (l *Logger) setLevel(maxLevel int16) { 200 if maxLevel < -1 { 201 maxLevel = -1 202 } 203 l.level = maxLevel 204 l.mutex.Lock() 205 l.updateMaxLevel() 206 l.mutex.Unlock() 207 } 208 209 func (l *Logger) updateMaxLevel() { 210 maxLevel := l.level 211 for streamer := range l.streamers { 212 if streamer.debugLevel > maxLevel { 213 maxLevel = streamer.debugLevel 214 } 215 } 216 l.maxLevel = maxLevel 217 } 218 219 func (l *Logger) watch(conn *srpc.Conn, streamer *streamerType) { 220 channel := make(chan []byte, 256) 221 streamer.output = channel 222 l.mutex.Lock() 223 l.streamers[streamer] = struct{}{} 224 l.updateMaxLevel() 225 l.mutex.Unlock() 226 timer := time.NewTimer(time.Millisecond * 100) 227 flushPending := false 228 closeNotifier := conn.GetCloseNotifier() 229 for keepGoing := true; keepGoing; { 230 select { 231 case <-closeNotifier: 232 keepGoing = false 233 break 234 case data, ok := <-channel: 235 if !ok { 236 keepGoing = false 237 break 238 } 239 if _, err := conn.Write(data); err != nil { 240 keepGoing = false 241 break 242 } 243 if !flushPending { 244 timer.Reset(time.Millisecond * 100) 245 flushPending = true 246 } 247 case <-timer.C: 248 if conn.Flush() != nil { 249 keepGoing = false 250 break 251 } 252 flushPending = false 253 } 254 } 255 if flushPending { 256 conn.Flush() 257 } 258 l.mutex.Lock() 259 delete(l.streamers, streamer) 260 l.updateMaxLevel() 261 l.mutex.Unlock() 262 // Drain the channel. 263 for { 264 select { 265 case <-channel: 266 default: 267 return 268 } 269 } 270 } 271 272 func (t *loggerMapT) getLogger(name string, 273 authInfo *srpc.AuthInformation) (*Logger, error) { 274 loggerMap.Lock() 275 defer loggerMap.Unlock() 276 if logger, ok := loggerMap.loggerMap[name]; !ok { 277 return nil, errors.New("unknown logger: " + name) 278 } else if err := logger.checkAuth(authInfo); err != nil { 279 return nil, err 280 } else { 281 return logger, nil 282 } 283 } 284 285 func (t *loggerMapT) Debug(conn *srpc.Conn, 286 request proto.DebugRequest, reply *proto.DebugResponse) error { 287 authInfo := conn.GetAuthInformation() 288 if logger, err := t.getLogger(request.Name, authInfo); err != nil { 289 return err 290 } else { 291 logger.Debugf(request.Level, "Logger.Debug(%d): %s\n", 292 request.Level, strings.Join(request.Args, " ")) 293 return nil 294 } 295 } 296 297 func (t *loggerMapT) GetStackTrace(conn *srpc.Conn, 298 request proto.GetStackTraceRequest, 299 reply *proto.GetStackTraceResponse) error { 300 buffer := make([]byte, 1<<20) 301 nBytes := runtime.Stack(buffer, true) 302 reply.Data = buffer[:nBytes] 303 return nil 304 } 305 306 func (t *loggerMapT) Print(conn *srpc.Conn, 307 request proto.PrintRequest, 308 reply *proto.PrintResponse) error { 309 authInfo := conn.GetAuthInformation() 310 if logger, err := t.getLogger(request.Name, authInfo); err != nil { 311 return err 312 } else { 313 logger.Println("Logger.Print():", strings.Join(request.Args, " ")) 314 return nil 315 } 316 } 317 318 func (t *loggerMapT) SetDebugLevel(conn *srpc.Conn, 319 request proto.SetDebugLevelRequest, 320 reply *proto.SetDebugLevelResponse) error { 321 authInfo := conn.GetAuthInformation() 322 if logger, err := t.getLogger(request.Name, authInfo); err != nil { 323 return err 324 } else { 325 logger.Printf("Logger.SetDebugLevel(%d)\n", request.Level) 326 logger.SetLevel(request.Level) 327 return nil 328 } 329 } 330 331 func (t *loggerMapT) Watch(conn *srpc.Conn) error { 332 var request proto.WatchRequest 333 if err := conn.Decode(&request); err != nil { 334 return err 335 } 336 authInfo := conn.GetAuthInformation() 337 if logger, err := t.getLogger(request.Name, authInfo); err != nil { 338 return conn.Encode(proto.WatchResponse{Error: err.Error()}) 339 } else if streamer, err := logger.makeStreamer(request); err != nil { 340 return conn.Encode(proto.WatchResponse{Error: err.Error()}) 341 } else { 342 if err := conn.Encode(proto.WatchResponse{}); err != nil { 343 return err 344 } 345 if err := conn.Flush(); err != nil { 346 return err 347 } 348 logger.watch(conn, streamer) 349 return srpc.ErrorCloseClient 350 } 351 } 352 353 func (l *Logger) writeHtml(writer io.Writer) { 354 if numPanics := srpc.GetNumPanicedCalls(); numPanics > 0 { 355 var suffix string 356 if numPanics > 1 { 357 suffix = "s" 358 } 359 fmt.Fprintf(writer, 360 "<p><font color=\"red\">SRPC Server recorded %d call%s which paniced</font><br>", 361 numPanics, suffix) 362 } 363 l.circularBuffer.WriteHtml(writer) 364 }