Destructurama.Attributed
This package makes it possible to manipulate how objects are logged to Serilog using attributes.
Enabling the module:
Install from NuGet:
Install-Package Destructurama.Attributed
Modify logger configuration:
var log = new LoggerConfiguration()
.Destructure.UsingAttributes()
...
Changing a property name
Apply the LogWithName
attribute:
public class PersonalData
{
[LogWithName("FullName")]
public string Name { get; set; }
}
Ignoring a property
Apply the NotLogged
attribute:
public class LoginCommand
{
public string Username { get; set; }
[NotLogged]
public string Password { get; set; }
}
When the object is passed using {@...}
syntax the attributes will be consulted.
var command = new LoginCommand { Username = "logged", Password = "not logged" };
log.Information("Logging in {@Command}", command);
Treating types and properties as scalars
To prevent destructuring of a type or property at all, apply the [LogAsScalar]
attribute.
Masking a string property
Apply the LogMasked
attribute with various settings:
- Text: If set, the property value will be set to this text.
- ShowFirst: Shows the first x characters in the property value.
- ShowLast: Shows the last x characters in the property value.
- PreserveLength: If set, it will swap out each character with the default value. Note that this property will be ignored if Text has been set to custom value.
Note that masking also works for properties of type IEnumerable<string>
or derived from it, for example, string[]
or List<string>
.
Examples
public class CustomizedMaskedLogs
{
/// <summary>
/// 123456789 results in "***"
/// </summary>
[LogMasked]
public string DefaultMasked { get; set; }
/// <summary>
/// [123456789,123456789,123456789] results in [***,***,***]
/// </summary>
[LogMasked]
public string[] DefaultMaskedArray { get; set; }
/// <summary>
/// 123456789 results in "*********"
/// </summary>
[LogMasked(PreserveLength = true)]
public string DefaultMaskedPreserved { get; set; }
/// <summary>
/// 123456789 results in "#"
/// </summary>
[LogMasked(Text = "_REMOVED_")]
public string CustomMasked { get; set; }
/// <summary>
/// 123456789 results in "#########"
/// </summary>
[LogMasked(Text = "#", PreserveLength = true)]
public string CustomMaskedPreservedLength { get; set; }
/// <summary>
/// 123456789 results in "123******"
/// </summary>
[LogMasked(ShowFirst = 3)]
public string ShowFirstThreeThenDefaultMasked { get; set; }
/// <summary>
/// 123456789 results in "123******"
/// </summary>
[LogMasked(ShowFirst = 3, PreserveLength = true)]
public string ShowFirstThreeThenDefaultMaskedPreservedLength { get; set; }
/// <summary>
/// 123456789 results in "***789"
/// </summary>
[LogMasked(ShowLast = 3)]
public string ShowLastThreeThenDefaultMasked { get; set; }
/// <summary>
/// 123456789 results in "******789"
/// </summary>
[LogMasked(ShowLast = 3, PreserveLength = true)]
public string ShowLastThreeThenDefaultMaskedPreservedLength { get; set; }
/// <summary>
/// 123456789 results in "123REMOVED"
/// </summary>
[LogMasked(Text = "_REMOVED_", ShowFirst = 3)]
public string ShowFirstThreeThenCustomMask { get; set; }
/// <summary>
/// 123456789 results in "123_REMOVED_"
/// </summary>
[LogMasked(Text = "_REMOVED_", ShowFirst = 3, PreserveLength = true)]
public string ShowFirstThreeThenCustomMaskPreservedLengthIgnored { get; set; }
/// <summary>
/// 123456789 results in "_REMOVED_789"
/// </summary>
[LogMasked(Text = "_REMOVED_", ShowLast = 3)]
public string ShowLastThreeThenCustomMask { get; set; }
/// <summary>
/// 123456789 results in "_REMOVED_789"
/// </summary>
[LogMasked(Text = "_REMOVED_", ShowLast = 3, PreserveLength = true)]
public string ShowLastThreeThenCustomMaskPreservedLengthIgnored { get; set; }
/// <summary>
/// 123456789 results in "123***789"
/// </summary>
[LogMasked(ShowFirst = 3, ShowLast = 3)]
public string ShowFirstAndLastThreeAndDefaultMaskInTheMiddle { get; set; }
/// <summary>
/// 123456789 results in "123***789"
/// </summary>
[LogMasked(ShowFirst = 3, ShowLast = 3, PreserveLength = true)]
public string ShowFirstAndLastThreeAndDefaultMaskInTheMiddlePreservedLength { get; set; }
/// <summary>
/// 123456789 results in "123_REMOVED_789"
/// </summary>
[LogMasked(Text = "_REMOVED_", ShowFirst = 3, ShowLast = 3)]
public string ShowFirstAndLastThreeAndCustomMaskInTheMiddle { get; set; }
/// <summary>
/// 123456789 results in "123_REMOVED_789". PreserveLength is ignored"
/// </summary>
[LogMasked(Text = "_REMOVED_", ShowFirst = 3, ShowLast = 3, PreserveLength = true)]
public string ShowFirstAndLastThreeAndCustomMaskInTheMiddlePreservedLengthIgnored { get; set; }
}
Masking a string property with regular expressions
Apply the LogReplaced
attribute on a string to apply a RegEx replacement during Logging.
This is applicable in scenarios which a string contains both Sensitive and Non-Sensitive information. An example of this could be a string such as "Sensitive|NonSensitive". Then apply the attribute like the following snippet:
[LogReplaced(@"([a-zA-Z0-9]+)\|([a-zA-Z0-9]+)", "***|$2")]
public property Information { get; set; }
// Will log: "***|NonSensitive"
LogReplaced
attribute is available with the following constructor:
LogReplaced(string pattern, string replacement)
Constructor arguments:
- pattern: The pattern that should be applied on value.
- replacement: The string that will be applied by RegEx.
Available properties:
- Options: The RegexOptions that will be applied. Defaults to RegexOptions.None
- Timeout: A time-out interval to evaluate regular expression. Defaults to Regex.InfiniteMatchTimeout
Examples
public class WithRegex
{
const string RegexWithVerticalBars = @"([a-zA-Z0-9]+)\|([a-zA-Z0-9]+)\|([a-zA-Z0-9]+)";
/// <summary>
/// 123|456|789 results in "***|456|789"
/// </summary>
[LogReplaced(RegexWithVerticalBars, "***|$2|$3")]
public string RegexReplaceFirst { get; set; }
/// <summary>
/// 123|456|789 results in "123|***|789"
/// </summary>
[LogReplaced(RegexWithVerticalBars, "$1|***|$3")]
public string RegexReplaceSecond { get; set; }
}