Skip to content

Commit

Permalink
Move code, fix comments
Browse files Browse the repository at this point in the history
  • Loading branch information
thockin committed Apr 23, 2021
1 parent 988d334 commit 0fdc879
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 223 deletions.
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ This is a BETA grade API.

There are implementations for the following logging libraries:

- **a function**: [funcr](https://github.com/go-logr/logr/funcr)
- **github.com/google/glog**: [glogr](https://github.com/go-logr/glogr)
- **k8s.io/klog**: [klogr](https://git.k8s.io/klog/klogr)
- **go.uber.org/zap**: [zapr](https://github.com/go-logr/zapr)
- **log** (the Go standard library logger):
[stdr](https://github.com/go-logr/stdr)
- **log** (the Go standard library logger): [stdr](https://github.com/go-logr/stdr)
- **github.com/sirupsen/logrus**: [logrusr](https://github.com/bombsimon/logrusr)
- **github.com/wojas/genericr**: [genericr](https://github.com/wojas/genericr) (makes it easy to implement your own backend)
- **logfmt** (Heroku style [logging](https://www.brandur.org/logfmt)): [logfmtr](https://github.com/iand/logfmtr)
Expand All @@ -60,7 +60,7 @@ There are implementations for the following logging libraries:
Similarly to searchability, if you maintain conventions around your
keys, it becomes easy to gather all log lines related to a particular
concept.

- **Structured logs allow better dimensions of filtering**: if you have
structure to your logs, you've got more precise control over how much
information is logged -- you might choose in a particular configuration
Expand Down Expand Up @@ -169,7 +169,7 @@ Then gradually choose levels in between as you need them, working your way
down from 10 (for debug and trace style logs) and up from 1 (for chattier
info-type logs).

## How do I choose my keys
## How do I choose my keys?

- make your keys human-readable
- constant keys are generally a good idea
Expand All @@ -180,4 +180,19 @@ While key names are mostly unrestricted (and spaces are acceptable),
it's generally a good idea to stick to printable ascii characters, or at
least match the general character set of your log lines.

## Why should keys be constant values?

The point of structured logging is to make later log processing easier. Your
keys are, effectively, the schema of each log message. If you use different
keys across instances of the same log-line, you will make your structured logs
much harder to use. `Sprintf()` is for values, not for keys!

## Why is this not a pure interface?

The Logger type is implemented as a struct in order to allow the Go compiler to
optimize things like high-V Info logs tht are not triggered. Not all of these
implementations are implemented yet, but this structure was suggested as a way to
ensure they *can* be implemented. All of the real work is behind the LogSink
interface.

[warning-makes-no-sense]: http://dave.cheney.net/2015/11/05/lets-talk-about-logging
17 changes: 10 additions & 7 deletions discard.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@ limitations under the License.

package logr

// Discard returns a valid Logger that discards all messages logged to it.
// It can be used whenever the caller is not interested in the logs.
// Discard returns a Logger that discards all messages logged to it. It can be
// used whenever the caller is not interested in the logs.
func Discard() Logger {
return Logger{0, DiscardLogger{}}
return Logger{
level: 0,
sink: DiscardLogger{},
}
}

// DiscardLogger is a Logger that discards all messages.
// DiscardLogger is a LogSink that discards all messages.
type DiscardLogger struct{}

// Verify that it actually implements the interface
var _ LogSink = DiscardLogger{}

func (l DiscardLogger) Enabled(int) bool {
return false
}
Expand All @@ -42,6 +48,3 @@ func (l DiscardLogger) WithValues(...interface{}) LogSink {
func (l DiscardLogger) WithName(string) LogSink {
return l
}

// Verify that it actually implements the interface
var _ LogSink = DiscardLogger{}
2 changes: 1 addition & 1 deletion discard_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (

func TestDiscard(t *testing.T) {
l := Discard()
if _, ok := l.(DiscardLogger); !ok {
if _, ok := l.sink.(DiscardLogger); !ok {
t.Error("did not return the expected underlying type")
}
// Verify that none of the methods panic, there is not more we can test.
Expand Down
40 changes: 18 additions & 22 deletions examples/tab_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,21 @@ import (
"github.com/go-logr/logr"
)

// TabLogger is a sample logr.Logger that logs to stderr.
// It's terribly inefficient, and is *only* a basic example.
type TabLogger struct {
// tabLogSink is a sample logr.LogSink that logs to stderr.
// It's terribly inefficient, and is only a basic example.
type tabLogSink struct {
name string
keyValues map[string]interface{}

writer *tabwriter.Writer
writer *tabwriter.Writer
}

var _ logr.Logger = &TabLogger{}
var _ logr.LogSink = tabLogSink{}

func (l *TabLogger) Info(msg string, kvs ...interface{}) {
func (_ tabLogSink) Enabled(level int) bool {
return true
}

func (l tabLogSink) Info(level int, msg string, kvs ...interface{}) {
fmt.Fprintf(l.writer, "%s\t%s\t", l.name, msg)
for k, v := range l.keyValues {
fmt.Fprintf(l.writer, "%s: %+v ", k, v)
Expand All @@ -47,44 +50,37 @@ func (l *TabLogger) Info(msg string, kvs ...interface{}) {
l.writer.Flush()
}

func (_ *TabLogger) Enabled() bool {
return true
}

func (l *TabLogger) Error(err error, msg string, kvs ...interface{}) {
func (l tabLogSink) Error(err error, msg string, kvs ...interface{}) {
kvs = append(kvs, "error", err)
l.Info(msg, kvs...)
}

func (l *TabLogger) V(_ int) logr.Logger {
return l
l.Info(0, msg, kvs...)
}

func (l *TabLogger) WithName(name string) logr.Logger {
return &TabLogger{
func (l tabLogSink) WithName(name string) logr.LogSink {
return tabLogSink{
name: l.name + "." + name,
keyValues: l.keyValues,
writer: l.writer,
}
}

func (l *TabLogger) WithValues(kvs ...interface{}) logr.Logger {
func (l tabLogSink) WithValues(kvs ...interface{}) logr.LogSink {
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{
return tabLogSink{
name: l.name,
keyValues: newMap,
writer: l.writer,
}
}

func NewTabLogger() logr.Logger {
return &TabLogger{
sink := tabLogSink{
writer: tabwriter.NewWriter(os.Stderr, 40, 8, 2, '\t', 0),
}
return logr.New(0, sink)
}
16 changes: 16 additions & 0 deletions funcr/funcr_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
Copyright 2021 The logr Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package funcr

import (
Expand Down
Loading

0 comments on commit 0fdc879

Please sign in to comment.