Skip to content

Commit d63999a

Browse files
committed
Merge branch 'develop'
2 parents 511ae11 + 866b81e commit d63999a

File tree

6 files changed

+148
-192
lines changed

6 files changed

+148
-192
lines changed

README.md

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,8 @@
11
# log - aah framework
22
[![Build Status](https://travis-ci.org/go-aah/log.svg?branch=master)](https://travis-ci.org/go-aah/log) [![Go Report Card](https://goreportcard.com/badge/github.com/go-aah/log)](https://goreportcard.com/report/github.com/go-aah/log) [![GoDoc](https://godoc.org/github.com/go-aah/log?status.svg)](https://godoc.org/github.com/go-aah/log) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
33

4-
Package `log` is used across **aah framework**. It's independent library, can be used separately with any `Go` language project. Feel free to use it.
4+
Simple, flexible & powerful `Go` logger. aah framework utilizes `log` library across.
55

6-
`log` supports following receivers:
7-
* Console
8-
* Log level is colored (for windows it's plain)
9-
* File
10-
* Log Rotation
11-
* Daily
12-
* Size
13-
* No. of lines
14-
* No. of Backups (upcoming)
15-
* Remote - TCP & UDP (upcoming)
6+
*It's independent library, can be used separately with any `Go` language project. Feel free to use it.*
167

17-
## Quick Start
18-
19-
```
20-
go get -u github.com/go-aah/log
21-
```
22-
23-
## Sample
24-
```go
25-
log.Info("Welcome ", "to ", "aah ", "logger")
26-
log.Infof("%v, %v, & %v", "simple", "flexible", "powerful logger")
27-
28-
// Output:
29-
2016-07-03 19:22:11.504 INFO - Welcome to aah logger
30-
2016-07-03 19:22:11.504 INFO - simple, flexible, & powerful logger
31-
```
32-
33-
## Author
34-
Jeevanandam M. - [email protected]
35-
36-
## Contributors
37-
Have a look on [Contributors](https://github.com/go-aah/log/graphs/contributors) page.
38-
39-
## License
40-
Released under MIT license, refer [LICENSE](LICENSE) file.
8+
See official page [TODO]

formatter.go

Lines changed: 3 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,66 +5,11 @@
55
package log
66

77
import (
8-
"errors"
98
"fmt"
10-
"os"
119
"strconv"
1210
"strings"
13-
)
14-
15-
// FmtFlag type definition
16-
type FmtFlag uint8
17-
18-
// Format flags used to define log message format for each log entry
19-
const (
20-
FmtFlagLevel FmtFlag = iota
21-
FmtFlagTime
22-
FmtFlagUTCTime
23-
FmtFlagLongfile
24-
FmtFlagShortfile
25-
FmtFlagLine
26-
FmtFlagMessage
27-
FmtFlagCustom
28-
FmtFlagUnknown
29-
)
30-
31-
var (
32-
// FmtFlags is the list of log format flags supported by aah/log library
33-
// Usage of flag order is up to format composition.
34-
// level - outputs INFO, DEBUG, ERROR, so on
35-
// time - outputs local time as per format supplied
36-
// utctime - outputs UTC time as per format supplied
37-
// longfile - outputs full file name: /a/b/c/d.go
38-
// shortfile - outputs final file name element: d.go
39-
// line - outputs file line number: L23
40-
// message - outputs given message along supplied arguments if they present
41-
// custom - outputs string as-is into log entry
42-
FmtFlags = map[string]FmtFlag{
43-
"level": FmtFlagLevel,
44-
"time": FmtFlagTime,
45-
"utctime": FmtFlagUTCTime,
46-
"longfile": FmtFlagLongfile,
47-
"shortfile": FmtFlagShortfile,
48-
"line": FmtFlagLine,
49-
"message": FmtFlagMessage,
50-
"custom": FmtFlagCustom,
51-
}
52-
53-
// DefaultPattern is default log entry pattern in aah/log
54-
// For e.g:
55-
// 2006-01-02 15:04:05.000 INFO - This is my message
56-
DefaultPattern = "%time:2006-01-02 15:04:05.000 %level:-5 %custom:- %message"
57-
58-
// BackupTimeFormat is used for timestamp with filename on rotation
59-
BackupTimeFormat = "2006-01-02-15-04-05.000"
60-
61-
// ErrFormatStringEmpty returned when log format parameter is empty
62-
ErrFormatStringEmpty = errors.New("log format string is empty")
6311

64-
flagSeparator = "%"
65-
flagValueSeparator = ":"
66-
defaultFormat = "%v"
67-
filePermission = os.FileMode(0755)
12+
"github.com/go-aah/essentials"
6813
)
6914

7015
// FormatterFunc is the handler function to implement log entry
@@ -88,7 +33,7 @@ type FlagPart struct {
8833
// For e.g.:
8934
// %time:2006-01-02 15:04:05.000 %level %custom:- %msg
9035
func parseFlag(format string) (*[]FlagPart, error) {
91-
if strIsEmpty(format) {
36+
if ess.StrIsEmpty(format) {
9237
return nil, ErrFormatStringEmpty
9338
}
9439

@@ -149,7 +94,7 @@ func DefaultFormatter(flags *[]FlagPart, entry *Entry, isColor bool) (*[]byte, e
14994
case FmtFlagLine:
15095
buf = append(buf, fmt.Sprintf(part.Format, "L"+strconv.Itoa(entry.Line))...)
15196
case FmtFlagMessage:
152-
if strIsEmpty(entry.Format) {
97+
if ess.StrIsEmpty(entry.Format) {
15398
buf = append(buf, fmt.Sprint(entry.Values...)...)
15499
} else {
155100
buf = append(buf, fmt.Sprintf(entry.Format, entry.Values...)...)

log.go

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ import (
2424
"strings"
2525
"time"
2626

27-
"github.com/go-aah/forge"
27+
"github.com/go-aah/config"
28+
"github.com/go-aah/essentials"
2829
)
2930

3031
// Level type definition
3132
type Level uint8
3233

34+
// FmtFlag type definition
35+
type FmtFlag uint8
36+
3337
// Log Level definition
3438
const (
3539
LevelError Level = iota
@@ -40,10 +44,60 @@ const (
4044
LevelUnknown
4145
)
4246

47+
// Format flags used to define log message format for each log entry
48+
const (
49+
FmtFlagLevel FmtFlag = iota
50+
FmtFlagTime
51+
FmtFlagUTCTime
52+
FmtFlagLongfile
53+
FmtFlagShortfile
54+
FmtFlagLine
55+
FmtFlagMessage
56+
FmtFlagCustom
57+
FmtFlagUnknown
58+
)
59+
4360
var (
61+
// FmtFlags is the list of log format flags supported by aah/log library
62+
// Usage of flag order is up to format composition.
63+
// level - outputs INFO, DEBUG, ERROR, so on
64+
// time - outputs local time as per format supplied
65+
// utctime - outputs UTC time as per format supplied
66+
// longfile - outputs full file name: /a/b/c/d.go
67+
// shortfile - outputs final file name element: d.go
68+
// line - outputs file line number: L23
69+
// message - outputs given message along supplied arguments if they present
70+
// custom - outputs string as-is into log entry
71+
FmtFlags = map[string]FmtFlag{
72+
"level": FmtFlagLevel,
73+
"time": FmtFlagTime,
74+
"utctime": FmtFlagUTCTime,
75+
"longfile": FmtFlagLongfile,
76+
"shortfile": FmtFlagShortfile,
77+
"line": FmtFlagLine,
78+
"message": FmtFlagMessage,
79+
"custom": FmtFlagCustom,
80+
}
81+
82+
// DefaultPattern is default log entry pattern in aah/log
83+
// For e.g:
84+
// 2006-01-02 15:04:05.000 INFO - This is my message
85+
DefaultPattern = "%time:2006-01-02 15:04:05.000 %level:-5 %custom:- %message"
86+
87+
// BackupTimeFormat is used for timestamp with filename on rotation
88+
BackupTimeFormat = "2006-01-02-15-04-05.000"
89+
90+
// ErrFormatStringEmpty returned when log format parameter is empty
91+
ErrFormatStringEmpty = errors.New("log format string is empty")
92+
4493
// ErrWriterIsClosed returned when log writer is closed
4594
ErrWriterIsClosed = errors.New("log writer is closed")
4695

96+
flagSeparator = "%"
97+
flagValueSeparator = ":"
98+
defaultFormat = "%v"
99+
filePermission = os.FileMode(0755)
100+
47101
levelNameToLevel = map[string]Level{
48102
"ERROR": LevelError,
49103
"WARN": LevelWarn,
@@ -114,37 +168,29 @@ type Logger interface {
114168
}
115169

116170
// New creates the logger based config supplied
117-
func New(config string) (Logger, error) {
118-
if strIsEmpty(config) {
171+
func New(configStr string) (Logger, error) {
172+
if ess.StrIsEmpty(configStr) {
119173
return nil, errors.New("logger config is empty")
120174
}
121175

122-
cfg, err := forge.ParseString(config)
176+
cfg, err := config.ParseString(configStr)
123177
if err != nil {
124178
return nil, err
125179
}
126180

127-
receiverType, err := cfg.GetString("receiver")
128-
if err != nil {
129-
return nil, err
181+
receiverType, found := cfg.String("receiver")
182+
if !found {
183+
return nil, errors.New("receiver configuration is required")
130184
}
131185
receiverType = strings.ToUpper(receiverType)
132186

133-
levelName, err := cfg.GetString("level")
134-
if err != nil {
135-
levelName = "DEBUG"
136-
}
137-
187+
levelName := cfg.StringDefault("level", "DEBUG")
138188
level := levelByName(levelName)
139189
if level == LevelUnknown {
140190
return nil, fmt.Errorf("unrecognized log level: %v", levelName)
141191
}
142192

143-
pattern, err := cfg.GetString("pattern")
144-
if err != nil {
145-
pattern = DefaultPattern
146-
}
147-
193+
pattern := cfg.StringDefault("pattern", DefaultPattern)
148194
flags, err := parseFlag(pattern)
149195
if err != nil {
150196
return nil, err
@@ -197,7 +243,7 @@ func fetchCallerInfo(calldepth int) (string, int) {
197243
return file, line
198244
}
199245

200-
func newConsoleReceiver(cfg *forge.Section, receiverType string, level Level, flags *[]FlagPart) (*Receiver, error) {
246+
func newConsoleReceiver(cfg *config.Config, receiverType string, level Level, flags *[]FlagPart) (*Receiver, error) {
201247
receiver := Receiver{
202248
Config: cfg,
203249
Type: receiverType,
@@ -214,7 +260,12 @@ func newConsoleReceiver(cfg *forge.Section, receiverType string, level Level, fl
214260
return &receiver, nil
215261
}
216262

217-
func newFileReceiver(cfg *forge.Section, receiverType string, level Level, flags *[]FlagPart) (*Receiver, error) {
263+
func newFileReceiver(cfg *config.Config, receiverType string, level Level, flags *[]FlagPart) (*Receiver, error) {
264+
maxSize := cfg.IntDefault("rotate.size", 100)
265+
if maxSize > 2048 { // maximum 2GB file size
266+
return nil, errors.New("maximum 2GB file size supported for rotation")
267+
}
268+
218269
receiver := Receiver{
219270
Config: cfg,
220271
Type: receiverType,
@@ -232,16 +283,16 @@ func newFileReceiver(cfg *forge.Section, receiverType string, level Level, flags
232283
return nil, err
233284
}
234285

235-
rotate, _ := cfg.GetSection("rotate")
236-
receiver.rotate, _ = rotate.GetString("mode")
286+
receiver.rotate = cfg.StringDefault("rotate.mode", "daily")
287+
// rotate, _ := cfg.GetSection("rotate")
288+
// receiver.rotate, _ = rotate.GetString("mode")
237289
switch receiver.rotate {
238290
case "daily":
239291
receiver.setOpenDay()
240292
case "lines":
241-
receiver.maxLines, _ = rotate.GetInteger("lines")
293+
receiver.maxLines = int64(cfg.IntDefault("rotate.lines", 0))
242294
case "size":
243-
receiver.maxSize, _ = rotate.GetInteger("size")
244-
receiver.maxSize = receiver.maxSize * 1024 * 1024
295+
receiver.maxSize = int64(maxSize * 1024 * 1024)
245296
}
246297

247298
return &receiver, nil

log_test.go

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package log
66

77
import (
88
"fmt"
9+
"strings"
910
"testing"
1011
)
1112

@@ -132,7 +133,7 @@ func TestNewCustomFileReceiverLinesRotation(t *testing.T) {
132133
receiver = "file"
133134
134135
# "debug" lowercase works too and if not supplied then defaults to DEBUG
135-
level = "info"
136+
level = "trace"
136137
137138
# if not suppiled then default pattern is used
138139
pattern = "%time:2006-01-02 15:04:05.000 %level:-5 %shortfile %line %custom:- %message"
@@ -178,7 +179,7 @@ func TestNewCustomFileReceiverSizeRotation(t *testing.T) {
178179
receiver = "file"
179180
180181
# if not suppiled then default pattern is used
181-
pattern = "%time:2006-01-02 15:04:05.000 %level:-5 %longfile %line %custom:- %message"
182+
pattern = "%utctime:2006-01-02 15:04:05.000 %level:-5 %longfile %line %custom:- %message"
182183
rotate {
183184
mode = "size"
184185
@@ -208,3 +209,61 @@ rotate {
208209
logger.Errorf("Yes, yes, yes - finally an error: %v, finally an error: %v, finally an error: %v", 0, 000, 0000)
209210
}
210211
}
212+
213+
func TestUnknownFormatFlag(t *testing.T) {
214+
_, err := parseFlag("")
215+
if err != ErrFormatStringEmpty {
216+
t.Errorf("Unexpected error: %v", err)
217+
t.FailNow()
218+
}
219+
220+
_, err = parseFlag("%time:2006-01-02 15:04:05.000 %level:-5 %longfile %unknown %custom:- %message")
221+
if !strings.Contains(err.Error(), "unrecognized log format flag") {
222+
t.Errorf("Unexpected error: %v", err)
223+
t.FailNow()
224+
}
225+
}
226+
227+
func TestNewMisc(t *testing.T) {
228+
_, err := New("")
229+
if err.Error() != "logger config is empty" {
230+
t.Errorf("Unexpected error: %v", err)
231+
t.FailNow()
232+
}
233+
234+
_, err = New(`receiver = "file" level="info"`)
235+
if !strings.HasPrefix(err.Error(), "syntax error") {
236+
t.Errorf("Unexpected error: %v", err)
237+
t.FailNow()
238+
}
239+
240+
_, err = New(`level="info";`)
241+
if !strings.HasPrefix(err.Error(), "receiver configuration") {
242+
t.Errorf("Unexpected error: %v", err)
243+
t.FailNow()
244+
}
245+
246+
_, err = New(`receiver = "file"; level="unknown";`)
247+
if !strings.HasPrefix(err.Error(), "unrecognized log level") {
248+
t.Errorf("Unexpected error: %v", err)
249+
t.FailNow()
250+
}
251+
252+
_, err = New(`receiver = "remote"; level="debug";`)
253+
if !strings.HasPrefix(err.Error(), "unsupported receiver") {
254+
t.Errorf("Unexpected error: %v", err)
255+
t.FailNow()
256+
}
257+
258+
_, err = New(`receiver = "file"; level="debug"; rotate { mode="size"; size=2500; }`)
259+
if !strings.HasPrefix(err.Error(), "maximum 2GB file size") {
260+
t.Errorf("Unexpected error: %v", err)
261+
t.FailNow()
262+
}
263+
264+
_, err = New(`receiver = "console"; level="debug"; pattern="%time:2006-01-02 15:04:05.000 %level:-5 %unknown %message";`)
265+
if !strings.HasPrefix(err.Error(), "unrecognized log format flag") {
266+
t.Errorf("Unexpected error: %v", err)
267+
t.FailNow()
268+
}
269+
}

0 commit comments

Comments
 (0)