Skip to content

Commit 3afc5d2

Browse files
karakayasemiSemih Serhat Karakaya
authored andcommitted
[processor/redaction] apply redaction to log.body (#37239)
1 parent 3387398 commit 3afc5d2

File tree

3 files changed

+114
-12
lines changed

3 files changed

+114
-12
lines changed

.chloggen/redact-log-body.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: processor/redaction
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: "Apply redaction to log.body"
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [37239]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

processor/redactionprocessor/processor.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,23 @@ func (s *redaction) processResourceLog(ctx context.Context, rl plog.ResourceLogs
118118
for k := 0; k < ils.LogRecords().Len(); k++ {
119119
log := ils.LogRecords().At(k)
120120
s.processAttrs(ctx, log.Attributes())
121+
s.processLogBody(ctx, log.Body(), log.Attributes())
122+
}
123+
}
124+
}
125+
126+
func (s *redaction) processLogBody(ctx context.Context, body pcommon.Value, attributes pcommon.Map) {
127+
if body.Type() == pcommon.ValueTypeMap {
128+
s.processAttrs(ctx, body.Map())
129+
return
130+
}
131+
132+
maskedBody, redactionCount := s.processString(body.Str())
133+
// If redaction happened, update the body and add to attributes for the summary
134+
if redactionCount > 0 {
135+
body.SetStr(maskedBody)
136+
if s.config.Summary == info || s.config.Summary == debug {
137+
attributes.PutInt(bodyMaskedCount, int64(redactionCount))
121138
}
122139
}
123140
}
@@ -258,6 +275,21 @@ func (s *redaction) addMetaAttrs(redactedAttrs []string, attributes pcommon.Map,
258275
}
259276
}
260277

