1package gocbcore
2
3import (
4	"fmt"
5	"log"
6	"os"
7	"strings"
8)
9
10// LogLevel specifies the severity of a log message.
11type LogLevel int
12
13// Various logging levels (or subsystems) which can categorize the message.
14// Currently these are ordered in decreasing severity.
15const (
16	LogError LogLevel = iota
17	LogWarn
18	LogInfo
19	LogDebug
20	LogTrace
21	LogSched
22	LogMaxVerbosity
23)
24
25// LogRedactLevel specifies the degree with which to redact the logs.
26type LogRedactLevel int
27
28const (
29	// RedactNone indicates to perform no redactions
30	RedactNone LogRedactLevel = iota
31
32	// RedactPartial indicates to redact all possible user-identifying information from logs.
33	RedactPartial
34
35	// RedactFull indicates to fully redact all possible identifying information from logs.
36	RedactFull
37)
38
39// SetLogRedactionLevel specifies the level with which logs should be redacted.
40func SetLogRedactionLevel(level LogRedactLevel) {
41	globalLogRedactionLevel = level
42}
43
44func isLogRedactionLevelNone() bool {
45	return globalLogRedactionLevel == RedactNone
46}
47
48func isLogRedactionLevelPartial() bool {
49	return globalLogRedactionLevel == RedactPartial
50}
51
52func isLogRedactionLevelFull() bool {
53	return globalLogRedactionLevel == RedactFull
54}
55
56func logLevelToString(level LogLevel) string {
57	switch level {
58	case LogError:
59		return "error"
60	case LogWarn:
61		return "warn"
62	case LogInfo:
63		return "info"
64	case LogDebug:
65		return "debug"
66	case LogTrace:
67		return "trace"
68	case LogSched:
69		return "sched"
70	}
71
72	return fmt.Sprintf("unknown (%d)", level)
73}
74
75// Logger defines a logging interface. You can either use one of the default loggers
76// (DefaultStdioLogger(), VerboseStdioLogger()) or implement your own.
77type Logger interface {
78	// Outputs logging information:
79	// level is the verbosity level
80	// offset is the position within the calling stack from which the message
81	// originated. This is useful for contextual loggers which retrieve file/line
82	// information.
83	Log(level LogLevel, offset int, format string, v ...interface{}) error
84}
85
86type defaultLogger struct {
87	Level    LogLevel
88	GoLogger *log.Logger
89}
90
91func (l *defaultLogger) Log(level LogLevel, offset int, format string, v ...interface{}) error {
92	if level > l.Level {
93		return nil
94	}
95	s := fmt.Sprintf(format, v...)
96	return l.GoLogger.Output(offset+2, s)
97}
98
99var (
100	globalDefaultLogger = defaultLogger{
101		GoLogger: log.New(os.Stderr, "GOCB ", log.Lmicroseconds|log.Lshortfile), Level: LogDebug,
102	}
103
104	globalVerboseLogger = defaultLogger{
105		GoLogger: globalDefaultLogger.GoLogger, Level: LogMaxVerbosity,
106	}
107
108	globalLogger            Logger
109	globalLogRedactionLevel LogRedactLevel
110)
111
112// DefaultStdOutLogger gets the default logger. This actually logs to stderr
113// rather than stdout. Use DefaultStdioLogger which has a correct name, since
114// the "standard" logger logs to stderr, rather than stdout.
115//
116// Deprecated: Use DefaultStdioLogger() instead.
117func DefaultStdOutLogger() Logger {
118	return &globalDefaultLogger
119}
120
121// DefaultStdioLogger gets the default standard I/O logger.
122//  gocbcore.SetLogger(gocbcore.DefaultStdioLogger())
123func DefaultStdioLogger() Logger {
124	return &globalDefaultLogger
125}
126
127// VerboseStdioLogger is a more verbose level of DefaultStdioLogger(). Messages
128// pertaining to the scheduling of ordinary commands (and their responses) will
129// also be emitted.
130//  gocbcore.SetLogger(gocbcore.VerboseStdioLogger())
131func VerboseStdioLogger() Logger {
132	return &globalVerboseLogger
133}
134
135// SetLogger sets a logger to be used by the library. A logger can be obtained via
136// the DefaultStdioLogger() or VerboseStdioLogger() functions. You can also implement
137// your own logger using the Logger interface.
138func SetLogger(logger Logger) {
139	globalLogger = logger
140}
141
142func logExf(level LogLevel, offset int, format string, v ...interface{}) {
143	if globalLogger != nil {
144		err := globalLogger.Log(level, offset+1, format, v...)
145		if err != nil {
146			log.Printf("Logger error occurred (%s)\n", err)
147		}
148	}
149}
150
151func logDebugf(format string, v ...interface{}) {
152	logExf(LogDebug, 1, format, v...)
153}
154
155func logSchedf(format string, v ...interface{}) {
156	logExf(LogSched, 1, format, v...)
157}
158
159func logWarnf(format string, v ...interface{}) {
160	logExf(LogWarn, 1, format, v...)
161}
162
163func logErrorf(format string, v ...interface{}) {
164	logExf(LogError, 1, format, v...)
165}
166
167func reindentLog(indent, message string) string {
168	reindentedMessage := strings.Replace(message, "\n", "\n"+indent, -1)
169	return fmt.Sprintf("%s%s", indent, reindentedMessage)
170}
171