Skip to content

Commit 9c8ed17

Browse files
Add option to exclude properties from masking
1 parent c119d6c commit 9c8ed17

File tree

5 files changed

+87
-0
lines changed

5 files changed

+87
-0
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 1.3.0
44

55
- Add the default enricher logo to package [#5](https://github.com/serilog-contrib/Serilog.Enrichers.Sensitive/issues/5)
6+
- Add option to exclude properties from masking [#9](https://github.com/serilog-contrib/Serilog.Enrichers.Sensitive/issues/9)
67

78
## 1.2.0
89

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,28 @@ logger.Information("This is a sensitive {Email}", "this doesn't match the regex
133133

134134
the rendered log message comes out as: `"This is a sensitive ***MASKED***"`
135135

136+
## Never mask a property
137+
138+
It may be that you never want to mask the value of a property regardless of whether it matches a pattern for any of the masking operators. In that case you can specify that the property is never masked:
139+
140+
```csharp
141+
var logger = new LoggerConfiguration()
142+
.Enrich.WithSensitiveDataMasking(options => options.ExcludeProperties.Add("email"))
143+
.WriteTo.Console()
144+
.CreateLogger();
145+
```
146+
147+
> **Note:** The property names are treated case-insensitive. If you specify `EMAIL` and the property name is `eMaIL` it will still be excluded.
148+
149+
When you log any message with an `email` property it will not be masked:
150+
151+
```csharp
152+
logger.Information("This is a sensitive {Email}", "[email protected]");
153+
```
154+
155+
the rendered log message comes out as: `"This is a sensitive [email protected]"`
156+
157+
136158
## Extending to additional use cases
137159

138160
Depending on the type of masking operation you want to perform, the `RegexMaskingOperator` base class is most likely your best starting point. It provides a number of extension points:

src/Serilog.Enrichers.Sensitive/SensitiveDataEnricher.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ internal class SensitiveDataEnricher : ILogEventEnricher
1919
private readonly List<IMaskingOperator> _maskingOperators;
2020
private readonly string _maskValue;
2121
private readonly List<string> _maskProperties;
22+
private readonly List<string> _excludeProperties;
2223

2324
public SensitiveDataEnricher(
2425
Action<SensitiveDataEnricherOptions> options)
@@ -38,6 +39,7 @@ public SensitiveDataEnricher(
3839
_maskingMode = enricherOptions.Mode;
3940
_maskValue = enricherOptions.MaskValue;
4041
_maskProperties = enricherOptions.MaskProperties ?? new List<string>();
42+
_excludeProperties = enricherOptions.ExcludeProperties ?? new List<string>();
4143

4244
var fields = typeof(LogEvent).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
4345

@@ -69,6 +71,11 @@ public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
6971

7072
foreach (var property in logEvent.Properties.ToList())
7173
{
74+
if (_excludeProperties.Contains(property.Key, StringComparer.InvariantCultureIgnoreCase))
75+
{
76+
continue;
77+
}
78+
7279
if (_maskProperties.Contains(property.Key, StringComparer.InvariantCultureIgnoreCase))
7380
{
7481
logEvent.AddOrUpdateProperty(

src/Serilog.Enrichers.Sensitive/SensitiveDataEnricherOptions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,13 @@ public class SensitiveDataEnricherOptions
2323
/// </summary>
2424
/// <remarks>The property name is case-insensitive, when the property is present on the log message it will always be masked even if it is empty</remarks>
2525
public List<string> MaskProperties { get; set; } = new List<string>();
26+
/// <summary>
27+
/// The list of properties that should never be masked
28+
/// </summary>
29+
/// <remarks>
30+
/// <para>The property name is case-insensitive, when the property is present on the log message it will always be masked even if it is empty.</para>
31+
/// <para>This property takes precedence over <see cref="MaskProperties"/> and the masking operators.</para>
32+
/// </remarks>
33+
public List<string> ExcludeProperties { get; set; } = new List<string>();
2634
}
2735
}

test/Serilog.Enrichers.Sensitive.Tests.Unit/WhenMaskingSensitiveDataBasedOnPropertyName.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,54 @@ public void GivenLogMessageHasSpecificPropertyAndLogMessageHasPropertyButLowerCa
5353
.WithProperty("email")
5454
.WithValue("***MASKED***");
5555
}
56+
57+
[Fact]
58+
public void GivenLogMessageHasSpecificPropertyAndPropertyIsExcluded_PropertyValueIsNotMasked()
59+
{
60+
var inMemorySink = new InMemorySink();
61+
62+
var logger = new LoggerConfiguration()
63+
.Enrich.WithSensitiveDataMasking(options =>
64+
{
65+
options.ExcludeProperties.Add("Email");
66+
})
67+
.WriteTo.Sink(inMemorySink)
68+
.CreateLogger();
69+
70+
logger.Information("Example {email}", "[email protected]");
71+
72+
inMemorySink
73+
.Should()
74+
.HaveMessage("Example {email}")
75+
.Appearing()
76+
.Once()
77+
.WithProperty("email")
78+
.WithValue("[email protected]");
79+
}
80+
81+
[Fact]
82+
public void GivenLogMessageHasSpecificPropertyAndPropertyIsExcludedAndAlsoIncluded_PropertyValueIsNotMasked()
83+
{
84+
var inMemorySink = new InMemorySink();
85+
86+
var logger = new LoggerConfiguration()
87+
.Enrich.WithSensitiveDataMasking(options =>
88+
{
89+
options.MaskProperties.Add("Email");
90+
options.ExcludeProperties.Add("Email");
91+
})
92+
.WriteTo.Sink(inMemorySink)
93+
.CreateLogger();
94+
95+
logger.Information("Example {email}", "[email protected]");
96+
97+
inMemorySink
98+
.Should()
99+
.HaveMessage("Example {email}")
100+
.Appearing()
101+
.Once()
102+
.WithProperty("email")
103+
.WithValue("[email protected]");
104+
}
56105
}
57106
}

0 commit comments

Comments
 (0)