278+
// processString applies regex-based redaction to a string and returns the modified string & count.
279+
func (s *redaction) processString(str string) (string, int) {
280+
maskedStr := str
281+
redactionCount := 0
282+
283+
// Apply redaction using regex patterns and count matches
284+
for _, compiledRE := range s.blockRegexList {
285+
matches := compiledRE.FindAllString(str, -1)
286+
redactionCount += len(matches)
287+
maskedStr = compiledRE.ReplaceAllString(maskedStr, "****")
288+
}
289+
290+
return maskedStr, redactionCount
291+
}
292+
261293
const (
262294
debug = "debug"
263295
info = "info"
@@ -268,6 +300,7 @@ const (
268300
allowedValues = "redaction.allowed.keys"
269301
allowedValueCount = "redaction.allowed.count"
270302
ignoredKeyCount = "redaction.ignored.count"
303+
bodyMaskedCount = "redaction.body.masked.count"
271304
)
272305

273306
// makeAllowList sets up a lookup table of allowed span attribute keys

processor/redactionprocessor/processor_test.go

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ func TestRedactUnknownAttributes(t *testing.T) {
3535
redacted := map[string]pcommon.Value{
3636
"credit_card": pcommon.NewValueStr("4111111111111111"),
3737
}
38+
logBody := pcommon.NewValueStr("first-batch-first-logEntry")
3839

3940
outTraces := runTest(t, allowed, redacted, nil, nil, ignored, config)
40-
outLogs := runLogsTest(t, allowed, redacted, nil, nil, ignored, config)
41+
outLogs := runLogsTest(t, allowed, redacted, nil, nil, ignored, logBody, config)
4142
outMetricsGauge := runMetricsTest(t, allowed, redacted, nil, nil, ignored, config, pmetric.MetricTypeGauge)
4243
outMetricsSum := runMetricsTest(t, allowed, redacted, nil, nil, ignored, config, pmetric.MetricTypeSum)
4344
outMetricsHistogram := runMetricsTest(t, allowed, redacted, nil, nil, ignored, config, pmetric.MetricTypeHistogram)
@@ -80,9 +81,10 @@ func TestAllowAllKeys(t *testing.T) {
8081
"id": pcommon.NewValueInt(5),
8182
"name": pcommon.NewValueStr("placeholder"),
8283
}
84+
logBody := pcommon.NewValueStr("first-batch-first-logEntry")
8385

8486
outTraces := runTest(t, allowed, nil, nil, nil, nil, config)
85-
outLogs := runLogsTest(t, allowed, nil, nil, nil, nil, config)
87+
outLogs := runLogsTest(t, allowed, nil, nil, nil, nil, logBody, config)
8688
outMetricsGauge := runMetricsTest(t, allowed, nil, nil, nil, nil, config, pmetric.MetricTypeGauge)
8789
outMetricsSum := runMetricsTest(t, allowed, nil, nil, nil, nil, config, pmetric.MetricTypeSum)
8890
outMetricsHistogram := runMetricsTest(t, allowed, nil, nil, nil, nil, config, pmetric.MetricTypeHistogram)
@@ -131,9 +133,10 @@ func TestAllowAllKeysMaskValuesAllowValues(t *testing.T) {
131133
"credit_card2": pcommon.NewValueStr("placeholder 4111111111111112"),
132134
"email": pcommon.NewValueStr("[email protected]"),
133135
}
136+
logBody := pcommon.NewValueStr("first-batch-first-logEntry")
134137

135138
outTraces := runTest(t, allowed, nil, masked, allowedValues, nil, config)
136-
outLogs := runLogsTest(t, allowed, nil, masked, allowedValues, nil, config)
139+
outLogs := runLogsTest(t, allowed, nil, masked, allowedValues, nil, logBody, config)
137140
outMetricsGauge := runMetricsTest(t, allowed, nil, nil, masked, allowedValues, config, pmetric.MetricTypeGauge)
138141
outMetricsSum := runMetricsTest(t, allowed, nil, masked, allowedValues, nil, config, pmetric.MetricTypeSum)
139142
outMetricsHistogram := runMetricsTest(t, allowed, nil, masked, allowedValues, nil, config, pmetric.MetricTypeHistogram)
@@ -197,9 +200,10 @@ func TestRedactSummaryDebug(t *testing.T) {
197200
allowedValues := map[string]pcommon.Value{
198201
"email": pcommon.NewValueStr("[email protected]"),
199202
}
203+
logBody := pcommon.NewValueStr("placeholder 4111111111111111")
200204

201205
outTraces := runTest(t, allowed, redacted, masked, allowedValues, ignored, config)
202-
outLogs := runLogsTest(t, allowed, redacted, masked, allowedValues, ignored, config)
206+
outLogs := runLogsTest(t, allowed, redacted, masked, allowedValues, ignored, logBody, config)
203207
outMetricsGauge := runMetricsTest(t, allowed, redacted, masked, allowedValues, ignored, config, pmetric.MetricTypeGauge)
204208
outMetricsSum := runMetricsTest(t, allowed, redacted, masked, allowedValues, ignored, config, pmetric.MetricTypeSum)
205209
outMetricsHistogram := runMetricsTest(t, allowed, redacted, masked, allowedValues, ignored, config, pmetric.MetricTypeHistogram)
@@ -251,6 +255,12 @@ func TestRedactSummaryDebug(t *testing.T) {
251255
value, _ = attr.Get("email")
252256
assert.Equal(t, "[email protected]", value.Str())
253257
}
258+
259+
outLog := outLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0)
260+
assert.Equal(t, "placeholder ****", outLog.Body().Str())
261+
outLogBodyMaskedCount, ok := outLog.Attributes().Get(bodyMaskedCount)
262+
assert.True(t, ok)
263+
assert.Equal(t, int64(1), outLogBodyMaskedCount.Int())
254264
}
255265

256266
// TestRedactSummaryInfo validates that the processor writes a verbose summary
@@ -280,9 +290,10 @@ func TestRedactSummaryInfo(t *testing.T) {
280290
allowedValues := map[string]pcommon.Value{
281291
"email": pcommon.NewValueStr("[email protected]"),
282292
}
293+
logBody := pcommon.NewValueStr("placeholder 4111111111111111")
283294

284295
outTraces := runTest(t, allowed, redacted, masked, allowedValues, ignored, config)
285-
outLogs := runLogsTest(t, allowed, redacted, masked, allowedValues, ignored, config)
296+
outLogs := runLogsTest(t, allowed, redacted, masked, allowedValues, ignored, logBody, config)
286297
outMetricsGauge := runMetricsTest(t, allowed, redacted, masked, allowedValues, ignored, config, pmetric.MetricTypeGauge)
287298
outMetricsSum := runMetricsTest(t, allowed, redacted, masked, allowedValues, ignored, config, pmetric.MetricTypeSum)
288299
outMetricsHistogram := runMetricsTest(t, allowed, redacted, masked, allowedValues, ignored, config, pmetric.MetricTypeHistogram)
@@ -332,6 +343,12 @@ func TestRedactSummaryInfo(t *testing.T) {
332343
value, _ = attr.Get("safe_attribute")
333344
assert.Equal(t, "harmless but suspicious 4111111111111141", value.Str())
334345
}
346+
347+
outLog := outLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0)
348+
assert.Equal(t, "placeholder ****", outLog.Body().Str())
349+
outLogBodyMaskedCount, ok := outLog.Attributes().Get(bodyMaskedCount)
350+
assert.True(t, ok)
351+
assert.Equal(t, int64(1), outLogBodyMaskedCount.Int())
335352
}
336353

