Skip to content

Conversation

Pliner
Copy link
Contributor

@Pliner Pliner commented Mar 6, 2017

Hi guys!

Here is a small addition to the Serilog 😉

@nblumhardt
Copy link
Member

Thanks for the PR, @Pliner!

It doesn't look like this implementation excludes the properties accounted for by the message template (see the example in #825).

@Pliner
Copy link
Contributor Author

Pliner commented Mar 8, 2017

@nblumhardt Thank you for the feedback. Without any doubts I missed that requirement 😞

After brief investigation I found two ways to fix it:

  1. Check MessageTemplate.NamedProperties
  2. Filter MessageTemplate.Tokens to PropertyToken[] and check.

Could you tell me what way you prefer or maybe you can advice me another one? Thanks...

@Pliner
Copy link
Contributor Author

Pliner commented Mar 8, 2017

@nblumhardt Anyway, I pushed fix with inspecting MessageTemplate.NamedProperties.

var delim = "";
foreach (var kvp in _properties)
{
if (_template.NamedProperties.Any(x => x.PropertyName == kvp.Key))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since NamedProperties is an array, this can use indexer-based access and avoid allocating a LINQ enumerator. (Keeping an eye on allocations, as they build up.)

@nblumhardt
Copy link
Member

Looking good! Just the minor comment.

@serilog/reviewers-core any thoughts on this one?

adamchester
adamchester previously approved these changes Mar 8, 2017
Copy link
Member

@adamchester adamchester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it

@nblumhardt
Copy link
Member

Cool! :-) Me too. I think we should just make the LINQ change then hit the button.

@Pliner
Copy link
Contributor Author

Pliner commented Mar 9, 2017

@nblumhardt I hope I fixed your comment 😉

@nblumhardt nblumhardt changed the title Fix #825 Support {Properties} in output templates Mar 10, 2017

static bool TemplateContainsPropertyName(MessageTemplate template, string propertyName)
{
foreach (var namedProperty in template.NamedProperties)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Pliner I actually had the ol' for(var i = ... in mind here.

@nblumhardt
Copy link
Member

Added a clarification. Thanks @Pliner!

Just stepping back for a second, there's one scenario where this might not be enough to achieve what we want.

I.e. in Serilog.Extensions.Logging.File we use the output template:

{Timestamp:o} {RequestId,13} [{Level:u3}] {Message} ({EventId:x8}){NewLine}{Exception}

To take advantage of this change, we'd want something resembling:

{Timestamp:o} {RequestId,13} [{Level:u3}] {Message} ({EventId:x8}) {Properties}{NewLine}{Exception}

Although we've got RequestId and EventId going out on every line, they'll still be repeated in the {Properties} block.

Maybe not a show-stopper, but possibly worth a second thought?

@Pliner
Copy link
Contributor Author

Pliner commented Mar 14, 2017

@nblumhardt To be honest, log4net approach is ok for me: if %properties% is used in patternlayout, all properties from all contexts will be captured with any exclusions.

@nblumhardt
Copy link
Member

Thanks for the follow-up Yuri. I guess the difference here is that for log4net, the %properties% layout will not duplicate data that's in the log message, because log4net doesn't capture the arguments to the message format string the way Serilog does. With Serilog, there will be 100% duplication of these if we don't exclude them.

@Noctis-
Copy link

Noctis- commented Mar 20, 2017

Hey guys, what's the reasoning behind preferring the for loop to the foreach one ?

@nblumhardt
Copy link
Member

@Noctis- microbenchmarks :-) ... less allocation.

@nblumhardt
Copy link
Member

@serilog/reviewers-core any thoughts/opinions on #944 (comment) ?

@adamchester
Copy link
Member

I think {Properties} should not include those properties already rendered in the message template.

@adamchester
Copy link
Member

Another quick note that provides more evidence... in Logary we also implemented it by ignoring the fields already in the template.

@merbla
Copy link
Contributor

merbla commented Apr 2, 2017

Agreed, we should not duplicate.

@Pliner
Copy link
Contributor Author

Pliner commented Apr 3, 2017

@nblumhardt @adamchester @merbla
Thank you for the feedback 😉

Will make another commit today or tomorow.

@nblumhardt
Copy link
Member

Thank you @Pliner :-) 👍

@Pliner
Copy link
Contributor Author

Pliner commented Apr 4, 2017

@nblumhardt I'm not sure about my approach, but now I haven't any ideas how to do it differently 😢

@nblumhardt
Copy link
Member

Great! I think it's about as good as we are likely to get, here, without deeper changes (which we could still consider in the future).

:shipit: ?

@@ -72,7 +72,7 @@ public static class OutputProperties
result[TimestampPropertyName] = new ScalarValue(logEvent.Timestamp);
result[LevelPropertyName] = new LogEventLevelValue(logEvent.Level);
result[NewLinePropertyName] = new LiteralStringValue(Environment.NewLine);
result[PropertiesPropertyName] = new LogEventPropertiesValue(logEvent.MessageTemplate, logEvent.Properties);
result[PropertiesPropertyName] = new LogEventPropertiesValue(logEvent.MessageTemplate, logEvent.Properties, result);
Copy link
Contributor

@johnduhart johnduhart Apr 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just add a comment before this line to remind future explorers to make sure this property always comes last so it picks up all the existing properties.

@Pliner
Copy link
Contributor Author

Pliner commented Apr 5, 2017

@nblumhardt Sorry, but I have to rewrite implementation, because agait it doesn't do everything right.

I should not use output properties, but use output message template instead.

@adamchester adamchester dismissed their stale review April 5, 2017 09:21

drastically changed

@Pliner
Copy link
Contributor Author

Pliner commented Apr 5, 2017

@adamchester Unfortunatly yes, because previous implementation is simply not working 😞

/// <returns>A dictionary with properties representing the log event.</returns>
public static IReadOnlyDictionary<string, LogEventPropertyValue> GetOutputProperties(LogEvent logEvent)
public static IReadOnlyDictionary<string, LogEventPropertyValue> GetOutputProperties(LogEvent logEvent, MessageTemplate outputTemplate)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this will break the literate console sink binary:

https://github.com/serilog/serilog-sinks-literate/blob/dev/src/Serilog.Sinks.Literate/Sinks/Literate/LiterateConsoleSink.cs#L88

One obvious option would be to:

  1. Keep this overload
  2. Add back the one without the additional parameter, but make it forward calls to the full version (we could pass MessageTemplate.Empty as outputTemplate, so that the arguments could still be null-checked)
  3. Mark the old overload [Obsolete("Pass the full output template using the other overload.")]

An alternative, which might be worth considering, is to add the new overload as internal, mark the old one obsolete, and stop offering a public GetOutputProperties() at some time in the future. With the literate console being the only consumer, it may be defensible to simply duplicate the code there.

I like the latter alternative because it'd allow us to re-think how the MessageTemplateTextFormatter works in the future - hopefully to improve on the O(N) scans of the message templates - without then needing to break further public API surface.

Any thoughts?

@nblumhardt
Copy link
Member

@Pliner good spotting - thanks for the thorough check :-)

@Pliner
Copy link
Contributor Author

Pliner commented Apr 5, 2017

@nblumhardt I made an obvious changes for backward compatibility as you mentioned before.

@nblumhardt nblumhardt merged commit 643dfa4 into serilog:dev Apr 5, 2017
@nblumhardt
Copy link
Member

🎉 thanks for the great contribution, Yuri!

@adamchester
Copy link
Member

img_0054

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants