1package hclog
2
3import (
4	"io"
5	"log"
6	"os"
7	"strings"
8	"sync"
9)
10
11var (
12	//DefaultOutput is used as the default log output.
13	DefaultOutput io.Writer = os.Stderr
14
15	// DefaultLevel is used as the default log level.
16	DefaultLevel = Info
17)
18
19// Level represents a log level.
20type Level int32
21
22const (
23	// NoLevel is a special level used to indicate that no level has been
24	// set and allow for a default to be used.
25	NoLevel Level = 0
26
27	// Trace is the most verbose level. Intended to be used for the tracing
28	// of actions in code, such as function enters/exits, etc.
29	Trace Level = 1
30
31	// Debug information for programmer lowlevel analysis.
32	Debug Level = 2
33
34	// Info information about steady state operations.
35	Info Level = 3
36
37	// Warn information about rare but handled events.
38	Warn Level = 4
39
40	// Error information about unrecoverable events.
41	Error Level = 5
42)
43
44// Format is a simple convience type for when formatting is required. When
45// processing a value of this type, the logger automatically treats the first
46// argument as a Printf formatting string and passes the rest as the values
47// to be formatted. For example: L.Info(Fmt{"%d beans/day", beans}).
48type Format []interface{}
49
50// Fmt returns a Format type. This is a convience function for creating a Format
51// type.
52func Fmt(str string, args ...interface{}) Format {
53	return append(Format{str}, args...)
54}
55
56// LevelFromString returns a Level type for the named log level, or "NoLevel" if
57// the level string is invalid. This facilitates setting the log level via
58// config or environment variable by name in a predictable way.
59func LevelFromString(levelStr string) Level {
60	// We don't care about case. Accept both "INFO" and "info".
61	levelStr = strings.ToLower(strings.TrimSpace(levelStr))
62	switch levelStr {
63	case "trace":
64		return Trace
65	case "debug":
66		return Debug
67	case "info":
68		return Info
69	case "warn":
70		return Warn
71	case "error":
72		return Error
73	default:
74		return NoLevel
75	}
76}
77
78// Logger describes the interface that must be implemeted by all loggers.
79type Logger interface {
80	// Args are alternating key, val pairs
81	// keys must be strings
82	// vals can be any type, but display is implementation specific
83	// Emit a message and key/value pairs at the TRACE level
84	Trace(msg string, args ...interface{})
85
86	// Emit a message and key/value pairs at the DEBUG level
87	Debug(msg string, args ...interface{})
88
89	// Emit a message and key/value pairs at the INFO level
90	Info(msg string, args ...interface{})
91
92	// Emit a message and key/value pairs at the WARN level
93	Warn(msg string, args ...interface{})
94
95	// Emit a message and key/value pairs at the ERROR level
96	Error(msg string, args ...interface{})
97
98	// Indicate if TRACE logs would be emitted. This and the other Is* guards
99	// are used to elide expensive logging code based on the current level.
100	IsTrace() bool
101
102	// Indicate if DEBUG logs would be emitted. This and the other Is* guards
103	IsDebug() bool
104
105	// Indicate if INFO logs would be emitted. This and the other Is* guards
106	IsInfo() bool
107
108	// Indicate if WARN logs would be emitted. This and the other Is* guards
109	IsWarn() bool
110
111	// Indicate if ERROR logs would be emitted. This and the other Is* guards
112	IsError() bool
113
114	// Creates a sublogger that will always have the given key/value pairs
115	With(args ...interface{}) Logger
116
117	// Create a logger that will prepend the name string on the front of all messages.
118	// If the logger already has a name, the new value will be appended to the current
119	// name. That way, a major subsystem can use this to decorate all it's own logs
120	// without losing context.
121	Named(name string) Logger
122
123	// Create a logger that will prepend the name string on the front of all messages.
124	// This sets the name of the logger to the value directly, unlike Named which honor
125	// the current name as well.
126	ResetNamed(name string) Logger
127
128	// Updates the level. This should affect all sub-loggers as well. If an
129	// implementation cannot update the level on the fly, it should no-op.
130	SetLevel(level Level)
131
132	// Return a value that conforms to the stdlib log.Logger interface
133	StandardLogger(opts *StandardLoggerOptions) *log.Logger
134
135	// Return a value that conforms to io.Writer, which can be passed into log.SetOutput()
136	StandardWriter(opts *StandardLoggerOptions) io.Writer
137}
138
139// StandardLoggerOptions can be used to configure a new standard logger.
140type StandardLoggerOptions struct {
141	// Indicate that some minimal parsing should be done on strings to try
142	// and detect their level and re-emit them.
143	// This supports the strings like [ERROR], [ERR] [TRACE], [WARN], [INFO],
144	// [DEBUG] and strip it off before reapplying it.
145	InferLevels bool
146
147	// ForceLevel is used to force all output from the standard logger to be at
148	// the specified level. Similar to InferLevels, this will strip any level
149	// prefix contained in the logged string before applying the forced level.
150	// If set, this override InferLevels.
151	ForceLevel Level
152}
153
154// LoggerOptions can be used to configure a new logger.
155type LoggerOptions struct {
156	// Name of the subsystem to prefix logs with
157	Name string
158
159	// The threshold for the logger. Anything less severe is supressed
160	Level Level
161
162	// Where to write the logs to. Defaults to os.Stderr if nil
163	Output io.Writer
164
165	// An optional mutex pointer in case Output is shared
166	Mutex *sync.Mutex
167
168	// Control if the output should be in JSON.
169	JSONFormat bool
170
171	// Include file and line information in each log line
172	IncludeLocation bool
173
174	// The time format to use instead of the default
175	TimeFormat string
176}
177