pax_global_header00006660000000000000000000000064135764323140014522gustar00rootroot0000000000000052 comment=cbf5cacfbfff319fd20a42367df566e0ace3d4ee log-0.2.0/000077500000000000000000000000001357643231400123025ustar00rootroot00000000000000log-0.2.0/LICENSE000066400000000000000000000020321357643231400133040ustar00rootroot00000000000000Copyright (c) 2017 Go Log Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. log-0.2.0/README.md000066400000000000000000000077221357643231400135710ustar00rootroot00000000000000# Log [![GoDoc](https://godoc.org/github.com/go-log/log?status.svg)](https://godoc.org/github.com/go-log/log) Log is a logging interface for Go. That's it. Pass around the interface. ## Rationale Users want to standardise logging. Sometimes libraries log. We leave the underlying logging implementation to the user while allowing libraries to log by simply expecting something that satisfies the `Logger` interface. This leaves the user free to pre-configure structure, output, etc. ## Interface The interface is minimalistic on purpose: ```go type Logger interface { Log(v ...interface{}) Logf(format string, v ...interface{}) } ``` For more motivation for this minimal interface, see [Dave Cheney's blog post][cheney]. ## Implementations Libraries will only need [the `Logger` interface](#interface), although they may choose to use [the `nest` package][nest] to create subloggers with additional context. Calling code will need to create a `Logger` interface, and there are a number of implementations and wrappers available to make that easy: * [capture][] is an implementation that saves logged lines in memory. It is especially useful for unit tests that want to check for logged messages. * [fmt][] is an implementation wrapping [an `io.Writer`][io.Writer] like [`os.Stdout`][os.Stdout]. It uses [`fmt.Sprint`][fmt.Sprint] and [`Sprintf`][fmt.Sprintf] to generate the logged lines. * [info][] is an implementation wrapping `Info` and `Infof` calls. It can be used to wrap implementations like [`glog.Verbose`][glog.Verbose] and [`logrus.Entry`][logrus.Entry.Info]. * [print][] is an implementation wrapping `Print` and `Printf` calls. It can be used to wrap implementations like [`glog.Verbose`][logrus.Entry.Print]. * [log][] is an implementation wrapping [`log.Print`][log.Print] and [`log.Printf`][log.Printf]. Outside of this repository, there are additional wrappers for: * [appengine/log][appengine], [here][appengine-wrapper]. * [logrus][], [here][logrus-wrapper]. Although as mentioned above, you can also use the [info][] and [print][] wrappers for logrus. The `Logger` interface is also simple enough to make writing your own implementation or wrapper very straightforward. ## Example Pre-configure a logger using [`WithFields`][logrus.WithFields] and pass it as an option to a library: ```go import ( "github.com/go-log/log/print" "github.com/lib/foo" "github.com/sirupsen/logrus" ) logger := print.New(logrus.WithFields(logrus.Fields{ "library": "github.com/lib/foo", })) f := foo.New(logger) ``` ## Related projects [github.com/go-logr/logr][logr] is a similar interface approach to logging, although [the `logr.Logger` interface][logr.Logger] is more elaborate. [appengine]: https://cloud.google.com/appengine/docs/standard/go/logs/ [appengine-wrapper]: https://github.com/go-log/appengine [capture]: https://godoc.org/github.com/go-log/log/capture [cheney]: https://dave.cheney.net/2015/11/05/lets-talk-about-logging [fmt]: https://godoc.org/github.com/go-log/log/fmt [fmt.Sprint]: https://golang.org/pkg/fmt/#Sprint [fmt.Sprintf]: https://golang.org/pkg/fmt/#Sprintf [glog.Verbose]: https://godoc.org/github.com/golang/glog#Verbose.Info [info]: https://godoc.org/github.com/go-log/log/info [io.Writer]: https://golang.org/pkg/io/#Writer [log]: https://godoc.org/github.com/go-log/log/log [log.Print]: https://golang.org/pkg/log/#Print [log.Printf]: https://golang.org/pkg/log/#Printf [logr]: https://github.com/go-logr/logr [logr.Logger]: https://godoc.org/github.com/go-logr/logr#Logger [logrus]: https://github.com/sirupsen/logrus [logrus-wrapper]: https://github.com/go-log/logrus [logrus.Entry.Info]: https://godoc.org/github.com/sirupsen/logrus#Entry.Info [logrus.Entry.Print]: https://godoc.org/github.com/sirupsen/logrus#Entry.Print [logrus.WithFields]: https://godoc.org/github.com/sirupsen/logrus#WithFields [nest]: https://godoc.org/github.com/go-log/log/nest [os.Stdout]: https://golang.org/pkg/os/#Stdout [print]: https://godoc.org/github.com/go-log/log/print log-0.2.0/capture/000077500000000000000000000000001357643231400137455ustar00rootroot00000000000000log-0.2.0/capture/capture.go000066400000000000000000000015501357643231400157400ustar00rootroot00000000000000// Package capture implements the Logger interface by capturing logged // lines. This is useful for log inspection during unit-testing, // if you want to assert that a particular line has, or has not, been // logged. package capture import ( "fmt" "sync" ) // Logger implements the log.Logger interface by capturing logged // lines. type Logger struct { mutex *sync.Mutex // Entries holds logged entries in submission order. Entries []string } func (logger *Logger) Log(v ...interface{}) { logger.log(fmt.Sprint(v...)) } func (logger *Logger) Logf(format string, v ...interface{}) { logger.log(fmt.Sprintf(format, v...)) } func (logger *Logger) log(entry string) { logger.mutex.Lock() defer logger.mutex.Unlock() logger.Entries = append(logger.Entries, entry) } func New() *Logger { return &Logger{ mutex: &sync.Mutex{}, Entries: []string{}, } } log-0.2.0/capture/capture_test.go000066400000000000000000000013731357643231400170020ustar00rootroot00000000000000package capture import ( "testing" "github.com/go-log/log" ) func testLog(l log.Logger) { l.Log("test") } func testLogf(l log.Logger) { l.Logf("%s", "test") } func TestFMTLogger(t *testing.T) { logger := New() testLog(logger) testLogf(logger) expectedEntries := []string{"test", "test"} for i, expectedEntry := range expectedEntries { if i >= len(logger.Entries) { t.Errorf("missing expected entry %d: %q", i, expectedEntry) continue } actualEntry := logger.Entries[i] if actualEntry != expectedEntry { t.Errorf("unexpected entry %d: %q (expected %q)", i, actualEntry, expectedEntry) } } if len(logger.Entries) > len(expectedEntries) { t.Errorf("additional unexpected entries: %v", logger.Entries[len(expectedEntries):]) } } log-0.2.0/fmt/000077500000000000000000000000001357643231400130705ustar00rootroot00000000000000log-0.2.0/fmt/fmt.go000066400000000000000000000013301357643231400142020ustar00rootroot00000000000000package fmt import ( "fmt" "io" "os" "strings" ) type fmtLogger struct { writer io.Writer } func (t *fmtLogger) Log(v ...interface{}) { t.output(fmt.Sprint(v...)) } func (t *fmtLogger) Logf(format string, v ...interface{}) { t.output(fmt.Sprintf(format, v...)) } func (logger *fmtLogger) output(line string) (n int, err error) { if !strings.HasSuffix(line, "\n") { line += "\n" } return logger.writer.Write([]byte(line)) } // New creates a new fmt logger which writes to stdout. func New() *fmtLogger { return &fmtLogger{writer: os.Stdout} } // NewFromWriter creates a new fmt logger which writes to the given // writer. func NewFromWriter(writer io.Writer) *fmtLogger { return &fmtLogger{writer: writer} } log-0.2.0/fmt/fmt_test.go000066400000000000000000000006401357643231400152440ustar00rootroot00000000000000package fmt import ( "strings" "testing" "github.com/go-log/log" ) func TestFMTLogger(t *testing.T) { builder := &strings.Builder{} var logger log.Logger logger = &fmtLogger{writer: builder} logger.Log("a") logger.Log("b\n") logger.Logf("%s", "c") logger.Logf("%s\n", "d") expected := "a\nb\nc\nd\n" if builder.String() != expected { t.Fatalf("got %q, expected %q", builder.String(), expected) } } log-0.2.0/go.mod000066400000000000000000000000461357643231400134100ustar00rootroot00000000000000module github.com/go-log/log go 1.13 log-0.2.0/info/000077500000000000000000000000001357643231400132355ustar00rootroot00000000000000log-0.2.0/info/info.go000066400000000000000000000010711357643231400145160ustar00rootroot00000000000000// Package info allows users to create a Logger interface from any // object that supports Info and Infof. package info // Info is an interface for Info and Infof. type Info interface { Info(v ...interface{}) Infof(format string, v ...interface{}) } type logger struct { info Info } func (logger *logger) Log(v ...interface{}) { logger.info.Info(v...) } func (logger *logger) Logf(format string, v ...interface{}) { logger.info.Infof(format, v...) } // New creates a new logger wrapping info. func New(info Info) *logger { return &logger{ info: info, } } log-0.2.0/info/info_test.go000066400000000000000000000006371357643231400155640ustar00rootroot00000000000000package info import ( "fmt" "testing" "github.com/go-log/log" ) type info struct{} func (*info) Info(v ...interface{}) { fmt.Println(v...) } func (*info) Infof(format string, v ...interface{}) { fmt.Printf(format+"\n", v...) } func testLog(l log.Logger) { l.Log("test") } func testLogf(l log.Logger) { l.Logf("%s", "test") } func TestNew(t *testing.T) { l := New(&info{}) testLog(l) testLogf(l) } log-0.2.0/log.go000066400000000000000000000016371357643231400134210ustar00rootroot00000000000000// Package log provides a log interface package log // Logger is a generic logging interface type Logger interface { // Log inserts a log entry. Arguments may be handled in the manner // of fmt.Print, but the underlying logger may also decide to handle // them differently. Log(v ...interface{}) // Logf insets a log entry. Arguments are handled in the manner of // fmt.Printf. Logf(format string, v ...interface{}) } var ( // The global default logger DefaultLogger Logger = &noOpLogger{} ) // noOpLogger is used as a placeholder for the default logger type noOpLogger struct{} func (n *noOpLogger) Log(v ...interface{}) {} func (n *noOpLogger) Logf(format string, v ...interface{}) {} // Log logs using the default logger func Log(v ...interface{}) { DefaultLogger.Log(v...) } // Logf logs formatted using the default logger func Logf(format string, v ...interface{}) { DefaultLogger.Logf(format, v...) } log-0.2.0/log/000077500000000000000000000000001357643231400130635ustar00rootroot00000000000000log-0.2.0/log/log.go000066400000000000000000000005541357643231400141770ustar00rootroot00000000000000package log import ( "os" golog "log" ) type logLogger struct { log *golog.Logger } func (t *logLogger) Log(v ...interface{}) { t.log.Print(v...) } func (t *logLogger) Logf(format string, v ...interface{}) { t.log.Printf(format, v...) } func New() *logLogger { return &logLogger{ log: golog.New(os.Stderr, "", golog.LstdFlags|golog.Lshortfile), } } log-0.2.0/log/log_test.go000066400000000000000000000003561357643231400152360ustar00rootroot00000000000000package log import ( "testing" "github.com/go-log/log" ) func testLog(l log.Logger) { l.Log("test") } func testLogf(l log.Logger) { l.Logf("%s", "test") } func TestLogLogger(t *testing.T) { l := New() testLog(l) testLogf(l) } log-0.2.0/log_test.go000066400000000000000000000007031357643231400144510ustar00rootroot00000000000000package log import ( "testing" ) type testLogger struct{} func (t *testLogger) Log(v ...interface{}) { return } func (t *testLogger) Logf(format string, v ...interface{}) { return } func testLog(l Logger) { l.Log("test") } func testLogf(l Logger) { l.Logf("%s", "test") } func TestLogger(t *testing.T) { l := new(testLogger) testLog(l) testLogf(l) } func TestNoOpLogger(t *testing.T) { l := new(noOpLogger) testLog(l) testLogf(l) } log-0.2.0/nest/000077500000000000000000000000001357643231400132535ustar00rootroot00000000000000log-0.2.0/nest/nest.go000066400000000000000000000027171357643231400145620ustar00rootroot00000000000000// Package nest allows users to use a Logger interface to // create another Logger interface. package nest import ( "fmt" "github.com/go-log/log" ) const ( // PreNest is a marker placed between the parent and child values // when calling the wrapped Log method. For example: // // parent := SomeLogger() // child := New(parent, "a", "b") // child.Log("c", "d") // // will result in: // // parent.Log("a", "b", PreLog, "c", "d") PreNest Marker = "pre-nest" ) // Marker is a string synonym. The type difference allows underlying // log implementations to distinguish between the PreNest marker and a // "pre-nest" string literal. type Marker string // String returns a single space (regardless of the underlying marker // string). This makes the output of parent loggers based on a // fmt.Print style more readable, because fmt.Print only inserts space // between two non-string operands. func (m Marker) String() string { return " " } type logger struct { logger log.Logger values []interface{} } func (logger *logger) Log(v ...interface{}) { values := append(logger.values, PreNest) logger.logger.Log(append(values, v...)...) } func (logger *logger) Logf(format string, v ...interface{}) { logger.Log(fmt.Sprintf(format, v...)) } func New(log log.Logger, v ...interface{}) *logger { return &logger{ logger: log, values: v, } } func Newf(log log.Logger, format string, v ...interface{}) *logger { return New(log, fmt.Sprintf(format, v...)) } log-0.2.0/nest/nest_test.go000066400000000000000000000033471357643231400156210ustar00rootroot00000000000000package nest import ( "reflect" "testing" "github.com/go-log/log/capture" ) func TestNew(t *testing.T) { base := capture.New() logger := New(base, map[string]interface{}{"count": 1, "key": "value"}) logger.Log("Log()", "arg") logger.Logf("Logf(%s)", "arg") expectedEntries := []string{"map[count:1 key:value] Log()arg", "map[count:1 key:value] Logf(arg)"} for i, expectedEntry := range expectedEntries { if i >= len(base.Entries) { t.Errorf("missing expected entry %d: %q", i, expectedEntry) continue } actualEntry := base.Entries[i] if actualEntry != expectedEntry { t.Errorf("unexpected entry %d: %q (expected %q)", i, actualEntry, expectedEntry) } } if len(base.Entries) > len(expectedEntries) { t.Errorf("additional unexpected entries: %v", base.Entries[len(expectedEntries):]) } } func TestNewf(t *testing.T) { base := capture.New() logger := Newf(base, "wrap(%s,%d)", "a", 1) logger.Log("Log()", "arg") logger.Logf("Logf(%s)", "arg") expectedEntries := []string{"wrap(a,1) Log()arg", "wrap(a,1) Logf(arg)"} for i, expectedEntry := range expectedEntries { if i >= len(base.Entries) { t.Errorf("missing expected entry %d: %q", i, expectedEntry) continue } actualEntry := base.Entries[i] if actualEntry != expectedEntry { t.Errorf("unexpected entry %d: %q (expected %q)", i, actualEntry, expectedEntry) } } if len(base.Entries) > len(expectedEntries) { t.Errorf("additional unexpected entries: %v", base.Entries[len(expectedEntries):]) } } func TestPreNestComparison(t *testing.T) { if PreNest != "pre-nest" { t.Fatal("the type difference is insufficient to break equality") } if reflect.DeepEqual(PreNest, "pre-nest") { t.Fatal("DeepEqual should be able to distinguish the marker") } } log-0.2.0/print/000077500000000000000000000000001357643231400134365ustar00rootroot00000000000000log-0.2.0/print/print.go000066400000000000000000000011441357643231400151210ustar00rootroot00000000000000// Package print allows users to create a Logger interface from any // object that supports Print and Printf. package print // Printer is an interface for Print and Printf. type Printer interface { Print(v ...interface{}) Printf(format string, v ...interface{}) } type logger struct { printer Printer } func (logger *logger) Log(v ...interface{}) { logger.printer.Print(v...) } func (logger *logger) Logf(format string, v ...interface{}) { logger.printer.Printf(format, v...) } // New creates a new logger wrapping printer. func New(printer Printer) *logger { return &logger{ printer: printer, } } log-0.2.0/print/print_test.go000066400000000000000000000006561357643231400161670ustar00rootroot00000000000000package print import ( "fmt" "testing" "github.com/go-log/log" ) type printer struct{} func (*printer) Print(v ...interface{}) { fmt.Println(v...) } func (*printer) Printf(format string, v ...interface{}) { fmt.Printf(format+"\n", v...) } func testLog(l log.Logger) { l.Log("test") } func testLogf(l log.Logger) { l.Logf("%s", "test") } func TestNew(t *testing.T) { l := New(&printer{}) testLog(l) testLogf(l) }