github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/mgo/logger.go (about) 1 // Copyright 2020 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package mgo 5 6 import ( 7 "runtime" 8 "strings" 9 10 "github.com/juju/loggo" 11 "github.com/juju/mgo/v3" 12 "github.com/juju/mgo/v3/txn" 13 ) 14 15 const ( 16 mgoLoggerName = "juju.mgo" 17 mgoTxnLoggerName = "juju.mgo.txn" 18 ) 19 20 var mgoLogger = loggo.GetLogger(mgoLoggerName) 21 var mgoTxnLogger = loggo.GetLogger(mgoTxnLoggerName) 22 23 // ConfigureMgoLogging sets up juju/mgo package logging according 24 // to the logging config value for "juju.mgo". 25 func ConfigureMgoLogging() { 26 logLevel := mgoLogger.EffectiveLogLevel() 27 // mgo logging is quite verbose. 28 // mgo "debug" is similar to juju "trace". 29 mgo.SetDebug(logLevel == loggo.TRACE) 30 // Only output mgo logging for juju "debug" or greater. 31 if logLevel == loggo.UNSPECIFIED || logLevel >= loggo.INFO { 32 mgo.SetLogger(nil) 33 return 34 } 35 mgo.SetLogger(&mgoLogWriter{ 36 logger: mgoLogger, 37 }) 38 39 logLevel = mgoTxnLogger.EffectiveLogLevel() 40 txn.SetDebug(logLevel == loggo.DEBUG) 41 // Only output mgo txn logging for juju "info" or greater. 42 if logLevel == loggo.UNSPECIFIED || logLevel >= loggo.WARNING { 43 mgo.SetLogger(nil) 44 return 45 } 46 txn.SetLogger(&mgoTxnLogWriter{ 47 logger: mgoLogger, 48 }) 49 } 50 51 type mgoLogWriter struct { 52 logger loggo.Logger 53 } 54 55 // Output implements the mgo log_Logger interface. 56 func (s *mgoLogWriter) Output(calldepth int, message string) error { 57 // If the output results from a debug function, 58 // log at trace level. 59 caller := callerFunc(calldepth - 1) 60 level := loggo.DEBUG 61 if strings.HasPrefix(caller, "debug") { 62 level = loggo.TRACE 63 } 64 s.logger.LogCallf(calldepth, level, message) 65 return nil 66 } 67 68 type mgoTxnLogWriter struct { 69 logger loggo.Logger 70 } 71 72 // Output implements the mgo log_Logger interface. 73 func (s *mgoTxnLogWriter) Output(calldepth int, message string) error { 74 // If the output results from a debug function, 75 // log at debug level. 76 caller := callerFunc(calldepth - 1) 77 level := loggo.INFO 78 if strings.HasPrefix(caller, "debug") { 79 level = loggo.DEBUG 80 } 81 s.logger.LogCallf(calldepth, level, message) 82 return nil 83 } 84 85 // callerFunc returns the name of the function 86 // at the specified call depth. 87 func callerFunc(calldepth int) string { 88 var pcs [100]uintptr 89 n := runtime.Callers(calldepth+2, pcs[:]) 90 frames := runtime.CallersFrames(pcs[:n]) 91 frame, _ := frames.Next() 92 if frame.Func == nil { 93 return "" 94 } 95 parts := strings.Split(frame.Func.Name(), ".") 96 return parts[len(parts)-1] 97 }