summaryrefslogtreecommitdiff
path: root/vendor/github.com/go-logr/logr/logr.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-logr/logr/logr.go')
-rw-r--r--vendor/github.com/go-logr/logr/logr.go533
1 files changed, 384 insertions, 149 deletions
diff --git a/vendor/github.com/go-logr/logr/logr.go b/vendor/github.com/go-logr/logr/logr.go
index 842428bd3..c05482a20 100644
--- a/vendor/github.com/go-logr/logr/logr.go
+++ b/vendor/github.com/go-logr/logr/logr.go
@@ -16,83 +16,104 @@ limitations under the License.
// This design derives from Dave Cheney's blog:
// http://dave.cheney.net/2015/11/05/lets-talk-about-logging
-//
-// This is a BETA grade API. Until there is a significant 2nd implementation,
-// I don't really know how it will change.
-// Package logr defines abstract interfaces for logging. Packages can depend on
-// these interfaces and callers can implement logging in whatever way is
-// appropriate.
+// Package logr defines a general-purpose logging API and abstract interfaces
+// to back that API. Packages in the Go ecosystem can depend on this package,
+// while callers can implement logging with whatever backend is appropriate.
//
// Usage
//
-// Logging is done using a Logger. Loggers can have name prefixes and named
-// values attached, so that all log messages logged with that Logger have some
-// base context associated.
+// Logging is done using a Logger instance. Logger is a concrete type with
+// methods, which defers the actual logging to a LogSink interface. The main
+// methods of Logger are Info() and Error(). Arguments to Info() and Error()
+// are key/value pairs rather than printf-style formatted strings, emphasizing
+// "structured logging".
//
-// The term "key" is used to refer to the name associated with a particular
-// value, to disambiguate it from the general Logger name.
+// With Go's standard log package, we might write:
+// log.Printf("setting target value %s", targetValue)
//
-// For instance, suppose we're trying to reconcile the state of an object, and
-// we want to log that we've made some decision.
+// With logr's structured logging, we'd write:
+// logger.Info("setting target", "value", targetValue)
//
-// With the traditional log package, we might write:
-// log.Printf("decided to set field foo to value %q for object %s/%s",
-// targetValue, object.Namespace, object.Name)
+// Errors are much the same. Instead of:
+// log.Printf("failed to open the pod bay door for user %s: %v", user, err)
//
-// With logr's structured logging, we'd write:
-// // elsewhere in the file, set up the logger to log with the prefix of
-// // "reconcilers", and the named value target-type=Foo, for extra context.
-// log := mainLogger.WithName("reconcilers").WithValues("target-type", "Foo")
+// We'd write:
+// logger.Error(err, "failed to open the pod bay door", "user", user)
//
-// // later on...
-// log.Info("setting foo on object", "value", targetValue, "object", object)
+// Info() and Error() are very similar, but they are separate methods so that
+// LogSink implementations can choose to do things like attach additional
+// information (such as stack traces) on calls to Error(). Error() messages are
+// always logged, regardless of the current verbosity. If there is no error
+// instance available, passing nil is valid.
+//
+// Verbosity
+//
+// Often we want to log information only when the application in "verbose
+// mode". To write log lines that are more verbose, Logger has a V() method.
+// The higher the V-level of a log line, the less critical it is considered.
+// Log-lines with V-levels that are not enabled (as per the LogSink) will not
+// be written. Level V(0) is the default, and logger.V(0).Info() has the same
+// meaning as logger.Info(). Negative V-levels have the same meaning as V(0).
+// Error messages do not have a verbosity level and are always logged.
+//
+// Where we might have written:
+// if flVerbose >= 2 {
+// log.Printf("an unusual thing happened")
+// }
+//
+// We can write:
+// logger.V(2).Info("an unusual thing happened")
+//
+// Logger Names
+//
+// Logger instances can have name strings so that all messages logged through
+// that instance have additional context. For example, you might want to add
+// a subsystem name:
//
-// Depending on our logging implementation, we could then make logging decisions
-// based on field values (like only logging such events for objects in a certain
-// namespace), or copy the structured information into a structured log store.
+// logger.WithName("compactor").Info("started", "time", time.Now())
//
-// For logging errors, Logger has a method called Error. Suppose we wanted to
-// log an error while reconciling. With the traditional log package, we might
-// write:
-// log.Errorf("unable to reconcile object %s/%s: %v", object.Namespace, object.Name, err)
+// The WithName() method returns a new Logger, which can be passed to
+// constructors or other functions for further use. Repeated use of WithName()
+// will accumulate name "segments". These name segments will be joined in some
+// way by the LogSink implementation. It is strongly recommended that name
+// segments contain simple identifiers (letters, digits, and hyphen), and do
+// not contain characters that could muddle the log output or confuse the
+// joining operation (e.g. whitespace, commas, periods, slashes, brackets,
+// quotes, etc).
//
-// With logr, we'd instead write:
-// // assuming the above setup for log
-// log.Error(err, "unable to reconcile object", "object", object)
+// Saved Values
//
-// This functions similarly to:
-// log.Info("unable to reconcile object", "error", err, "object", object)
+// Logger instances can store any number of key/value pairs, which will be
+// logged alongside all messages logged through that instance. For example,
+// you might want to create a Logger instance per managed object:
//
-// However, it ensures that a standard key for the error value ("error") is used
-// across all error logging. Furthermore, certain implementations may choose to
-// attach additional information (such as stack traces) on calls to Error, so
-// it's preferred to use Error to log errors.
+// With the standard log package, we might write:
+// log.Printf("decided to set field foo to value %q for object %s/%s",
+// targetValue, object.Namespace, object.Name)
//
-// Parts of a log line
+// With logr we'd write:
+// // Elsewhere: set up the logger to log the object name.
+// obj.logger = mainLogger.WithValues(
+// "name", obj.name, "namespace", obj.namespace)
//
-// Each log message from a Logger has four types of context:
-// logger name, log verbosity, log message, and the named values.
+// // later on...
+// obj.logger.Info("setting foo", "value", targetValue)
//
-// The Logger name consists of a series of name "segments" added by successive
-// calls to WithName. These name segments will be joined in some way by the
-// underlying implementation. It is strongly recommended that name segments
-// contain simple identifiers (letters, digits, and hyphen), and do not contain
-// characters that could muddle the log output or confuse the joining operation
-// (e.g. whitespace, commas, periods, slashes, brackets, quotes, etc).
+// Best Practices
//
-// Log verbosity represents how little a log matters. Level zero, the default,
-// matters most. Increasing levels matter less and less. Try to avoid lots of
-// different verbosity levels, and instead provide useful keys, logger names,
-// and log messages for users to filter on. It's illegal to pass a log level
-// below zero.
+// Logger has very few hard rules, with the goal that LogSink implementations
+// might have a lot of freedom to differentiate. There are, however, some
+// things to consider.
//
// The log message consists of a constant message attached to the log line.
// This should generally be a simple description of what's occurring, and should
-// never be a format string.
+// never be a format string. Variable information can then be attached using
+// named values.
//
-// Variable information can then be attached using named values (key/value
-// pairs). Keys are arbitrary strings, while values may be any Go value.
+// Keys are arbitrary strings, but should generally be constant values. Values
+// may be any Go value, but how the value is formatted is determined by the
+// LogSink implementation.
//
// Key Naming Conventions
//
@@ -102,6 +123,7 @@ limitations under the License.
// * be constant (not dependent on input data)
// * contain only printable characters
// * not contain whitespace or punctuation
+// * use lower case for simple keys and lowerCamelCase for more complex ones
//
// These guidelines help ensure that log data is processed properly regardless
// of the log implementation. For example, log implementations will try to
@@ -110,21 +132,22 @@ limitations under the License.
// While users are generally free to use key names of their choice, it's
// generally best to avoid using the following keys, as they're frequently used
// by implementations:
-//
-// * `"caller"`: the calling information (file/line) of a particular log line.
-// * `"error"`: the underlying error value in the `Error` method.
-// * `"level"`: the log level.
-// * `"logger"`: the name of the associated logger.
-// * `"msg"`: the log message.
-// * `"stacktrace"`: the stack trace associated with a particular log line or
-// error (often from the `Error` message).
-// * `"ts"`: the timestamp for a log line.
+// * "caller": the calling information (file/line) of a particular log line
+// * "error": the underlying error value in the `Error` method
+// * "level": the log level
+// * "logger": the name of the associated logger
+// * "msg": the log message
+// * "stacktrace": the stack trace associated with a particular log line or
+// error (often from the `Error` message)
+// * "ts": the timestamp for a log line
//
// Implementations are encouraged to make use of these keys to represent the
// above concepts, when necessary (for example, in a pure-JSON output form, it
// would be necessary to represent at least message and timestamp as ordinary
// named values).
//
+// Break Glass
+//
// Implementations may choose to give callers access to the underlying
// logging implementation. The recommended pattern for this is:
// // Underlier exposes access to the underlying logging implementation.
@@ -134,81 +157,222 @@ limitations under the License.
// type Underlier interface {
// GetUnderlying() <underlying-type>
// }
+//
+// Logger grants access to the sink to enable type assertions like this:
+// func DoSomethingWithImpl(log logr.Logger) {
+// if underlier, ok := log.GetSink()(impl.Underlier) {
+// implLogger := underlier.GetUnderlying()
+// ...
+// }
+// }
+//
+// Custom `With*` functions can be implemented by copying the complete
+// Logger struct and replacing the sink in the copy:
+// // WithFooBar changes the foobar parameter in the log sink and returns a
+// // new logger with that modified sink. It does nothing for loggers where
+// // the sink doesn't support that parameter.
+// func WithFoobar(log logr.Logger, foobar int) logr.Logger {
+// if foobarLogSink, ok := log.GetSink()(FoobarSink); ok {
+// log = log.WithSink(foobarLogSink.WithFooBar(foobar))
+// }
+// return log
+// }
+//
+// Don't use New to construct a new Logger with a LogSink retrieved from an
+// existing Logger. Source code attribution might not work correctly and
+// unexported fields in Logger get lost.
+//
+// Beware that the same LogSink instance may be shared by different logger
+// instances. Calling functions that modify the LogSink will affect all of
+// those.
package logr
import (
"context"
)
-// TODO: consider adding back in format strings if they're really needed
-// TODO: consider other bits of zap/zapcore functionality like ObjectMarshaller (for arbitrary objects)
-// TODO: consider other bits of glog functionality like Flush, OutputStats
+// New returns a new Logger instance. This is primarily used by libraries
+// implementing LogSink, rather than end users.
+func New(sink LogSink) Logger {
+ logger := Logger{}
+ logger.setSink(sink)
+ sink.Init(runtimeInfo)
+ return logger
+}
-// Logger represents the ability to log messages, both errors and not.
-type Logger interface {
- // Enabled tests whether this Logger is enabled. For example, commandline
- // flags might be used to set the logging verbosity and disable some info
- // logs.
- Enabled() bool
+// setSink stores the sink and updates any related fields. It mutates the
+// logger and thus is only safe to use for loggers that are not currently being
+// used concurrently.
+func (l *Logger) setSink(sink LogSink) {
+ l.sink = sink
+}
- // Info logs a non-error message with the given key/value pairs as context.
- //
- // The msg argument should be used to add some constant description to
- // the log line. The key/value pairs can then be used to add additional
- // variable information. The key/value pairs should alternate string
- // keys and arbitrary values.
- Info(msg string, keysAndValues ...interface{})
-
- // Error logs an error, with the given message and key/value pairs as context.
- // It functions similarly to calling Info with the "error" named value, but may
- // have unique behavior, and should be preferred for logging errors (see the
- // package documentations for more information).
- //
- // The msg field should be used to add context to any underlying error,
- // while the err field should be used to attach the actual error that
- // triggered this log line, if present.
- Error(err error, msg string, keysAndValues ...interface{})
+// GetSink returns the stored sink.
+func (l Logger) GetSink() LogSink {
+ return l.sink
+}
+
+// WithSink returns a copy of the logger with the new sink.
+func (l Logger) WithSink(sink LogSink) Logger {
+ l.setSink(sink)
+ return l
+}
+
+// Logger is an interface to an abstract logging implementation. This is a
+// concrete type for performance reasons, but all the real work is passed on to
+// a LogSink. Implementations of LogSink should provide their own constructors
+// that return Logger, not LogSink.
+//
+// The underlying sink can be accessed through GetSink and be modified through
+// WithSink. This enables the implementation of custom extensions (see "Break
+// Glass" in the package documentation). Normally the sink should be used only
+// indirectly.
+type Logger struct {
+ sink LogSink
+ level int
+}
+
+// Enabled tests whether this Logger is enabled. For example, commandline
+// flags might be used to set the logging verbosity and disable some info logs.
+func (l Logger) Enabled() bool {
+ return l.sink.Enabled(l.level)
+}
+
+// Info logs a non-error message with the given key/value pairs as context.
+//
+// The msg argument should be used to add some constant description to the log
+// line. The key/value pairs can then be used to add additional variable
+// information. The key/value pairs must alternate string keys and arbitrary
+// values.
+func (l Logger) Info(msg string, keysAndValues ...interface{}) {
+ if l.Enabled() {
+ if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
+ withHelper.GetCallStackHelper()()
+ }
+ l.sink.Info(l.level, msg, keysAndValues...)
+ }
+}
+
+// Error logs an error, with the given message and key/value pairs as context.
+// It functions similarly to Info, but may have unique behavior, and should be
+// preferred for logging errors (see the package documentations for more
+// information). The log message will always be emitted, regardless of
+// verbosity level.
+//
+// The msg argument should be used to add context to any underlying error,
+// while the err argument should be used to attach the actual error that
+// triggered this log line, if present. The err parameter is optional
+// and nil may be passed instead of an error instance.
+func (l Logger) Error(err error, msg string, keysAndValues ...interface{}) {
+ if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
+ withHelper.GetCallStackHelper()()
+ }
+ l.sink.Error(err, msg, keysAndValues...)
+}
+
+// V returns a new Logger instance for a specific verbosity level, relative to
+// this Logger. In other words, V-levels are additive. A higher verbosity
+// level means a log message is less important. Negative V-levels are treated
+// as 0.
+func (l Logger) V(level int) Logger {
+ if level < 0 {
+ level = 0
+ }
+ l.level += level
+ return l
+}
+
+// WithValues returns a new Logger instance with additional key/value pairs.
+// See Info for documentation on how key/value pairs work.
+func (l Logger) WithValues(keysAndValues ...interface{}) Logger {
+ l.setSink(l.sink.WithValues(keysAndValues...))
+ return l
+}
- // V returns an Logger value for a specific verbosity level, relative to
- // this Logger. In other words, V values are additive. V higher verbosity
- // level means a log message is less important. It's illegal to pass a log
- // level less than zero.
- V(level int) Logger
-
- // WithValues adds some key-value pairs of context to a logger.
- // See Info for documentation on how key/value pairs work.
- WithValues(keysAndValues ...interface{}) Logger
-
- // WithName adds a new element to the logger's name.
- // Successive calls with WithName continue to append
- // suffixes to the logger's name. It's strongly recommended
- // that name segments contain only letters, digits, and hyphens
- // (see the package documentation for more information).
- WithName(name string) Logger
+// WithName returns a new Logger instance with the specified name element added
+// to the Logger's name. Successive calls with WithName append additional
+// suffixes to the Logger's name. It's strongly recommended that name segments
+// contain only letters, digits, and hyphens (see the package documentation for
+// more information).
+func (l Logger) WithName(name string) Logger {
+ l.setSink(l.sink.WithName(name))
+ return l
}
-// InfoLogger provides compatibility with code that relies on the v0.1.0
-// interface.
+// WithCallDepth returns a Logger instance that offsets the call stack by the
+// specified number of frames when logging call site information, if possible.
+// This is useful for users who have helper functions between the "real" call
+// site and the actual calls to Logger methods. If depth is 0 the attribution
+// should be to the direct caller of this function. If depth is 1 the
+// attribution should skip 1 call frame, and so on. Successive calls to this
+// are additive.
+//
+// If the underlying log implementation supports a WithCallDepth(int) method,
+// it will be called and the result returned. If the implementation does not
+// support CallDepthLogSink, the original Logger will be returned.
+//
+// To skip one level, WithCallStackHelper() should be used instead of
+// WithCallDepth(1) because it works with implementions that support the
+// CallDepthLogSink and/or CallStackHelperLogSink interfaces.
+func (l Logger) WithCallDepth(depth int) Logger {
+ if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
+ l.setSink(withCallDepth.WithCallDepth(depth))
+ }
+ return l
+}
+
+// WithCallStackHelper returns a new Logger instance that skips the direct
+// caller when logging call site information, if possible. This is useful for
+// users who have helper functions between the "real" call site and the actual
+// calls to Logger methods and want to support loggers which depend on marking
+// each individual helper function, like loggers based on testing.T.
+//
+// In addition to using that new logger instance, callers also must call the
+// returned function.
//
-// Deprecated: InfoLogger is an artifact of early versions of this API. New
-// users should never use it and existing users should use Logger instead. This
-// will be removed in a future release.
-type InfoLogger = Logger
+// If the underlying log implementation supports a WithCallDepth(int) method,
+// WithCallDepth(1) will be called to produce a new logger. If it supports a
+// WithCallStackHelper() method, that will be also called. If the
+// implementation does not support either of these, the original Logger will be
+// returned.
+func (l Logger) WithCallStackHelper() (func(), Logger) {
+ var helper func()
+ if withCallDepth, ok := l.sink.(CallDepthLogSink); ok {
+ l.setSink(withCallDepth.WithCallDepth(1))
+ }
+ if withHelper, ok := l.sink.(CallStackHelperLogSink); ok {
+ helper = withHelper.GetCallStackHelper()
+ } else {
+ helper = func() {}
+ }
+ return helper, l
+}
+// contextKey is how we find Loggers in a context.Context.
type contextKey struct{}
-// FromContext returns a Logger constructed from ctx or nil if no
-// logger details are found.
-func FromContext(ctx context.Context) Logger {
+// FromContext returns a Logger from ctx or an error if no Logger is found.
+func FromContext(ctx context.Context) (Logger, error) {
if v, ok := ctx.Value(contextKey{}).(Logger); ok {
- return v
+ return v, nil
}
- return nil
+ return Logger{}, notFoundError{}
}
-// FromContextOrDiscard returns a Logger constructed from ctx or a Logger
-// that discards all messages if no logger details are found.
+// notFoundError exists to carry an IsNotFound method.
+type notFoundError struct{}
+
+func (notFoundError) Error() string {
+ return "no logr.Logger was present"
+}
+
+func (notFoundError) IsNotFound() bool {
+ return true
+}
+
+// FromContextOrDiscard returns a Logger from ctx. If no Logger is found, this
+// returns a Logger that discards all log messages.
func FromContextOrDiscard(ctx context.Context) Logger {
if v, ok := ctx.Value(contextKey{}).(Logger); ok {
return v
@@ -217,12 +381,59 @@ func FromContextOrDiscard(ctx context.Context) Logger {
return Discard()
}
-// NewContext returns a new context derived from ctx that embeds the Logger.
-func NewContext(ctx context.Context, l Logger) context.Context {
- return context.WithValue(ctx, contextKey{}, l)
+// NewContext returns a new Context, derived from ctx, which carries the
+// provided Logger.
+func NewContext(ctx context.Context, logger Logger) context.Context {
+ return context.WithValue(ctx, contextKey{}, logger)
}
-// CallDepthLogger represents a Logger that knows how to climb the call stack
+// RuntimeInfo holds information that the logr "core" library knows which
+// LogSinks might want to know.
+type RuntimeInfo struct {
+ // CallDepth is the number of call frames the logr library adds between the
+ // end-user and the LogSink. LogSink implementations which choose to print
+ // the original logging site (e.g. file & line) should climb this many
+ // additional frames to find it.
+ CallDepth int
+}
+
+// runtimeInfo is a static global. It must not be changed at run time.
+var runtimeInfo = RuntimeInfo{
+ CallDepth: 1,
+}
+
+// LogSink represents a logging implementation. End-users will generally not
+// interact with this type.
+type LogSink interface {
+ // Init receives optional information about the logr library for LogSink
+ // implementations that need it.
+ Init(info RuntimeInfo)
+
+ // Enabled tests whether this LogSink is enabled at the specified V-level.
+ // For example, commandline flags might be used to set the logging
+ // verbosity and disable some info logs.
+ Enabled(level int) bool
+
+ // Info logs a non-error message with the given key/value pairs as context.
+ // The level argument is provided for optional logging. This method will
+ // only be called when Enabled(level) is true. See Logger.Info for more
+ // details.
+ Info(level int, msg string, keysAndValues ...interface{})
+
+ // Error logs an error, with the given message and key/value pairs as
+ // context. See Logger.Error for more details.
+ Error(err error, msg string, keysAndValues ...interface{})
+
+ // WithValues returns a new LogSink with additional key/value pairs. See
+ // Logger.WithValues for more details.
+ WithValues(keysAndValues ...interface{}) LogSink
+
+ // WithName returns a new LogSink with the specified name appended. See
+ // Logger.WithName for more details.
+ WithName(name string) LogSink
+}
+
+// CallDepthLogSink represents a Logger that knows how to climb the call stack
// to identify the original call site and can offset the depth by a specified
// number of frames. This is useful for users who have helper functions
// between the "real" call site and the actual calls to Logger methods.
@@ -232,35 +443,59 @@ func NewContext(ctx context.Context, l Logger) context.Context {
//
// This is an optional interface and implementations are not required to
// support it.
-type CallDepthLogger interface {
- Logger
-
- // WithCallDepth returns a Logger that will offset the call stack by the
- // specified number of frames when logging call site information. If depth
- // is 0 the attribution should be to the direct caller of this method. If
- // depth is 1 the attribution should skip 1 call frame, and so on.
+type CallDepthLogSink interface {
+ // WithCallDepth returns a LogSink that will offset the call
+ // stack by the specified number of frames when logging call
+ // site information.
+ //
+ // If depth is 0, the LogSink should skip exactly the number
+ // of call frames defined in RuntimeInfo.CallDepth when Info
+ // or Error are called, i.e. the attribution should be to the
+ // direct caller of Logger.Info or Logger.Error.
+ //
+ // If depth is 1 the attribution should skip 1 call frame, and so on.
// Successive calls to this are additive.
- WithCallDepth(depth int) Logger
+ WithCallDepth(depth int) LogSink
}
-// WithCallDepth returns a Logger that will offset the call stack by the
-// specified number of frames when logging call site information, if possible.
-// This is useful for users who have helper functions between the "real" call
-// site and the actual calls to Logger methods. If depth is 0 the attribution
-// should be to the direct caller of this function. If depth is 1 the
-// attribution should skip 1 call frame, and so on. Successive calls to this
-// are additive.
+// CallStackHelperLogSink represents a Logger that knows how to climb
+// the call stack to identify the original call site and can skip
+// intermediate helper functions if they mark themselves as
+// helper. Go's testing package uses that approach.
//
-// If the underlying log implementation supports the CallDepthLogger interface,
-// the WithCallDepth method will be called and the result returned. If the
-// implementation does not support CallDepthLogger, the original Logger will be
-// returned.
+// This is useful for users who have helper functions between the
+// "real" call site and the actual calls to Logger methods.
+// Implementations that log information about the call site (such as
+// file, function, or line) would otherwise log information about the
+// intermediate helper functions.
//
-// Callers which care about whether this was supported or not should test for
-// CallDepthLogger support themselves.
-func WithCallDepth(logger Logger, depth int) Logger {
- if decorator, ok := logger.(CallDepthLogger); ok {
- return decorator.WithCallDepth(depth)
- }
- return logger
+// This is an optional interface and implementations are not required
+// to support it. Implementations that choose to support this must not
+// simply implement it as WithCallDepth(1), because
+// Logger.WithCallStackHelper will call both methods if they are
+// present. This should only be implemented for LogSinks that actually
+// need it, as with testing.T.
+type CallStackHelperLogSink interface {
+ // GetCallStackHelper returns a function that must be called
+ // to mark the direct caller as helper function when logging
+ // call site information.
+ GetCallStackHelper() func()
+}
+
+// Marshaler is an optional interface that logged values may choose to
+// implement. Loggers with structured output, such as JSON, should
+// log the object return by the MarshalLog method instead of the
+// original value.
+type Marshaler interface {
+ // MarshalLog can be used to:
+ // - ensure that structs are not logged as strings when the original
+ // value has a String method: return a different type without a
+ // String method
+ // - select which fields of a complex type should get logged:
+ // return a simpler struct with fewer fields
+ // - log unexported fields: return a different struct
+ // with exported fields
+ //
+ // It may return any value of any type.
+ MarshalLog() interface{}
}