-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add log filtering functionality (#71)
* New utility function in `internal/hclogutils`: `ArgsToKeys` It takes `ImplicitArgs()` from `hclog.Logger`, and returns the keys of the k/v pairs slice * Implementing the business logic of filtering in `internal/logging` package * Defining utilities to create `loggerKey`s for storing log filtering configuration in Context * Exposing log filtering on all offerings of this library - tflog root logger - tflog subsystem logger - tfsdklog root logger - tfsdklog subsystem logger * Adding CHANGELOG entries for log filtering and preparing for v0.5.0 release
- Loading branch information
Ivan De Marino
authored
Jul 14, 2022
1 parent
0f9eafb
commit 6c641bd
Showing
18 changed files
with
3,738 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
```release-note:feature | ||
tflog: Added `WithOmitLogWithFieldKeys()`, `WithOmitLogWithMessageRegex()`, `WithOmitLogMatchingString()`, `WithMaskFieldValueWithFieldKeys()`, `WithMaskMessageRegex()` and `WithMaskLogMatchingString()` functions, which provide log omission and log masking filtering, based on message and argument keys, for the provider root logger | ||
``` | ||
|
||
```release-note:feature | ||
tflog: Added `SubsystemWithOmitLogWithFieldKeys()`, `SubsystemWithOmitLogWithMessageRegex()`, `SubsystemWithOmitLogMatchingString()`, `SubsystemWithMaskFieldValueWithFieldKeys()`, `SubsystemWithMaskMessageRegex()` and `SubsystemWithMaskLogMatchingString()` functions, which provide log omission and log masking filtering, based on message and argument keys, for provider subsystem loggers | ||
``` | ||
|
||
```release-note:feature | ||
tfsdklog: Added `WithOmitLogWithFieldKeys()`, `WithOmitLogWithMessageRegex()`, `WithOmitLogMatchingString()`, `WithMaskFieldValueWithFieldKeys()`, `WithMaskMessageRegex()` and `WithMaskLogMatchingString()` functions, which provide log omission and log masking filtering, based on message and argument keys, for the SDK root logger | ||
``` | ||
|
||
```release-note:feature | ||
tfsdklog: Added `SubsystemWithOmitLogWithFieldKeys()`, `SubsystemWithOmitLogWithMessageRegex()`, `SubsystemWithOmitLogMatchingString()`, `SubsystemWithMaskFieldValueWithFieldKeys()`, `SubsystemWithMaskMessageRegex()`and `SubsystemWithMaskLogMatchingString()` functions, which provide log omission and log masking filtering, based on message and argument keys, for SDK subsystem loggers | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package logging | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/hashicorp/terraform-plugin-log/internal/hclogutils" | ||
) | ||
|
||
const logMaskingReplacementString = "***" | ||
|
||
// ShouldOmit takes a log's *string message and slices of arguments, | ||
// and determines, based on the LoggerOpts configuration, if the | ||
// log should be omitted (i.e. prevent it to be printed on the final writer). | ||
func (lo LoggerOpts) ShouldOmit(msg *string, argSlices ...[]interface{}) bool { | ||
// Omit log if any of the configured keys is found | ||
// either in the logger implied arguments, | ||
// or in the additional arguments | ||
if len(lo.OmitLogWithFieldKeys) > 0 { | ||
for _, args := range argSlices { | ||
argKeys := hclogutils.ArgsToKeys(args) | ||
if argKeysContain(argKeys, lo.OmitLogWithFieldKeys) { | ||
return true | ||
} | ||
} | ||
} | ||
|
||
// Omit log if any of the configured regexp matches the log message | ||
if len(lo.OmitLogWithMessageRegex) > 0 { | ||
for _, r := range lo.OmitLogWithMessageRegex { | ||
if r.MatchString(*msg) { | ||
return true | ||
} | ||
} | ||
} | ||
|
||
// Omit log if any of the configured strings is contained in the log message | ||
if len(lo.OmitLogWithMessageStrings) > 0 { | ||
for _, s := range lo.OmitLogWithMessageStrings { | ||
if strings.Contains(*msg, s) { | ||
return true | ||
} | ||
} | ||
} | ||
|
||
return false | ||
} | ||
|
||
// ApplyMask takes a log's *string message and slices of arguments, | ||
// and applies masking of keys' values and/or message, | ||
// based on the LoggerOpts configuration. | ||
// | ||
// Note that the given input is changed-in-place by this method. | ||
func (lo LoggerOpts) ApplyMask(msg *string, argSlices ...[]interface{}) { | ||
if len(lo.MaskFieldValueWithFieldKeys) > 0 { | ||
for _, k := range lo.MaskFieldValueWithFieldKeys { | ||
for _, args := range argSlices { | ||
// Here we loop `i` with steps of 2, starting from position 1 (i.e. `1, 3, 5, 7...`). | ||
// We then look up the key for each argument, by looking at `i-1`. | ||
// This ensures that in case of malformed arg slices that don't have | ||
// an even number of elements, we simply skip the last k/v pair. | ||
for i := 1; i < len(args); i += 2 { | ||
switch argK := args[i-1].(type) { | ||
case string: | ||
if k == argK { | ||
args[i] = logMaskingReplacementString | ||
} | ||
default: | ||
if k == fmt.Sprintf("%s", argK) { | ||
args[i] = logMaskingReplacementString | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Replace any part of the log message matching any of the configured regexp, | ||
// with a masking replacement string | ||
if len(lo.MaskMessageRegex) > 0 { | ||
for _, r := range lo.MaskMessageRegex { | ||
*msg = r.ReplaceAllString(*msg, logMaskingReplacementString) | ||
} | ||
} | ||
|
||
// Replace any part of the log message equal to any of the configured strings, | ||
// with a masking replacement string | ||
if len(lo.MaskMessageStrings) > 0 { | ||
for _, s := range lo.MaskMessageStrings { | ||
*msg = strings.ReplaceAll(*msg, s, logMaskingReplacementString) | ||
} | ||
} | ||
} | ||
|
||
func argKeysContain(haystack []string, needles []string) bool { | ||
for _, h := range haystack { | ||
for _, n := range needles { | ||
if n == h { | ||
return true | ||
} | ||
} | ||
} | ||
|
||
return false | ||
} |
Oops, something went wrong.