Skip to content

Commit

Permalink
Merge pull request #1 from golage/refactor/implementation
Browse files Browse the repository at this point in the history
Refactor/implementation
  • Loading branch information
mohsensamiei authored May 4, 2020
2 parents b606674 + ee95118 commit 29681a2
Show file tree
Hide file tree
Showing 11 changed files with 662 additions and 31 deletions.
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,36 @@ go get github.com/golage/log
Import into your code:
```go
import "github.com/golage/log"
```
```
Set output writer:
```go
log.SetOutput(w)
```
Set minimum log level (default: LevelInfo):
```go
log.SetLevel(log.LevelDebug)
```
Set log formatter (default: TextFormatter):
```go
log.SetFormatter(log.NewTextFormatter)
log.SetFormatter(log.NewJSONFormatter)
log.SetFormatter(log.NewYAMLFormatter)
```
Set constants data in all logs:
```go
log.SetConstant("key", "value")
```
Add data to log:
```go
log.With(err)
log.Value("key", "value")
```
Write log:
```go
log.Debug("message")
log.Info("message")
log.Warning("message")
log.Error("message")
log.Fatal("message")
```
For more see [example](examples/main.go)
51 changes: 28 additions & 23 deletions entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package log
import (
"fmt"
"log"
"os"
"reflect"
"runtime"
"time"
Expand All @@ -16,11 +15,20 @@ const (

// Entry implements log data
type Entry struct {
Raised time.Time
Level Level
Source string
// Raised keeps log raised time
Raised time.Time

// Level keeps log level
Level Level

// Source keeps log source code with line
Source string

// Message keeps log message text
Message string
Data map[string]interface{}

// Data keeps all data
Data map[string]interface{}
}

// NewEntry returns new entry with defaults
Expand All @@ -41,34 +49,29 @@ func NewEntry() *Entry {
}

// Debug logs entry with message in debug level
func (entry *Entry) Debug(message string) {
entry.Level = LevelDebug
entry.log(message)
func (entry Entry) Debug(message string) {
entry.log(LevelDebug, message)
}

// Info logs entry with message in info level
func (entry *Entry) Info(message string) {
entry.Level = LevelInfo
entry.log(message)
func (entry Entry) Info(message string) {
entry.log(LevelInfo, message)
}

// Warning logs entry with message in warning level
func (entry *Entry) Warning(message string) {
entry.Level = LevelWarning
entry.log(message)
func (entry Entry) Warning(message string) {
entry.log(LevelWarning, message)
}

// Error logs entry with message in error level
func (entry *Entry) Error(message string) {
entry.Level = LevelError
entry.log(message)
func (entry Entry) Error(message string) {
entry.log(LevelError, message)
}

// Fatal logs entry with message in fatal level so exit with code 1
func (entry *Entry) Fatal(message string) {
entry.Level = LevelFatal
entry.log(message)
os.Exit(1)
func (entry Entry) Fatal(message string) {
entry.log(LevelFatal, message)
exit(1)
}

// With appends data to entry and returns that
Expand All @@ -83,6 +86,7 @@ func (entry *Entry) With(data interface{}) *Entry {
value = reflect.ValueOf(value).Elem().Interface()
}
refType := reflect.TypeOf(value)

switch refType.Kind() {
case reflect.Map:
dic := reflect.ValueOf(value)
Expand All @@ -108,8 +112,9 @@ func (entry *Entry) Value(key string, value interface{}) *Entry {
return entry
}

func (entry *Entry) log(message string) {
entry.Message = message
func (entry *Entry) log(lvl Level, msg string) {
entry.Level = lvl
entry.Message = msg
if entry.Level >= level {
if _, err := fmt.Fprintln(output, formatter.Format(*entry)); err != nil {
log.Printf("can not write on output: %v", err)
Expand Down
159 changes: 159 additions & 0 deletions entry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package log

import (
"fmt"
"github.com/stretchr/testify/assert"
"strings"
"testing"
"time"
)

func createTestEntry() *Entry {
return &Entry{
Raised: time.Now(),
Source: "at test in test.go:11",
Data: make(map[string]interface{}),
}
}

func TestEntry_Debug(t *testing.T) {
resetTest()
t.Run("must returns debug message in output", func(t *testing.T) {
message := "text message"
createTestEntry().Debug(message)
text := strings.ToLower(testOutput.String())
assert.Contains(t, text, fmt.Sprintf("\"message\":\"%v\"", message))
assert.Contains(t, text, fmt.Sprintf("\"level\":%d", LevelDebug))
})
}

func TestEntry_Info(t *testing.T) {
resetTest()
t.Run("must returns info message in output", func(t *testing.T) {
message := "text message"
createTestEntry().Info(message)
text := strings.ToLower(testOutput.String())
assert.Contains(t, text, fmt.Sprintf("\"message\":\"%v\"", message))
assert.Contains(t, text, fmt.Sprintf("\"level\":%d", LevelInfo))
})
}

func TestEntry_Warning(t *testing.T) {
resetTest()
t.Run("must returns warning message in output", func(t *testing.T) {
message := "text message"
createTestEntry().Warning(message)
text := strings.ToLower(testOutput.String())
assert.Contains(t, text, fmt.Sprintf("\"message\":\"%v\"", message))
assert.Contains(t, text, fmt.Sprintf("\"level\":%d", LevelWarning))
})
}

func TestEntry_Error(t *testing.T) {
resetTest()
t.Run("must returns error message in output", func(t *testing.T) {
message := "text message"
createTestEntry().Error(message)
text := strings.ToLower(testOutput.String())
assert.Contains(t, text, fmt.Sprintf("\"message\":\"%v\"", message))
assert.Contains(t, text, fmt.Sprintf("\"level\":%d", LevelError))
})
}

func TestEntry_Fatal(t *testing.T) {
resetTest()
t.Run("must returns error message in output", func(t *testing.T) {
message := "text message"
exit = func(code int) {
assert.Equal(t, code, 1)
}
createTestEntry().Fatal(message)
text := strings.ToLower(testOutput.String())
assert.Contains(t, text, fmt.Sprintf("\"message\":\"%v\"", message))
assert.Contains(t, text, fmt.Sprintf("\"level\":%d", LevelFatal))
})
}

func TestEntry_Value(t *testing.T) {
resetTest()
t.Run("must returns entry with value", func(t *testing.T) {
entry := createTestEntry().Value("key", "value")
assert.Equal(t, entry.Data["key"], "value")
})
}

func TestEntry_With(t *testing.T) {
resetTest()
t.Run("must returns entry with value", func(t *testing.T) {
entry := createTestEntry().With("value1").With("value2").With("value3")
assert.Equal(t, entry.Data[dataValues], []interface{}{"value1", "value2", "value3"})
})
t.Run("must returns entry with pointer value", func(t *testing.T) {
now := time.Now()
entry := createTestEntry().With(&now)
assert.Equal(t, entry.Data["Time"], now)
})
t.Run("must returns entry with inline struct", func(t *testing.T) {
testData := struct {
Name string
}{
Name: "name",
}
entry := createTestEntry().With(testData)
assert.Equal(t, entry.Data[""], testData)
})
t.Run("must returns entry with defined struct", func(t *testing.T) {
type testData struct {
Name string
}
td := testData{Name: "name"}
entry := createTestEntry().With(td)
assert.Equal(t, entry.Data["testData"], td)
})
t.Run("must returns entry with error", func(t *testing.T) {
err := fmt.Errorf("test message")
entry := createTestEntry().With(err)
assert.Equal(t, entry.Data[dataError], err.Error())
})
t.Run("must returns entry with map", func(t *testing.T) {
dict := map[string]interface{}{
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
entry := createTestEntry().With(dict)
for key, value := range dict {
assert.Equal(t, entry.Data[key], value)
}
})
t.Run("must returns entry without data affect with nil", func(t *testing.T) {
entry := createTestEntry().With(nil)
assert.NotNil(t, entry)
})
}

func TestNewEntry(t *testing.T) {
tests := []struct {
name string
want *Entry
}{
{
name: "must returns new entry with defaults",
want: &Entry{
Raised: time.Now(),
Source: "at .* in .*[.]go:[\\d]*",
Data: make(map[string]interface{}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
entry := NewEntry()
assert.Equal(t, entry.Data, tt.want.Data)
assert.Equal(t, entry.Message, tt.want.Message)
assert.Equal(t, entry.Level, tt.want.Level)
assert.Equal(t, entry.Raised.Format("2006-01-02 15:04:05"), tt.want.Raised.Format("2006-01-02 15:04:05"))
assert.Regexp(t, tt.want.Source, entry.Source)
})
}
}
2 changes: 2 additions & 0 deletions examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"errors"

"github.com/golage/log"
)

Expand All @@ -11,6 +12,7 @@ type data struct {

func main() {
log.SetLevel(log.LevelDebug)

log.SetConstant("code_name", "example")

log.Value("name", "john").Debug("debug message")
Expand Down
Loading

0 comments on commit 29681a2

Please sign in to comment.