aboutsummaryrefslogtreecommitdiffstats
path: root/lib/log/logger.go
blob: 80c78d183695bb7d0b94734c8468cd840a8bf464 (plain) (blame)
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
package log

import (
	"fmt"
	"io"
	"log"
	"os"
	"strings"
)

type LogLevel int

const (
	TRACE LogLevel = 5
	DEBUG LogLevel = 10
	INFO  LogLevel = 20
	WARN  LogLevel = 30
	ERROR LogLevel = 40
)

type logfilePtr struct {
	f         *os.File
	useStdout bool
}

func newLogfilePtr(f *os.File, isStdout bool) *logfilePtr {
	return &logfilePtr{f: f, useStdout: isStdout}
}

func (l *logfilePtr) Close() error {
	if l.useStdout || l.f == nil {
		return nil
	}
	return l.f.Close()
}

var (
	trace    *log.Logger
	dbg      *log.Logger
	info     *log.Logger
	warn     *log.Logger
	err      *log.Logger
	minLevel LogLevel = TRACE

	// logfile stores a pointer to the log file descriptor
	logfile *logfilePtr
)

func Init(file *os.File, useStdout bool, level LogLevel) error {
	trace = nil
	dbg = nil
	info = nil
	warn = nil
	err = nil

	if logfile != nil {
		e := logfile.Close()
		if e != nil {
			return e
		}
		logfile = nil
	}

	minLevel = level
	flags := log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile
	if file != nil {
		logfile = newLogfilePtr(file, useStdout)
		trace = log.New(file, "TRACE ", flags)
		dbg = log.New(file, "DEBUG ", flags)
		info = log.New(file, "INFO  ", flags)
		warn = log.New(file, "WARN  ", flags)
		err = log.New(file, "ERROR ", flags)
	}

	return nil
}

func ParseLevel(value string) (LogLevel, error) {
	switch strings.ToLower(value) {
	case "trace":
		return TRACE, nil
	case "debug":
		return DEBUG, nil
	case "info":
		return INFO, nil
	case "warn", "warning":
		return WARN, nil
	case "err", "error":
		return ERROR, nil
	}
	return 0, fmt.Errorf("%s: invalid log level", value)
}

func ErrorLogger() *log.Logger {
	if err == nil {
		return log.New(io.Discard, "", log.LstdFlags)
	}
	return err
}

type Logger interface {
	Tracef(string, ...interface{})
	Debugf(string, ...interface{})
	Infof(string, ...interface{})
	Warnf(string, ...interface{})
	Errorf(string, ...interface{})
}

type logger struct {
	name      string
	calldepth int
}

func NewLogger(name string, calldepth int) Logger {
	return &logger{name: name, calldepth: calldepth}
}

func (l *logger) format(message string, args ...interface{}) string {
	if len(args) > 0 {
		message = fmt.Sprintf(message, args...)
	}
	if l.name != "" {
		message = fmt.Sprintf("[%s] %s", l.name, message)
	}
	return message
}

func (l *logger) Tracef(message string, args ...interface{}) {
	if trace == nil || minLevel > TRACE {
		return
	}
	message = l.format(message, args...)
	trace.Output(l.calldepth, message) //nolint:errcheck // we can't do anything with what we log
}

func (l *logger) Debugf(message string, args ...interface{}) {
	if dbg == nil || minLevel > DEBUG {
		return
	}
	message = l.format(message, args...)
	dbg.Output(l.calldepth, message) //nolint:errcheck // we can't do anything with what we log
}

func (l *logger) Infof(message string, args ...interface{}) {
	if info == nil || minLevel > INFO {
		return
	}
	message = l.format(message, args...)
	info.Output(l.calldepth, message) //nolint:errcheck // we can't do anything with what we log
}

func (l *logger) Warnf(message string, args ...interface{}) {
	if warn == nil || minLevel > WARN {
		return
	}
	message = l.format(message, args...)
	warn.Output(l.calldepth, message) //nolint:errcheck // we can't do anything with what we log
}

func (l *logger) Errorf(message string, args ...interface{}) {
	if err == nil || minLevel > ERROR {
		return
	}
	message = l.format(message, args...)
	err.Output(l.calldepth, message) //nolint:errcheck // we can't do anything with what we log
}

var root = logger{calldepth: 3}

func Tracef(message string, args ...interface{}) {
	root.Tracef(message, args...)
}

func Debugf(message string, args ...interface{}) {
	root.Debugf(message, args...)
}

func Infof(message string, args ...interface{}) {
	root.Infof(message, args...)
}

func Warnf(message string, args ...interface{}) {
	root.Warnf(message, args...)
}

func Errorf(message string, args ...interface{}) {
	root.Errorf(message, args...)
}