337354
// TestRedactSummarySilent validates that the processor does not create the
@@ -351,9 +368,10 @@ func TestRedactSummarySilent(t *testing.T) {
351368
redacted := map[string]pcommon.Value{
352369
"credit_card": pcommon.NewValueStr("4111111111111111"),
353370
}
371+
logBody := pcommon.NewValueStr("placeholder 4111111111111111")
354372

355-
outTraces := runTest(t, allowed, redacted, masked, nil, nil, config)
356-
outLogs := runLogsTest(t, allowed, redacted, masked, nil, nil, config)
373+
outTraces := runTest(t, allowed, nil, masked, nil, nil, config)
374+
outLogs := runLogsTest(t, allowed, nil, masked, nil, nil, logBody, config)
357375
outMetricsGauge := runMetricsTest(t, allowed, redacted, nil, masked, nil, config, pmetric.MetricTypeGauge)
358376
outMetricsSum := runMetricsTest(t, allowed, redacted, masked, nil, nil, config, pmetric.MetricTypeSum)
359377
outMetricsHistogram := runMetricsTest(t, allowed, redacted, masked, nil, nil, config, pmetric.MetricTypeHistogram)
@@ -386,12 +404,20 @@ func TestRedactSummarySilent(t *testing.T) {
386404
value, _ := attr.Get("name")
387405
assert.Equal(t, "placeholder ****", value.Str())
388406
}
407+
408+
outLog := outLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0)
409+
assert.Equal(t, "placeholder ****", outLog.Body().Str())
410+
_, ok := outLog.Attributes().Get(bodyMaskedCount)
411+
assert.False(t, ok)
389412
}
390413

