/
subsystem.go
122 lines (110 loc) · 5.17 KB
/
subsystem.go
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
package tflog
import (
"context"
"github.com/hashicorp/go-hclog"
)
const newSubsystemLoggerWarning = "This log was generated by a subsystem logger that wasn't created before being used. Use tflog.NewSubsystem to create this logger before it is used."
func getSubsystemLogger(ctx context.Context, subsystem string) hclog.Logger {
logger := ctx.Value(providerSpaceRootLoggerKey + loggerKey("."+subsystem))
if logger == nil {
return nil
}
return logger.(hclog.Logger)
}
func setSubsystemLogger(ctx context.Context, subsystem string, logger hclog.Logger) context.Context {
return context.WithValue(ctx, providerSpaceRootLoggerKey+loggerKey("."+subsystem), logger)
}
// NewSubsystem returns a new context.Context that contains a subsystem logger
// configured with the passed options, named after the subsystem argument.
//
// Subsystem loggers allow different areas of a plugin codebase to use
// different logging levels, giving developers more fine-grained control over
// what is logging and with what verbosity. They're best utilized for logical
// concerns that are sometimes helpful to log, but may generate unwanted noise
// at other times.
//
// The only Options supported for subsystems are the Options for setting the
// level of the logger.
func NewSubsystem(ctx context.Context, subsystem string, options ...Option) context.Context {
logger := getProviderSpaceRootLogger(ctx)
if logger == nil {
// this essentially should never happen in production
// the root logger for provider code should be injected
// by whatever SDK the provider developer is using, so
// really this is only likely in unit tests, at most
// so just making this a no-op is fine
return ctx
}
subLogger := logger.Named(subsystem)
opts := applyLoggerOpts(options...)
if opts.level != hclog.NoLevel {
subLogger.SetLevel(opts.level)
}
return setSubsystemLogger(ctx, subsystem, subLogger)
}
// SubsystemWith returns a new context.Context that has a modified logger for
// the specified subsystem in it which will include key and value as arguments
// in all its log output.
func SubsystemWith(ctx context.Context, subsystem, key string, value interface{}) context.Context {
logger := getSubsystemLogger(ctx, subsystem)
if logger == nil {
// create a new logger if one doesn't exist
logger = getSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", newSubsystemLoggerWarning)
}
return setSubsystemLogger(ctx, subsystem, logger.With(key, value))
}
// SubsystemTrace logs `msg` at the trace level to the subsystem logger
// specified in `ctx`, with `args` as structured arguments in the log output.
// `args` is expected to be pairs of key and value.
func SubsystemTrace(ctx context.Context, subsystem, msg string, args ...interface{}) {
logger := getSubsystemLogger(ctx, subsystem)
if logger == nil {
// create a new logger if one doesn't exist
logger = getSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", newSubsystemLoggerWarning)
}
logger.Trace(msg, args...)
}
// SubsystemDebug logs `msg` at the debug level to the subsystem logger
// specified in `ctx`, with `args` as structured arguments in the log output.
// `args` is expected to be pairs of key and value.
func SubsystemDebug(ctx context.Context, subsystem, msg string, args ...interface{}) {
logger := getSubsystemLogger(ctx, subsystem)
if logger == nil {
// create a new logger if one doesn't exist
logger = getSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", newSubsystemLoggerWarning)
}
logger.Debug(msg, args...)
}
// SubsystemInfo logs `msg` at the info level to the subsystem logger
// specified in `ctx`, with `args` as structured arguments in the log output.
// `args` is expected to be pairs of key and value.
func SubsystemInfo(ctx context.Context, subsystem, msg string, args ...interface{}) {
logger := getSubsystemLogger(ctx, subsystem)
if logger == nil {
// create a new logger if one doesn't exist
logger = getSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", newSubsystemLoggerWarning)
}
logger.Info(msg, args...)
}
// SubsystemWarn logs `msg` at the warn level to the subsystem logger
// specified in `ctx`, with `args` as structured arguments in the log output.
// `args` is expected to be pairs of key and value.
func SubsystemWarn(ctx context.Context, subsystem, msg string, args ...interface{}) {
logger := getSubsystemLogger(ctx, subsystem)
if logger == nil {
// create a new logger if one doesn't exist
logger = getSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", newSubsystemLoggerWarning)
}
logger.Warn(msg, args...)
}
// SubsystemError logs `msg` at the error level to the subsystem logger
// specified in `ctx`, with `args` as structured arguments in the log output.
// `args` is expected to be pairs of key and value.
func SubsystemError(ctx context.Context, subsystem, msg string, args ...interface{}) {
logger := getSubsystemLogger(ctx, subsystem)
if logger == nil {
// create a new logger if one doesn't exist
logger = getSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", newSubsystemLoggerWarning)
}
logger.Error(msg, args...)
}