terraform-provider-gitea/vendor/github.com/hashicorp/terraform-plugin-log/internal/logging/options.go
dependabot[bot] 84c9110a24
Bump github.com/hashicorp/terraform-plugin-sdk/v2 from 2.24.1 to 2.26.0
Bumps [github.com/hashicorp/terraform-plugin-sdk/v2](https://github.com/hashicorp/terraform-plugin-sdk) from 2.24.1 to 2.26.0.
- [Release notes](https://github.com/hashicorp/terraform-plugin-sdk/releases)
- [Changelog](https://github.com/hashicorp/terraform-plugin-sdk/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/terraform-plugin-sdk/compare/v2.24.1...v2.26.0)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/terraform-plugin-sdk/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 20:25:53 +00:00

370 lines
14 KiB
Go

package logging
import (
"io"
"os"
"regexp"
"github.com/hashicorp/go-hclog"
)
// Option defines a modification to the configuration for a logger.
type Option func(LoggerOpts) LoggerOpts
// LoggerOpts is a collection of configuration settings for loggers.
type LoggerOpts struct {
// Name is the name or "@module" of a logger.
Name string
// Level is the most verbose level that a logger will write logs for.
Level hclog.Level
// IncludeLocation indicates whether logs should include the location
// of the logging statement or not.
IncludeLocation bool
// AdditionalLocationOffset is the number of additional stack levels to
// skip when finding the file and line information for the log line.
// Defaults to 1 to account for the tflog and tfsdklog logging functions.
AdditionalLocationOffset int
// Output dictates where logs are written to. Output should only ever
// be set by tflog or tfsdklog, never by SDK authors or provider
// developers. Where logs get written to is complex and delicate and
// requires a deep understanding of Terraform's architecture, and it's
// easy to mess up on accident.
Output io.Writer
// IncludeTime indicates whether logs should include the time they were
// written or not. It should only be set to true when testing tflog or
// tfsdklog; providers and SDKs should always include the time logs
// were written as part of the log.
IncludeTime bool
// Fields indicates the key/value pairs to be added to each of its log output.
Fields map[string]interface{}
// IncludeRootFields indicates whether a new subsystem logger should
// copy existing fields from the root logger. This is only performed
// at the time of new subsystem creation.
IncludeRootFields bool
// OmitLogWithFieldKeys indicates that the logger should omit to write
// any log when any of the given keys is found within the fields.
//
// Example:
//
// OmitLogWithFieldKeys = `['foo', 'baz']`
//
// log1 = `{ msg = "...", fields = { 'foo': '...', 'bar': '...' }` -> omitted
// log2 = `{ msg = "...", fields = { 'bar': '...' }` -> printed
// log3 = `{ msg = "...", fields = { 'baz': '...', 'boo': '...' }` -> omitted
//
OmitLogWithFieldKeys []string
// OmitLogWithMessageRegexes indicates that the logger should omit to write
// any log that matches any of the given *regexp.Regexp.
//
// Example:
//
// OmitLogWithMessageRegexes = `[regexp.MustCompile("(foo|bar)")]`
//
// log1 = `{ msg = "banana apple foo", fields = {...}` -> omitted
// log2 = `{ msg = "pineapple mango", fields = {...}` -> printed
// log3 = `{ msg = "pineapple mango bar", fields = {...}` -> omitted
//
OmitLogWithMessageRegexes []*regexp.Regexp
// OmitLogWithMessageStrings indicates that the logger should omit to write
// any log that matches any of the given string.
//
// Example:
//
// OmitLogWithMessageStrings = `['foo', 'bar']`
//
// log1 = `{ msg = "banana apple foo", fields = {...}` -> omitted
// log2 = `{ msg = "pineapple mango", fields = {...}` -> printed
// log3 = `{ msg = "pineapple mango bar", fields = {...}` -> omitted
//
OmitLogWithMessageStrings []string
// MaskFieldValuesWithFieldKeys indicates that the logger should mask with asterisks (`*`)
// any field value where the key matches one of the given keys.
//
// Example:
//
// MaskFieldValuesWithFieldKeys = `['foo', 'baz']`
//
// log1 = `{ msg = "...", fields = { 'foo': '***', 'bar': '...' }` -> masked value
// log2 = `{ msg = "...", fields = { 'bar': '...' }` -> as-is value
// log3 = `{ msg = "...", fields = { 'baz': '***', 'boo': '...' }` -> masked value
//
MaskFieldValuesWithFieldKeys []string
// MaskAllFieldValuesRegexes indicates that the logger should replace, within
// all the log field values, the portion matching one of the given *regexp.Regexp.
//
// Note that the replacement will happen, only for field values that are of type string.
//
// Example:
//
// MaskAllFieldValuesRegexes = `[regexp.MustCompile("(foo|bar)")]`
//
// log1 = `{ msg = "...", fields = { 'k1': '***', 'k2': '***', 'k3': 'baz' }` -> masked value
// log2 = `{ msg = "...", fields = { 'k1': 'boo', 'k2': 'far', 'k3': 'baz' }` -> as-is value
// log2 = `{ msg = "...", fields = { 'k1': '*** *** baz' }` -> masked value
//
MaskAllFieldValuesRegexes []*regexp.Regexp
// MaskAllFieldValuesStrings indicates that the logger should replace, within
// all the log field values, the portion equal to one of the given strings.
//
// Note that the replacement will happen, only for field values that are of type string.
//
// Example:
//
// MaskAllFieldValuesStrings = `['foo', 'baz']`
//
// log1 = `{ msg = "...", fields = { 'k1': '***', 'k2': 'bar', 'k3': '***' }` -> masked value
// log2 = `{ msg = "...", fields = { 'k1': 'boo', 'k2': 'far', 'k3': '***' }` -> as-is value
// log2 = `{ msg = "...", fields = { 'k1': '*** bar ***' }` -> masked value
MaskAllFieldValuesStrings []string
// MaskMessageRegexes indicates that the logger should replace, within
// a log message, the portion matching one of the given *regexp.Regexp.
//
// Example:
//
// MaskMessageRegexes = `[regexp.MustCompile("(foo|bar)")]`
//
// log1 = `{ msg = "banana apple ***", fields = {...}` -> masked portion
// log2 = `{ msg = "pineapple mango", fields = {...}` -> as-is
// log3 = `{ msg = "pineapple mango ***", fields = {...}` -> masked portion
//
MaskMessageRegexes []*regexp.Regexp
// MaskMessageStrings indicates that the logger should replace, within
// a log message, the portion equal to one of the given strings.
//
// Example:
//
// MaskMessageStrings = `['foo', 'bar']`
//
// log1 = `{ msg = "banana apple ***", fields = {...}` -> masked portion
// log2 = `{ msg = "pineapple mango", fields = {...}` -> as-is
// log3 = `{ msg = "pineapple mango ***", fields = {...}` -> masked portion
//
MaskMessageStrings []string
}
// Copy creates a duplicate LoggerOpts. This should be used to ensure
// safe LoggerOpts modification when the LoggerOpts could be saved into a
// new context.Context.
func (o LoggerOpts) Copy() LoggerOpts {
result := LoggerOpts{
AdditionalLocationOffset: o.AdditionalLocationOffset,
Fields: make(map[string]any, len(o.Fields)),
IncludeLocation: o.IncludeLocation,
IncludeRootFields: o.IncludeRootFields,
IncludeTime: o.IncludeTime,
Level: o.Level,
MaskAllFieldValuesRegexes: make([]*regexp.Regexp, len(o.MaskAllFieldValuesRegexes)),
MaskAllFieldValuesStrings: make([]string, len(o.MaskAllFieldValuesStrings)),
MaskFieldValuesWithFieldKeys: make([]string, len(o.MaskFieldValuesWithFieldKeys)),
MaskMessageRegexes: make([]*regexp.Regexp, len(o.MaskMessageRegexes)),
MaskMessageStrings: make([]string, len(o.MaskMessageStrings)),
Name: o.Name,
OmitLogWithFieldKeys: make([]string, len(o.OmitLogWithFieldKeys)),
OmitLogWithMessageRegexes: make([]*regexp.Regexp, len(o.OmitLogWithMessageRegexes)),
OmitLogWithMessageStrings: make([]string, len(o.OmitLogWithMessageStrings)),
Output: o.Output,
}
// Copy all slice/map contents to prevent leaking memory references
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
for key, value := range o.Fields {
result.Fields[key] = value
}
copy(result.MaskAllFieldValuesRegexes, o.MaskAllFieldValuesRegexes)
copy(result.MaskAllFieldValuesStrings, o.MaskAllFieldValuesStrings)
copy(result.MaskFieldValuesWithFieldKeys, o.MaskFieldValuesWithFieldKeys)
copy(result.MaskMessageRegexes, o.MaskMessageRegexes)
copy(result.MaskMessageStrings, o.MaskMessageStrings)
copy(result.OmitLogWithFieldKeys, o.OmitLogWithFieldKeys)
copy(result.OmitLogWithMessageRegexes, o.OmitLogWithMessageRegexes)
copy(result.OmitLogWithMessageStrings, o.OmitLogWithMessageStrings)
return result
}
// ApplyLoggerOpts generates a LoggerOpts out of a list of Option
// implementations. By default, AdditionalLocationOffset is 1, IncludeLocation
// is true, IncludeTime is true, and Output is os.Stderr.
func ApplyLoggerOpts(opts ...Option) LoggerOpts {
// set some defaults
l := LoggerOpts{
AdditionalLocationOffset: 1,
IncludeLocation: true,
IncludeTime: true,
Output: os.Stderr,
}
for _, opt := range opts {
l = opt(l)
}
return l
}
// WithAdditionalLocationOffset sets the WithAdditionalLocationOffset
// configuration option, allowing implementations to fix location information
// when implementing helper functions. The default offset of 1 is automatically
// added to the provided value to account for the tflog and tfsdk logging
// functions.
func WithAdditionalLocationOffset(additionalLocationOffset int) Option {
return func(l LoggerOpts) LoggerOpts {
l.AdditionalLocationOffset = additionalLocationOffset + 1
return l
}
}
// WithOutput sets the Output configuration option, controlling where logs get
// written to. This is mostly used for testing (to write to os.Stdout, so the
// test framework can compare it against the example output) and as a helper
// when implementing safe, specific output strategies in tfsdklog.
func WithOutput(output io.Writer) Option {
return func(l LoggerOpts) LoggerOpts {
l.Output = output
return l
}
}
// WithField sets the provided key/value pair, onto the LoggerOpts.Fields field.
//
// Behind the scene, fields are stored in a map[string]interface{}:
// this means that in case the same key is used multiple times (key collision),
// the last one set is the one that gets persisted and then outputted with the logs.
func WithField(key string, value interface{}) Option {
return func(l LoggerOpts) LoggerOpts {
// Lazily create this map, on first assignment
if l.Fields == nil {
l.Fields = make(map[string]interface{})
}
l.Fields[key] = value
return l
}
}
// WithFields sets all the provided key/value pairs, onto the LoggerOpts.Fields field.
//
// Behind the scene, fields are stored in a map[string]interface{}:
// this means that in case the same key is used multiple times (key collision),
// the last one set is the one that gets persisted and then outputted with the logs.
func WithFields(fields map[string]interface{}) Option {
return func(l LoggerOpts) LoggerOpts {
// Lazily create this map, on first assignment
if l.Fields == nil {
l.Fields = make(map[string]interface{})
}
for k, v := range fields {
l.Fields[k] = v
}
return l
}
}
// WithRootFields enables the copying of root logger fields to a new subsystem
// logger during creation.
func WithRootFields() Option {
return func(l LoggerOpts) LoggerOpts {
l.IncludeRootFields = true
return l
}
}
// WithoutLocation disables the location included with logging statements. It
// should only ever be used to make log output deterministic when testing
// terraform-plugin-log.
func WithoutLocation() Option {
return func(l LoggerOpts) LoggerOpts {
l.IncludeLocation = false
return l
}
}
// WithoutTimestamp disables the timestamp included with logging statements. It
// should only ever be used to make log output deterministic when testing
// terraform-plugin-log.
func WithoutTimestamp() Option {
return func(l LoggerOpts) LoggerOpts {
l.IncludeTime = false
return l
}
}
// WithOmitLogWithFieldKeys appends keys to the LoggerOpts.OmitLogWithFieldKeys field.
func WithOmitLogWithFieldKeys(keys ...string) Option {
return func(l LoggerOpts) LoggerOpts {
l.OmitLogWithFieldKeys = append(l.OmitLogWithFieldKeys, keys...)
return l
}
}
// WithOmitLogWithMessageRegexes appends *regexp.Regexp to the LoggerOpts.OmitLogWithMessageRegexes field.
func WithOmitLogWithMessageRegexes(expressions ...*regexp.Regexp) Option {
return func(l LoggerOpts) LoggerOpts {
l.OmitLogWithMessageRegexes = append(l.OmitLogWithMessageRegexes, expressions...)
return l
}
}
// WithOmitLogWithMessageStrings appends string to the LoggerOpts.OmitLogWithMessageStrings field.
func WithOmitLogWithMessageStrings(matchingStrings ...string) Option {
return func(l LoggerOpts) LoggerOpts {
l.OmitLogWithMessageStrings = append(l.OmitLogWithMessageStrings, matchingStrings...)
return l
}
}
// WithMaskFieldValuesWithFieldKeys appends keys to the LoggerOpts.MaskFieldValuesWithFieldKeys field.
func WithMaskFieldValuesWithFieldKeys(keys ...string) Option {
return func(l LoggerOpts) LoggerOpts {
l.MaskFieldValuesWithFieldKeys = append(l.MaskFieldValuesWithFieldKeys, keys...)
return l
}
}
// WithMaskAllFieldValuesRegexes appends keys to the LoggerOpts.MaskAllFieldValuesRegexes field.
func WithMaskAllFieldValuesRegexes(expressions ...*regexp.Regexp) Option {
return func(l LoggerOpts) LoggerOpts {
l.MaskAllFieldValuesRegexes = append(l.MaskAllFieldValuesRegexes, expressions...)
return l
}
}
// WithMaskAllFieldValuesStrings appends keys to the LoggerOpts.MaskAllFieldValuesStrings field.
func WithMaskAllFieldValuesStrings(matchingStrings ...string) Option {
return func(l LoggerOpts) LoggerOpts {
l.MaskAllFieldValuesStrings = append(l.MaskAllFieldValuesStrings, matchingStrings...)
return l
}
}
// WithMaskMessageRegexes appends *regexp.Regexp to the LoggerOpts.MaskMessageRegexes field.
func WithMaskMessageRegexes(expressions ...*regexp.Regexp) Option {
return func(l LoggerOpts) LoggerOpts {
l.MaskMessageRegexes = append(l.MaskMessageRegexes, expressions...)
return l
}
}
// WithMaskMessageStrings appends string to the LoggerOpts.MaskMessageStrings field.
func WithMaskMessageStrings(matchingStrings ...string) Option {
return func(l LoggerOpts) LoggerOpts {
l.MaskMessageStrings = append(l.MaskMessageStrings, matchingStrings...)
return l
}
}