Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serilog log certain object attributes of a list of objects

Tags:

c#

.net

serilog

Given a list of objects, I'd like to log a specific attribute of each element in the list (say, its name). The only thing I can think of is logging in a forloop. Is there a better way to achieve what I want?

Small example:

public class Dog
{
    public string Name { get; set; }

    public int Id { get; set; }

    public bool CanBark{ get; set; }
}

and then somewhere else in my code

public void GetAllDogsWithLogs(){
    List<Dog> barkingDogs = GetBarkingDogs();
    foreach(var dog in barkingDogs){  // ---> I'd like to avoid a forloop just for logging
        Log.Debug("Found barking dog {Name} with Id {Id}", dog.Name, dog.Id);
    }
}

Note that I cannot log all attributes of my objects, since that would introduce way too much noise into my logs.

like image 496
emilaz Avatar asked Sep 06 '25 03:09

emilaz


2 Answers

For posterity: I ended up solving this using LINQ:

Log.Debug("Found barking dogs with name and ID {NameIds}", 
            barkingDogs.Select(dog => (dog.Name, dog.Id));
like image 51
emilaz Avatar answered Sep 07 '25 22:09

emilaz


I'd recommend leveraging the destructuring mechanism in Serilog to support this.

You can use the special @ character when logging the entity to trigger destructuring of the object as documented here:

  • Preserving Object Structure
Log.Debug("Found barking dog {@Dog}", dog);

Then, configure the destructuring logic as per here:

  • Customizing the stored data
new LoggerConfiguration()
    .Destructure.ByTransforming<Dog>(
        d => new { Name = d.Name, /* add other properties here */ })

This relies on inline configuration so it can get a bit verbose.

If you want a more general purpose destructuring logic, you could implement your own IDestructuringPolicy that checks for the presence of an attribute on each property for example, or just use one of the existing solutions from here:

  • https://github.com/destructurama

This particular package allows you to control destructuring via attributes which would give you the general purpose solution right away without having to implement your own logic:

  • https://github.com/destructurama/attributed

Just configure the logger like this:

var log = new LoggerConfiguration()
  .Destructure.UsingAttributes()

And then use the [LogWithName] and [NotLogger] attributes accordingly to customize the name / opt-out of the log data for a particular object:

public class Dog
{
    [LogWithName("DogNameOrSomething")]
    public string Name { get; set; }

    [NotLogged]
    public int Id { get; set; }

    [NotLogged]
    public bool CanBark{ get; set; }
}
like image 41
julealgon Avatar answered Sep 07 '25 22:09

julealgon