/
logOutputSubject.go
124 lines (100 loc) · 3.16 KB
/
logOutputSubject.go
1
2
3
4
5
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package logger
import (
"fmt"
"io"
"sync"
"github.com/Reshusk23/dme-go-logger/check"
)
var _ LogOutputHandler = (*logOutputSubject)(nil)
// logOutputSubject follows the observer-subject pattern by which it holds n Writer and n Formatters.
// Each time a call to the Output method is done, it iterates through the containing formatters and writers
// in order to output the data
type logOutputSubject struct {
mutObservers sync.RWMutex
writers []io.Writer
formatters []Formatter
}
// NewLogOutputSubject returns an initialized, empty logOutputSubject with no observers
func NewLogOutputSubject() *logOutputSubject {
return &logOutputSubject{
writers: make([]io.Writer, 0),
formatters: make([]Formatter, 0),
}
}
// Output triggers calls to all containing formatters and writers in order to output provided log line
func (los *logOutputSubject) Output(line *LogLine) {
los.mutObservers.RLock()
convertedLine := los.convertLogLine(line)
for i := 0; i < len(los.writers); i++ {
format := los.formatters[i]
buff := format.Output(convertedLine)
_, _ = los.writers[i].Write(buff)
}
los.mutObservers.RUnlock()
}
func (los *logOutputSubject) convertLogLine(logLine *LogLine) LogLineHandler {
if logLine == nil {
return nil
}
line := &LogLineWrapper{}
line.LoggerName = logLine.LoggerName
line.Correlation = logLine.Correlation
line.Message = logLine.Message
line.LogLevel = int32(logLine.LogLevel)
line.Args = make([]string, len(logLine.Args))
line.Timestamp = logLine.Timestamp.UnixNano()
mutDisplayByteSlice.RLock()
displayHandler := displayByteSlice
mutDisplayByteSlice.RUnlock()
for i, obj := range logLine.Args {
switch obj := obj.(type) {
case []byte:
line.Args[i] = displayHandler(obj)
default:
line.Args[i] = fmt.Sprintf("%v", obj)
}
}
return line
}
// AddObserver adds a writer + formatter (called here observer) to the containing observer-like lists
func (los *logOutputSubject) AddObserver(w io.Writer, format Formatter) error {
if w == nil {
return ErrNilWriter
}
if check.IfNil(format) {
return ErrNilFormatter
}
los.mutObservers.Lock()
los.writers = append(los.writers, w)
los.formatters = append(los.formatters, format)
los.mutObservers.Unlock()
return nil
}
// RemoveObserver will remove the observer based on the writer provided. The comparision is done on pointers.
// If the provided writer is not contained, the function will return an error.
func (los *logOutputSubject) RemoveObserver(w io.Writer) error {
if w == nil {
return ErrNilWriter
}
los.mutObservers.Lock()
defer los.mutObservers.Unlock()
for i := 0; i < len(los.writers); i++ {
if los.writers[i] == w {
los.writers = append(los.writers[0:i], los.writers[i+1:]...)
los.formatters = append(los.formatters[0:i], los.formatters[i+1:]...)
return nil
}
}
return ErrWriterNotFound
}
// ClearObservers clears the observers lists
func (los *logOutputSubject) ClearObservers() {
los.mutObservers.Lock()
los.writers = make([]io.Writer, 0)
los.formatters = make([]Formatter, 0)
los.mutObservers.Unlock()
}
// IsInterfaceNil returns true if there is no value under the interface
func (los *logOutputSubject) IsInterfaceNil() bool {
return los == nil
}