391414
// TestRedactSummaryDefault validates that the processor does not create the
392415
// summary attributes by default
393416
func TestRedactSummaryDefault(t *testing.T) {
394-
config := &Config{AllowedKeys: []string{"id", "name", "group"}}
417+
config := &Config{
418+
AllowedKeys: []string{"id", "name", "group"},
419+
BlockedValues: []string{"4[0-9]{12}(?:[0-9]{3})?"},
420+
}
395421
allowed := map[string]pcommon.Value{
396422
"id": pcommon.NewValueInt(5),
397423
}
@@ -401,9 +427,10 @@ func TestRedactSummaryDefault(t *testing.T) {
401427
masked := map[string]pcommon.Value{
402428
"name": pcommon.NewValueStr("placeholder 4111111111111111"),
403429
}
430+
logBody := pcommon.NewValueStr("placeholder 4111111111111111")
404431

405-
outTraces := runTest(t, allowed, nil, masked, nil, ignored, config)
406-
outLogs := runLogsTest(t, allowed, nil, masked, nil, ignored, config)
432+
outTraces := runTest(t, allowed, nil, masked, nil, nil, config)
433+
outLogs := runLogsTest(t, allowed, nil, masked, nil, nil, logBody, config)
407434
outMetricsGauge := runMetricsTest(t, allowed, nil, masked, nil, ignored, config, pmetric.MetricTypeGauge)
408435
outMetricsSum := runMetricsTest(t, allowed, nil, masked, nil, ignored, config, pmetric.MetricTypeSum)
409436
outMetricsHistogram := runMetricsTest(t, allowed, nil, masked, nil, ignored, config, pmetric.MetricTypeHistogram)
@@ -431,7 +458,14 @@ func TestRedactSummaryDefault(t *testing.T) {
431458
assert.False(t, ok)
432459
_, ok = attr.Get(ignoredKeyCount)
433460
assert.False(t, ok)
461+
value, _ := attr.Get("name")
462+
assert.Equal(t, "placeholder ****", value.Str())
434463
}
464+
465+
outLog := outLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0)
466+
assert.Equal(t, "placeholder ****", outLog.Body().Str())
467+
_, ok := outLog.Attributes().Get(bodyMaskedCount)
468+
assert.False(t, ok)
435469
}
436470

437471
// TestMultipleBlockValues validates that the processor can block multiple
@@ -452,9 +486,10 @@ func TestMultipleBlockValues(t *testing.T) {
452486
redacted := map[string]pcommon.Value{
453487
"credit_card": pcommon.NewValueStr("4111111111111111"),
454488
}
489+
logBody := pcommon.NewValueStr("placeholder 4111111111111111 52000")
455490

456491
outTraces := runTest(t, allowed, redacted, masked, nil, nil, config)
457-
outLogs := runLogsTest(t, allowed, redacted, masked, nil, nil, config)
492+
outLogs := runLogsTest(t, allowed, redacted, masked, nil, nil, logBody, config)
458493
outMetricsGauge := runMetricsTest(t, allowed, redacted, masked, nil, nil, config, pmetric.MetricTypeGauge)
459494
outMetricsSum := runMetricsTest(t, allowed, redacted, masked, nil, nil, config, pmetric.MetricTypeSum)
460495
outMetricsHistogram := runMetricsTest(t, allowed, redacted, masked, nil, nil, config, pmetric.MetricTypeHistogram)
@@ -500,6 +535,12 @@ func TestMultipleBlockValues(t *testing.T) {
500535
assert.Equal(t, "placeholder **** ****", nameValue.Str())
501536
assert.Equal(t, "mystery ****", mysteryValue.Str())
502537
}
538+
539+
outLog := outLogs.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0)
540+
assert.Equal(t, "placeholder **** ****", outLog.Body().Str())
541+
outLogBodyMaskedCount, ok := outLog.Attributes().Get(bodyMaskedCount)
542+
assert.True(t, ok)
543+
assert.Equal(t, int64(2), outLogBodyMaskedCount.Int())
503544
}
504545

505546
// TestProcessAttrsAppliedTwice validates a use case when data is coming through redaction processor more than once.
@@ -601,6 +642,7 @@ func runLogsTest(
601642
masked map[string]pcommon.Value,
602643
allowedValues map[string]pcommon.Value,
603644
ignored map[string]pcommon.Value,
645+
body pcommon.Value,
604646
config *Config,
605647
) plog.Logs {
606648
inBatch := plog.NewLogs()
@@ -611,7 +653,7 @@ func runLogsTest(
611653
library := ils.Scope()
612654
library.SetName("first-library")
613655
logEntry := ils.LogRecords().AppendEmpty()
614-
logEntry.Body().SetStr("first-batch-first-logEntry")
656+
body.CopyTo(logEntry.Body())
615657
logEntry.SetTraceID([16]byte{1, 2, 3, 4})
616658

617659
length := len(allowed) + len(masked) + len(redacted) + len(ignored) + len(allowedValues)

0 commit comments

Comments
 (0)