2017-03-29 20:55:42 -04:00
|
|
|
// +build linux,cgo
|
2013-11-27 22:12:51 -05:00
|
|
|
|
2014-11-05 18:10:38 -05:00
|
|
|
package devicemapper
|
2013-10-10 09:24:39 -04:00
|
|
|
|
|
|
|
import "C"
|
|
|
|
|
2014-04-24 16:17:04 -04:00
|
|
|
import (
|
2017-06-27 11:46:47 -04:00
|
|
|
"fmt"
|
2014-04-24 16:17:04 -04:00
|
|
|
"strings"
|
2017-06-27 11:46:47 -04:00
|
|
|
|
2017-07-26 17:42:13 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
2014-04-24 16:17:04 -04:00
|
|
|
)
|
|
|
|
|
2017-06-27 11:46:47 -04:00
|
|
|
// DevmapperLogger defines methods required to register as a callback for
|
2017-09-06 04:54:24 -04:00
|
|
|
// logging events received from devicemapper. Note that devicemapper will send
|
2017-06-27 11:46:47 -04:00
|
|
|
// *all* logs regardless to callbacks (including debug logs) so it's
|
|
|
|
// recommended to not spam the console with the outputs.
|
|
|
|
type DevmapperLogger interface {
|
|
|
|
// DMLog is the logging callback containing all of the information from
|
|
|
|
// devicemapper. The interface is identical to the C libdm counterpart.
|
|
|
|
DMLog(level int, file string, line int, dmError int, message string)
|
|
|
|
}
|
|
|
|
|
|
|
|
// dmLogger is the current logger in use that is being forwarded our messages.
|
|
|
|
var dmLogger DevmapperLogger
|
|
|
|
|
|
|
|
// LogInit changes the logging callback called after processing libdm logs for
|
|
|
|
// error message information. The default logger simply forwards all logs to
|
|
|
|
// logrus. Calling LogInit(nil) disables the calling of callbacks.
|
|
|
|
func LogInit(logger DevmapperLogger) {
|
|
|
|
dmLogger = logger
|
|
|
|
}
|
|
|
|
|
2013-10-10 09:24:39 -04:00
|
|
|
// Due to the way cgo works this has to be in a separate file, as devmapper.go has
|
|
|
|
// definitions in the cgo block, which is incompatible with using "//export"
|
|
|
|
|
2017-06-27 11:46:47 -04:00
|
|
|
// DevmapperLogCallback exports the devmapper log callback for cgo. Note that
|
|
|
|
// because we are using callbacks, this function will be called for *every* log
|
|
|
|
// in libdm (even debug ones because there's no way of setting the verbosity
|
|
|
|
// level for an external logging callback).
|
2013-10-10 09:24:39 -04:00
|
|
|
//export DevmapperLogCallback
|
2017-06-27 11:46:47 -04:00
|
|
|
func DevmapperLogCallback(level C.int, file *C.char, line, dmErrnoOrClass C.int, message *C.char) {
|
2014-04-24 16:17:04 -04:00
|
|
|
msg := C.GoString(message)
|
2017-06-27 11:46:47 -04:00
|
|
|
|
|
|
|
// Track what errno libdm saw, because the library only gives us 0 or 1.
|
|
|
|
if level < LogLevelDebug {
|
2014-04-24 16:17:04 -04:00
|
|
|
if strings.Contains(msg, "busy") {
|
|
|
|
dmSawBusy = true
|
|
|
|
}
|
2014-04-24 16:36:45 -04:00
|
|
|
|
|
|
|
if strings.Contains(msg, "File exists") {
|
|
|
|
dmSawExist = true
|
|
|
|
}
|
2015-04-21 18:14:59 -04:00
|
|
|
|
|
|
|
if strings.Contains(msg, "No such device or address") {
|
|
|
|
dmSawEnxio = true
|
|
|
|
}
|
2014-04-24 16:17:04 -04:00
|
|
|
}
|
|
|
|
|
2013-10-10 09:24:39 -04:00
|
|
|
if dmLogger != nil {
|
2015-09-04 08:56:45 -04:00
|
|
|
dmLogger.DMLog(int(level), C.GoString(file), int(line), int(dmErrnoOrClass), msg)
|
2013-10-10 09:24:39 -04:00
|
|
|
}
|
|
|
|
}
|
2017-06-27 11:46:47 -04:00
|
|
|
|
|
|
|
// DefaultLogger is the default logger used by pkg/devicemapper. It forwards
|
|
|
|
// all logs that are of higher or equal priority to the given level to the
|
|
|
|
// corresponding logrus level.
|
|
|
|
type DefaultLogger struct {
|
|
|
|
// Level corresponds to the highest libdm level that will be forwarded to
|
|
|
|
// logrus. In order to change this, register a new DefaultLogger.
|
|
|
|
Level int
|
|
|
|
}
|
|
|
|
|
|
|
|
// DMLog is the logging callback containing all of the information from
|
|
|
|
// devicemapper. The interface is identical to the C libdm counterpart.
|
|
|
|
func (l DefaultLogger) DMLog(level int, file string, line, dmError int, message string) {
|
2017-08-24 13:11:44 -04:00
|
|
|
if level <= l.Level {
|
2017-06-27 11:46:47 -04:00
|
|
|
// Forward the log to the correct logrus level, if allowed by dmLogLevel.
|
|
|
|
logMsg := fmt.Sprintf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
|
|
|
|
switch level {
|
|
|
|
case LogLevelFatal, LogLevelErr:
|
|
|
|
logrus.Error(logMsg)
|
|
|
|
case LogLevelWarn:
|
|
|
|
logrus.Warn(logMsg)
|
|
|
|
case LogLevelNotice, LogLevelInfo:
|
|
|
|
logrus.Info(logMsg)
|
|
|
|
case LogLevelDebug:
|
|
|
|
logrus.Debug(logMsg)
|
|
|
|
default:
|
|
|
|
// Don't drop any "unknown" levels.
|
|
|
|
logrus.Info(logMsg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// registerLogCallback registers our own logging callback function for libdm
|
|
|
|
// (which is DevmapperLogCallback).
|
|
|
|
//
|
|
|
|
// Because libdm only gives us {0,1} error codes we need to parse the logs
|
|
|
|
// produced by libdm (to set dmSawBusy and so on). Note that by registering a
|
|
|
|
// callback using DevmapperLogCallback, libdm will no longer output logs to
|
|
|
|
// stderr so we have to log everything ourselves. None of this handling is
|
|
|
|
// optional because we depend on log callbacks to parse the logs, and if we
|
|
|
|
// don't forward the log information we'll be in a lot of trouble when
|
|
|
|
// debugging things.
|
|
|
|
func registerLogCallback() {
|
|
|
|
LogWithErrnoInit()
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
// Use the default logger by default. We only allow LogLevelFatal by
|
|
|
|
// default, because internally we mask a lot of libdm errors by retrying
|
|
|
|
// and similar tricks. Also, libdm is very chatty and we don't want to
|
|
|
|
// worry users for no reason.
|
|
|
|
dmLogger = DefaultLogger{
|
|
|
|
Level: LogLevelFatal,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register as early as possible so we don't miss anything.
|
|
|
|
registerLogCallback()
|
|
|
|
}
|