terraform-provider-gitea/vendor/github.com/hashicorp/terraform-plugin-log/tflog/subsystem.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

425 lines
18 KiB
Go

package tflog
import (
"context"
"regexp"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/terraform-plugin-log/internal/hclogutils"
"github.com/hashicorp/terraform-plugin-log/internal/logging"
)
// 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 and additional location offset of the logger.
func NewSubsystem(ctx context.Context, subsystem string, options ...logging.Option) context.Context {
logger := logging.GetProviderRootLogger(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
}
rootLoggerOptions := logging.GetProviderRootLoggerOptions(ctx)
subLoggerTFLoggerOpts := logging.ApplyLoggerOpts(options...)
// If root logger options are not available,
// fallback to creating a logger named like the given subsystem.
// This will preserve the root logger options,
// but cannot make changes beyond setting the level
// due to limitations with the hclog.Logger interface.
var subLogger hclog.Logger
if rootLoggerOptions == nil {
subLogger = logger.Named(subsystem)
if subLoggerTFLoggerOpts.AdditionalLocationOffset != 1 {
logger.Warn("Unable to create logging subsystem with AdditionalLocationOffset due to missing root logger options")
}
} else {
subLoggerOptions := hclogutils.LoggerOptionsCopy(rootLoggerOptions)
subLoggerOptions.Name = subLoggerOptions.Name + "." + subsystem
if subLoggerTFLoggerOpts.AdditionalLocationOffset != 1 {
subLoggerOptions.AdditionalLocationOffset = subLoggerTFLoggerOpts.AdditionalLocationOffset
}
subLogger = hclog.New(subLoggerOptions)
}
// Set the configured log level
if subLoggerTFLoggerOpts.Level != hclog.NoLevel {
subLogger.SetLevel(subLoggerTFLoggerOpts.Level)
}
// Propagate root fields to the subsystem logger
if subLoggerTFLoggerOpts.IncludeRootFields {
loggerTFOpts := logging.GetProviderRootTFLoggerOpts(ctx)
subLoggerTFLoggerOpts = logging.WithFields(loggerTFOpts.Fields)(subLoggerTFLoggerOpts)
}
// Set the subsystem LoggerOpts in the context
ctx = logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, subLoggerTFLoggerOpts)
return logging.SetProviderSubsystemLogger(ctx, subsystem, subLogger)
}
// SubsystemSetField returns a new context.Context that has a modified logger for
// the specified subsystem in it which will include key and value as fields
// in all its log output.
//
// In case of the same key is used multiple times (i.e. key collision),
// the last one set is the one that gets persisted and then outputted with the logs.
func SubsystemSetField(ctx context.Context, subsystem, key string, value interface{}) context.Context {
lOpts := logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem)
// Copy to prevent slice/map aliasing issues.
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
lOpts = logging.WithField(key, value)(lOpts.Copy())
return logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, lOpts)
}
// SubsystemTrace logs `msg` at the trace level to the subsystem logger
// specified in `ctx`, with optional `additionalFields` structured key-value
// fields in the log output. Fields are shallow merged with any defined on the
// subsystem logger, e.g. by the `SubsystemSetField()` function, and across
// multiple maps.
func SubsystemTrace(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{}) {
logger := logging.GetProviderSubsystemLogger(ctx, subsystem)
if logger == nil {
if logging.GetProviderRootLogger(ctx) == nil {
// logging isn't set up, nothing we can do, just silently fail
// this should basically never happen in production
return
}
// create a new logger if one doesn't exist
logger = logging.GetProviderSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", logging.NewProviderSubsystemLoggerWarning)
}
additionalArgs, shouldOmit := logging.OmitOrMask(logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem), &msg, additionalFields)
if shouldOmit {
return
}
logger.Trace(msg, additionalArgs...)
}
// SubsystemDebug logs `msg` at the debug level to the subsystem logger
// specified in `ctx`, with optional `additionalFields` structured key-value
// fields in the log output. Fields are shallow merged with any defined on the
// subsystem logger, e.g. by the `SubsystemSetField()` function, and across
// multiple maps.
func SubsystemDebug(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{}) {
logger := logging.GetProviderSubsystemLogger(ctx, subsystem)
if logger == nil {
if logging.GetProviderRootLogger(ctx) == nil {
// logging isn't set up, nothing we can do, just silently fail
// this should basically never happen in production
return
}
// create a new logger if one doesn't exist
logger = logging.GetProviderSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", logging.NewProviderSubsystemLoggerWarning)
}
additionalArgs, shouldOmit := logging.OmitOrMask(logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem), &msg, additionalFields)
if shouldOmit {
return
}
logger.Debug(msg, additionalArgs...)
}
// SubsystemInfo logs `msg` at the info level to the subsystem logger
// specified in `ctx`, with optional `additionalFields` structured key-value
// fields in the log output. Fields are shallow merged with any defined on the
// subsystem logger, e.g. by the `SubsystemSetField()` function, and across
// multiple maps.
func SubsystemInfo(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{}) {
logger := logging.GetProviderSubsystemLogger(ctx, subsystem)
if logger == nil {
if logging.GetProviderRootLogger(ctx) == nil {
// logging isn't set up, nothing we can do, just silently fail
// this should basically never happen in production
return
}
// create a new logger if one doesn't exist
logger = logging.GetProviderSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", logging.NewProviderSubsystemLoggerWarning)
}
additionalArgs, shouldOmit := logging.OmitOrMask(logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem), &msg, additionalFields)
if shouldOmit {
return
}
logger.Info(msg, additionalArgs...)
}
// SubsystemWarn logs `msg` at the warn level to the subsystem logger
// specified in `ctx`, with optional `additionalFields` structured key-value
// fields in the log output. Fields are shallow merged with any defined on the
// subsystem logger, e.g. by the `SubsystemSetField()` function, and across
// multiple maps.
func SubsystemWarn(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{}) {
logger := logging.GetProviderSubsystemLogger(ctx, subsystem)
if logger == nil {
if logging.GetProviderRootLogger(ctx) == nil {
// logging isn't set up, nothing we can do, just silently fail
// this should basically never happen in production
return
}
// create a new logger if one doesn't exist
logger = logging.GetProviderSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", logging.NewProviderSubsystemLoggerWarning)
}
additionalArgs, shouldOmit := logging.OmitOrMask(logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem), &msg, additionalFields)
if shouldOmit {
return
}
logger.Warn(msg, additionalArgs...)
}
// SubsystemError logs `msg` at the error level to the subsystem logger
// specified in `ctx`, with optional `additionalFields` structured key-value
// fields in the log output. Fields are shallow merged with any defined on the
// subsystem logger, e.g. by the `SubsystemSetField()` function, and across
// multiple maps.
func SubsystemError(ctx context.Context, subsystem, msg string, additionalFields ...map[string]interface{}) {
logger := logging.GetProviderSubsystemLogger(ctx, subsystem)
if logger == nil {
if logging.GetProviderRootLogger(ctx) == nil {
// logging isn't set up, nothing we can do, just silently fail
// this should basically never happen in production
return
}
// create a new logger if one doesn't exist
logger = logging.GetProviderSubsystemLogger(NewSubsystem(ctx, subsystem), subsystem).With("new_logger_warning", logging.NewProviderSubsystemLoggerWarning)
}
additionalArgs, shouldOmit := logging.OmitOrMask(logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem), &msg, additionalFields)
if shouldOmit {
return
}
logger.Error(msg, additionalArgs...)
}
// SubsystemOmitLogWithFieldKeys returns a new context.Context that has a modified logger
// that will omit to write any log when any of the given keys is found
// within its fields.
//
// Each call to this function is additive:
// the keys to omit by are added to the existing configuration.
//
// Example:
//
// configuration = `['foo', 'baz']`
//
// log1 = `{ msg = "...", fields = { 'foo': '...', 'bar': '...' }` -> omitted
// log2 = `{ msg = "...", fields = { 'bar': '...' }` -> printed
// log3 = `{ msg = "...", fields = { 'baz': '...', 'boo': '...' }` -> omitted
func SubsystemOmitLogWithFieldKeys(ctx context.Context, subsystem string, keys ...string) context.Context {
lOpts := logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem)
// Copy to prevent slice/map aliasing issues.
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
lOpts = logging.WithOmitLogWithFieldKeys(keys...)(lOpts.Copy())
return logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, lOpts)
}
// SubsystemOmitLogWithMessageRegexes returns a new context.Context that has a modified logger
// that will omit to write any log that has a message matching any of the
// given *regexp.Regexp.
//
// Each call to this function is additive:
// the regexp to omit by are added to the existing configuration.
//
// Example:
//
// configuration = `[regexp.MustCompile("(foo|bar)")]`
//
// log1 = `{ msg = "banana apple foo", fields = {...}` -> omitted
// log2 = `{ msg = "pineapple mango", fields = {...}` -> printed
// log3 = `{ msg = "pineapple mango bar", fields = {...}` -> omitted
func SubsystemOmitLogWithMessageRegexes(ctx context.Context, subsystem string, expressions ...*regexp.Regexp) context.Context {
lOpts := logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem)
// Copy to prevent slice/map aliasing issues.
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
lOpts = logging.WithOmitLogWithMessageRegexes(expressions...)(lOpts.Copy())
return logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, lOpts)
}
// SubsystemOmitLogWithMessageStrings returns a new context.Context that has a modified logger
// that will omit to write any log that matches any of the given string.
//
// Each call to this function is additive:
// the string to omit by are added to the existing configuration.
//
// Example:
//
// configuration = `['foo', 'bar']`
//
// log1 = `{ msg = "banana apple foo", fields = {...}` -> omitted
// log2 = `{ msg = "pineapple mango", fields = {...}` -> printed
// log3 = `{ msg = "pineapple mango bar", fields = {...}` -> omitted
func SubsystemOmitLogWithMessageStrings(ctx context.Context, subsystem string, matchingStrings ...string) context.Context {
lOpts := logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem)
// Copy to prevent slice/map aliasing issues.
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
lOpts = logging.WithOmitLogWithMessageStrings(matchingStrings...)(lOpts.Copy())
return logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, lOpts)
}
// SubsystemMaskFieldValuesWithFieldKeys returns a new context.Context that has a modified logger
// that masks (replaces) with asterisks (`***`) any argument value where the
// key matches one of the given keys.
//
// Each call to this function is additive:
// the keys to mask by are added to the existing configuration.
//
// Example:
//
// configuration = `['foo', 'baz']`
//
// log1 = `{ msg = "...", fields = { 'foo': '***', 'bar': '...' }` -> masked value
// log2 = `{ msg = "...", fields = { 'bar': '...' }` -> as-is value
// log3 = `{ msg = "...", fields = { 'baz': '***', 'boo': '...' }` -> masked value
func SubsystemMaskFieldValuesWithFieldKeys(ctx context.Context, subsystem string, keys ...string) context.Context {
lOpts := logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem)
// Copy to prevent slice/map aliasing issues.
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
lOpts = logging.WithMaskFieldValuesWithFieldKeys(keys...)(lOpts.Copy())
return logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, lOpts)
}
// SubsystemMaskAllFieldValuesRegexes returns a new context.Context that has a modified logger
// that masks (replaces) with asterisks (`***`) all field value substrings,
// matching one of the given *regexp.Regexp.
//
// Note that the replacement will happen, only for field values that are of type string.
//
// Each call to this function is additive:
// the regexp to mask by are added to the existing configuration.
//
// Example:
//
// configuration = `[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
func SubsystemMaskAllFieldValuesRegexes(ctx context.Context, subsystem string, expressions ...*regexp.Regexp) context.Context {
lOpts := logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem)
// Copy to prevent slice/map aliasing issues.
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
lOpts = logging.WithMaskAllFieldValuesRegexes(expressions...)(lOpts.Copy())
return logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, lOpts)
}
// SubsystemMaskAllFieldValuesStrings returns a new context.Context that has a modified logger
// that masks (replaces) with asterisks (`***`) all field value substrings,
// equal to one of the given strings.
//
// Note that the replacement will happen, only for field values that are of type string.
//
// Each call to this function is additive:
// the regexp to mask by are added to the existing configuration.
//
// Example:
//
// configuration = `[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
func SubsystemMaskAllFieldValuesStrings(ctx context.Context, subsystem string, matchingStrings ...string) context.Context {
lOpts := logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem)
// Copy to prevent slice/map aliasing issues.
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
lOpts = logging.WithMaskAllFieldValuesStrings(matchingStrings...)(lOpts.Copy())
return logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, lOpts)
}
// SubsystemMaskMessageRegexes returns a new context.Context that has a modified logger
// that masks (replaces) with asterisks (`***`) all message substrings,
// matching one of the given *regexp.Regexp.
//
// Each call to this function is additive:
// the regexp to mask by are added to the existing configuration.
//
// Example:
//
// configuration = `[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
func SubsystemMaskMessageRegexes(ctx context.Context, subsystem string, expressions ...*regexp.Regexp) context.Context {
lOpts := logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem)
// Copy to prevent slice/map aliasing issues.
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
lOpts = logging.WithMaskMessageRegexes(expressions...)(lOpts.Copy())
return logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, lOpts)
}
// SubsystemMaskMessageStrings returns a new context.Context that has a modified logger
// that masks (replace) with asterisks (`***`) all message substrings,
// equal to one of the given strings.
//
// Each call to this function is additive:
// the string to mask by are added to the existing configuration.
//
// Example:
//
// configuration = `['foo', 'bar']`
//
// log1 = `{ msg = "banana apple ***", fields = { 'k1': 'foo, bar, baz' }` -> masked portion
// log2 = `{ msg = "pineapple mango", fields = {...}` -> as-is
// log3 = `{ msg = "pineapple mango ***", fields = {...}` -> masked portion
func SubsystemMaskMessageStrings(ctx context.Context, subsystem string, matchingStrings ...string) context.Context {
lOpts := logging.GetProviderSubsystemTFLoggerOpts(ctx, subsystem)
// Copy to prevent slice/map aliasing issues.
// Reference: https://github.com/hashicorp/terraform-plugin-log/issues/131
lOpts = logging.WithMaskMessageStrings(matchingStrings...)(lOpts.Copy())
return logging.SetProviderSubsystemTFLoggerOpts(ctx, subsystem, lOpts)
}
// SubsystemMaskLogRegexes is a shortcut to invoke SubsystemMaskMessageRegexes and SubsystemMaskAllFieldValuesRegexes using the same input.
// Refer to those functions for details.
func SubsystemMaskLogRegexes(ctx context.Context, subsystem string, expressions ...*regexp.Regexp) context.Context {
return SubsystemMaskMessageRegexes(SubsystemMaskAllFieldValuesRegexes(ctx, subsystem, expressions...), subsystem, expressions...)
}
// SubsystemMaskLogStrings is a shortcut to invoke SubsystemMaskMessageStrings and SubsystemMaskAllFieldValuesStrings using the same input.
// Refer to those functions for details.
func SubsystemMaskLogStrings(ctx context.Context, subsystem string, matchingStrings ...string) context.Context {
return SubsystemMaskMessageStrings(SubsystemMaskAllFieldValuesStrings(ctx, subsystem, matchingStrings...), subsystem, matchingStrings...)
}