-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
Copy pathfield_remover.go
111 lines (90 loc) · 3.17 KB
/
field_remover.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
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package logdedupprocessor // import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/logdedupprocessor"
import (
"fmt"
"strings"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/plog"
)
const (
// fieldDelimiter is the delimiter used to split a field key into its parts.
fieldDelimiter = "."
// fieldEscapeKeyReplacement is the string used to temporarily replace escaped delimters while splitting a field key.
fieldEscapeKeyReplacement = "{TEMP_REPLACE}"
)
// fieldRemover handles removing excluded fields from log records
type fieldRemover struct {
fields []*field
}
// field represents a field and it's compound key to match on
type field struct {
keyParts []string
}
// newFieldRemover creates a new field remover based on the passed in field keys
func newFieldRemover(fieldKeys []string) *fieldRemover {
fe := &fieldRemover{
fields: make([]*field, 0, len(fieldKeys)),
}
for _, f := range fieldKeys {
fe.fields = append(fe.fields, &field{
keyParts: splitField(f),
})
}
return fe
}
// RemoveFields removes any body or attribute fields that match in the log record
func (fe *fieldRemover) RemoveFields(logRecord plog.LogRecord) {
for _, field := range fe.fields {
field.removeField(logRecord)
}
}
// removeField removes the field from the log record if it exists
func (f *field) removeField(logRecord plog.LogRecord) {
firstPart, remainingParts := f.keyParts[0], f.keyParts[1:]
switch firstPart {
case bodyField:
// If body is a map then recurse through to remove the field
if logRecord.Body().Type() == pcommon.ValueTypeMap {
removeFieldFromMap(logRecord.Body().Map(), remainingParts)
}
case attributeField:
// Remove all attributes
if len(remainingParts) == 0 {
logRecord.Attributes().Clear()
return
}
// Recurse through map and remove fields
removeFieldFromMap(logRecord.Attributes(), remainingParts)
}
}
// removeFieldFromMap recurses through the map and removes the field if it's found.
func removeFieldFromMap(valueMap pcommon.Map, keyParts []string) {
nextKeyPart, remainingParts := keyParts[0], keyParts[1:]
// Look for the value associated with the next key part.
// If we don't find it then return
value, ok := valueMap.Get(nextKeyPart)
if !ok {
return
}
// No more key parts that means we have found the value and remove it
if len(remainingParts) == 0 {
valueMap.Remove(nextKeyPart)
return
}
// If the value is a map then recurse through with the remaining parts
if value.Type() == pcommon.ValueTypeMap {
removeFieldFromMap(value.Map(), remainingParts)
}
}
// splitField splits a field key into its parts.
// It replaces escaped delimiters with the full delimiter after splitting.
func splitField(fieldKey string) []string {
escapedKey := strings.ReplaceAll(fieldKey, fmt.Sprintf("\\%s", fieldDelimiter), fieldEscapeKeyReplacement)
keyParts := strings.Split(escapedKey, fieldDelimiter)
// Replace the temporarily escaped delimiters with the actual delimiter.
for i := range keyParts {
keyParts[i] = strings.ReplaceAll(keyParts[i], fieldEscapeKeyReplacement, fieldDelimiter)
}
return keyParts
}