destructurama / attributed Goto Github PK
View Code? Open in Web Editor NEWUse attributes to control how complex types are logged to Serilog.
License: Apache License 2.0
Use attributes to control how complex types are logged to Serilog.
License: Apache License 2.0
System.ComponentModel.DataAnnotations.MetadataTypeAttribute
is a handy bridge to attributes defined in other files, especially in code generated files. It works with the validation frameworks. I don't see why it wouldn't here.
Example:
[GeneratedCode]
[MetadataTypeAttribute(typeof(DtoMetadata))]
public partial class Dto
{
public string Private { get; set; }
}
internal class DtoMetadata
{
[NotLogged]
public object Private { get; set; }
}
I think it would be great if both sources could be utilized, but the configuration on the primary class would win in the event of a conflict.
Would it be possible to add a method to the interface that only return the masked string ?
The main reason behind this is to leverage this attributes in other parts of an application.
For exemple we have this class
public class ResetPassword
{
[LogMasked]
public string Password { get; set; }
[LogMasked]
public string ConfirmPassword { get; set; }
}
If I log this object with serilog everyhting is fine.
What would be great is to be able to have the rendered string directly in order to use them in custom exception's message for exemple.
I want to use the 'Ignore null properties' functionality in a .NET 8 class library project, however I cannot use the UsingAttributes(x => x.IgnoreNullProperties = true)
extension method. I can only call the UsingAttributes()
variant. The NotLoggedIfNull
attribute is also not available for use.
Hi, I've spotted that using ".Destructure.UsingAttributes()" on sublogger LoggerConfigurations doesn't work, just on the top level LoggerConfiguration. Are there any plans to change that?
My use case is that I'm splitting the logs into a 'logger' and an 'auditor', the logger needing to have all personally identifiable data removed, whilst retaining it for audit purposes.
Hello, I'm using this github package, serilog-timings, and destructurama.attributed. I've found that when I set destructureObjects to true in the following code, op.Complete("Result", response, true);, it does not enforce the Destructure.MaxDepth and Destrcuture.UsingAttributes. It is only being enforced in the message template when I use the @ operator. I've also seen when using .ForContext(), its the same thing, log.ForContext("RequestBody", request, true).
Is it possible to apply destructuring rules to both?
Hello!
Thank you for all the efforts in producing this to help us!
I noticed that LogReplaced is not available on master branch for us to use.
Are there any plans to make this available in the near future?
Thank you!
Json.NET has [ExtensionData]
(see: https://www.newtonsoft.com/json/help/html/DeserializeExtensionData.htm). This is sometime used to allow for dynamic property population on deserialization.
By default, Serilog will capture all the pairs in a Dictionary<TKey, TValue>
. I'm proposing that there is a way to do a whitelist or blacklist with configuring the value masking for each key or using a default if not configured. I'm thinking it would work similarly to xUnit's theory class data.
Another option is to transform the dictionary into a list of its keys and logging that.
Hi! Me again :)
I wondering why GetPropertiesRecursive not looking into properties/fields types.
Example:
AuthMsg
{
UserAuthData AuthData { get; set; }
}
UserAuthData
{
string UserName { get; set; }
[NotLogged]
string Password { get; set; }
}
If i log AuthMsg object Password property will be logged.
It seems like for some reason I can't apply the LogAsScalar attribute for structs. It only allows classes and properties, not structs. Is there a way to allow structs as well?
Is it possible to ignore a method (or even file) altogether? The issue I am encountering is when Serilog logs a method that does not use a predefined object in which I can add the [NotLogged]
attribute to. For example, a method call that looks like this:
public SomeResponse GetMember(GetMemberObject request)
{
var member = memberRepository.GetMemberByCredentials(request.Email, request.Password);
...
}
and the method signature for GetMemberByCredentials
is: GetMemberByCredentials(string email, string password);
. I want to be able to ignore the string password
property from being logged. Is this possible? Or is the only "work around" to always pass in the object that contains the NotLogged
attribute?
Just upgradied to Serilog 3.0.0 and am getting:
[NU1608] Detected package version outside of dependency constraint: Destructurama.Attributed 3.0.0 requires Serilog (>= 2.8.0 && < 3.0.0) but version Serilog 3.0.0 was resolved
Hi,
[LogMasked] on an empty string doesn't mask the value, it returns an empty string. I would expect this behavior only when PreserveLength = true. Otherwise, I'd expect the string to be replaced to not leak the actual value.
What are your thoughts on this?
Thanks,
Jonathan
Initial data
1234567891234567891
[LogMasked(PreserveLength = true, ShowLast = 4)]
***************7891
[LogMasked(PreserveLength = true, ShowLast = 4, ShowFirst = 6)]
123456***7891
Expected result
123456*********7891
Judjing by the source code the attribute is simply ignored in this case.
Destructurama.Attributed, Version=2.0.0.0
I have an assembly that is using strong name signing and I would like to include Destructurama.Attributed. It looks like at one point you were strong name signing.
Change is simple. Reuse the existing strong name key under assets or create a new strong name. Modify the csproj file to strong name sign.
Good morning!
We are working on a project where we deal with a decent amount of sensitive data, and while logs are very useful, there are concerns about us adding new types, and forgetting to Mask a field (or many fields) on it.
It'd be nice if when we initialize Destructurama we could make a property such as MaskUnlessAllowed
.
This would implicitly apply LogMasked
to every field, unless that field specifically had AllowLog
or something along those lines.
If we have the bandwidth to do so, we may take a stab at this on our end and submit a PR for it. Would this feature be accepted if added? If so, any feedback on approach or naming?
Thanks!
I expected to be able to add [LogMasked]
to my IEnumerable<string>
and have it mask all instances within the IEnumerable
, but it seems that a null
value is returned to the log instead.
Apologies if I've missed something.
Thanks for your time, and fantastic work!
Currently only supports .NET Framework
Now you are able to extend the framework with new attributes that targets properties. But I would like to also be able to replace the hardcoding of the LogAsScalar attribute on class-level with a more generic solution.
Every time I build solution this package modifies README.md removing changes added in previous commits.
I have never used this package and other repos in destructurama org do not install it.
ping @SimonCropp
There is quite a bit of locking going on in AttributedDestructuringPolicy
- I wonder if using a ConcurrentDictionary
for the cache would be beneficial?
In any case, it would be nice to add a test that performs benchmarks, so the performance impact of using attributes can be assessed.
Hi! Be cool to have attribute that put hash of value to logs, like:
public class SignInResult {
[LogHash(HashAlgorithm.SHA1)]
public string Token {get; set;}
}
@nblumhardt,
Should I attempt to update this project or is there another plan or any concerns I should know about first?
Related to #28, I'd like it if I could manually list the types and members that I want excluded or masked - this also helps when consuming types from other libraries that handle or contain sensitive data but which cannot be annotated with Destructurama's attributes.
One example would be to allow the use of nameof()
to specify members to ignore or mask. This could be done by accepting a fully-qualified type and member path, e.g.:
var log = new LoggerConfiguration()
.Destructure.UsingMemberPaths( o => {
o.NotLogged( "FooNamespace.BarTypeName.PropertyName" );
o.NotLogged( "FooNamespace.BarTypeName+NestedType.PropertyName" );
} );
Programmer ergonomics and type-safety could be improved by using generics to specify the type and using nameof()
with a dummy instance lambda to get the property name:
void NotLogged<T>(Func<T,String> getPropertyName)
{
String typeName = typeof(T).FullName;
String propertyName = getPropertyName( default(T) );
this.NotLogged( typeName + "." + propertyName );
}
var log = new LoggerConfiguration()
.Destructure.UsingMemberPaths( o => {
o.NotLogged<FooNamespace.BarTypeName>( i => nameof(i.PropertyName) )
} );
Other function parameters (with default values or overloads to reduce noise) could be used to specify LogMasked
options:
var log = new LoggerConfiguration()
.Destructure.UsingMemberPaths( o => {
o.NotLogged<UserEditViewModel>( i => nameof(i.Password), showFirst: 1, preserveLength; true )
o.NotLogged<UserEditViewModel>( i => nameof(i.ConfirmPassword), showLast: 1 )
} );
Given I am using C# records
I want to decorate PI properties with [NotLogged] attribute
So that the properties are not logged
Example
public record LoginRequest([Required][EmailAddress] string EmailAddress, [NotLogged][Required] string Password);
gives me a compile error, `Attribute NotLogged is not valid on this declaration type.
Are there any release notes for version 3?
For now workflow is disabled here https://github.com/destructurama/attributed/actions/workflows/benchmarks.yml
When I install Destructurama.Attributed in our solution it adds a binding redirect to Serilog.dll, mapping 0.0.0.0-1.5.0.0 to 1.5.0.0 (I think those are the version numbers).
The problem is that we have 148 projects in our solution (I know; don't ask) and if a project does not have an app.config or web.config file, installing Attributed adds one to the project for us. It also adds the binding redirect to any existing app.config/web.config files.
We know we have an appropriate minimum version of Serilog, so why is Attributed doing this? (Hopefully this isn't really a NuGet question.)
In the readme, LogMasked
example incorrectly shows mask as
"123456789" -> "*********"
which is incorrect. It should be
"123456789" -> "***"
We're attempting to use v 2.0.0 and do not see a signature. We're having trouble creating a bindingRedirect between a prior signed version and the unsigned 2.0. Specifying the publickeytoken in the redirect appears to be the cause of the trouble. Just wanted to ask if we were missing something or if there is a workaround. Thanks
Similar to Json.NET
[JsonProperty(NullValueHandling=NullValueHandling.Ignore)]
We want to reduce the json size by ignoring those null property. I read your AttributedDestructuringPolicy.cs class and see no options to add a custom attribute to the framework.
Thanks
Hi,
I added the package but Destructure.UsingAttributes() property is not available LoggerConfiguration.
Best
Have you any thoughts on extending the attribute to take in string so you could rather log *** instead of "not logged".
[NotLogged(Text= "***")]
Also I would like to be able to choose to not just override all but just part of the message. Like e.g in card numbers you can save first 4 and last 4. It would be great to be able to choose starting index and length
Something like
[NotLogged(Char='*',Start=3, End=14)]
Just brainstorming here..
Suppose I'm logging a class that has another class inside of it, like so:
public class MessageBase
{
[LogWithName("messageContext")]
public ContextClass Context
}
public class ContextClass
{
public string foo;
public string bar;
public override stringToString() {return "ContextClass ToString Output"}
}
var outputMessageBase = new MessageBase()
logger.logInfo("{@0}", outputMessageBase)
So we see MessageBase has a ContextClass inside of it. If I add the [LogWithName()] attribute over the Context property in MessageBase, serilog will no longer destructure MessageBase's Context property in the output, and will simply output Context's ToString() method. So here's the difference in output:
Without [LogWithName("messageContext")] on MessageBase's Context Property:
{"ContextClass": {"foo":"", "bar":""}}
With [LogWithName("messageContext")] on MessageBase's Context Property:
{"messageContext":"ContextClass ToString Output" }
While this is likely intended behavior, I would like some way to destructure the properties that use the [LogWithName()]. Ideally, I'd like a way for my output to be this:
{"messageContext": {"foo":"", "bar":""}}
Perhaps an argument like a boolean could be passed to the [LogWithName()] attribute, so its API would now be
[LogWithName(string newName, bool destructureObjects=false)]
Note - I am using Serilog.Formatting.Compact.CompactJsonFormatter going into a Console sink, although I don't think that changes the spirit of my question minus some minor details on precisely what the output format looks like. I'm just concerned with destructuring every property that uses destructurama attributes in my output.
Thank you for your time.
Regex.Replace(string, string, string, RegexOptions)
returns the source string if it isn't a match. Is there a way that the LogReplaced
have a fallback in the event it doesn't match.
Also, might be good to specify a timeout on the call to .Replace
.
Hi there.
Is there any plans to support .net core 1.1 or 2 in the near future?
My frontend projects (which reference Serilog and Destructurama) have dependencies on libraries which expose objects containing sensitive data, however I'm not able to annotate the types in those libraries with the Destructurama [NotLogged]
and [LogMasked]
attributes. Incidentally the backend library I'm using right now does annotate sensitive data with its own CompanyName.ProductName.SensitiveDataAttribute
class.
I did try implementing my own destructuring policy but quickly found myself out of my depth.
I realise a better solution is if Destructurama allow us to specify custom attributes to respect for logging and masking, something like:
var log = new LoggerConfiguration()
.Destructure.UsingAttributes( o => {
// o.CustomNotLoggedAttribute = typeof(MyProject.SensitiveDataAttribute),
o.CustomLogMaskedConfiguration.AttributeType = typeof(MyProject.SensitiveDataAttribute);
o.CustomLogMaskedConfiguration.ShowFirst = 1;
o.CustomLogMaskedConfiguration.ShowLast = 1;
o.CustomLogMaskedConfiguration.PreserveLength = true;
} );
This design allows a non-parameterised custom attribute type for LogMasked
while default values for Text
, ShowFirst
, ShowLast
, and PreserveLength
can be specified.
Hi there, thanks for this amazing library!
I was wondering how I can configure it so that I can mask attributes only for a specific sink.
My log configuration is set up to write to console and to file (via the appsettings.json).
However, I need to mask the attributes only when logging to file, but not when logging to the console.
I would appreciate any suggestion for this.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.