github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/pkg/devicemapper/devmapper_log.go (about) 1 //go:build linux && cgo 2 // +build linux,cgo 3 4 package devicemapper // import "github.com/docker/docker/pkg/devicemapper" 5 6 import "C" 7 8 import ( 9 "fmt" 10 "strings" 11 12 "github.com/sirupsen/logrus" 13 ) 14 15 // DevmapperLogger defines methods required to register as a callback for 16 // logging events received from devicemapper. Note that devicemapper will send 17 // *all* logs regardless to callbacks (including debug logs) so it's 18 // recommended to not spam the console with the outputs. 19 type DevmapperLogger interface { 20 // DMLog is the logging callback containing all of the information from 21 // devicemapper. The interface is identical to the C libdm counterpart. 22 DMLog(level int, file string, line int, dmError int, message string) 23 } 24 25 // dmLogger is the current logger in use that is being forwarded our messages. 26 var dmLogger DevmapperLogger 27 28 // LogInit changes the logging callback called after processing libdm logs for 29 // error message information. The default logger simply forwards all logs to 30 // logrus. Calling LogInit(nil) disables the calling of callbacks. 31 func LogInit(logger DevmapperLogger) { 32 dmLogger = logger 33 } 34 35 // Due to the way cgo works this has to be in a separate file, as devmapper.go has 36 // definitions in the cgo block, which is incompatible with using "//export" 37 38 // DevmapperLogCallback exports the devmapper log callback for cgo. Note that 39 // because we are using callbacks, this function will be called for *every* log 40 // in libdm (even debug ones because there's no way of setting the verbosity 41 // level for an external logging callback). 42 // 43 //export DevmapperLogCallback 44 func DevmapperLogCallback(level C.int, file *C.char, line, dmErrnoOrClass C.int, message *C.char) { 45 msg := C.GoString(message) 46 47 // Track what errno libdm saw, because the library only gives us 0 or 1. 48 if level < LogLevelDebug { 49 if strings.Contains(msg, "busy") { 50 dmSawBusy = true 51 } 52 53 if strings.Contains(msg, "File exists") { 54 dmSawExist = true 55 } 56 57 if strings.Contains(msg, "No such device or address") { 58 dmSawEnxio = true 59 } 60 if strings.Contains(msg, "No data available") { 61 dmSawEnoData = true 62 } 63 } 64 65 if dmLogger != nil { 66 dmLogger.DMLog(int(level), C.GoString(file), int(line), int(dmErrnoOrClass), msg) 67 } 68 } 69 70 // DefaultLogger is the default logger used by pkg/devicemapper. It forwards 71 // all logs that are of higher or equal priority to the given level to the 72 // corresponding logrus level. 73 type DefaultLogger struct { 74 // Level corresponds to the highest libdm level that will be forwarded to 75 // logrus. In order to change this, register a new DefaultLogger. 76 Level int 77 } 78 79 // DMLog is the logging callback containing all of the information from 80 // devicemapper. The interface is identical to the C libdm counterpart. 81 func (l DefaultLogger) DMLog(level int, file string, line, dmError int, message string) { 82 if level <= l.Level { 83 // Forward the log to the correct logrus level, if allowed by dmLogLevel. 84 logMsg := fmt.Sprintf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message) 85 switch level { 86 case LogLevelFatal, LogLevelErr: 87 logrus.Error(logMsg) 88 case LogLevelWarn: 89 logrus.Warn(logMsg) 90 case LogLevelNotice, LogLevelInfo: 91 logrus.Info(logMsg) 92 case LogLevelDebug: 93 logrus.Debug(logMsg) 94 default: 95 // Don't drop any "unknown" levels. 96 logrus.Info(logMsg) 97 } 98 } 99 } 100 101 // registerLogCallback registers our own logging callback function for libdm 102 // (which is DevmapperLogCallback). 103 // 104 // Because libdm only gives us {0,1} error codes we need to parse the logs 105 // produced by libdm (to set dmSawBusy and so on). Note that by registering a 106 // callback using DevmapperLogCallback, libdm will no longer output logs to 107 // stderr so we have to log everything ourselves. None of this handling is 108 // optional because we depend on log callbacks to parse the logs, and if we 109 // don't forward the log information we'll be in a lot of trouble when 110 // debugging things. 111 func registerLogCallback() { 112 LogWithErrnoInit() 113 } 114 115 func init() { 116 // Use the default logger by default. We only allow LogLevelFatal by 117 // default, because internally we mask a lot of libdm errors by retrying 118 // and similar tricks. Also, libdm is very chatty and we don't want to 119 // worry users for no reason. 120 dmLogger = DefaultLogger{ 121 Level: LogLevelFatal, 122 } 123 124 // Register as early as possible so we don't miss anything. 125 registerLogCallback() 126 }