1//  Copyright (c) 2014 Couchbase, Inc.
2//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
3//  except in compliance with the License. You may obtain a copy of the License at
4//    http://www.apache.org/licenses/LICENSE-2.0
5//  Unless required by applicable law or agreed to in writing, software distributed under the
6//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
7//  either express or implied. See the License for the specific language governing permissions
8//  and limitations under the License.
9
10package logging
11
12import (
13	"runtime"
14	"strings"
15	"sync"
16)
17
18type Level int
19
20const (
21	NONE    = Level(iota) // Disable all logging
22	FATAL                 // System is in severe error state and has to terminate
23	SEVERE                // System is in severe error state and cannot recover reliably
24	ERROR                 // System is in error state but can recover and continue reliably
25	WARN                  // System approaching error state, or is in a correct but undesirable state
26	INFO                  // System-level events and status, in correct states
27	REQUEST               // Request-level events, with request-specific rlevel
28	TRACE                 // Trace detailed system execution, e.g. function entry / exit
29	DEBUG                 // Debug
30)
31
32func (level Level) String() string {
33	return _LEVEL_NAMES[level]
34}
35
36var _LEVEL_NAMES = []string{
37	DEBUG:   "DEBUG",
38	TRACE:   "TRACE",
39	REQUEST: "REQUEST",
40	INFO:    "INFO",
41	WARN:    "WARN",
42	ERROR:   "ERROR",
43	SEVERE:  "SEVERE",
44	FATAL:   "FATAL",
45	NONE:    "NONE",
46}
47
48var _LEVEL_MAP = map[string]Level{
49	"debug":   DEBUG,
50	"trace":   TRACE,
51	"request": REQUEST,
52	"info":    INFO,
53	"warn":    WARN,
54	"error":   ERROR,
55	"severe":  SEVERE,
56	"fatal":   FATAL,
57	"none":    NONE,
58}
59
60func ParseLevel(name string) (level Level, ok bool) {
61	level, ok = _LEVEL_MAP[strings.ToLower(name)]
62	return
63}
64
65/*
66
67Pair supports logging of key-value pairs.  Keys beginning with _ are
68reserved for the logger, e.g. _time, _level, _msg, and _rlevel. The
69Pair APIs are designed to avoid heap allocation and garbage
70collection.
71
72*/
73type Pairs []Pair
74type Pair struct {
75	Name  string
76	Value interface{}
77}
78
79/*
80
81Map allows key-value pairs to be specified using map literals or data
82structures. For example:
83
84Errorm(msg, Map{...})
85
86Map incurs heap allocation and garbage collection, so the Pair APIs
87should be preferred.
88
89*/
90type Map map[string]interface{}
91
92// Logger provides a common interface for logging libraries
93type Logger interface {
94	/*
95		These APIs write all the given pairs in addition to standard logger keys.
96	*/
97	Logp(level Level, msg string, kv ...Pair)
98
99	Debugp(msg string, kv ...Pair)
100
101	Tracep(msg string, kv ...Pair)
102
103	Requestp(rlevel Level, msg string, kv ...Pair)
104
105	Infop(msg string, kv ...Pair)
106
107	Warnp(msg string, kv ...Pair)
108
109	Errorp(msg string, kv ...Pair)
110
111	Severep(msg string, kv ...Pair)
112
113	Fatalp(msg string, kv ...Pair)
114
115	/*
116		These APIs write the fields in the given kv Map in addition to standard logger keys.
117	*/
118	Logm(level Level, msg string, kv Map)
119
120	Debugm(msg string, kv Map)
121
122	Tracem(msg string, kv Map)
123
124	Requestm(rlevel Level, msg string, kv Map)
125
126	Infom(msg string, kv Map)
127
128	Warnm(msg string, kv Map)
129
130	Errorm(msg string, kv Map)
131
132	Severem(msg string, kv Map)
133
134	Fatalm(msg string, kv Map)
135
136	/*
137
138		These APIs only write _msg, _time, _level, and other logger keys. If
139		the msg contains other fields, use the Pair or Map APIs instead.
140
141	*/
142	Logf(level Level, fmt string, args ...interface{})
143
144	Debugf(fmt string, args ...interface{})
145
146	Tracef(fmt string, args ...interface{})
147
148	Requestf(rlevel Level, fmt string, args ...interface{})
149
150	Infof(fmt string, args ...interface{})
151
152	Warnf(fmt string, args ...interface{})
153
154	Errorf(fmt string, args ...interface{})
155
156	Severef(fmt string, args ...interface{})
157
158	Fatalf(fmt string, args ...interface{})
159
160	/*
161		These APIs control the logging level
162	*/
163
164	SetLevel(Level) // Set the logging level
165
166	Level() Level // Get the current logging level
167}
168
169var logger Logger = nil
170var curLevel Level = DEBUG // initially set to never skip
171
172var loggerMutex sync.RWMutex
173
174// All the methods below first acquire the mutex (mostly in exclusive mode)
175// and only then check if logging at the current level is enabled.
176// This introduces a fair bottleneck for those log entries that should be
177// skipped (the majority, at INFO or below levels)
178// We try to predict here if we should lock the mutex at all by caching
179// the current log level: while dynamically changing logger, there might
180// be the odd entry skipped as the new level is cached.
181// Since we seem to never change the logger, this is not an issue.
182func skipLogging(level Level) bool {
183	if logger == nil {
184		return true
185	}
186	return level > curLevel
187}
188
189func SetLogger(newLogger Logger) {
190	loggerMutex.Lock()
191	defer loggerMutex.Unlock()
192	logger = newLogger
193	if logger == nil {
194		curLevel = NONE
195	} else {
196		curLevel = newLogger.Level()
197	}
198}
199
200func Logp(level Level, msg string, kv ...Pair) {
201	if skipLogging(level) {
202		return
203	}
204	loggerMutex.Lock()
205	defer loggerMutex.Unlock()
206	logger.Logp(level, msg, kv...)
207}
208
209func Debugp(msg string, kv ...Pair) {
210	if skipLogging(DEBUG) {
211		return
212	}
213	loggerMutex.Lock()
214	defer loggerMutex.Unlock()
215	logger.Debugp(msg, kv...)
216}
217
218func Tracep(msg string, kv ...Pair) {
219	if skipLogging(TRACE) {
220		return
221	}
222	loggerMutex.Lock()
223	defer loggerMutex.Unlock()
224	logger.Tracep(msg, kv...)
225}
226
227func Requestp(rlevel Level, msg string, kv ...Pair) {
228	if skipLogging(REQUEST) {
229		return
230	}
231	loggerMutex.Lock()
232	defer loggerMutex.Unlock()
233	logger.Requestp(rlevel, msg, kv...)
234}
235
236func Infop(msg string, kv ...Pair) {
237	if skipLogging(INFO) {
238		return
239	}
240	loggerMutex.Lock()
241	defer loggerMutex.Unlock()
242	logger.Infop(msg, kv...)
243}
244
245func Warnp(msg string, kv ...Pair) {
246	if skipLogging(WARN) {
247		return
248	}
249	loggerMutex.Lock()
250	defer loggerMutex.Unlock()
251	logger.Warnp(msg, kv...)
252}
253
254func Errorp(msg string, kv ...Pair) {
255	if skipLogging(ERROR) {
256		return
257	}
258	loggerMutex.Lock()
259	defer loggerMutex.Unlock()
260	logger.Errorp(msg, kv...)
261}
262
263func Severep(msg string, kv ...Pair) {
264	if skipLogging(SEVERE) {
265		return
266	}
267	loggerMutex.Lock()
268	defer loggerMutex.Unlock()
269	logger.Severep(msg, kv...)
270}
271
272func Fatalp(msg string, kv ...Pair) {
273	if skipLogging(FATAL) {
274		return
275	}
276	loggerMutex.Lock()
277	defer loggerMutex.Unlock()
278	logger.Fatalp(msg, kv...)
279}
280
281func Logm(level Level, msg string, kv Map) {
282	if skipLogging(level) {
283		return
284	}
285	loggerMutex.Lock()
286	defer loggerMutex.Unlock()
287	logger.Logm(level, msg, kv)
288}
289
290func Debugm(msg string, kv Map) {
291	if skipLogging(DEBUG) {
292		return
293	}
294	loggerMutex.Lock()
295	defer loggerMutex.Unlock()
296	logger.Debugm(msg, kv)
297}
298
299func Tracem(msg string, kv Map) {
300	if skipLogging(TRACE) {
301		return
302	}
303	loggerMutex.Lock()
304	defer loggerMutex.Unlock()
305	logger.Tracem(msg, kv)
306}
307
308func Requestm(rlevel Level, msg string, kv Map) {
309	if skipLogging(REQUEST) {
310		return
311	}
312	loggerMutex.Lock()
313	defer loggerMutex.Unlock()
314	logger.Requestm(rlevel, msg, kv)
315}
316
317func Infom(msg string, kv Map) {
318	if skipLogging(INFO) {
319		return
320	}
321	loggerMutex.Lock()
322	defer loggerMutex.Unlock()
323	logger.Infom(msg, kv)
324}
325
326func Warnm(msg string, kv Map) {
327	if skipLogging(WARN) {
328		return
329	}
330	loggerMutex.Lock()
331	defer loggerMutex.Unlock()
332	logger.Warnm(msg, kv)
333}
334
335func Errorm(msg string, kv Map) {
336	if skipLogging(ERROR) {
337		return
338	}
339	loggerMutex.Lock()
340	defer loggerMutex.Unlock()
341	logger.Errorm(msg, kv)
342}
343
344func Severem(msg string, kv Map) {
345	if skipLogging(SEVERE) {
346		return
347	}
348	loggerMutex.Lock()
349	defer loggerMutex.Unlock()
350	logger.Severem(msg, kv)
351}
352
353func Fatalm(msg string, kv Map) {
354	if skipLogging(FATAL) {
355		return
356	}
357	loggerMutex.Lock()
358	defer loggerMutex.Unlock()
359	logger.Fatalm(msg, kv)
360}
361
362func Logf(level Level, fmt string, args ...interface{}) {
363	if skipLogging(level) {
364		return
365	}
366	loggerMutex.Lock()
367	defer loggerMutex.Unlock()
368	logger.Logf(level, fmt, args...)
369}
370
371func Debugf(fmt string, args ...interface{}) {
372	if skipLogging(DEBUG) {
373		return
374	}
375	loggerMutex.Lock()
376	defer loggerMutex.Unlock()
377	logger.Debugf(fmt, args...)
378}
379
380func Tracef(fmt string, args ...interface{}) {
381	if skipLogging(TRACE) {
382		return
383	}
384	loggerMutex.Lock()
385	defer loggerMutex.Unlock()
386	logger.Tracef(fmt, args...)
387}
388
389func Requestf(rlevel Level, fmt string, args ...interface{}) {
390	if skipLogging(REQUEST) {
391		return
392	}
393	loggerMutex.Lock()
394	defer loggerMutex.Unlock()
395	logger.Requestf(rlevel, fmt, args...)
396}
397
398func Infof(fmt string, args ...interface{}) {
399	if skipLogging(INFO) {
400		return
401	}
402	loggerMutex.Lock()
403	defer loggerMutex.Unlock()
404	logger.Infof(fmt, args...)
405}
406
407func Warnf(fmt string, args ...interface{}) {
408	if skipLogging(WARN) {
409		return
410	}
411	loggerMutex.Lock()
412	defer loggerMutex.Unlock()
413	logger.Warnf(fmt, args...)
414}
415
416func Errorf(fmt string, args ...interface{}) {
417	if skipLogging(ERROR) {
418		return
419	}
420	loggerMutex.Lock()
421	defer loggerMutex.Unlock()
422	logger.Errorf(fmt, args...)
423}
424
425func Severef(fmt string, args ...interface{}) {
426	if skipLogging(SEVERE) {
427		return
428	}
429	loggerMutex.Lock()
430	defer loggerMutex.Unlock()
431	logger.Severef(fmt, args...)
432}
433
434func Fatalf(fmt string, args ...interface{}) {
435	if skipLogging(FATAL) {
436		return
437	}
438	loggerMutex.Lock()
439	defer loggerMutex.Unlock()
440	logger.Fatalf(fmt, args...)
441}
442
443func SetLevel(level Level) {
444	loggerMutex.Lock()
445	defer loggerMutex.Unlock()
446	logger.SetLevel(level)
447	curLevel = level
448}
449
450func LogLevel() Level {
451	loggerMutex.RLock()
452	defer loggerMutex.RUnlock()
453	return logger.Level()
454}
455
456func Stackf(level Level, fmt string, args ...interface{}) {
457	if skipLogging(level) {
458		return
459	}
460	buf := make([]byte, 1<<16)
461	n := runtime.Stack(buf, false)
462	s := string(buf[0:n])
463	loggerMutex.Lock()
464	defer loggerMutex.Unlock()
465	logger.Logf(level, fmt, args...)
466	logger.Logf(level, s)
467}
468