├── .gitignore ├── CODEOWNERS ├── in-repo.yaml ├── images ├── go-logger.png └── go-logger.svg ├── .travis.yml ├── shims ├── _fake │ ├── fake_test.go │ ├── fake_suite_test.go │ └── fake_logger.go ├── kitlog │ ├── kitlog_suite_test.go │ ├── kitlog.go │ └── kitlog_test.go ├── zerolog │ ├── zerolog_suite_test.go │ ├── zerolog.go │ └── zerolog_test.go ├── logrus │ ├── logrus_suite_test.go │ ├── logrus.go │ └── logrus_test.go └── testlog │ ├── testlog_suite_test.go │ ├── safe.go │ ├── testlog.go │ └── testlog_test.go ├── log_suite_test.go ├── LICENSE ├── _example └── example.go ├── Makefile ├── log_test.go ├── log.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .idea 3 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @InVisionApp/architecture -------------------------------------------------------------------------------- /in-repo.yaml: -------------------------------------------------------------------------------- 1 | owner: 2 | active: 3 | team: core 4 | since: 2018-02-04 5 | -------------------------------------------------------------------------------- /images/go-logger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InVisionApp/go-logger/HEAD/images/go-logger.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | before_install: 4 | - go get -t -v ./... 5 | 6 | script: 7 | - make test/codecov 8 | 9 | after_success: 10 | - bash <(curl -s https://codecov.io/bash) 11 | -------------------------------------------------------------------------------- /shims/_fake/fake_test.go: -------------------------------------------------------------------------------- 1 | package fake 2 | 3 | import ( 4 | "github.com/InVisionApp/go-logger" 5 | . "github.com/onsi/ginkgo" 6 | ) 7 | 8 | var _ = Describe("meets the interface", func() { 9 | var _ log.Logger = &FakeLogger{} 10 | }) 11 | -------------------------------------------------------------------------------- /shims/kitlog/kitlog_suite_test.go: -------------------------------------------------------------------------------- 1 | package kitlog_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestKitlog(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Kitlog Suite") 13 | } 14 | -------------------------------------------------------------------------------- /shims/zerolog/zerolog_suite_test.go: -------------------------------------------------------------------------------- 1 | package zerolog_test 2 | 3 | import ( 4 | . "github.com/onsi/ginkgo" 5 | . "github.com/onsi/gomega" 6 | 7 | "testing" 8 | ) 9 | 10 | func TestZerolog(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Zerolog Suite") 13 | } 14 | -------------------------------------------------------------------------------- /log_suite_test.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | ) 11 | 12 | func TestLoggersSuite(t *testing.T) { 13 | // reduce the noise when testing 14 | logrus.SetLevel(logrus.FatalLevel) 15 | 16 | RegisterFailHandler(Fail) 17 | RunSpecs(t, "Loggers Suite") 18 | } 19 | -------------------------------------------------------------------------------- /shims/logrus/logrus_suite_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | ) 11 | 12 | func TestLogrusSuite(t *testing.T) { 13 | // reduce the noise when testing 14 | logrus.SetLevel(logrus.FatalLevel) 15 | 16 | RegisterFailHandler(Fail) 17 | RunSpecs(t, "Logrus Suite") 18 | } 19 | -------------------------------------------------------------------------------- /shims/_fake/fake_suite_test.go: -------------------------------------------------------------------------------- 1 | package fake 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | ) 11 | 12 | func TestFakeLoggerSuite(t *testing.T) { 13 | // reduce the noise when testing 14 | logrus.SetLevel(logrus.FatalLevel) 15 | 16 | RegisterFailHandler(Fail) 17 | RunSpecs(t, "FakeLogger Suite") 18 | } 19 | -------------------------------------------------------------------------------- /shims/testlog/testlog_suite_test.go: -------------------------------------------------------------------------------- 1 | package testlog 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/sirupsen/logrus" 7 | 8 | . "github.com/onsi/ginkgo" 9 | . "github.com/onsi/gomega" 10 | ) 11 | 12 | func TestSuiteNameSuite(t *testing.T) { 13 | // reduce the noise when testing 14 | logrus.SetLevel(logrus.FatalLevel) 15 | 16 | RegisterFailHandler(Fail) 17 | RunSpecs(t, "SuiteName Suite") 18 | } 19 | -------------------------------------------------------------------------------- /shims/testlog/safe.go: -------------------------------------------------------------------------------- 1 | package testlog 2 | 3 | import "sync" 4 | 5 | /************* 6 | Safe Counter 7 | *************/ 8 | 9 | type counter struct { 10 | num int 11 | mu *sync.Mutex 12 | } 13 | 14 | //New counter stating at 0 15 | func newCounter() *counter { 16 | return &counter{num: 0, mu: &sync.Mutex{}} 17 | } 18 | 19 | func (c *counter) inc() { 20 | c.mu.Lock() 21 | defer c.mu.Unlock() 22 | c.num++ 23 | } 24 | 25 | func (c *counter) reset() { 26 | c.mu.Lock() 27 | defer c.mu.Unlock() 28 | c.num = 0 29 | } 30 | 31 | func (c *counter) val() int { 32 | c.mu.Lock() 33 | defer c.mu.Unlock() 34 | return c.num 35 | } 36 | -------------------------------------------------------------------------------- /shims/logrus/logrus.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "github.com/InVisionApp/go-logger" 5 | "github.com/sirupsen/logrus" 6 | ) 7 | 8 | type shim struct { 9 | *logrus.Entry 10 | } 11 | 12 | // NewLogrus can be used to override the default logger. 13 | // Optionally pass in an existing logrus logger or pass in 14 | // `nil` to use the default logger. 15 | func New(logger *logrus.Logger) log.Logger { 16 | if logger == nil { 17 | logger = logrus.StandardLogger() 18 | } 19 | 20 | return &shim{logrus.NewEntry(logger)} 21 | } 22 | 23 | // WithFields will return a new logger based on the original logger with 24 | // the additional supplied fields. Wrapper for logrus Entry.WithFields() 25 | func (s *shim) WithFields(fields log.Fields) log.Logger { 26 | cp := &shim{ 27 | s.Entry.WithFields(logrus.Fields(fields)), 28 | } 29 | return cp 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 InVision 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_example/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/InVisionApp/go-logger" 8 | "github.com/InVisionApp/go-logger/shims/_fake" 9 | "github.com/InVisionApp/go-logger/shims/logrus" 10 | "github.com/InVisionApp/go-logger/shims/testlog" 11 | ) 12 | 13 | func main() { 14 | /********************** 15 | Simple, no-op, logrus 16 | **********************/ 17 | 18 | loggers := map[string]log.Logger{ 19 | "Simple": log.NewSimple(), 20 | "No-op": log.NewNoop(), 21 | "Logrus": logrus.New(nil), 22 | } 23 | 24 | // sleeps for print order 25 | for name, lg := range loggers { 26 | time.Sleep(time.Millisecond * 10) 27 | fmt.Printf("__%s Logger__________\n", name) 28 | time.Sleep(time.Millisecond * 10) 29 | 30 | lg.Info(name, "logger") 31 | lg.WithFields(log.Fields{"foo": "bar"}).Errorf("%s logger", name) 32 | 33 | time.Sleep(time.Millisecond * 10) 34 | fmt.Println() 35 | } 36 | 37 | time.Sleep(time.Millisecond * 10) 38 | 39 | /************ 40 | Test Logger 41 | ************/ 42 | 43 | fmt.Println("__Test Logger__________") 44 | tl := testlog.New() 45 | tl.Infof("this is a test %s", "log") 46 | fmt.Print(string(tl.Bytes())) 47 | fmt.Println("call count:", tl.CallCount()) 48 | fmt.Println() 49 | 50 | /************ 51 | Fake Logger 52 | ************/ 53 | 54 | fmt.Println("__Fake Logger__________") 55 | fakeLog := &fake.FakeLogger{} 56 | 57 | fakeLog.Debug("this is a ", "fakelog") 58 | fmt.Println("call count:", fakeLog.DebugCallCount()) 59 | } 60 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | OUTPUT_DIR = build 2 | TMP_DIR := .tmp 3 | RELEASE_VER := $(shell git rev-parse --short HEAD) 4 | NAME = default 5 | COVERMODE = atomic 6 | 7 | TEST_PACKAGES := $(shell go list ./... | grep -v vendor | grep -v fakes) 8 | 9 | .PHONY: help 10 | .DEFAULT_GOAL := help 11 | 12 | test: getdeps test/integration ## Perform both unit and integration tests 13 | 14 | testv: getdeps testv/integration ## Perform both unit and integration tests (with verbose flags) 15 | 16 | test/unit: ## Perform unit tests 17 | go test -cover $(TEST_PACKAGES) 18 | 19 | testv/unit: ## Perform unit tests (with verbose flag) 20 | go test -v -cover $(TEST_PACKAGES) 21 | 22 | test/integration: ## Perform integration tests 23 | go test -cover -tags integration $(TEST_PACKAGES) 24 | 25 | testv/integration: ## Perform integration tests 26 | go test -v -cover -tags integration $(TEST_PACKAGES) 27 | 28 | test/race: ## Perform unit tests and enable the race detector 29 | go test -race -cover $(TEST_PACKAGES) 30 | 31 | test/cover: ## Run all tests + open coverage report for all packages 32 | echo 'mode: $(COVERMODE)' > .coverage 33 | for PKG in $(TEST_PACKAGES); do \ 34 | go test -coverprofile=.coverage.tmp -tags "integration" $$PKG; \ 35 | grep -v -E '^mode:' .coverage.tmp >> .coverage; \ 36 | done 37 | go tool cover -html=.coverage 38 | $(RM) .coverage .coverage.tmp 39 | 40 | test/codecov: ## Run all tests + open coverage report for all packages 41 | ECODE=0; \ 42 | for PKG in $(TEST_PACKAGES); do \ 43 | go test -covermode=$(COVERMODE) -coverprofile=profile.out $$PKG; \ 44 | ECODE=$$((ECODE+$$?));\ 45 | if [ -f profile.out ]; then\ 46 | cat profile.out >> coverage.txt;\ 47 | rm profile.out;\ 48 | fi;\ 49 | done;\ 50 | $(RM) profile.out ;\ 51 | exit $$ECODE;\ 52 | 53 | getdeps: ## Install needed dependencies for various middlewares 54 | go get -t -v ./... 55 | 56 | generate: ## Run generate for non-vendor packages only 57 | go list ./... | grep -v vendor | xargs go generate 58 | 59 | help: ## Display this help message 60 | @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_\/-]+:.*?## / {printf "\033[34m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | \ 61 | sort | \ 62 | grep -v '#' 63 | -------------------------------------------------------------------------------- /shims/kitlog/kitlog.go: -------------------------------------------------------------------------------- 1 | package kitlog 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/InVisionApp/go-logger" 8 | kitlog "github.com/go-kit/kit/log" 9 | "github.com/go-kit/kit/log/level" 10 | ) 11 | 12 | type shim struct { 13 | logger kitlog.Logger 14 | } 15 | 16 | // New can be used to override the default logger. 17 | // Optionally pass in an existing kitlog logger or 18 | // pass in `nil` to use the default logger. 19 | func New(logger kitlog.Logger) log.Logger { 20 | if logger == nil { 21 | logger = kitlog.NewLogfmtLogger(kitlog.NewSyncWriter(os.Stdout)) 22 | } 23 | 24 | return &shim{logger: logger} 25 | } 26 | 27 | // this will add a space between all elements in the slice 28 | // this func is needed because fmt.Sprint will not separate 29 | // inputs by a space in all cases, which makes the resulting 30 | // output very hard to read 31 | func spaceSep(a []interface{}) []interface{} { 32 | aLen := len(a) 33 | if aLen <= 1 { 34 | return a 35 | } 36 | 37 | // we only allocate enough room to add a single space between 38 | // all elements, so len(a) - 1 39 | spaceSlice := make([]interface{}, aLen-1) 40 | // add the empty space to the end of the original slice 41 | a = append(a, spaceSlice...) 42 | 43 | // stagger the values. this will leave an empty slot between all 44 | // values to be filled with a space 45 | for i := aLen - 1; i > 0; i-- { 46 | a[i+i] = a[i] 47 | a[i+i-1] = " " 48 | } 49 | 50 | return a 51 | } 52 | 53 | func (s *shim) Debug(msg ...interface{}) { 54 | level.Debug(s.logger).Log("msg", fmt.Sprint(spaceSep(msg)...)) 55 | } 56 | 57 | func (s *shim) Info(msg ...interface{}) { 58 | level.Info(s.logger).Log("msg", fmt.Sprint(spaceSep(msg)...)) 59 | } 60 | 61 | func (s *shim) Warn(msg ...interface{}) { 62 | level.Warn(s.logger).Log("msg", fmt.Sprint(spaceSep(msg)...)) 63 | } 64 | 65 | func (s *shim) Error(msg ...interface{}) { 66 | level.Error(s.logger).Log("msg", fmt.Sprint(spaceSep(msg)...)) 67 | } 68 | 69 | func (s *shim) Debugln(msg ...interface{}) { 70 | level.Debug(s.logger).Log("msg", fmt.Sprint(spaceSep(msg)...)) 71 | } 72 | 73 | func (s *shim) Infoln(msg ...interface{}) { 74 | level.Info(s.logger).Log("msg", fmt.Sprint(spaceSep(msg)...)) 75 | } 76 | 77 | func (s *shim) Warnln(msg ...interface{}) { 78 | level.Warn(s.logger).Log("msg", fmt.Sprint(spaceSep(msg)...)) 79 | } 80 | 81 | func (s *shim) Errorln(msg ...interface{}) { 82 | level.Error(s.logger).Log("msg", fmt.Sprint(spaceSep(msg)...)) 83 | } 84 | 85 | func (s *shim) Debugf(format string, args ...interface{}) { 86 | level.Debug(s.logger).Log("msg", fmt.Sprintf(format, args...)) 87 | } 88 | 89 | func (s *shim) Infof(format string, args ...interface{}) { 90 | level.Info(s.logger).Log("msg", fmt.Sprintf(format, args...)) 91 | } 92 | 93 | func (s *shim) Warnf(format string, args ...interface{}) { 94 | level.Warn(s.logger).Log("msg", fmt.Sprintf(format, args...)) 95 | } 96 | 97 | func (s *shim) Errorf(format string, args ...interface{}) { 98 | level.Error(s.logger).Log("msg", fmt.Sprintf(format, args...)) 99 | } 100 | 101 | // WithFields will return a new logger derived from the original 102 | // kitlog logger, with the provided fields added to the log string, 103 | // as a key-value pair 104 | func (s *shim) WithFields(fields log.Fields) log.Logger { 105 | var keyvals []interface{} 106 | 107 | for key, value := range fields { 108 | keyvals = append(keyvals, key, value) 109 | } 110 | 111 | return &shim{ 112 | logger: kitlog.With(s.logger, keyvals...), 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /shims/zerolog/zerolog.go: -------------------------------------------------------------------------------- 1 | package zerolog 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/InVisionApp/go-logger" 8 | "github.com/rs/zerolog" 9 | ) 10 | 11 | type shim struct { 12 | logger *zerolog.Logger 13 | } 14 | 15 | // New can be used to override the default logger. 16 | // Optionally pass in an existing zerolog logger or 17 | // pass in `nil` to use the default logger 18 | func New(logger *zerolog.Logger) log.Logger { 19 | if logger == nil { 20 | lg := zerolog.New(os.Stdout).With().Timestamp().Logger() 21 | logger = &lg 22 | } 23 | 24 | return &shim{logger: logger} 25 | } 26 | 27 | // this will add a space between all elements in the slice 28 | // this func is needed because fmt.Sprint will not separate 29 | // inputs by a space in all cases, which makes the resulting 30 | // output very hard to read 31 | func spaceSep(a []interface{}) []interface{} { 32 | aLen := len(a) 33 | if aLen <= 1 { 34 | return a 35 | } 36 | 37 | // we only allocate enough room to add a single space between 38 | // all elements, so len(a) - 1 39 | spaceSlice := make([]interface{}, aLen-1) 40 | // add the empty space to the end of the original slice 41 | a = append(a, spaceSlice...) 42 | 43 | // stagger the values. this will leave an empty slot between all 44 | // values to be filled with a space 45 | for i := aLen - 1; i > 0; i-- { 46 | a[i+i] = a[i] 47 | a[i+i-1] = " " 48 | } 49 | 50 | return a 51 | } 52 | 53 | func (s *shim) Debug(msg ...interface{}) { 54 | s.logger.Debug().Msg(fmt.Sprint(spaceSep(msg)...)) 55 | } 56 | 57 | func (s *shim) Info(msg ...interface{}) { 58 | s.logger.Info().Msg(fmt.Sprint(spaceSep(msg)...)) 59 | } 60 | 61 | func (s *shim) Warn(msg ...interface{}) { 62 | s.logger.Warn().Msg(fmt.Sprint(spaceSep(msg)...)) 63 | } 64 | 65 | func (s *shim) Error(msg ...interface{}) { 66 | s.logger.Error().Msg(fmt.Sprint(spaceSep(msg)...)) 67 | } 68 | 69 | /******************************************************************* 70 | *ln funcs 71 | zerolog is a json-only structured logger. 72 | To implement human-readable console logging, 73 | you must initialize the logger using zerolog.ConsoleWriter 74 | as your io.Writer. Calling a *ln func when zerolog 75 | is in structured logging mode is a no-op 76 | *******************************************************************/ 77 | 78 | func (s *shim) Debugln(msg ...interface{}) { 79 | msg = append(msg, "\n") 80 | s.logger.Debug().Msg(fmt.Sprint(spaceSep(msg)...)) 81 | } 82 | 83 | func (s *shim) Infoln(msg ...interface{}) { 84 | msg = append(msg, "\n") 85 | s.logger.Info().Msg(fmt.Sprint(spaceSep(msg)...)) 86 | } 87 | 88 | func (s *shim) Warnln(msg ...interface{}) { 89 | msg = append(msg, "\n") 90 | s.logger.Warn().Msg(fmt.Sprint(spaceSep(msg)...)) 91 | } 92 | 93 | func (s *shim) Errorln(msg ...interface{}) { 94 | msg = append(msg, "\n") 95 | s.logger.Error().Msg(fmt.Sprint(spaceSep(msg)...)) 96 | } 97 | 98 | func (s *shim) Debugf(format string, args ...interface{}) { 99 | s.logger.Debug().Msgf(format, args...) 100 | } 101 | 102 | func (s *shim) Infof(format string, args ...interface{}) { 103 | s.logger.Info().Msgf(format, args...) 104 | } 105 | 106 | func (s *shim) Warnf(format string, args ...interface{}) { 107 | s.logger.Warn().Msgf(format, args...) 108 | } 109 | 110 | func (s *shim) Errorf(format string, args ...interface{}) { 111 | s.logger.Error().Msgf(format, args...) 112 | } 113 | 114 | // WithFields will return a new logger derived from the original 115 | // zerolog logger, with the provided fields added to the log string, 116 | // as a key-value pair 117 | func (s *shim) WithFields(fields log.Fields) log.Logger { 118 | lg := s.logger.With().Fields(fields).Logger() 119 | s.logger = &lg 120 | 121 | return s 122 | } 123 | -------------------------------------------------------------------------------- /shims/testlog/testlog.go: -------------------------------------------------------------------------------- 1 | package testlog 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | 7 | "github.com/InVisionApp/go-logger" 8 | ) 9 | 10 | // TestLogger is used to capture logs during the execution of a test. 11 | // It writes the logs to a byte buffer which can be dumped and 12 | // inspected. It also tracks a call count of the total number of 13 | // times the logger has been called. Note that this logger is not 14 | // meant to be used in production. It is meant only for tests. 15 | type TestLogger struct { 16 | buf *bytes.Buffer 17 | count *counter 18 | fields map[string]interface{} 19 | } 20 | 21 | // NewTestLog generates a new TestLogger 22 | func New() *TestLogger { 23 | b := &bytes.Buffer{} 24 | 25 | return &TestLogger{ 26 | buf: b, 27 | count: newCounter(), 28 | } 29 | } 30 | 31 | // Bytes returns all bytes of the log buffer 32 | func (t *TestLogger) Bytes() []byte { 33 | return t.buf.Bytes() 34 | } 35 | 36 | // CallCount returns the number of times this logger was called 37 | func (t *TestLogger) CallCount() int { 38 | return t.count.val() 39 | } 40 | 41 | // Reset the log buffer and call count 42 | func (t *TestLogger) Reset() { 43 | t.buf.Reset() 44 | t.count.reset() 45 | } 46 | 47 | func (t *TestLogger) write(level, msg string) { 48 | t.buf.WriteString(fmt.Sprintf("[%s] %s %s", level, msg, pretty(t.fields)+"\n")) 49 | t.count.inc() 50 | } 51 | 52 | //Debugln log line message 53 | func (t *TestLogger) Debugln(msg ...interface{}) { 54 | a := fmt.Sprintln(msg...) 55 | t.write("DEBUG", a[:len(a)-1]) 56 | } 57 | 58 | //Infoln log line message 59 | func (t *TestLogger) Infoln(msg ...interface{}) { 60 | a := fmt.Sprintln(msg...) 61 | t.write("INFO", a[:len(a)-1]) 62 | } 63 | 64 | //Warnln log line message 65 | func (t *TestLogger) Warnln(msg ...interface{}) { 66 | a := fmt.Sprintln(msg...) 67 | t.write("WARN", a[:len(a)-1]) 68 | } 69 | 70 | //Errorln log line message 71 | func (t *TestLogger) Errorln(msg ...interface{}) { 72 | a := fmt.Sprintln(msg...) 73 | t.write("ERROR", a[:len(a)-1]) 74 | } 75 | 76 | // Debug log message 77 | func (t *TestLogger) Debug(msg ...interface{}) { 78 | t.write("DEBUG", fmt.Sprint(msg...)) 79 | } 80 | 81 | // Info log message 82 | func (t *TestLogger) Info(msg ...interface{}) { 83 | t.write("INFO", fmt.Sprint(msg...)) 84 | } 85 | 86 | // Warn log message 87 | func (t *TestLogger) Warn(msg ...interface{}) { 88 | t.write("WARN", fmt.Sprint(msg...)) 89 | } 90 | 91 | // Error log message 92 | func (t *TestLogger) Error(msg ...interface{}) { 93 | t.write("ERROR", fmt.Sprint(msg...)) 94 | } 95 | 96 | // Debugf log message with formatting 97 | func (t *TestLogger) Debugf(format string, args ...interface{}) { 98 | t.write("DEBUG", fmt.Sprintf(format, args...)) 99 | } 100 | 101 | // Infof log message with formatting 102 | func (t *TestLogger) Infof(format string, args ...interface{}) { 103 | t.write("INFO", fmt.Sprintf(format, args...)) 104 | } 105 | 106 | // Warnf log message with formatting 107 | func (t *TestLogger) Warnf(format string, args ...interface{}) { 108 | t.write("WARN", fmt.Sprintf(format, args...)) 109 | } 110 | 111 | // Errorf log message with formatting 112 | func (t *TestLogger) Errorf(format string, args ...interface{}) { 113 | t.write("ERROR", fmt.Sprintf(format, args...)) 114 | } 115 | 116 | // WithFields will return a new logger based on the original logger 117 | // with the additional supplied fields 118 | func (t *TestLogger) WithFields(fields log.Fields) log.Logger { 119 | cp := &TestLogger{ 120 | buf: t.buf, 121 | count: t.count, 122 | } 123 | 124 | if t.fields == nil { 125 | cp.fields = fields 126 | return cp 127 | } 128 | 129 | cp.fields = make(map[string]interface{}, len(t.fields)+len(fields)) 130 | for k, v := range t.fields { 131 | cp.fields[k] = v 132 | } 133 | 134 | for k, v := range fields { 135 | cp.fields[k] = v 136 | } 137 | 138 | return cp 139 | } 140 | 141 | // helper for pretty printing of fields 142 | func pretty(m map[string]interface{}) string { 143 | if len(m) < 1 { 144 | return "" 145 | } 146 | 147 | s := "" 148 | for k, v := range m { 149 | s += fmt.Sprintf("%s=%v ", k, v) 150 | } 151 | 152 | return s[:len(s)-1] 153 | } 154 | -------------------------------------------------------------------------------- /shims/logrus/logrus_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | 6 | "github.com/InVisionApp/go-logger" 7 | . "github.com/onsi/ginkgo" 8 | . "github.com/onsi/gomega" 9 | "github.com/sirupsen/logrus" 10 | ) 11 | 12 | var _ = Describe("meets the interface", func() { 13 | var _ log.Logger = &shim{} 14 | }) 15 | 16 | var _ = Describe("logrus logger", func() { 17 | var ( 18 | newOut *bytes.Buffer 19 | l log.Logger 20 | ) 21 | 22 | BeforeEach(func() { 23 | newOut = &bytes.Buffer{} 24 | logrus.SetOutput(newOut) 25 | logrus.SetLevel(logrus.DebugLevel) 26 | l = New(nil) 27 | }) 28 | 29 | Context("happy path", func() { 30 | It("prints all log levels", func() { 31 | logFuncs := map[string]func(...interface{}){ 32 | "debug": l.Debug, 33 | "info": l.Info, 34 | "warn": l.Warn, 35 | "error": l.Error, 36 | } 37 | 38 | for level, logFunc := range logFuncs { 39 | logFunc("hi there") 40 | 41 | b := newOut.Bytes() 42 | newOut.Reset() 43 | Expect(string(b)).To(SatisfyAll( 44 | ContainSubstring("hi there"), 45 | ContainSubstring("level="+level), 46 | )) 47 | } 48 | }) 49 | 50 | It("prints all log levels", func() { 51 | logFuncs := map[string]func(...interface{}){ 52 | "debug": l.Debugln, 53 | "info": l.Infoln, 54 | "warn": l.Warnln, 55 | "error": l.Errorln, 56 | } 57 | 58 | for level, logFunc := range logFuncs { 59 | logFunc("hi", "there") 60 | 61 | b := newOut.Bytes() 62 | newOut.Reset() 63 | Expect(string(b)).To(SatisfyAll( 64 | ContainSubstring("hi there"), 65 | ContainSubstring("level="+level), 66 | )) 67 | } 68 | }) 69 | 70 | It("prints all log levels on formatted", func() { 71 | logFuncs := map[string]func(string, ...interface{}){ 72 | "debug": l.Debugf, 73 | "info": l.Infof, 74 | "warn": l.Warnf, 75 | "error": l.Errorf, 76 | } 77 | 78 | for level, logFunc := range logFuncs { 79 | logFunc("hi %s", "there") 80 | 81 | b := newOut.Bytes() 82 | newOut.Reset() 83 | Expect(string(b)).To(SatisfyAll( 84 | ContainSubstring("hi there"), 85 | ContainSubstring("level="+level), 86 | )) 87 | } 88 | }) 89 | 90 | It("join multiple strings", func() { 91 | l.Debug("hi there ", "you") 92 | 93 | b := newOut.Bytes() 94 | Expect(string(b)).To(SatisfyAll( 95 | ContainSubstring("hi there you"), 96 | ContainSubstring("level=debug"), 97 | )) 98 | }) 99 | 100 | It("formatting", func() { 101 | l.Debugf("hi there %s", "you") 102 | 103 | b := newOut.Bytes() 104 | Expect(string(b)).To(SatisfyAll( 105 | ContainSubstring("hi there you"), 106 | ContainSubstring("level=debug"), 107 | )) 108 | }) 109 | 110 | Context("with fields", func() { 111 | It("appends to preexisting fields", func() { 112 | withFields := l.WithFields(map[string]interface{}{ 113 | "foo": "oldval", 114 | "baz": "origval", 115 | }) 116 | 117 | withFields.WithFields(map[string]interface{}{ 118 | "foo": "newval", 119 | "biz": "buzz", 120 | }).Debug("hi there") 121 | 122 | b := newOut.Bytes() 123 | Expect(string(b)).To(SatisfyAll( 124 | ContainSubstring("hi there"), 125 | ContainSubstring("foo=newval"), 126 | ContainSubstring("baz=origval"), 127 | ContainSubstring("biz=buzz"), 128 | )) 129 | 130 | }) 131 | 132 | It("creates a copy", func() { 133 | l.WithFields(map[string]interface{}{ 134 | "foo": "bar", 135 | "baz": 2, 136 | }).Debug("hi there ", "you") 137 | 138 | b := newOut.Bytes() 139 | Expect(string(b)).To(SatisfyAll( 140 | ContainSubstring("hi there you"), 141 | ContainSubstring("foo=bar"), 142 | ContainSubstring("baz=2"), 143 | )) 144 | 145 | newOut.Reset() 146 | 147 | // should not see any of the other fields 148 | 149 | l.WithFields(map[string]interface{}{ 150 | "biz": "bar", 151 | "buz": 2, 152 | }).Debugf("hi there %s", "you") 153 | 154 | bb := newOut.Bytes() 155 | Expect(string(bb)).To(SatisfyAll( 156 | ContainSubstring("hi there you"), 157 | ContainSubstring("biz=bar"), 158 | ContainSubstring("buz=2"), 159 | )) 160 | Expect(string(bb)).ToNot(SatisfyAll( 161 | ContainSubstring("foo=bar"), 162 | ContainSubstring("baz=2"), 163 | )) 164 | }) 165 | }) 166 | }) 167 | }) 168 | -------------------------------------------------------------------------------- /shims/kitlog/kitlog_test.go: -------------------------------------------------------------------------------- 1 | package kitlog 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "math/rand" 8 | 9 | "github.com/InVisionApp/go-logger" 10 | kitlog "github.com/go-kit/kit/log" 11 | 12 | . "github.com/onsi/ginkgo" 13 | . "github.com/onsi/gomega" 14 | "io" 15 | "os" 16 | ) 17 | 18 | var _ = Describe("satisfies interface", func() { 19 | var _ log.Logger = &shim{} 20 | }) 21 | 22 | var _ = Describe("kitlog logger", func() { 23 | var ( 24 | newOut *bytes.Buffer 25 | l log.Logger 26 | ) 27 | BeforeEach(func() { 28 | newOut = &bytes.Buffer{} 29 | l = New(kitlog.NewLogfmtLogger(kitlog.NewSyncWriter(newOut))) 30 | }) 31 | Context("spaceSep", func() { 32 | It("works on even length slices", func() { 33 | s := []interface{}{ 34 | 1, "cat", errors.New("foo"), struct{ Name string }{"bar"}, 35 | } 36 | s = spaceSep(s) 37 | Expect(len(s)).To(Equal(7)) 38 | 39 | sstr := fmt.Sprint(s...) 40 | Expect(sstr).To(Equal("1 cat foo {bar}")) 41 | }) 42 | It("works on odd length slices", func() { 43 | s := []interface{}{ 44 | 1, "cat", errors.New("foo"), struct{ Name string }{"bar"}, []string{}, 45 | } 46 | s = spaceSep(s) 47 | Expect(len(s)).To(Equal(9)) 48 | 49 | sstr := fmt.Sprint(s...) 50 | Expect(sstr).To(Equal("1 cat foo {bar} []")) 51 | }) 52 | It("works on big slices", func() { 53 | s := make([]interface{}, 10000) 54 | for i := 0; i < 10000; i++ { 55 | s[i] = rand.Intn(10) 56 | } 57 | s = spaceSep(s) 58 | Expect(len(s)).To(Equal(19999)) 59 | 60 | sstr := fmt.Sprint(s...) 61 | Expect(len(sstr)).To(Equal(19999)) 62 | }) 63 | It("works on little slices", func() { 64 | s := []interface{}{1, 2} 65 | 66 | s = spaceSep(s) 67 | Expect(len(s)).To(Equal(3)) 68 | 69 | sstr := fmt.Sprint(s...) 70 | Expect(sstr).To(Equal("1 2")) 71 | }) 72 | It("works on really little slices", func() { 73 | s := []interface{}{1} 74 | 75 | s = spaceSep(s) 76 | Expect(len(s)).To(Equal(1)) 77 | 78 | sstr := fmt.Sprint(s...) 79 | Expect(sstr).To(Equal("1")) 80 | }) 81 | }) 82 | Context("log funcs", func() { 83 | It("prints all the log levels", func() { 84 | logFuncs := map[string]func(...interface{}){ 85 | "debug": l.Debug, 86 | "info": l.Info, 87 | "warn": l.Warn, 88 | "error": l.Error, 89 | } 90 | 91 | for level, logFunc := range logFuncs { 92 | logFunc("hi there") 93 | 94 | b := newOut.Bytes() 95 | newOut.Reset() 96 | Expect(string(b)).To(SatisfyAll( 97 | ContainSubstring("hi there"), 98 | ContainSubstring("level="+level), 99 | )) 100 | } 101 | }) 102 | It("prints all the log levels: *ln", func() { 103 | logFuncs := map[string]func(...interface{}){ 104 | "debug?": l.Debugln, 105 | "info": l.Infoln, 106 | "warn": l.Warnln, 107 | "error?": l.Errorln, 108 | } 109 | for level, logFunc := range logFuncs { 110 | logFunc("hi", "there") 111 | 112 | b := newOut.Bytes() 113 | newOut.Reset() 114 | Expect(string(b)).To(SatisfyAll( 115 | ContainSubstring("hi there"), 116 | MatchRegexp(level), 117 | )) 118 | } 119 | }) 120 | It("prints all the log levels: *f", func() { 121 | logFuncs := map[string]func(string, ...interface{}){ 122 | "debug": l.Debugf, 123 | "info": l.Infof, 124 | "warn": l.Warnf, 125 | "error": l.Errorf, 126 | } 127 | for level, logFunc := range logFuncs { 128 | logFunc("hi %s", "there") 129 | 130 | b := newOut.Bytes() 131 | newOut.Reset() 132 | Expect(string(b)).To(SatisfyAll( 133 | ContainSubstring("hi there"), 134 | ContainSubstring("level="+level), 135 | )) 136 | } 137 | }) 138 | It("nil logger", func() { 139 | // need to intercept stdout 140 | // https://stackoverflow.com/a/10476304 141 | old := os.Stdout 142 | 143 | r, w, _ := os.Pipe() 144 | os.Stdout = w 145 | 146 | l = New(nil) 147 | l.Debug("i am default") 148 | 149 | outC := make(chan string) 150 | go func() { 151 | var buf bytes.Buffer 152 | io.Copy(&buf, r) 153 | outC <- buf.String() 154 | }() 155 | w.Close() 156 | os.Stdout = old 157 | 158 | out := <-outC 159 | Expect(out).To(MatchRegexp(`level=debug msg="i am default"`)) 160 | }) 161 | }) 162 | Context("fields", func() { 163 | It("", func() { 164 | l = l.WithFields(log.Fields{ 165 | "foo": "bar", 166 | "tf": true, 167 | "pet": "cat", 168 | "age": 1, 169 | }) 170 | 171 | l.Debug("hi there") 172 | b := newOut.Bytes() 173 | 174 | Expect(string(b)).To(SatisfyAll( 175 | ContainSubstring("hi there"), 176 | ContainSubstring("level=debug"), 177 | ContainSubstring("foo=bar"), 178 | ContainSubstring("tf=true"), 179 | ContainSubstring("pet=cat"), 180 | ContainSubstring("age=1"), 181 | )) 182 | }) 183 | }) 184 | }) 185 | -------------------------------------------------------------------------------- /shims/testlog/testlog_test.go: -------------------------------------------------------------------------------- 1 | package testlog 2 | 3 | import ( 4 | "github.com/InVisionApp/go-logger" 5 | . "github.com/onsi/ginkgo" 6 | . "github.com/onsi/gomega" 7 | ) 8 | 9 | var _ = Describe("meets the interface", func() { 10 | var _ log.Logger = &TestLogger{} 11 | }) 12 | 13 | var _ = Describe("test logger", func() { 14 | var ( 15 | testOut *TestLogger 16 | l log.Logger 17 | ) 18 | 19 | BeforeEach(func() { 20 | testOut = New() 21 | l = testOut 22 | }) 23 | 24 | Context("happy path", func() { 25 | It("prints all log levels", func() { 26 | logFuncs := map[string]func(...interface{}){ 27 | "DEBUG": l.Debug, 28 | "INFO": l.Info, 29 | "WARN": l.Warn, 30 | "ERROR": l.Error, 31 | } 32 | 33 | for level, logFunc := range logFuncs { 34 | logFunc("hi there") 35 | 36 | b := testOut.Bytes() 37 | testOut.Reset() 38 | Expect(string(b)).To(SatisfyAll( 39 | ContainSubstring("hi there"), 40 | ContainSubstring(level), 41 | )) 42 | } 43 | }) 44 | 45 | It("prints all log line levels", func() { 46 | logFuncs := map[string]func(...interface{}){ 47 | "DEBUG": l.Debugln, 48 | "INFO": l.Infoln, 49 | "WARN": l.Warnln, 50 | "ERROR": l.Errorln, 51 | } 52 | 53 | for level, logFunc := range logFuncs { 54 | logFunc("hi", "there") 55 | 56 | b := testOut.Bytes() 57 | testOut.Reset() 58 | Expect(string(b)).To(SatisfyAll( 59 | ContainSubstring("hi there"), 60 | ContainSubstring(level), 61 | )) 62 | } 63 | }) 64 | 65 | It("prints all log levels on formatted", func() { 66 | logFuncs := map[string]func(string, ...interface{}){ 67 | "DEBUG": l.Debugf, 68 | "INFO": l.Infof, 69 | "WARN": l.Warnf, 70 | "ERROR": l.Errorf, 71 | } 72 | 73 | for level, logFunc := range logFuncs { 74 | logFunc("hi %s", "there") 75 | 76 | b := testOut.Bytes() 77 | testOut.Reset() 78 | Expect(string(b)).To(SatisfyAll( 79 | ContainSubstring("hi there"), 80 | ContainSubstring(level), 81 | )) 82 | } 83 | }) 84 | 85 | It("join multiple strings", func() { 86 | l.Debug("hi there ", "you") 87 | 88 | b := testOut.Bytes() 89 | Expect(string(b)).To(SatisfyAll( 90 | ContainSubstring("hi there you"), 91 | ContainSubstring("DEBUG"), 92 | )) 93 | }) 94 | 95 | It("formatting", func() { 96 | l.Debugf("hi there %s", "you") 97 | 98 | b := testOut.Bytes() 99 | Expect(string(b)).To(SatisfyAll( 100 | ContainSubstring("hi there you"), 101 | ContainSubstring("DEBUG"), 102 | )) 103 | }) 104 | 105 | Context("Bytes", func() { 106 | It("returns the bytes in the buffer", func() { 107 | testOut.buf.WriteString("foo") 108 | 109 | b := testOut.Bytes() 110 | 111 | Expect(string(b)).To(Equal("foo")) 112 | }) 113 | }) 114 | 115 | Context("CallCount", func() { 116 | It("returns the call count", func() { 117 | l.Info("foo") 118 | l.Info("foo") 119 | l.Info("foo") 120 | 121 | Expect(testOut.CallCount()).To(Equal(3)) 122 | }) 123 | }) 124 | 125 | Context("reset", func() { 126 | It("resets the buffer and the call count", func() { 127 | l.Info("foo") 128 | 129 | testOut.Reset() 130 | 131 | Expect(testOut.Bytes()).To(BeEmpty()) 132 | Expect(testOut.CallCount()).To(Equal(0)) 133 | }) 134 | }) 135 | 136 | Context("with fields", func() { 137 | It("appends to preexisting fields", func() { 138 | withFields := l.WithFields(map[string]interface{}{ 139 | "foo": "oldval", 140 | "baz": "origval", 141 | }) 142 | 143 | withFields.WithFields(map[string]interface{}{ 144 | "foo": "newval", 145 | "biz": "buzz", 146 | }).Debug("hi there") 147 | 148 | b := testOut.Bytes() 149 | Expect(string(b)).To(SatisfyAll( 150 | ContainSubstring("hi there"), 151 | ContainSubstring("foo=newval"), 152 | ContainSubstring("baz=origval"), 153 | ContainSubstring("biz=buzz"), 154 | )) 155 | 156 | }) 157 | 158 | It("creates a copy", func() { 159 | l.WithFields(map[string]interface{}{ 160 | "foo": "bar", 161 | "baz": 2, 162 | }).Debug("hi there ", "you") 163 | 164 | b := testOut.Bytes() 165 | Expect(string(b)).To(SatisfyAll( 166 | ContainSubstring("hi there you"), 167 | ContainSubstring("foo=bar"), 168 | ContainSubstring("baz=2"), 169 | )) 170 | 171 | testOut.Reset() 172 | 173 | // should not see any of the other fields 174 | 175 | l.WithFields(map[string]interface{}{ 176 | "biz": "bar", 177 | "buz": 2, 178 | }).Debugf("hi there %s", "you") 179 | 180 | bb := testOut.Bytes() 181 | Expect(string(bb)).To(SatisfyAll( 182 | ContainSubstring("hi there you"), 183 | ContainSubstring("biz=bar"), 184 | ContainSubstring("buz=2"), 185 | )) 186 | Expect(string(bb)).ToNot(SatisfyAll( 187 | ContainSubstring("foo=bar"), 188 | ContainSubstring("baz=2"), 189 | )) 190 | }) 191 | }) 192 | }) 193 | }) 194 | -------------------------------------------------------------------------------- /shims/zerolog/zerolog_test.go: -------------------------------------------------------------------------------- 1 | package zerolog 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "math/rand" 8 | 9 | "github.com/InVisionApp/go-logger" 10 | "github.com/rs/zerolog" 11 | 12 | . "github.com/onsi/ginkgo" 13 | . "github.com/onsi/gomega" 14 | "io" 15 | "os" 16 | ) 17 | 18 | var _ = Describe("satisfies interface", func() { 19 | var _ log.Logger = &shim{} 20 | }) 21 | 22 | var _ = Describe("zerolog logger", func() { 23 | var ( 24 | newOut *bytes.Buffer 25 | l log.Logger 26 | ) 27 | BeforeEach(func() { 28 | newOut = &bytes.Buffer{} 29 | zerolog.SetGlobalLevel(zerolog.DebugLevel) 30 | zl := zerolog.New(newOut).With().Timestamp().Logger() 31 | l = New(&zl) 32 | }) 33 | Context("spaceSep", func() { 34 | It("works on even length slices", func() { 35 | s := []interface{}{ 36 | 1, "cat", errors.New("foo"), struct{ Name string }{"bar"}, 37 | } 38 | s = spaceSep(s) 39 | Expect(len(s)).To(Equal(7)) 40 | 41 | sstr := fmt.Sprint(s...) 42 | Expect(sstr).To(Equal("1 cat foo {bar}")) 43 | }) 44 | It("works on odd length slices", func() { 45 | s := []interface{}{ 46 | 1, "cat", errors.New("foo"), struct{ Name string }{"bar"}, []string{}, 47 | } 48 | s = spaceSep(s) 49 | Expect(len(s)).To(Equal(9)) 50 | 51 | sstr := fmt.Sprint(s...) 52 | Expect(sstr).To(Equal("1 cat foo {bar} []")) 53 | }) 54 | It("works on big slices", func() { 55 | s := make([]interface{}, 10000) 56 | for i := 0; i < 10000; i++ { 57 | s[i] = rand.Intn(10) 58 | } 59 | s = spaceSep(s) 60 | Expect(len(s)).To(Equal(19999)) 61 | 62 | sstr := fmt.Sprint(s...) 63 | Expect(len(sstr)).To(Equal(19999)) 64 | }) 65 | It("works on little slices", func() { 66 | s := []interface{}{1, 2} 67 | 68 | s = spaceSep(s) 69 | Expect(len(s)).To(Equal(3)) 70 | 71 | sstr := fmt.Sprint(s...) 72 | Expect(sstr).To(Equal("1 2")) 73 | }) 74 | It("works on really little slices", func() { 75 | s := []interface{}{1} 76 | 77 | s = spaceSep(s) 78 | Expect(len(s)).To(Equal(1)) 79 | 80 | sstr := fmt.Sprint(s...) 81 | Expect(sstr).To(Equal("1")) 82 | }) 83 | }) 84 | Context("log funcs", func() { 85 | It("prints all the log levels", func() { 86 | logFuncs := map[string]func(...interface{}){ 87 | "debug": l.Debug, 88 | "info": l.Info, 89 | "warn": l.Warn, 90 | "error": l.Error, 91 | } 92 | 93 | for level, logFunc := range logFuncs { 94 | logFunc("hi there") 95 | 96 | b := newOut.Bytes() 97 | newOut.Reset() 98 | Expect(string(b)).To(SatisfyAll( 99 | ContainSubstring("hi there"), 100 | ContainSubstring(`"level":"`+level+`"`), 101 | )) 102 | } 103 | }) 104 | It("prints all the log levels: *ln", func() { 105 | zl := zerolog.New(zerolog.ConsoleWriter{ 106 | Out: newOut, 107 | NoColor: true, 108 | }) 109 | l = New(&zl) 110 | logFuncs := map[string]func(...interface{}){ 111 | "DEBUG?": l.Debugln, 112 | "INFO": l.Infoln, 113 | "WARN": l.Warnln, 114 | "ERROR?": l.Errorln, 115 | } 116 | for level, logFunc := range logFuncs { 117 | logFunc("hi", "there") 118 | 119 | b := newOut.Bytes() 120 | newOut.Reset() 121 | Expect(string(b)).To(SatisfyAll( 122 | ContainSubstring("hi there"), 123 | MatchRegexp(level), 124 | )) 125 | } 126 | }) 127 | It("prints all the log levels: *f", func() { 128 | logFuncs := map[string]func(string, ...interface{}){ 129 | "debug": l.Debugf, 130 | "info": l.Infof, 131 | "warn": l.Warnf, 132 | "error": l.Errorf, 133 | } 134 | for level, logFunc := range logFuncs { 135 | logFunc("hi %s", "there") 136 | 137 | b := newOut.Bytes() 138 | newOut.Reset() 139 | Expect(string(b)).To(SatisfyAll( 140 | ContainSubstring("hi there"), 141 | ContainSubstring(`"level":"`+level+`"`), 142 | )) 143 | } 144 | }) 145 | It("nil logger", func() { 146 | // need to intercept stdout 147 | // https://stackoverflow.com/a/10476304 148 | old := os.Stdout 149 | 150 | r, w, _ := os.Pipe() 151 | os.Stdout = w 152 | 153 | l = New(nil) 154 | l.Debug("i am default") 155 | 156 | outC := make(chan string) 157 | go func() { 158 | var buf bytes.Buffer 159 | io.Copy(&buf, r) 160 | outC <- buf.String() 161 | }() 162 | w.Close() 163 | os.Stdout = old 164 | 165 | out := <-outC 166 | Expect(out).To(MatchRegexp(`{"level":"debug","time":"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z?(-\d{2}:\d{2})?","message":"i am default"}`)) 167 | }) 168 | }) 169 | Context("fields", func() { 170 | It("", func() { 171 | l = l.WithFields(log.Fields{ 172 | "foo": "bar", 173 | "tf": true, 174 | "pet": "cat", 175 | "age": 1, 176 | }) 177 | 178 | l.Debug("hi there") 179 | b := newOut.Bytes() 180 | 181 | Expect(string(b)).To(SatisfyAll( 182 | ContainSubstring("hi there"), 183 | ContainSubstring(`"level":"debug"`), 184 | ContainSubstring(`"foo":"bar"`), 185 | ContainSubstring(`"tf":true`), 186 | ContainSubstring(`"pet":"cat"`), 187 | ContainSubstring(`"age":1`), 188 | )) 189 | }) 190 | }) 191 | }) 192 | -------------------------------------------------------------------------------- /log_test.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "bytes" 5 | stdlog "log" 6 | 7 | . "github.com/onsi/ginkgo" 8 | . "github.com/onsi/gomega" 9 | ) 10 | 11 | var _ = Describe("simple logger", func() { 12 | Describe("meets the interface", func() { 13 | var _ Logger = &simple{} 14 | }) 15 | 16 | var ( 17 | newOut *bytes.Buffer 18 | l Logger 19 | ) 20 | 21 | BeforeEach(func() { 22 | newOut = &bytes.Buffer{} 23 | stdlog.SetOutput(newOut) 24 | l = NewSimple() 25 | }) 26 | 27 | Context("happy path", func() { 28 | It("prints all log levels", func() { 29 | logFuncs := map[string]func(...interface{}){ 30 | "DEBUG": l.Debug, 31 | "INFO": l.Info, 32 | "WARN": l.Warn, 33 | "ERROR": l.Error, 34 | } 35 | 36 | for level, logFunc := range logFuncs { 37 | logFunc("hi there") 38 | 39 | b := newOut.Bytes() 40 | newOut.Reset() 41 | Expect(string(b)).To(SatisfyAll( 42 | ContainSubstring("hi there"), 43 | ContainSubstring(level), 44 | )) 45 | } 46 | }) 47 | 48 | It("prints all log line levels", func() { 49 | logFuncs := map[string]func(...interface{}){ 50 | "DEBUG": l.Debugln, 51 | "INFO": l.Infoln, 52 | "WARN": l.Warnln, 53 | "ERROR": l.Errorln, 54 | } 55 | 56 | for level, logFunc := range logFuncs { 57 | logFunc("hi", "there") 58 | 59 | b := newOut.Bytes() 60 | newOut.Reset() 61 | Expect(string(b)).To(SatisfyAll( 62 | ContainSubstring("hi there"), 63 | ContainSubstring(level), 64 | )) 65 | } 66 | }) 67 | 68 | It("prints all log levels on formatted", func() { 69 | logFuncs := map[string]func(string, ...interface{}){ 70 | "DEBUG": l.Debugf, 71 | "INFO": l.Infof, 72 | "WARN": l.Warnf, 73 | "ERROR": l.Errorf, 74 | } 75 | 76 | for level, logFunc := range logFuncs { 77 | logFunc("hi %s", "there") 78 | 79 | b := newOut.Bytes() 80 | newOut.Reset() 81 | Expect(string(b)).To(SatisfyAll( 82 | ContainSubstring("hi there"), 83 | ContainSubstring(level), 84 | )) 85 | } 86 | }) 87 | 88 | It("join multiple strings", func() { 89 | l.Debug("hi there ", "you") 90 | 91 | b := newOut.Bytes() 92 | Expect(string(b)).To(ContainSubstring("[DEBUG] hi there you")) 93 | }) 94 | 95 | It("formatting", func() { 96 | l.Debugf("hi there %s", "you") 97 | 98 | b := newOut.Bytes() 99 | Expect(string(b)).To(ContainSubstring("[DEBUG] hi there you")) 100 | }) 101 | 102 | Context("with fields", func() { 103 | It("appends to preexisting fields", func() { 104 | withFields := l.WithFields(map[string]interface{}{ 105 | "foo": "oldval", 106 | "baz": "origval", 107 | }) 108 | 109 | withFields.WithFields(map[string]interface{}{ 110 | "foo": "newval", 111 | "biz": "buzz", 112 | }).Debug("hi there") 113 | 114 | b := newOut.Bytes() 115 | Expect(string(b)).To(SatisfyAll( 116 | ContainSubstring("[DEBUG] hi there"), 117 | ContainSubstring("foo=newval"), 118 | ContainSubstring("baz=origval"), 119 | ContainSubstring("biz=buzz"), 120 | )) 121 | 122 | }) 123 | 124 | It("creates a copy", func() { 125 | l.WithFields(map[string]interface{}{ 126 | "foo": "bar", 127 | "baz": 2, 128 | }).Debug("hi there ", "you") 129 | 130 | b := newOut.Bytes() 131 | Expect(string(b)).To(SatisfyAll( 132 | ContainSubstring("[DEBUG] hi there you"), 133 | ContainSubstring("foo=bar"), 134 | ContainSubstring("baz=2"), 135 | )) 136 | 137 | newOut.Reset() 138 | 139 | // should not see any of the other fields 140 | 141 | l.WithFields(map[string]interface{}{ 142 | "biz": "bar", 143 | "buz": 2, 144 | }).Debugf("hi there %s", "you") 145 | 146 | bb := newOut.Bytes() 147 | Expect(string(bb)).To(SatisfyAll( 148 | ContainSubstring("[DEBUG] hi there you"), 149 | ContainSubstring("biz=bar"), 150 | ContainSubstring("buz=2"), 151 | )) 152 | Expect(string(bb)).ToNot(SatisfyAll( 153 | ContainSubstring("foo=bar"), 154 | ContainSubstring("baz=2"), 155 | )) 156 | }) 157 | }) 158 | }) 159 | }) 160 | 161 | var _ = Describe("noop logger", func() { 162 | Describe("meets the interface", func() { 163 | var _ Logger = &noop{} 164 | }) 165 | 166 | var ( 167 | l Logger 168 | ) 169 | 170 | BeforeEach(func() { 171 | l = NewNoop() 172 | }) 173 | 174 | Context("happy path", func() { 175 | It("does nothing", func() { 176 | logFuncs := map[string]func(...interface{}){ 177 | "DEBUG": l.Debugln, 178 | "INFO": l.Infoln, 179 | "WARN": l.Warnln, 180 | "ERROR": l.Errorln, 181 | } 182 | 183 | for _, logFunc := range logFuncs { 184 | logFunc("hi there") 185 | } 186 | }) 187 | 188 | It("does nothing", func() { 189 | logFuncs := map[string]func(...interface{}){ 190 | "DEBUG": l.Debug, 191 | "INFO": l.Info, 192 | "WARN": l.Warn, 193 | "ERROR": l.Error, 194 | } 195 | 196 | for _, logFunc := range logFuncs { 197 | logFunc("hi there") 198 | } 199 | }) 200 | 201 | It("does nothing on formatted", func() { 202 | logFuncs := map[string]func(string, ...interface{}){ 203 | "DEBUG": l.Debugf, 204 | "INFO": l.Infof, 205 | "WARN": l.Warnf, 206 | "ERROR": l.Errorf, 207 | } 208 | 209 | for _, logFunc := range logFuncs { 210 | logFunc("hi %s", "there") 211 | } 212 | }) 213 | 214 | It("join multiple strings", func() { 215 | l.Debug("hi there ", "you") 216 | }) 217 | 218 | It("formatting", func() { 219 | l.Debugf("hi there %s", "you") 220 | }) 221 | 222 | Context("with fields", func() { 223 | It("appends to preexisting fields", func() { 224 | withFields := l.WithFields(map[string]interface{}{ 225 | "foo": "oldval", 226 | "baz": "origval", 227 | }) 228 | 229 | withFields.WithFields(map[string]interface{}{ 230 | "foo": "newval", 231 | "biz": "buzz", 232 | }).Debug("hi there") 233 | }) 234 | }) 235 | }) 236 | }) 237 | -------------------------------------------------------------------------------- /log.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | import ( 4 | "fmt" 5 | stdlog "log" 6 | ) 7 | 8 | //go:generate counterfeiter -o shims/fake/fake_logger.go . Logger 9 | 10 | // Logger interface allows you to maintain a unified interface while using a 11 | // custom logger. This allows you to write log statements without dictating 12 | // the specific underlying library used for logging. You can avoid vendoring 13 | // of logging libraries, which is especially useful when writing shared code 14 | // such as a library. This package contains a simple logger and a no-op logger 15 | // which both implement this interface. It is also supplemented with some 16 | // additional helpers/shims for other common logging libraries such as logrus 17 | type Logger interface { 18 | Debug(msg ...interface{}) 19 | Info(msg ...interface{}) 20 | Warn(msg ...interface{}) 21 | Error(msg ...interface{}) 22 | 23 | Debugln(msg ...interface{}) 24 | Infoln(msg ...interface{}) 25 | Warnln(msg ...interface{}) 26 | Errorln(msg ...interface{}) 27 | 28 | Debugf(format string, args ...interface{}) 29 | Infof(format string, args ...interface{}) 30 | Warnf(format string, args ...interface{}) 31 | Errorf(format string, args ...interface{}) 32 | 33 | WithFields(Fields) Logger 34 | } 35 | 36 | // Fields is used to define structured fields which are appended to log messages 37 | type Fields map[string]interface{} 38 | 39 | /************** 40 | Simple Logger 41 | **************/ 42 | 43 | type simple struct { 44 | fields map[string]interface{} 45 | } 46 | 47 | // NewSimple creates a basic logger that wraps the core log library. 48 | func NewSimple() Logger { 49 | return &simple{} 50 | } 51 | 52 | // WithFields will return a new logger based on the original logger 53 | // with the additional supplied fields 54 | func (b *simple) WithFields(fields Fields) Logger { 55 | cp := &simple{} 56 | 57 | if b.fields == nil { 58 | cp.fields = fields 59 | return cp 60 | } 61 | 62 | cp.fields = make(map[string]interface{}, len(b.fields)+len(fields)) 63 | for k, v := range b.fields { 64 | cp.fields[k] = v 65 | } 66 | 67 | for k, v := range fields { 68 | cp.fields[k] = v 69 | } 70 | 71 | return cp 72 | } 73 | 74 | // Debug log message 75 | func (b *simple) Debug(msg ...interface{}) { 76 | stdlog.Printf("[DEBUG] %s %s", fmt.Sprint(msg...), pretty(b.fields)) 77 | } 78 | 79 | // Info log message 80 | func (b *simple) Info(msg ...interface{}) { 81 | stdlog.Printf("[INFO] %s %s", fmt.Sprint(msg...), pretty(b.fields)) 82 | } 83 | 84 | // Warn log message 85 | func (b *simple) Warn(msg ...interface{}) { 86 | stdlog.Printf("[WARN] %s %s", fmt.Sprint(msg...), pretty(b.fields)) 87 | } 88 | 89 | // Error log message 90 | func (b *simple) Error(msg ...interface{}) { 91 | stdlog.Printf("[ERROR] %s %s", fmt.Sprint(msg...), pretty(b.fields)) 92 | } 93 | 94 | // Debugln log line message 95 | func (b *simple) Debugln(msg ...interface{}) { 96 | a := fmt.Sprintln(msg...) 97 | stdlog.Println("[DEBUG]", a[:len(a)-1], pretty(b.fields)) 98 | } 99 | 100 | // Infoln log line message 101 | func (b *simple) Infoln(msg ...interface{}) { 102 | a := fmt.Sprintln(msg...) 103 | stdlog.Println("[INFO]", a[:len(a)-1], pretty(b.fields)) 104 | } 105 | 106 | // Warnln log line message 107 | func (b *simple) Warnln(msg ...interface{}) { 108 | a := fmt.Sprintln(msg...) 109 | stdlog.Println("[WARN]", a[:len(a)-1], pretty(b.fields)) 110 | } 111 | 112 | // Errorln log line message 113 | func (b *simple) Errorln(msg ...interface{}) { 114 | a := fmt.Sprintln(msg...) 115 | stdlog.Println("[ERROR]", a[:len(a)-1], pretty(b.fields)) 116 | } 117 | 118 | // Debugf log message with formatting 119 | func (b *simple) Debugf(format string, args ...interface{}) { 120 | stdlog.Print(fmt.Sprintf("[DEBUG] "+format, args...), " ", pretty(b.fields)) 121 | } 122 | 123 | // Infof log message with formatting 124 | func (b *simple) Infof(format string, args ...interface{}) { 125 | stdlog.Print(fmt.Sprintf("[INFO] "+format, args...), " ", pretty(b.fields)) 126 | } 127 | 128 | // Warnf log message with formatting 129 | func (b *simple) Warnf(format string, args ...interface{}) { 130 | stdlog.Print(fmt.Sprintf("[WARN] "+format, args...), " ", pretty(b.fields)) 131 | } 132 | 133 | // Errorf log message with formatting 134 | func (b *simple) Errorf(format string, args ...interface{}) { 135 | stdlog.Print(fmt.Sprintf("[ERROR] "+format, args...), " ", pretty(b.fields)) 136 | } 137 | 138 | // helper for pretty printing of fields 139 | func pretty(m map[string]interface{}) string { 140 | if len(m) < 1 { 141 | return "" 142 | } 143 | 144 | s := "" 145 | for k, v := range m { 146 | s += fmt.Sprintf("%s=%v ", k, v) 147 | } 148 | 149 | return s[:len(s)-1] 150 | } 151 | 152 | /************* 153 | No-Op Logger 154 | *************/ 155 | 156 | type noop struct{} 157 | 158 | // NewNoop creates a no-op logger that can be used to silence 159 | // all logging from this library. Also useful in tests. 160 | func NewNoop() Logger { 161 | return &noop{} 162 | } 163 | 164 | // Debug log message no-op 165 | func (n *noop) Debug(msg ...interface{}) {} 166 | 167 | // Info log message no-op 168 | func (n *noop) Info(msg ...interface{}) {} 169 | 170 | // Warn log message no-op 171 | func (n *noop) Warn(msg ...interface{}) {} 172 | 173 | // Error log message no-op 174 | func (n *noop) Error(msg ...interface{}) {} 175 | 176 | // Debugln line log message no-op 177 | func (n *noop) Debugln(msg ...interface{}) {} 178 | 179 | // Infoln line log message no-op 180 | func (n *noop) Infoln(msg ...interface{}) {} 181 | 182 | // Warnln line log message no-op 183 | func (n *noop) Warnln(msg ...interface{}) {} 184 | 185 | // Errorln line log message no-op 186 | func (n *noop) Errorln(msg ...interface{}) {} 187 | 188 | // Debugf log message with formatting no-op 189 | func (n *noop) Debugf(format string, args ...interface{}) {} 190 | 191 | // Infof log message with formatting no-op 192 | func (n *noop) Infof(format string, args ...interface{}) {} 193 | 194 | // Warnf log message with formatting no-op 195 | func (n *noop) Warnf(format string, args ...interface{}) {} 196 | 197 | // Errorf log message with formatting no-op 198 | func (n *noop) Errorf(format string, args ...interface{}) {} 199 | 200 | // WithFields no-op 201 | func (n *noop) WithFields(fields Fields) Logger { return n } 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | | :warning: This project is no longer actively supported. 2 | | --- 3 | 4 | [![LICENSE](https://img.shields.io/badge/license-MIT-orange.svg)](LICENSE) 5 | [![Build Status](https://travis-ci.com/InVisionApp/go-logger.svg?token=KosA43m1X3ikri8JEukQ&branch=master)](https://travis-ci.com/InVisionApp/go-logger) 6 | [![codecov](https://codecov.io/gh/InVisionApp/go-logger/branch/master/graph/badge.svg?token=hhqA1l88kx)](https://codecov.io/gh/InVisionApp/go-logger) 7 | [![Go Report Card](https://goreportcard.com/badge/github.com/InVisionApp/go-logger)](https://goreportcard.com/report/github.com/InVisionApp/go-logger) 8 | [![Godocs](https://img.shields.io/badge/golang-documentation-blue.svg)](https://godoc.org/github.com/InVisionApp/go-logger) 9 | 10 | 11 | 12 | 13 | 14 | # go-logger 15 | This package provides a standard interface for logging in any go application. 16 | Logger interface allows you to maintain a unified interface while using a custom logger. This allows you to write log statements without dictating the specific underlying library used for logging. You can avoid vendoring of logging libraries, which is especially useful when writing shared code such as a library. 17 | This package also contains a simple logger and a no-op logger which both implement the interface. The simple logger is a wrapper for the standard logging library which meets this logger interface. The no-op logger can be used to easily silence all logging. 18 | This library is also supplemented with some additional helpers/shims for other common logging libraries such as logrus to allow them to meet the logger interface. 19 | 20 | ## Usage 21 | The logger interface defines 4 levels of logging: `Debug`, `Info`, `Warn`, and `Error`. These will accept a variadic list of strings as in `fmt.Println`. All the string parameters will be concatenated into a single message. 22 | Additionally, each of the log levels offers a formatted string as well: `Debugf`, `Infof`, `Warnf`, and `Errorf`. These functions, like `fmt.Printf` and offer the ability to define a format string and parameters to populate it. 23 | Finally, there is a `WithFields(Fields)` method that will allow you to define a set of fields that will always be logged with evey message. This method returns copy of the logger and appends all fields to any preexisting fields. 24 | 25 | ## Implementations 26 | 27 | ### Simple Logger 28 | The simple logger is a wrapper for the standard logging library which meets this logger interface. It provides very basic logging functionality with log levels in messages. 29 | 30 | ```go 31 | import "github.com/InVisionApp/go-logger" 32 | 33 | logger := log.NewSimple() 34 | logger.Debug("this is a debug message") 35 | ``` 36 | output: 37 | ``` 38 | 2018/03/04 12:55:08 [DEBUG] Simplelogger 39 | ``` 40 | 41 | ### No-op Logger 42 | If you do not wish to perform any sort of logging whatsoever, you can point to a noop logger. This is useful for silencing logs in tests, or allowing users to turn of logging in your library. 43 | 44 | ```go 45 | import "github.com/InVisionApp/go-logger" 46 | 47 | logger := log.NewNoop() 48 | logger.Debug("this is a debug message") 49 | ``` 50 | _no output_ 51 | 52 | ### Logrus Logger 53 | This shim allows you to use logrus as your logger implementation. If you wish to use the standard logrus logger, pass `nil` to the constructor. Otherwise, pass in your own `logrus.Logger`. 54 | 55 | ```go 56 | import "github.com/InVisionApp/go-logger/shims/logrus" 57 | 58 | // Default logrus logger 59 | logger := logrus.New(nil) 60 | logger.Debug("this is a debug message") 61 | ``` 62 | 63 | Or alternatively, you can provide your own logrus logger: 64 | ```go 65 | import ( 66 | lgrs "github.com/sirupsen/logrus" 67 | "github.com/InVisionApp/go-logger/shims/logrus" 68 | ) 69 | 70 | myLogrus := lgrs.New() 71 | myLogrus.Out = &bytes.Buffer{} 72 | logger := logrus.New(myLogrus) 73 | logger.Debug("this is a debug message") 74 | ``` 75 | 76 | output: 77 | ``` 78 | time="2018-03-04T13:12:35-08:00" level=debug msg="this is a debug message" 79 | ``` 80 | 81 | ### Zerolog Logger 82 | This shim allows you to use [zerolog](https://github.com/rs/zerolog) as your logging implementation. If you pass `nil` into `New(...)`, 83 | you will get a default `zerolog.Logger` writing to `stdout` with a timestamp attached. 84 | 85 | Alternatively, you can pass your own instance of `zerolog.Logger` to `New(...)`. 86 | 87 | Using the `zerolog` default logger: 88 | ```go 89 | import "github.com/InVisionApp/go-logger/shims/zerolog" 90 | 91 | func main() { 92 | logger := zerolog.New(nil) 93 | logger.Debug("this is a debug message!") 94 | } 95 | 96 | ``` 97 | 98 | Using your own logger: 99 | ```go 100 | import ( 101 | "os" 102 | 103 | zl "github.com/rs/zerolog" 104 | "github.com/InVisionApp/go-logger/shims/zerolog" 105 | ) 106 | 107 | func main() { 108 | // zerolog is a structured logger by default 109 | structuredLogger := zl.New(os.Stdout).Logger() 110 | sLogger := zerolog.New(structuredLogger) 111 | sLogger.Debug("debug message") 112 | // {"level":"debug", "message":"debug message"} 113 | 114 | // If you want to use zerolog for human-readable console logging, 115 | // you create a ConsoleWriter and use it as your io.Writer implementation 116 | consoleLogger := zl.New(zl.ConsoleWriter{ 117 | Out: os.Stdout, 118 | }) 119 | cLogger := zerolog.New(consoleLogger) 120 | cLogger.Debug("debug message") 121 | // |DEBUG| debug message 122 | } 123 | ``` 124 | 125 | ### Test Logger 126 | The test logger is for capturing logs during the execution of a test. It writes the logs to a byte buffer which can be dumped and inspected. It also tracks a call count of the total number of times the logger has been called. 127 | **_Note:_** this logger is not meant to be used in production. It is purely designed for use in tests. 128 | 129 | ### Fake Logger 130 | A generated fake that meets the logger interface. This is useful if you want to stub out your own functionality for the logger in tests. This logger is meant for use in tests and not in production. If you simply want to silence logs, use the no-op logger. 131 | 132 | --- 133 | 134 | #### \[Credit\] 135 | The go-logger gopher image by [talpert](https://github.com/talpert) 136 | Original artwork designed by Renée French 137 | -------------------------------------------------------------------------------- /shims/_fake/fake_logger.go: -------------------------------------------------------------------------------- 1 | // Code generated by counterfeiter. DO NOT EDIT. 2 | package fake 3 | 4 | import ( 5 | "sync" 6 | 7 | log "github.com/InVisionApp/go-logger" 8 | ) 9 | 10 | type FakeLogger struct { 11 | DebugStub func(msg ...interface{}) 12 | debugMutex sync.RWMutex 13 | debugArgsForCall []struct { 14 | msg []interface{} 15 | } 16 | InfoStub func(msg ...interface{}) 17 | infoMutex sync.RWMutex 18 | infoArgsForCall []struct { 19 | msg []interface{} 20 | } 21 | WarnStub func(msg ...interface{}) 22 | warnMutex sync.RWMutex 23 | warnArgsForCall []struct { 24 | msg []interface{} 25 | } 26 | ErrorStub func(msg ...interface{}) 27 | errorMutex sync.RWMutex 28 | errorArgsForCall []struct { 29 | msg []interface{} 30 | } 31 | DebugfStub func(format string, args ...interface{}) 32 | debugfMutex sync.RWMutex 33 | debugfArgsForCall []struct { 34 | format string 35 | args []interface{} 36 | } 37 | InfofStub func(format string, args ...interface{}) 38 | infofMutex sync.RWMutex 39 | infofArgsForCall []struct { 40 | format string 41 | args []interface{} 42 | } 43 | WarnfStub func(format string, args ...interface{}) 44 | warnfMutex sync.RWMutex 45 | warnfArgsForCall []struct { 46 | format string 47 | args []interface{} 48 | } 49 | ErrorfStub func(format string, args ...interface{}) 50 | errorfMutex sync.RWMutex 51 | errorfArgsForCall []struct { 52 | format string 53 | args []interface{} 54 | } 55 | WithFieldsStub func(log.Fields) log.Logger 56 | withFieldsMutex sync.RWMutex 57 | withFieldsArgsForCall []struct { 58 | arg1 log.Fields 59 | } 60 | withFieldsReturns struct { 61 | result1 log.Logger 62 | } 63 | withFieldsReturnsOnCall map[int]struct { 64 | result1 log.Logger 65 | } 66 | invocations map[string][][]interface{} 67 | invocationsMutex sync.RWMutex 68 | } 69 | 70 | func (fake *FakeLogger) Debug(msg ...interface{}) { 71 | fake.debugMutex.Lock() 72 | fake.debugArgsForCall = append(fake.debugArgsForCall, struct { 73 | msg []interface{} 74 | }{msg}) 75 | fake.recordInvocation("Debug", []interface{}{msg}) 76 | fake.debugMutex.Unlock() 77 | if fake.DebugStub != nil { 78 | fake.DebugStub(msg...) 79 | } 80 | } 81 | 82 | func (fake *FakeLogger) DebugCallCount() int { 83 | fake.debugMutex.RLock() 84 | defer fake.debugMutex.RUnlock() 85 | return len(fake.debugArgsForCall) 86 | } 87 | 88 | func (fake *FakeLogger) DebugArgsForCall(i int) []interface{} { 89 | fake.debugMutex.RLock() 90 | defer fake.debugMutex.RUnlock() 91 | return fake.debugArgsForCall[i].msg 92 | } 93 | 94 | func (fake *FakeLogger) Info(msg ...interface{}) { 95 | fake.infoMutex.Lock() 96 | fake.infoArgsForCall = append(fake.infoArgsForCall, struct { 97 | msg []interface{} 98 | }{msg}) 99 | fake.recordInvocation("Info", []interface{}{msg}) 100 | fake.infoMutex.Unlock() 101 | if fake.InfoStub != nil { 102 | fake.InfoStub(msg...) 103 | } 104 | } 105 | 106 | func (fake *FakeLogger) InfoCallCount() int { 107 | fake.infoMutex.RLock() 108 | defer fake.infoMutex.RUnlock() 109 | return len(fake.infoArgsForCall) 110 | } 111 | 112 | func (fake *FakeLogger) InfoArgsForCall(i int) []interface{} { 113 | fake.infoMutex.RLock() 114 | defer fake.infoMutex.RUnlock() 115 | return fake.infoArgsForCall[i].msg 116 | } 117 | 118 | func (fake *FakeLogger) Warn(msg ...interface{}) { 119 | fake.warnMutex.Lock() 120 | fake.warnArgsForCall = append(fake.warnArgsForCall, struct { 121 | msg []interface{} 122 | }{msg}) 123 | fake.recordInvocation("Warn", []interface{}{msg}) 124 | fake.warnMutex.Unlock() 125 | if fake.WarnStub != nil { 126 | fake.WarnStub(msg...) 127 | } 128 | } 129 | 130 | func (fake *FakeLogger) WarnCallCount() int { 131 | fake.warnMutex.RLock() 132 | defer fake.warnMutex.RUnlock() 133 | return len(fake.warnArgsForCall) 134 | } 135 | 136 | func (fake *FakeLogger) WarnArgsForCall(i int) []interface{} { 137 | fake.warnMutex.RLock() 138 | defer fake.warnMutex.RUnlock() 139 | return fake.warnArgsForCall[i].msg 140 | } 141 | 142 | func (fake *FakeLogger) Error(msg ...interface{}) { 143 | fake.errorMutex.Lock() 144 | fake.errorArgsForCall = append(fake.errorArgsForCall, struct { 145 | msg []interface{} 146 | }{msg}) 147 | fake.recordInvocation("Error", []interface{}{msg}) 148 | fake.errorMutex.Unlock() 149 | if fake.ErrorStub != nil { 150 | fake.ErrorStub(msg...) 151 | } 152 | } 153 | 154 | func (fake *FakeLogger) ErrorCallCount() int { 155 | fake.errorMutex.RLock() 156 | defer fake.errorMutex.RUnlock() 157 | return len(fake.errorArgsForCall) 158 | } 159 | 160 | func (fake *FakeLogger) ErrorArgsForCall(i int) []interface{} { 161 | fake.errorMutex.RLock() 162 | defer fake.errorMutex.RUnlock() 163 | return fake.errorArgsForCall[i].msg 164 | } 165 | 166 | func (fake *FakeLogger) Debugf(format string, args ...interface{}) { 167 | fake.debugfMutex.Lock() 168 | fake.debugfArgsForCall = append(fake.debugfArgsForCall, struct { 169 | format string 170 | args []interface{} 171 | }{format, args}) 172 | fake.recordInvocation("Debugf", []interface{}{format, args}) 173 | fake.debugfMutex.Unlock() 174 | if fake.DebugfStub != nil { 175 | fake.DebugfStub(format, args...) 176 | } 177 | } 178 | 179 | func (fake *FakeLogger) DebugfCallCount() int { 180 | fake.debugfMutex.RLock() 181 | defer fake.debugfMutex.RUnlock() 182 | return len(fake.debugfArgsForCall) 183 | } 184 | 185 | func (fake *FakeLogger) DebugfArgsForCall(i int) (string, []interface{}) { 186 | fake.debugfMutex.RLock() 187 | defer fake.debugfMutex.RUnlock() 188 | return fake.debugfArgsForCall[i].format, fake.debugfArgsForCall[i].args 189 | } 190 | 191 | func (fake *FakeLogger) Infof(format string, args ...interface{}) { 192 | fake.infofMutex.Lock() 193 | fake.infofArgsForCall = append(fake.infofArgsForCall, struct { 194 | format string 195 | args []interface{} 196 | }{format, args}) 197 | fake.recordInvocation("Infof", []interface{}{format, args}) 198 | fake.infofMutex.Unlock() 199 | if fake.InfofStub != nil { 200 | fake.InfofStub(format, args...) 201 | } 202 | } 203 | 204 | func (fake *FakeLogger) InfofCallCount() int { 205 | fake.infofMutex.RLock() 206 | defer fake.infofMutex.RUnlock() 207 | return len(fake.infofArgsForCall) 208 | } 209 | 210 | func (fake *FakeLogger) InfofArgsForCall(i int) (string, []interface{}) { 211 | fake.infofMutex.RLock() 212 | defer fake.infofMutex.RUnlock() 213 | return fake.infofArgsForCall[i].format, fake.infofArgsForCall[i].args 214 | } 215 | 216 | func (fake *FakeLogger) Warnf(format string, args ...interface{}) { 217 | fake.warnfMutex.Lock() 218 | fake.warnfArgsForCall = append(fake.warnfArgsForCall, struct { 219 | format string 220 | args []interface{} 221 | }{format, args}) 222 | fake.recordInvocation("Warnf", []interface{}{format, args}) 223 | fake.warnfMutex.Unlock() 224 | if fake.WarnfStub != nil { 225 | fake.WarnfStub(format, args...) 226 | } 227 | } 228 | 229 | func (fake *FakeLogger) WarnfCallCount() int { 230 | fake.warnfMutex.RLock() 231 | defer fake.warnfMutex.RUnlock() 232 | return len(fake.warnfArgsForCall) 233 | } 234 | 235 | func (fake *FakeLogger) WarnfArgsForCall(i int) (string, []interface{}) { 236 | fake.warnfMutex.RLock() 237 | defer fake.warnfMutex.RUnlock() 238 | return fake.warnfArgsForCall[i].format, fake.warnfArgsForCall[i].args 239 | } 240 | 241 | func (fake *FakeLogger) Errorf(format string, args ...interface{}) { 242 | fake.errorfMutex.Lock() 243 | fake.errorfArgsForCall = append(fake.errorfArgsForCall, struct { 244 | format string 245 | args []interface{} 246 | }{format, args}) 247 | fake.recordInvocation("Errorf", []interface{}{format, args}) 248 | fake.errorfMutex.Unlock() 249 | if fake.ErrorfStub != nil { 250 | fake.ErrorfStub(format, args...) 251 | } 252 | } 253 | 254 | func (fake *FakeLogger) ErrorfCallCount() int { 255 | fake.errorfMutex.RLock() 256 | defer fake.errorfMutex.RUnlock() 257 | return len(fake.errorfArgsForCall) 258 | } 259 | 260 | func (fake *FakeLogger) ErrorfArgsForCall(i int) (string, []interface{}) { 261 | fake.errorfMutex.RLock() 262 | defer fake.errorfMutex.RUnlock() 263 | return fake.errorfArgsForCall[i].format, fake.errorfArgsForCall[i].args 264 | } 265 | 266 | func (fake *FakeLogger) WithFields(arg1 log.Fields) log.Logger { 267 | fake.withFieldsMutex.Lock() 268 | ret, specificReturn := fake.withFieldsReturnsOnCall[len(fake.withFieldsArgsForCall)] 269 | fake.withFieldsArgsForCall = append(fake.withFieldsArgsForCall, struct { 270 | arg1 log.Fields 271 | }{arg1}) 272 | fake.recordInvocation("WithFields", []interface{}{arg1}) 273 | fake.withFieldsMutex.Unlock() 274 | if fake.WithFieldsStub != nil { 275 | return fake.WithFieldsStub(arg1) 276 | } 277 | if specificReturn { 278 | return ret.result1 279 | } 280 | return fake.withFieldsReturns.result1 281 | } 282 | 283 | func (fake *FakeLogger) WithFieldsCallCount() int { 284 | fake.withFieldsMutex.RLock() 285 | defer fake.withFieldsMutex.RUnlock() 286 | return len(fake.withFieldsArgsForCall) 287 | } 288 | 289 | func (fake *FakeLogger) WithFieldsArgsForCall(i int) log.Fields { 290 | fake.withFieldsMutex.RLock() 291 | defer fake.withFieldsMutex.RUnlock() 292 | return fake.withFieldsArgsForCall[i].arg1 293 | } 294 | 295 | func (fake *FakeLogger) WithFieldsReturns(result1 log.Logger) { 296 | fake.WithFieldsStub = nil 297 | fake.withFieldsReturns = struct { 298 | result1 log.Logger 299 | }{result1} 300 | } 301 | 302 | func (fake *FakeLogger) WithFieldsReturnsOnCall(i int, result1 log.Logger) { 303 | fake.WithFieldsStub = nil 304 | if fake.withFieldsReturnsOnCall == nil { 305 | fake.withFieldsReturnsOnCall = make(map[int]struct { 306 | result1 log.Logger 307 | }) 308 | } 309 | fake.withFieldsReturnsOnCall[i] = struct { 310 | result1 log.Logger 311 | }{result1} 312 | } 313 | 314 | func (fake *FakeLogger) Invocations() map[string][][]interface{} { 315 | fake.invocationsMutex.RLock() 316 | defer fake.invocationsMutex.RUnlock() 317 | fake.debugMutex.RLock() 318 | defer fake.debugMutex.RUnlock() 319 | fake.infoMutex.RLock() 320 | defer fake.infoMutex.RUnlock() 321 | fake.warnMutex.RLock() 322 | defer fake.warnMutex.RUnlock() 323 | fake.errorMutex.RLock() 324 | defer fake.errorMutex.RUnlock() 325 | fake.debugfMutex.RLock() 326 | defer fake.debugfMutex.RUnlock() 327 | fake.infofMutex.RLock() 328 | defer fake.infofMutex.RUnlock() 329 | fake.warnfMutex.RLock() 330 | defer fake.warnfMutex.RUnlock() 331 | fake.errorfMutex.RLock() 332 | defer fake.errorfMutex.RUnlock() 333 | fake.withFieldsMutex.RLock() 334 | defer fake.withFieldsMutex.RUnlock() 335 | copiedInvocations := map[string][][]interface{}{} 336 | for key, value := range fake.invocations { 337 | copiedInvocations[key] = value 338 | } 339 | return copiedInvocations 340 | } 341 | 342 | func (fake *FakeLogger) recordInvocation(key string, args []interface{}) { 343 | fake.invocationsMutex.Lock() 344 | defer fake.invocationsMutex.Unlock() 345 | if fake.invocations == nil { 346 | fake.invocations = map[string][][]interface{}{} 347 | } 348 | if fake.invocations[key] == nil { 349 | fake.invocations[key] = [][]interface{}{} 350 | } 351 | fake.invocations[key] = append(fake.invocations[key], args) 352 | } 353 | 354 | var _ log.Logger = new(FakeLogger) 355 | -------------------------------------------------------------------------------- /images/go-logger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Gopher 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | --------------------------------------------------------------------------------