Skip to content

Commit 8a9fae7

Browse files
authored
Fix the data race in the formatter and content packages (#19)
1 parent c702c1c commit 8a9fae7

File tree

5 files changed

+103
-2
lines changed

5 files changed

+103
-2
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v0.2.1
1+
v0.2.2

content/time.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package content
22

3-
import "time"
3+
import (
4+
"sync"
5+
"time"
6+
)
47

58
var (
69
defaultLogTimeFormat = "2006-01-02 15:04:05"
10+
mu sync.RWMutex
711
)
812

913
// Time the custom Time for log
@@ -15,12 +19,16 @@ type Time struct {
1519
// InitDefaultLogTimeFormat init the global default log time format
1620
func InitDefaultLogTimeFormat(f string) {
1721
if len(f) > 0 {
22+
mu.Lock()
1823
defaultLogTimeFormat = f
24+
mu.Unlock()
1925
}
2026
}
2127

2228
// DefaultLogTimeFormat return the default log time format
2329
func DefaultLogTimeFormat() string {
30+
mu.RLock()
31+
defer mu.RUnlock()
2432
return defaultLogTimeFormat
2533
}
2634

content/time_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package content
22

33
import (
4+
"sync"
45
"testing"
56
"time"
67
)
@@ -34,5 +35,22 @@ func TestTime_MarshalText(t *testing.T) {
3435
t.Errorf("test Time.MarshalText failed, expect to get %s, but actual get %s", expect, actual)
3536
}
3637
}
38+
}
39+
40+
func TestInitDefaultLogTimeFormat_Concurrency(t *testing.T) {
41+
c := 10
42+
wg := sync.WaitGroup{}
43+
wg.Add(c * 2)
44+
for i := 0; i < c; i++ {
45+
go func() {
46+
InitDefaultLogTimeFormat(time.RFC3339)
47+
wg.Done()
48+
}()
3749

50+
go func() {
51+
NewTime(time.Now())
52+
wg.Done()
53+
}()
54+
}
55+
wg.Wait()
3856
}

formatter/formatter.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package formatter
22

33
import (
44
"strings"
5+
"sync"
56

67
"github.com/no-src/log/content"
78
)
@@ -16,10 +17,13 @@ var (
1617
formatters = make(map[string]Formatter)
1718
defaultFormatterType = TextFormatter
1819
defaultTerminator = "\n"
20+
mu sync.RWMutex
1921
)
2022

2123
// Default return the global default Formatter
2224
func Default() Formatter {
25+
mu.RLock()
26+
defer mu.RUnlock()
2327
return New(defaultFormatterType)
2428
}
2529

@@ -37,7 +41,9 @@ func NewTextFormatter() Formatter {
3741
func InitDefaultFormatter(t string) {
3842
_, ok := formatters[t]
3943
if ok {
44+
mu.Lock()
4045
defaultFormatterType = t
46+
mu.Unlock()
4147
}
4248
}
4349

formatter/formatter_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package formatter_test
2+
3+
import (
4+
"sync"
5+
"testing"
6+
"time"
7+
8+
"github.com/no-src/log/content"
9+
"github.com/no-src/log/formatter"
10+
_ "github.com/no-src/log/formatter/json"
11+
_ "github.com/no-src/log/formatter/text"
12+
"github.com/no-src/log/level"
13+
)
14+
15+
func TestInitDefaultFormatter_Concurrency(t *testing.T) {
16+
c := 10
17+
wg := sync.WaitGroup{}
18+
wg.Add(c * 2)
19+
for i := 0; i < c; i++ {
20+
go func() {
21+
formatter.InitDefaultFormatter(formatter.JsonFormatter)
22+
wg.Done()
23+
}()
24+
25+
go func() {
26+
formatter.Default()
27+
wg.Done()
28+
}()
29+
}
30+
wg.Wait()
31+
}
32+
33+
func TestNewJsonFormatter(t *testing.T) {
34+
f := formatter.NewJsonFormatter()
35+
data, err := f.Serialize(content.NewContent(level.DebugLevel, nil, false, time.RFC3339, "json formatter"))
36+
if err != nil {
37+
t.Errorf("test json formatter error => %v", err)
38+
return
39+
}
40+
expect := `{"level":"DEBUG","log":"json formatter"}` + "\n"
41+
actual := string(data)
42+
if expect != actual {
43+
t.Errorf("test json formatter failed, expect to get %s, but actual get %s", expect, actual)
44+
return
45+
}
46+
}
47+
48+
func TestNewTextFormatter(t *testing.T) {
49+
testNewTextFormatter(t, formatter.NewTextFormatter())
50+
}
51+
52+
func testNewTextFormatter(t *testing.T, f formatter.Formatter) {
53+
data, err := f.Serialize(content.NewContent(level.DebugLevel, nil, false, time.RFC3339, "text formatter"))
54+
if err != nil {
55+
t.Errorf("test text formatter error => %v", err)
56+
return
57+
}
58+
expect := `[DEBUG] text formatter` + "\n"
59+
actual := string(data)
60+
if expect != actual {
61+
t.Errorf("test text formatter failed, expect to get %s, but actual get %s", expect, actual)
62+
return
63+
}
64+
}
65+
66+
func TestNew_Unsupported(t *testing.T) {
67+
formatter.InitDefaultFormatter(formatter.TextFormatter)
68+
testNewTextFormatter(t, formatter.New("unsupported"))
69+
}

0 commit comments

Comments
 (0)