1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/pkg/devicemapper/devmapper_log.go
Aleksa Sarai cfd39e8d6d
devicemapper: change LogInit and move all callbacks to pkg
LogInit used to act as a manual way of registering the *necessary*
pkg/devicemapper logging callbacks. In addition, it was used to split up
the logic of pkg/devicemapper into daemon/graphdriver/devmapper (such
that some things were logged from libdm).

The manual aspect of this API was completely non-sensical and was just
begging for incorrect usage of pkg/devicemapper, so remove that semantic
and always register our own libdm callbacks.

In addition, recombine the split out logging callbacks into
pkg/devicemapper so that the default logger is local to the library and
also shown to be the recommended logger. This makes the code
substantially easier to read. Also the new DefaultLogger now has
configurable upper-bound for the log level, which allows for dynamically
changing the logging level.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
2017-07-04 02:04:26 +10:00

121 lines
4.1 KiB
Go

// +build linux,cgo
package devicemapper
import "C"
import (
"fmt"
"strings"
"github.com/Sirupsen/logrus"
)
// DevmapperLogger defines methods required to register as a callback for
// logging events recieved from devicemapper. Note that devicemapper will send
// *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
}
// 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"
// 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).
//export DevmapperLogCallback
func DevmapperLogCallback(level C.int, file *C.char, line, dmErrnoOrClass C.int, message *C.char) {
msg := C.GoString(message)
// Track what errno libdm saw, because the library only gives us 0 or 1.
if level < LogLevelDebug {
if strings.Contains(msg, "busy") {
dmSawBusy = true
}
if strings.Contains(msg, "File exists") {
dmSawExist = true
}
if strings.Contains(msg, "No such device or address") {
dmSawEnxio = true
}
}
if dmLogger != nil {
dmLogger.DMLog(int(level), C.GoString(file), int(line), int(dmErrnoOrClass), msg)
}
}
// 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) {
if int(level) <= l.Level {
// 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()
}