-
Notifications
You must be signed in to change notification settings - Fork 0
/
logging.go
188 lines (150 loc) · 3.93 KB
/
logging.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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package config
import (
"os"
"strings"
"sync"
"github.com/zgordan-vv/zacmm-server/mlog"
)
type LogSrcListener func(old, new mlog.LogTargetCfg)
type FileGetter interface {
GetFile(name string) ([]byte, error)
}
// LogConfigSrc abstracts the Advanced Logging configuration so that implementations can
// fetch from file, database, etc.
type LogConfigSrc interface {
// Get fetches the current, cached configuration.
Get() mlog.LogTargetCfg
// Set updates the dsn specifying the source and reloads
Set(dsn string, fget FileGetter) (err error)
// AddListener adds a callback function to invoke when the configuration is modified.
AddListener(listener LogSrcListener) string
// RemoveListener removes a callback function using an id returned from AddListener.
RemoveListener(id string)
// Close cleans up resources.
Close() error
}
// NewLogConfigSrc creates an advanced logging configuration source, backed by a
// file, JSON string, or database.
func NewLogConfigSrc(dsn string, isJSON bool, fget FileGetter) (LogConfigSrc, error) {
dsn = strings.TrimSpace(dsn)
if isJSON {
return newJSONSrc(dsn)
}
return newFileSrc(dsn, fget)
}
// jsonSrc
type jsonSrc struct {
logSrcEmitter
mutex sync.RWMutex
cfg mlog.LogTargetCfg
}
func newJSONSrc(data string) (*jsonSrc, error) {
src := &jsonSrc{}
return src, src.Set(data, nil)
}
// Get fetches the current, cached configuration
func (src *jsonSrc) Get() mlog.LogTargetCfg {
src.mutex.RLock()
defer src.mutex.RUnlock()
return src.cfg
}
// Set updates the JSON specifying the source and reloads
func (src *jsonSrc) Set(data string, _ FileGetter) error {
cfg, err := JSONToLogTargetCfg([]byte(data))
if err != nil {
return err
}
src.set(cfg)
return nil
}
func (src *jsonSrc) set(cfg mlog.LogTargetCfg) {
src.mutex.Lock()
defer src.mutex.Unlock()
old := src.cfg
src.cfg = cfg
src.invokeConfigListeners(old, cfg)
}
// Close cleans up resources.
func (src *jsonSrc) Close() error {
return nil
}
// fileSrc
type fileSrc struct {
logSrcEmitter
mutex sync.RWMutex
cfg mlog.LogTargetCfg
path string
watcher *watcher
}
func newFileSrc(path string, fget FileGetter) (*fileSrc, error) {
src := &fileSrc{
path: path,
}
if err := src.Set(path, fget); err != nil {
return nil, err
}
return src, nil
}
// Get fetches the current, cached configuration
func (src *fileSrc) Get() mlog.LogTargetCfg {
src.mutex.RLock()
defer src.mutex.RUnlock()
return src.cfg
}
// Set updates the dsn specifying the file source and reloads.
// The file will be watched for changes and reloaded as needed,
// and all listeners notified.
func (src *fileSrc) Set(path string, fget FileGetter) error {
data, err := fget.GetFile(path)
if err != nil {
return err
}
cfg, err := JSONToLogTargetCfg(data)
if err != nil {
return err
}
src.set(cfg)
// If path is a real file and not just the name of a database resource then watch it for changes.
// Absolute paths are explicit and require no resolution.
if _, err = os.Stat(path); os.IsNotExist(err) {
return nil
}
src.mutex.Lock()
defer src.mutex.Unlock()
if src.watcher != nil {
if err = src.watcher.Close(); err != nil {
mlog.Error("Failed to close watcher", mlog.Err(err))
}
src.watcher = nil
}
watcher, err := newWatcher(path, func() {
if serr := src.Set(path, fget); serr != nil {
mlog.Error("Failed to reload file on change", mlog.String("path", path), mlog.Err(serr))
}
})
if err != nil {
return err
}
src.watcher = watcher
return nil
}
func (src *fileSrc) set(cfg mlog.LogTargetCfg) {
src.mutex.Lock()
defer src.mutex.Unlock()
old := src.cfg
src.cfg = cfg
src.invokeConfigListeners(old, cfg)
}
// Close cleans up resources.
func (src *fileSrc) Close() error {
var err error
src.mutex.Lock()
defer src.mutex.Unlock()
if src.watcher != nil {
err = src.watcher.Close()
src.watcher = nil
}
return err
}