Lurgle.Logging v1.2.2 - Destructure and mask structured properties!

Table of Contents

Update

After the original post, I tackled another item I'd been meaning to look at - being able to configure proxy settings for the Serilog Seq sink. Lurgle.Logging v1.2.3 now includes additional optional configurations for the Seq sink's proxy. This is particularly useful for console apps like Seq Reporter, to ensure they don't attempt to use your proxy config when logging to Seq.

You can configure the new settings in your app.config (as per below) or via the LoggingConfig() constructor with Logging.SetConfig()!

    <!-- Optional Seq proxy settings -->
    <add key="LogSeqUseProxy" value="false" />
    <add key="LogSeqProxyServer" value ="" />
    <add key="LogSeqBypassProxyOnLocal" value = "false" />
    <add key="LogSeqProxyBypass" value = "" />
    <add key="LogSeqProxyUser" value = "" />
    <add key="LogSeqProxyPassword" value = "" />

Original post on the destructure and masking goodies below!

Lurgle Contemplation

It seems like such a long time ago since I first released Lurgle.Logging, but in fact it was only last month! In the original post I said:

This implementation does not currently destructure properties, but it's an enhancement to contemplate for future updates.

Well, I contemplated it, and here it is.

The purpose of destructuring is to ensure that on object passed which contains structured data - such as a class with its own properties - is reflected in your logging. If you pass a class to the log without destructuring, Serilog will return a ToString() representation of the class type. If you destructure - you'll get the properties within that class. 

The original logging class that became Lurgle.Logging didn't really account for destructuring since it wasn't needed for the implementation. When I created Lurgle, I was conscious that it was needed, but I parked it until now. 

Destructured Lurgles, and a bonus - updating common properties!

It was, overall, quite simple to add the functionality. I needed to amend the AddProperty() methods to include a bool (destructure), and then it was just a matter of ensuring that the flag was passed on to Serilog, and that masking was also handled accordingly.

I inserted the new flag before the optional correlationId, which means that the various static AddProperty() methods have changed in implementation; for example:

public static ILevel AddProperty(string name, object value, 
            string correlationId = null,
            bool showMethod = false,
            [CallerMemberName] string methodName = null, [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)

is now:

public static ILevel AddProperty(string name, object value, bool destructure = false,
            string correlationId = null,
            bool showMethod = false,
            [CallerMemberName] string methodName = null, [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)

and similarly, the fluent AddProperty() methods have changed to implementations like;

public IAddProperty AddProperty(string name, object value, bool destructure = false)

I usually try to avoid breaking changes, but the static AddProperty methods are  only a recent addition, and it's a relatively minor change.

This functionality also applies to common properties - properties that are persisted through all log events until cleared. As a bonus - while adding the destructure flag to AddCommonProperty(), I also made it possible to update common properties that already exist. So the AddCommonProperty() methods have changed to implementations like:

public static void AddCommonProperty(string name, object value, bool destructure = false, bool update = false)

The adddition of the update  flag means that if you already have a common property set, but need to update it for some reason, you can do so without having to clear the common properties and start again.

Masking destructured Lurgles

So one of the key benefits to destructuring is that we can apply masking to the destructured properties. There's an excellent implementation in the Masking.Serilog code, which was mostly workable but needed a little adjustment to avoid overlap with the Lurgle masking implementation.

I have therefore adapted the code to suit the Lurgle masking policy and configuration, and made it into an integrated destructurer, as shown by part of the LoggerConfiguration():

return config
                .Destructure.WithMaskProperties()

The masking is controlled by your configuration for the LogMaskPolicy; if my config is set to a masking policy, or if (as in my LurgleTest app) I were to enable masking using one of;

Logging.SetConfig(new LoggingConfig(Logging.Config, logMaskPolicy: MaskPolicy.MaskWithString));
Logging.SetConfig(new LoggingConfig(Logging.Config, logWriteInit: true, logMaskPolicy: MaskPolicy.MaskLettersAndNumbers));

Whether masking with a string, or masking letters or numbers - the result will be that any property within the LogMaskProperties config that match within the destructured data will be masked.

Lurgle Logging destructuring and masking properties!

In the above screenshot, the log message shows the deconstructed "Test" property that was passed to Serilog, and the Mechagodzilla property that has been enabled for masking is correctly masked as per the LogMaskPolicy.MaskLettersAndNumbers settings.

Lurgle it now!

As usual, you can update Lurgle.Logging via Nuget, or use the oh-so-fancy links:

 

Comments

You may also like:

Lurgle.Logging v1.1.14 and Lurgle.Alerting v1.1.9 Released

I've pushed out updates to Lurgle.Logging and Lurgle.Alerting today. The Lurgle.Logging update is minor - I noticed that Log.Add wasn't correctly passing the calling method, source file, and line number. Lurgle.Alerting has received a more substantial update: This helps to make Lurgle.Alerting even more useful and reliable! You can get...

Lurgle.Logging v1.2.0 - Multi-threaded correlation ids are now a thing

Implementing Multi-Threaded Lurgles If we revisit my example from earlier, we'll see a much simpler implementation for multi-threaded code; Log.Level().Add("Here is my log entry"); Log.Level(LurgLevel.Error).Add("Oh no! An error!"); Log.Level().Add("Phew ... moment passed"); Log.Level(correlationId: Logging.NewCorrelationId()).Add("After all that, I'd really like a different correlation id"); Log.Level(LurgLevel.Debug).Add("CorrelationId is {CorrelationId}"); You can see...

Structured Logging with Seq and Serilog

A few years back, I picked up an old "unloved" business application for document handling, and brought it into the modern era. I completed some work on adding automated OCR, running as a service, and then started to enhance it well beyond its original capabilities, such as moving a manual...