Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename WithTags, clarify docs #2

Merged
merged 3 commits into from
Jun 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions examples/tab_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// It's terribly inefficient, and is *only* a basic example.
type TabLogger struct{
name string
tags map[string]interface{}
keyValues map[string]interface{}

writer *tabwriter.Writer
}
Expand All @@ -21,7 +21,7 @@ var _ logr.Logger = &TabLogger{}

func (l *TabLogger) Info(msg string, kvs ...interface{}) {
fmt.Fprintf(l.writer, "%s\t%s\t", l.name, msg)
for k, v := range l.tags {
for k, v := range l.keyValues {
fmt.Fprintf(l.writer, "%s: %+v ", k, v)
}
for i := 0; i < len(kvs); i += 2 {
Expand All @@ -47,22 +47,22 @@ func (l *TabLogger) V(_ int) logr.InfoLogger {
func (l *TabLogger) WithName(name string) logr.Logger {
return &TabLogger{
name: l.name+"."+name,
tags: l.tags,
keyValues: l.keyValues,
writer: l.writer,
}
}

func (l *TabLogger) WithTags(kvs ...interface{}) logr.Logger {
newMap := make(map[string]interface{}, len(l.tags)+len(kvs)/2)
for k, v := range l.tags {
func (l *TabLogger) WithValues(kvs ...interface{}) logr.Logger {
newMap := make(map[string]interface{}, len(l.keyValues)+len(kvs)/2)
for k, v := range l.keyValues {
newMap[k] = v
}
for i := 0; i < len(kvs); i += 2 {
newMap[kvs[i].(string)] = kvs[i+1]
}
return &TabLogger{
name: l.name,
tags: newMap,
keyValues: newMap,
writer: l.writer,
}
}
Expand Down
6 changes: 3 additions & 3 deletions examples/usage_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ func (c *Controller) Run() {
c.log.Info("starting reconciliation")

for key := c.client.WatchNext(); key != ""; key = c.client.WatchNext() {
// we can make more specific loggers if we always want to attach a particular tag
log := c.log.WithTags("key", key)
// we can make more specific loggers if we always want to attach a particular named value
log := c.log.WithValues("key", key)

// fetch our object
obj, err := c.client.Get(key)
Expand All @@ -109,7 +109,7 @@ func (c *Controller) Run() {
}

// always log the object with log messages
log = log.WithTags("object", obj)
log = log.WithValues("object", obj)
log.V(1).Info("reconciling object for key")

// Do some complicated updates updates
Expand Down
58 changes: 41 additions & 17 deletions logr.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
//
// Usage
//
// Logging is done using a Logger. Loggers can have name prefixes and tags attached,
// so that all log messages logged with that Logger have some base context associated.
// 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.
//
// The term "key" is used to refer to the name associated with a particular value, to
// disambiguate it from the general Logger name.
//
// For instance, suppose we're trying to reconcile the state of an object, and we want
// to log that we've made some decision.
Expand All @@ -26,8 +30,8 @@
//
// 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 tag target-type=Foo, for extra context.
// log := mainLogger.WithName("reconcilers").WithTag("target-type", "Foo")
// // and the named value target-type=Foo, for extra context.
// log := mainLogger.WithName("reconcilers").WithValues("target-type", "Foo")
//
// // later on...
// log.Info("setting field foo on object", "value", targetValue, "object", object)
Expand All @@ -47,16 +51,17 @@
// This functions similarly to:
// log.Info("unable to reconcile object", "error", err, "object", object)
//
// However, it ensures that a standard tag ("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.
// 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.
//
// Parts of a log line
//
// Each log message from a Logger has four types of context:
// logger name, log verbosity, log message, and key-value pairs.
// logger name, log verbosity, log message, and the named values.
//
// The Logger name is constists of a series of name "segments" added by successive calls to WithName.
// The Logger name constists 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
// reccomended that name segements 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.
Expand All @@ -65,12 +70,30 @@
// 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.
//
// The log message consists of a constant message attached to the the log line. This
// should generally be a simple description of what's occuring, and should never be a format string.
//
// Variable information can then be attached using key/value pairs. Keys are arbitrary strings,
// and values may be any Go value.
// Variable information can then be attached using named values (key/value pairs). Keys are arbitrary
// strings, while values may be any Go value.
//
// Key Naming Conventions
//
// 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:
//
// - `"error"`: the underlying error value in the `Error` method.
// - `"stacktrace"`: the stack trace associated with a particular log line or error
// (often from the `Error` message).
// - `"caller"`: the calling information (file/line) of a particular log line.
// - `"msg"`: the log message.
// - `"level"`: the log level.
// - `"ts"`: the timestamp for a log line.
//
// Implementations are encouraged to make use of these keys to represent the above
// concepts, when neccessary (for example, in a pure-JSON output form, it would be
// necessary to represent at least message and timestamp as ordinary named values).
package logr

// TODO: consider adding back in format strings if they're really needed
Expand Down Expand Up @@ -101,22 +124,23 @@ type Logger interface {
InfoLogger

// Error logs an error, with the given message and key/value pairs as context.
// It functions similarly to calling Info with the "error" tag, but may have
// unique behavior, and should be preferred for logging errors (see the package
// documentations for more information).
// 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{})

// V returns an InfoLogger value for a specific verbosity level. A higher
// verbosity level means a log message is less important.
// verbosity level means a log message is less important. It's illegal to
// pass a log level less than zero.
V(level int) InfoLogger

// WithTags adds some key-value pairs of context to a logger.
// WithValues adds some key-value pairs of context to a logger.
// See Info for documentation on how key/value pairs work.
WithTags(keysAndValues ...interface{}) Logger
WithValues(keysAndValues ...interface{}) Logger

// WithName adds a new element to the logger's name.
// Successive calls with WithName continue to append
Expand Down
2 changes: 1 addition & 1 deletion testing/null.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ func (log NullLogger) WithName(_ string) logr.Logger {
return log
}

func (log NullLogger) WithTags(_ ...interface{}) logr.Logger {
func (log NullLogger) WithValues(_ ...interface{}) logr.Logger {
return log
}
2 changes: 1 addition & 1 deletion testing/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ func (log TestLogger) WithName(_ string) logr.Logger {
return log
}

func (log TestLogger) WithTags(_ ...interface{}) logr.Logger {
func (log TestLogger) WithValues(_ ...interface{}) logr.Logger {
return log
}