11
// Writer is implemented by any recipient of log messages.
12
type Writer interface {
13
// Write writes a message to the Writer with the given
14
// level and module name. The filename and line hold
15
// the file name and line number of the code that is
16
// generating the log message; the time stamp holds
17
// the time the log message was generated, and
18
// message holds the log message itself.
19
Write(level Level, name, filename string, line int, timestamp time.Time, message string)
22
type registeredWriter struct {
27
// defaultName is the name of a writer that is registered
28
// by default that writes to stderr.
29
const defaultName = "default"
32
writerMutex sync.Mutex
33
writers = map[string]*registeredWriter{
34
defaultName: ®isteredWriter{
35
writer: NewSimpleWriter(os.Stderr, &DefaultFormatter{}),
39
globalMinLevel = TRACE
42
// ResetWriters puts the list of writers back into the initial state.
45
defer writerMutex.Unlock()
46
writers = map[string]*registeredWriter{
47
"default": ®isteredWriter{
48
writer: NewSimpleWriter(os.Stderr, &DefaultFormatter{}),
55
// ReplaceDefaultWriter is a convenience method that does the equivalent of
56
// RemoveWriter and then RegisterWriter with the name "default". The previous
57
// default writer, if any is returned.
58
func ReplaceDefaultWriter(writer Writer) (Writer, error) {
60
return nil, fmt.Errorf("Writer cannot be nil")
63
defer writerMutex.Unlock()
64
reg, found := writers[defaultName]
66
return nil, fmt.Errorf("there is no %q writer", defaultName)
68
oldWriter := reg.writer
74
// RegisterWriter adds the writer to the list of writers that get notified
75
// when logging. When registering, the caller specifies the minimum logging
76
// level that will be written, and a name for the writer. If there is already
77
// a registered writer with that name, an error is returned.
78
func RegisterWriter(name string, writer Writer, minLevel Level) error {
80
return fmt.Errorf("Writer cannot be nil")
83
defer writerMutex.Unlock()
84
if _, found := writers[name]; found {
85
return fmt.Errorf("there is already a Writer registered with the name %q", name)
87
writers[name] = ®isteredWriter{writer: writer, level: minLevel}
92
// RemoveWriter removes the Writer identified by 'name' and returns it.
93
// If the Writer is not found, an error is returned.
94
func RemoveWriter(name string) (Writer, Level, error) {
96
defer writerMutex.Unlock()
97
registered, found := writers[name]
99
return nil, UNSPECIFIED, fmt.Errorf("Writer %q is not registered", name)
101
delete(writers, name)
103
return registered.writer, registered.level, nil
106
func findMinLevel() {
107
// We assume the lock is already held
109
for _, registered := range writers {
110
if registered.level < minLevel {
111
minLevel = registered.level
114
globalMinLevel.set(minLevel)
117
// WillWrite returns whether there are any writers registered
118
// at or above the given severity level. If it returns
119
// false, a log message at the given level will be discarded.
120
func WillWrite(level Level) bool {
121
return level >= globalMinLevel.get()
124
func writeToWriters(level Level, module, filename string, line int, timestamp time.Time, message string) {
126
defer writerMutex.Unlock()
127
for _, registered := range writers {
128
if level >= registered.level {
129
registered.writer.Write(level, module, filename, line, timestamp, message)
134
type simpleWriter struct {
139
// NewSimpleWriter returns a new writer that writes
140
// log messages to the given io.Writer formatting the
141
// messages with the given formatter.
142
func NewSimpleWriter(writer io.Writer, formatter Formatter) Writer {
143
return &simpleWriter{writer, formatter}
146
func (simple *simpleWriter) Write(level Level, module, filename string, line int, timestamp time.Time, message string) {
147
logLine := simple.formatter.Format(level, module, filename, line, timestamp, message)
148
fmt.Fprintln(simple.writer, logLine)