aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Hanley <felix@userspace.com.au>2020-05-20 01:35:50 +0000
committerFelix Hanley <felix@userspace.com.au>2020-05-20 01:36:03 +0000
commit21b31fdacf93bd5bb54937fb7c25a73b61205344 (patch)
treef1c50ff4a8dab9bd6e86ed3a8402ac0b1ef34ba0
parent0b93ba86bf1b495ebb765a6cdca20a121ac1e9c7 (diff)
downloadlogger-21b31fdacf93bd5bb54937fb7c25a73b61205344.tar.gz
logger-21b31fdacf93bd5bb54937fb7c25a73b61205344.tar.bz2
Reduce levels to debug and not debug
-rw-r--r--README.md43
-rw-r--r--comparison_test.go4
-rw-r--r--example_test.go31
-rw-r--r--internal/strings.go54
-rw-r--r--internal/strings_test.go54
-rw-r--r--logger.go104
-rw-r--r--logger_test.go68
-rw-r--r--message/level.go39
-rw-r--r--message/level_test.go25
-rw-r--r--message/message.go6
-rw-r--r--options.go14
-rw-r--r--std.go26
-rw-r--r--writers/json/json.go19
-rw-r--r--writers/json/json_test.go36
-rw-r--r--writers/kv/key_value.go27
-rw-r--r--writers/kv/key_value_test.go23
-rw-r--r--writers/rabbitmq/rabbitmq.go20
17 files changed, 136 insertions, 457 deletions
diff --git a/README.md b/README.md
index b6640ea..0ca8e34 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Simple structured logger for Go
-A simple logger package that provides levels, a number of output formats, and
+A simple logger package that provides a number of output formats, and
named sub-logs. Output formats include key/value, JSON, null and AMQP/RabbitMQ
## Installation
@@ -11,38 +11,38 @@ Documentation is available at http://godoc.org/src.userspace.com.au/logger
## Usage
-There is a package level logger that is set to level 'WARN'.
+There is a package level logger with two levels, debug and not!
### Create a key/value logger
```go
-log := logger.New(logger.Name("app"), logger.Level(logger.DEBUG))
-log.Error("unable to do anything")
+log := logger.New(logger.Name("app"))
+log.Log("unable to do anything")
```
```text
-... [info] app: unable to do anything
+... app: unable to do anything
```
### Add structure
```go
-log.Warn("invalid something", "id", 344, "error", "generally broken")
+log.Log("invalid something", "id", 344, "error", "generally broken")
```
```text
-... [warn] app: invalid something id=344 error="generally broken"
+... app: invalid something id=344 error="generally broken"
```
### Create a named sub-logger
```go
sublog := log.Named("database")
-sublog.Info("connection initialised")
+sublog.Log("connection initialised")
```
```text
-... [info] app.database: connection initialised
+... app.database: connection initialised
```
### Create a new Logger with pre-defined values
@@ -52,30 +52,19 @@ For major sub-systems there is no need to repeat values for each log call:
```go
reqID := "555"
msgLog := sublog.Field("request", reqID)
-msgLog.Error("failed to process message")
+msgLog.Log("failed to process message")
```
```text
-... [info] app.database: failed to process message request=555
-```
-
-There is also a Log command with no defined level. These messages are always
-printed:
-
-```go
-log.Log("metrics or whatnot", "something", large)
-```
-
-```text
-... metrics or whatnot something="12345678"
+... app.database: failed to process message request=555
```
## Comparison
```
-BenchmarkCoreLogger-12 5000000 288 ns/op
-BenchmarkLocal-12 2000000 654 ns/op
-BenchmarkLogrus-12 1000000 1738 ns/op
-BenchmarkFieldsLocal-12 1000000 1024 ns/op
-BenchmarkFieldsLogrus-12 1000000 2061 ns/op
+BenchmarkCoreLogger-12 4731555 243 ns/op
+BenchmarkLocal-12 2035790 597 ns/op
+BenchmarkLogrus-12 698662 1725 ns/op
+BenchmarkFieldsLocal-12 1000000 1010 ns/op
+BenchmarkFieldsLogrus-12 592014 2022 ns/op
```
diff --git a/comparison_test.go b/comparison_test.go
index 8e4a021..3dcc331 100644
--- a/comparison_test.go
+++ b/comparison_test.go
@@ -28,7 +28,7 @@ func BenchmarkCoreLogger(b *testing.B) {
func BenchmarkLocal(b *testing.B) {
l, _ := New(Writer(dummyWriter()))
for n := 0; n < b.N; n++ {
- l.Error("Some text")
+ l.Log("Some text")
}
}
@@ -44,7 +44,7 @@ func BenchmarkFieldsLocal(b *testing.B) {
l.Field("key", "value")
l.Field("one", "two")
for n := 0; n < b.N; n++ {
- l.Error("Some text")
+ l.Info("Some text")
}
}
diff --git a/example_test.go b/example_test.go
index 14521c0..d4af463 100644
--- a/example_test.go
+++ b/example_test.go
@@ -1,27 +1,28 @@
package logger
import (
- "src.userspace.com.au/logger/message"
+ "os"
+
"src.userspace.com.au/logger/writers/json"
"src.userspace.com.au/logger/writers/kv"
)
-func ExampleLevel() {
+func ExampleDebug() {
keyValue, _ := kv.New(kv.SetTimeFormat(""))
+ os.Setenv("DEBUG", "true")
log, _ := New(
Name("app"),
- Level(message.DEBUG),
Writer(keyValue),
)
- log.Error("unable to do anything")
- // Output: [error] app: unable to do anything
+ log.Debug("unable to do anything")
+ // Output: app: unable to do anything
}
func Example_structure() {
keyValue, _ := kv.New(kv.SetTimeFormat(""))
log, _ := New(Writer(keyValue))
- log.Warn("invalid something", "id", 344, "error", "generally broken")
- // Output: [warn] invalid something id=344 error="generally broken"
+ log.Fields("id", 344, "error", "generally broken").Log("invalid something")
+ // Output: invalid something id=344 error="generally broken"
}
func ExampleNamed() {
@@ -30,8 +31,8 @@ func ExampleNamed() {
Name("database"),
Writer(keyValue),
)
- log.Error("connection initialised")
- // Output: [error] database: connection initialised
+ log.Info("connection initialised")
+ // Output: database: connection initialised
}
func ExampleField() {
@@ -40,14 +41,6 @@ func ExampleField() {
// Create a new Logger with pre-defined values
reqID := "555"
msgLog := log.Field("request", reqID)
- msgLog.Error("failed to process message")
- // Output: {"_level":"error","_message":"failed to process message","_name":"app.database","_time":"","request":"555"}
-}
-
-func Example_nolevel() {
- keyValue, _ := kv.New(kv.SetTimeFormat(""))
- log, _ := New(Writer(keyValue))
- large := 12345678
- log.Log("metrics or whatnot", "something", large)
- // Output: metrics or whatnot something=12345678
+ msgLog.Log("failed to process message")
+ // Output: {"_message":"failed to process message","_name":"app.database","_time":"","request":"555"}
}
diff --git a/internal/strings.go b/internal/strings.go
deleted file mode 100644
index 8924734..0000000
--- a/internal/strings.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package internal
-
-import (
- "fmt"
- "strconv"
- "time"
-)
-
-// ToString converts interface to string
-func ToString(v interface{}) string {
- if v == nil {
- return ""
- }
- switch c := v.(type) {
- case string:
- return c
- case *string:
- return *c
- case int:
- return strconv.FormatInt(int64(c), 10)
- case int64:
- return strconv.FormatInt(int64(c), 10)
- case int32:
- return strconv.FormatInt(int64(c), 10)
- case int16:
- return strconv.FormatInt(int64(c), 10)
- case int8:
- return strconv.FormatInt(int64(c), 10)
- case uint:
- return strconv.FormatUint(uint64(c), 10)
- case uint64:
- return strconv.FormatUint(uint64(c), 10)
- case uint32:
- return strconv.FormatUint(uint64(c), 10)
- case uint16:
- return strconv.FormatUint(uint64(c), 10)
- case uint8:
- return strconv.FormatUint(uint64(c), 10)
- case float32:
- return strconv.FormatFloat(float64(c), 'g', -1, 32)
- case float64:
- return strconv.FormatFloat(c, 'g', -1, 64)
- case bool:
- return strconv.FormatBool(c)
- case *bool:
- return strconv.FormatBool(*c)
- case *time.Time:
- return fmt.Sprintf("%s", c)
- case fmt.Stringer:
- return c.String()
- default:
- return fmt.Sprintf("%v", c)
- }
-}
diff --git a/internal/strings_test.go b/internal/strings_test.go
deleted file mode 100644
index 4f1a0c8..0000000
--- a/internal/strings_test.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package internal
-
-import (
- "testing"
- "time"
-)
-
-type stringer struct{}
-
-func (s stringer) String() string {
- return "I am a stringer"
-}
-
-func TestToString(t *testing.T) {
- epoch := time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC)
- s := "string"
- b := true
- tests := []struct {
- in interface{}
- expected string
- }{
- {"string", "string"},
- {1, "1"},
- {0, "0"},
- {false, "false"},
- {int(-3), "-3"},
- {int8(3), "3"},
- {int16(30), "30"},
- {int32(30), "30"},
- {int64(30), "30"},
- {uint(3), "3"},
- {uint8(3), "3"},
- {uint16(30), "30"},
- {uint32(30), "30"},
- {uint64(30), "30"},
- {float32(3.0001), "3.0001"},
- {float64(3.0000001), "3.0000001"},
- {nil, ""},
- {new(stringer), "I am a stringer"},
- {epoch, "-0001-11-30 00:00:00 +0000 UTC"},
- {struct{ string }{"test"}, "{test}"},
- // Pointers
- {&s, "string"},
- {&epoch, "-0001-11-30 00:00:00 +0000 UTC"},
- {&b, "true"},
- }
-
- for _, tt := range tests {
- actual := ToString(tt.in)
- if actual != tt.expected {
- t.Errorf("ToString(%v) => %s, expected %s", tt.in, actual, tt.expected)
- }
- }
-}
diff --git a/logger.go b/logger.go
index 3ed94f3..9ac23c8 100644
--- a/logger.go
+++ b/logger.go
@@ -1,6 +1,7 @@
package logger
import (
+ "fmt"
"os"
"strings"
"sync"
@@ -10,11 +11,11 @@ import (
"src.userspace.com.au/logger/writers/kv"
)
-// Logger is a simple levelled logger.
+// Logger is a simple logger with optional structured.
type Logger struct {
+ debug bool
name string
- min message.Level
- fields map[string]interface{}
+ fields map[string]string
writers []message.Writer
lock *sync.RWMutex
}
@@ -22,8 +23,8 @@ type Logger struct {
// New creates a new logger instance
func New(opts ...Option) (*Logger, error) {
l := &Logger{
- min: message.WARN,
- fields: make(map[string]interface{}),
+ debug: (os.Getenv("DEBUG") != ""),
+ fields: make(map[string]string),
lock: new(sync.RWMutex),
writers: []message.Writer{},
}
@@ -46,28 +47,20 @@ func New(opts ...Option) (*Logger, error) {
return l, nil
}
-// Log a message with no level.
-func (l *Logger) Log(msg string, args ...interface{}) *Logger {
- l.LogAtLevel(message.NONE, msg, args...)
- return l
+// Log a message.
+func (l *Logger) Log(args ...interface{}) *Logger {
+ return l.log(args...)
}
-// LogAtLevel logs a message with a specified level.
-func (l *Logger) LogAtLevel(lvl message.Level, msg string, args ...interface{}) *Logger {
- if l.min < lvl {
+func (l *Logger) log(args ...interface{}) *Logger {
+ if len(args) == 0 {
return l
}
-
- l.lock.RLock()
- defer l.lock.RUnlock()
-
m := message.Message{
Name: l.name,
Time: time.Now(),
- Level: lvl,
- Content: msg,
+ Content: toString(args...),
Fields: l.fields,
- Extras: args,
}
for _, w := range l.writers {
@@ -76,56 +69,67 @@ func (l *Logger) LogAtLevel(lvl message.Level, msg string, args ...interface{})
return l
}
-// Error logs an error message.
-func (l *Logger) Error(msg string, args ...interface{}) *Logger {
- return l.LogAtLevel(message.ERROR, msg, args...)
-}
-
-// Warn logs an information message.
-func (l *Logger) Warn(msg string, args ...interface{}) *Logger {
- return l.LogAtLevel(message.WARN, msg, args...)
+// toString converts interface to string
+func toString(args ...interface{}) string {
+ var buf strings.Builder
+ last := len(args)
+ for i, a := range args {
+ buf.WriteString(fmt.Sprint(a))
+ if i < last-1 {
+ buf.WriteByte(' ')
+ }
+ }
+ return buf.String()
}
-// Info logs an information message.
-func (l *Logger) Info(msg string, args ...interface{}) *Logger {
- return l.LogAtLevel(message.INFO, msg, args...)
+// Info is an alias for Log.
+func (l *Logger) Info(args ...interface{}) *Logger {
+ return l.log(args...)
}
// Debug logs a debug message.
-func (l *Logger) Debug(msg string, args ...interface{}) *Logger {
- return l.LogAtLevel(message.DEBUG, msg, args...)
+func (l *Logger) Debug(args ...interface{}) *Logger {
+ if l.debug {
+ return l.log(args...)
+ }
+ return l
}
-// IsWarn determines the info status for a logger instance.
-// Use this to conditionally execute blocks of code depending on the log verbosity.
-func (l *Logger) IsWarn() bool { return l.min >= message.WARN }
-
-// IsInfo determines the info status for a logger instance.
-// Use this to conditionally execute blocks of code depending on the log verbosity.
-func (l *Logger) IsInfo() bool { return l.min >= message.INFO }
-
// IsDebug determines the debug status for a logger instance.
// Use this to conditionally execute blocks of code depending on the log verbosity.
-func (l *Logger) IsDebug() bool { return l.min >= message.DEBUG }
+func (l *Logger) IsDebug() bool { return l.debug }
+
+// Field enables setting or changing the default fields for a logger instance.
+func (l *Logger) Field(k string, v interface{}) *Logger {
+ l.lock.Lock()
+ defer l.lock.Unlock()
-// SetLevelAsString enables changing the minimum level for a logger instance.
-func (l *Logger) SetLevelAsString(lvl string) *Logger {
- l.SetLevel(message.Levels[strings.ToUpper(lvl)])
+ l.fields[k] = toString(v)
return l
}
-// SetLevel enables changing the minimum level for a logger instance.
-func (l *Logger) SetLevel(lvl message.Level) *Logger {
- l.min = lvl
+// Fields enables setting or changing the default fields for a logger instance.
+func (l *Logger) Fields(args ...interface{}) *Logger {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ if len(args)%2 != 0 {
+ args = append(args, "")
+ }
+ for i := 0; i < len(args); i += 2 {
+ l.fields[toString(args[i])] = toString(args[i+1])
+ }
return l
}
-// Field enables changing the default fields for a logger instance.
-func (l *Logger) Field(k string, v interface{}) *Logger {
+// FieldMap enables setting or changing the default fields for a logger instance.
+func (l *Logger) FieldMap(f map[string]interface{}) *Logger {
l.lock.Lock()
defer l.lock.Unlock()
- l.fields[k] = v
+ for k, v := range f {
+ l.fields[k] = toString(v)
+ }
return l
}
diff --git a/logger_test.go b/logger_test.go
index 1ea794d..f517d06 100644
--- a/logger_test.go
+++ b/logger_test.go
@@ -6,20 +6,12 @@ import (
"strings"
"testing"
- "src.userspace.com.au/logger/message"
"src.userspace.com.au/logger/writers/kv"
)
func TestLoggerOptions(t *testing.T) {
- l, err := New(Level(message.INFO))
- if err != nil {
- t.Errorf("New() failed: %s", err)
- }
- if !l.IsInfo() {
- t.Errorf("IsInfo() => %t, expected true", l.IsInfo())
- }
-
- err = Level(message.DEBUG)(l)
+ l, err := New()
+ err = ForceDebug(true)(l)
if err != nil {
t.Errorf("level option failed: %s", err)
}
@@ -28,38 +20,15 @@ func TestLoggerOptions(t *testing.T) {
}
}
-func TestLevels(t *testing.T) {
+func TestLog(t *testing.T) {
tests := []struct {
- min message.Level
- level message.Level
- output bool
+ input []interface{}
+ expected string
}{
- // error
- {message.ERROR, message.ERROR, true},
- {message.ERROR, message.WARN, false},
- {message.ERROR, message.INFO, false},
- {message.ERROR, message.DEBUG, false},
- // warn
- {message.WARN, message.ERROR, true},
- {message.WARN, message.WARN, true},
- {message.WARN, message.INFO, false},
- {message.WARN, message.DEBUG, false},
- // info
- {message.INFO, message.ERROR, true},
- {message.INFO, message.WARN, true},
- {message.INFO, message.INFO, true},
- {message.INFO, message.DEBUG, false},
- // debug
- {message.DEBUG, message.ERROR, true},
- {message.DEBUG, message.WARN, true},
- {message.DEBUG, message.INFO, true},
- {message.DEBUG, message.DEBUG, true},
+ {[]interface{}{"one", "two"}, "one two"},
}
var buf bytes.Buffer
- kv, err := kv.New(
- kv.SetOutput(&buf),
- kv.SetTimeFormat(""), // Ignore time
- )
+ kv, err := kv.New(kv.SetOutput(&buf))
if err != nil {
t.Fatal("failed to create keyvalue: ", err)
}
@@ -68,22 +37,13 @@ func TestLevels(t *testing.T) {
t.Fatal("failed to create logger: ", err)
}
- for i, tt := range tests {
- log.SetLevel(tt.min)
- log.LogAtLevel(tt.level, "test")
- actual := strings.TrimSpace(buf.String())
- buf.Reset()
- expected := fmt.Sprintf("[%s] test", tt.level)
- if (actual == expected) != tt.output {
- t.Errorf("invalid levelled output for test %d, got %q", i, actual)
- }
+ for _, tt := range tests {
+ log.Log(tt.input...)
- // Test logging without a level
- log.Log("test")
- actual = strings.TrimSpace(buf.String())
+ actual := buf.String()
buf.Reset()
- if actual != "test" {
- t.Errorf("invalid Log output for test %d, got %q", i, actual)
+ if !strings.Contains(actual, tt.expected) {
+ t.Errorf("expected %q got %q", tt.expected, actual)
}
}
}
@@ -111,11 +71,11 @@ func TestNamed(t *testing.T) {
for _, tt := range tests {
log.name = tt.existing
named := log.Named(tt.name)
- named.Error("test")
+ named.Log("test")
actual := buf.String()
buf.Reset()
- expected := fmt.Sprintf("[error] %s: test", tt.expected)
+ expected := fmt.Sprintf("%s: test", tt.expected)
if !strings.Contains(actual, expected) {
t.Errorf("expected %q got %q", expected, actual)
}
diff --git a/message/level.go b/message/level.go
deleted file mode 100644
index 8438cc1..0000000
--- a/message/level.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package message
-
-// Level defines the output level
-type Level int
-
-// Log levels
-const (
- NONE Level = iota // Always log it
- ERROR // Wake someone up
- WARN // Something failed but don't wake anyone up
- INFO // Good to know
- DEBUG // Not for production
-)
-
-func (l Level) String() string {
- switch l {
- case 0:
- return ""
- case 1:
- return "error"
- case 2:
- return "warn"
- case 3:
- return "info"
- case 4:
- return "debug"
- default:
- return "unknown"
- }
-}
-
-// Levels is a convenience for string -> level
-var Levels = map[string]Level{
- "NONE": NONE,
- "ERROR": ERROR,
- "WARN": WARN,
- "INFO": INFO,
- "DEBUG": DEBUG,
-}
diff --git a/message/level_test.go b/message/level_test.go
deleted file mode 100644
index d13f944..0000000
--- a/message/level_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package message
-
-import (
- "testing"
-)
-
-func TestLevel(t *testing.T) {
- tests := []struct {
- in string
- expected string
- }{
- {"ERROR", "error"},
- {"DEBUG", "debug"},
- {"WARN", "warn"},
- {"INFO", "info"},
- }
-
- for _, tt := range tests {
- l := Levels[tt.in]
- actual := l.String()
- if actual != tt.expected {
- t.Errorf("got %s, expected %s", actual, tt.expected)
- }
- }
-}
diff --git a/message/message.go b/message/message.go
index 72e3c40..c4049da 100644
--- a/message/message.go
+++ b/message/message.go
@@ -8,14 +8,10 @@ type Message struct {
Name string
// The time log() was called
Time time.Time
- // The log level
- Level Level
// The message content
Content string
// Optional fields for the logger
- Fields map[string]interface{}
- // Optional extras for this log message
- Extras []interface{}
+ Fields map[string]string
}
// Writer interface for writing messages.
diff --git a/options.go b/options.go
index cace429..4f75a07 100644
--- a/options.go
+++ b/options.go
@@ -1,6 +1,8 @@
package logger
import (
+ "os"
+
"src.userspace.com.au/logger/message"
)
@@ -15,18 +17,18 @@ func Writer(f message.Writer) Option {
}
}
-// Level configures the minimum level to log.
-func Level(lvl message.Level) Option {
+// ForceDebug sets debug.
+func ForceDebug(b bool) Option {
return func(l *Logger) error {
- l.SetLevel(lvl)
+ l.debug = b
return nil
}
}
-// LevelAsString configures the minimum level to log.
-func LevelAsString(lvl string) Option {
+// DebugEnvVar sets debug if the envvar 'v' is not empty.
+func DebugEnvVar(v string) Option {
return func(l *Logger) error {
- l.SetLevelAsString(lvl)
+ l.debug = (os.Getenv(v) != "")
return nil
}
}
diff --git a/std.go b/std.go
index 0bfe88e..cf70e51 100644
--- a/std.go
+++ b/std.go
@@ -7,39 +7,19 @@ import (
var std *Logger
func init() {
- std, _ = New(Level(message.WARN))
+ std, _ = New()
}
-// Error logs an error message.
-func Error(msg string, args ...interface{}) { std.Error(msg, args...) }
-
-// Warn logs an information message.
-func Warn(msg string, args ...interface{}) { std.Warn(msg, args...) }
-
// Info logs an information message.
-func Info(msg string, args ...interface{}) { std.Info(msg, args...) }
+func Info(args ...interface{}) { std.Info(args...) }
// Debug logs a debug message.
-func Debug(msg string, args ...interface{}) { std.Debug(msg, args...) }
-
-// IsWarn determines the info status for a logger instance.
-// Use this to conditionally execute blocks of code depending on the log verbosity.
-func IsWarn() bool { return std.IsWarn() }
-
-// IsInfo determines the info status for a logger instance.
-// Use this to conditionally execute blocks of code depending on the log verbosity.
-func IsInfo() bool { return std.IsInfo() }
+func Debug(args ...interface{}) { std.Debug(args...) }
// IsDebug determines the debug status for a logger instance.
// Use this to conditionally execute blocks of code depending on the log verbosity.
func IsDebug() bool { return std.IsDebug() }
-// SetLevelAsString enables changing the minimum level for a logger instance.
-func SetLevelAsString(lvl string) { std.SetLevelAsString(lvl) }
-
-// SetLevel enables changing the minimum level for a logger instance.
-func SetLevel(lvl message.Level) { std.SetLevel(lvl) }
-
// Field enables changing the default fields for a logger instance.
func Field(k string, v interface{}) *Logger { return std.Field(k, v) }
diff --git a/writers/json/json.go b/writers/json/json.go
index ecc2278..0dff446 100644
--- a/writers/json/json.go
+++ b/writers/json/json.go
@@ -6,7 +6,6 @@ import (
"io"
"os"
- "src.userspace.com.au/logger/internal"
"src.userspace.com.au/logger/message"
)
@@ -39,28 +38,10 @@ func (w Writer) Write(m message.Message) {
"_message": m.Content,
}
- if l := m.Level.String(); l != "" {
- vals["_level"] = m.Level.String()
- }
-
for k, v := range m.Fields {
vals[k] = v
}
- if len(m.Extras) > 0 {
- // Allow for an odd number of extras
- offset := len(m.Extras) % 2
- if offset != 0 {
- for k, v := range m.Extras {
- vals[fmt.Sprintf("extra%02d", k)] = v
- }
- } else {
- for i := offset; i < len(m.Extras); i = i + 2 {
- vals[internal.ToString(m.Extras[i])] = m.Extras[i+1]
- }
- }
- }
-
if err := json.NewEncoder(w.writer).Encode(vals); err != nil {
fmt.Fprintf(w.writer, "\"failed to encode JSON: %s\"", err)
}
diff --git a/writers/json/json_test.go b/writers/json/json_test.go
index 0bd29b1..5778f51 100644
--- a/writers/json/json_test.go
+++ b/writers/json/json_test.go
@@ -14,17 +14,16 @@ func TestWriter(t *testing.T) {
now, _ := time.Parse(time.RFC3339, "2019-05-03T13:38:29.987249+10:00")
var tests = []struct {
in message.Message
- expected map[string]interface{}
+ expected map[string]string
}{
{
in: message.Message{
Time: now,
Name: "test",
- Level: message.ERROR,
Content: "msg",
},
- expected: map[string]interface{}{
- "_level": "error", "_name": "test", "_message": "msg",
+ expected: map[string]string{
+ "_name": "test", "_message": "msg",
"_time": "2019-05-03T13:38:29.987+1000",
},
},
@@ -32,12 +31,10 @@ func TestWriter(t *testing.T) {
in: message.Message{
Time: now,
Name: "test",
- Level: message.ERROR,
Content: "msg",
- Extras: []interface{}{"one"},
},
- expected: map[string]interface{}{
- "_level": "error", "_name": "test", "_message": "msg", "extra00": "one",
+ expected: map[string]string{
+ "_name": "test", "_message": "msg",
"_time": "2019-05-03T13:38:29.987+1000",
},
},
@@ -45,12 +42,11 @@ func TestWriter(t *testing.T) {
in: message.Message{
Time: now,
Name: "test",
- Level: message.ERROR,
Content: "msg",
- Fields: map[string]interface{}{"one": "1"},
+ Fields: map[string]string{"one": "1"},
},
- expected: map[string]interface{}{
- "_level": "error", "_name": "test", "_message": "msg", "one": "1",
+ expected: map[string]string{
+ "_name": "test", "_message": "msg", "one": "1",
"_time": "2019-05-03T13:38:29.987+1000",
},
},
@@ -58,11 +54,10 @@ func TestWriter(t *testing.T) {
in: message.Message{
Time: now,
Name: "test",
- Level: message.ERROR,
- Content: "msg", Extras: []interface{}{"one", "1", "two", "2", "three", 3, "fo ur", "# 4"},
+ Content: "msg",
},
- expected: map[string]interface{}{
- "_level": "error", "_name": "test", "_message": "msg", "one": "1", "two": "2", "three": float64(3), "fo ur": "# 4",
+ expected: map[string]string{
+ "_name": "test", "_message": "msg",
"_time": "2019-05-03T13:38:29.987+1000",
},
},
@@ -70,12 +65,11 @@ func TestWriter(t *testing.T) {
in: message.Message{
Time: now,
Name: "test",
- Level: message.DEBUG,
Content: "msg",
- Extras: []interface{}{"one"}, Fields: map[string]interface{}{"f1": "v1"},
+ Fields: map[string]string{"f1": "v1"},
},
- expected: map[string]interface{}{
- "_level": "debug", "_name": "test", "_message": "msg", "f1": "v1", "extra00": "one",
+ expected: map[string]string{
+ "_name": "test", "_message": "msg", "f1": "v1",
"_time": "2019-05-03T13:38:29.987+1000",
},
},
@@ -90,7 +84,7 @@ func TestWriter(t *testing.T) {
for _, tt := range tests {
l.Write(tt.in)
- var raw map[string]interface{}
+ var raw map[string]string
if err := json.Unmarshal(buf.Bytes(), &raw); err != nil {
t.Fatal(err)
}
diff --git a/writers/kv/key_value.go b/writers/kv/key_value.go
index a3369c5..b4434be 100644
--- a/writers/kv/key_value.go
+++ b/writers/kv/key_value.go
@@ -6,7 +6,6 @@ import (
"os"
"strings"
- "src.userspace.com.au/logger/internal"
"src.userspace.com.au/logger/message"
)
@@ -33,11 +32,7 @@ func New(opts ...Option) (*Writer, error) {
// Write implements the message.Writer interface.
func (w Writer) Write(m message.Message) {
- //fmt.Fprintf(w, "%s [%-5s] ", m.Time, m.Level)
fmt.Fprintf(w.writer, "%s ", m.Time.Format(w.timeFormat))
- if l := m.Level.String(); l != "" {
- fmt.Fprintf(w.writer, "[%s] ", l)
- }
if m.Name != "" {
fmt.Fprintf(w.writer, "%s: ", m.Name)
}
@@ -45,32 +40,14 @@ func (w Writer) Write(m message.Message) {
// Write message content first
w.writer.Write([]byte(m.Content))
- // Write fields before extras
for k, v := range m.Fields {
writeKV(w.writer, k, v)
}
-
- if len(m.Extras) > 0 {
- // Allow for an odd number of extras
- offset := len(m.Extras) % 2
- if offset != 0 {
- for k, v := range m.Extras {
- writeKV(w.writer, fmt.Sprintf("extra%02d", k), v)
- }
- } else {
- for i := offset; i < len(m.Extras); i = i + 2 {
- writeKV(w.writer, m.Extras[i], m.Extras[i+1])
- }
- }
- }
w.writer.Write([]byte{'\n'})
}
-func writeKV(w io.Writer, k, v interface{}) (int, error) {
- return fmt.Fprintf(w, " %s=%s",
- maybeQuote(internal.ToString(k)),
- maybeQuote(internal.ToString(v)),
- )
+func writeKV(w io.Writer, k, v string) (int, error) {
+ return fmt.Fprintf(w, " %s=%s", maybeQuote(k), maybeQuote(v))
}
func maybeQuote(s string) string {
diff --git a/writers/kv/key_value_test.go b/writers/kv/key_value_test.go
index adf8bcd..241da87 100644
--- a/writers/kv/key_value_test.go
+++ b/writers/kv/key_value_test.go
@@ -19,50 +19,43 @@ func TestWriter(t *testing.T) {
in: message.Message{
Time: now,
Name: "test",
- Level: message.ERROR,
Content: "msg",
},
- expected: "2019-05-03T13:38:29.987+1000 [error] test: msg",
+ expected: "2019-05-03T13:38:29.987+1000 test: msg",
},
{
in: message.Message{
Time: now,
Name: "test",
- Level: message.ERROR,
Content: "msg",
- Extras: []interface{}{"one"},
},
- expected: "2019-05-03T13:38:29.987+1000 [error] test: msg extra00=one",
+ expected: "2019-05-03T13:38:29.987+1000 test: msg",
},
{
in: message.Message{
Time: now,
Name: "test",
- Level: message.ERROR,
Content: "msg",
- Fields: map[string]interface{}{"one": "1"},
+ Fields: map[string]string{"one": "1"},
},
- expected: "2019-05-03T13:38:29.987+1000 [error] test: msg one=1",
+ expected: "2019-05-03T13:38:29.987+1000 test: msg one=1",
},
{
in: message.Message{
Time: now,
Name: "test",
- Level: message.ERROR,
- Content: "msg", Extras: []interface{}{"one", "1", "two", "2", "three", 3, "fo ur", "# 4"},
+ Content: "msg",
},
- expected: `2019-05-03T13:38:29.987+1000 [error] test: msg one=1 two=2 three=3 "fo ur"="# 4"`,
+ expected: `2019-05-03T13:38:29.987+1000 test: msg`,
},
{
in: message.Message{
Time: now,
Name: "test",
- Level: message.DEBUG,
Content: "msg",
- Fields: map[string]interface{}{"f1": "v1"},
- Extras: []interface{}{"one"},
+ Fields: map[string]string{"f1": "v1"},
},
- expected: "2019-05-03T13:38:29.987+1000 [debug] test: msg f1=v1 extra00=one",
+ expected: "2019-05-03T13:38:29.987+1000 test: msg f1=v1",
},
}
diff --git a/writers/rabbitmq/rabbitmq.go b/writers/rabbitmq/rabbitmq.go
index be11f28..871a176 100644
--- a/writers/rabbitmq/rabbitmq.go
+++ b/writers/rabbitmq/rabbitmq.go
@@ -2,12 +2,10 @@ package amqp
import (
"encoding/json"
- "fmt"
"strings"
"time"
"github.com/streadway/amqp"
- "src.userspace.com.au/logger/internal"
"src.userspace.com.au/logger/message"
)
@@ -32,7 +30,7 @@ func New(url, exchange string, opts ...WriterOpt) (*Writer, error) {
exchangeName: exchange,
passive: false,
exchangeType: "topic",
- routingFormat: "{name}.{level}",
+ routingFormat: "{name}",
contentType: "application/json",
}
@@ -85,7 +83,6 @@ func New(url, exchange string, opts ...WriterOpt) (*Writer, error) {
func (w Writer) Write(m message.Message) {
vals := map[string]interface{}{
"@name": m.Name,
- "@level": m.Level.String(),
"@message": m.Content,
"@time": m.Time,
}
@@ -94,20 +91,6 @@ func (w Writer) Write(m message.Message) {
vals[k] = v
}
- if len(m.Extras) > 0 {
- // Allow for an odd number of extras
- offset := len(m.Extras) % 2
- if offset != 0 {
- for k, v := range m.Extras {
- vals[fmt.Sprintf("extra%02d", k)] = v
- }
- } else {
- for i := offset; i < len(m.Extras); i = i + 2 {
- vals[internal.ToString(m.Extras[i])] = m.Extras[i+1]
- }
- }
- }
-
d, err := json.Marshal(vals)
if err != nil {
panic(err)
@@ -121,7 +104,6 @@ func (w Writer) Write(m message.Message) {
}
routingKey := strings.Replace(w.routingFormat, "{name}", m.Name, 0)
- routingKey = strings.Replace(w.routingFormat, "{level}", m.Level.String(), 0)
if err := w.channel.Publish(
w.exchangeName,