Skip to content

Commit

Permalink
JsonLayout - Support Precalculate for async processing
Browse files Browse the repository at this point in the history
  • Loading branch information
snakefoot committed Jan 26, 2017
1 parent c65edc2 commit 620bdc7
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 76 deletions.
4 changes: 1 addition & 3 deletions src/NLog/Layouts/CompoundLayout.cs
Expand Up @@ -76,9 +76,7 @@ protected override void InitializeLayout()
/// <returns>A string representation of the log event.</returns>
protected override string GetFormattedMessage(LogEventInfo logEvent)
{
var sb = new StringBuilder();
RenderFormattedMessage(logEvent, sb);
return sb.ToString();
return RenderAllocateBuilder(logEvent);
}

/// <summary>
Expand Down
21 changes: 2 additions & 19 deletions src/NLog/Layouts/CsvLayout.cs
Expand Up @@ -162,16 +162,7 @@ protected override void InitializeLayout()
/// <returns>A string representation of the log event.</returns>
protected override string GetFormattedMessage(LogEventInfo logEvent)
{
string cachedValue;

if (logEvent.TryGetCachedLayoutValue(this, out cachedValue))
{
return cachedValue;
}

var sb = new StringBuilder();
RenderAllColumns(logEvent, sb);
return logEvent.AddCachedLayoutValue(this, sb.ToString());
return RenderAllocateBuilder(logEvent);
}

private void RenderAllColumns(LogEventInfo logEvent, StringBuilder sb)
Expand Down Expand Up @@ -332,15 +323,7 @@ public CsvHeaderLayout(CsvLayout parent)
/// <returns>The rendered layout.</returns>
protected override string GetFormattedMessage(LogEventInfo logEvent)
{
string cached;
if (logEvent.TryGetCachedLayoutValue(this, out cached))
{
return cached;
}

var sb = new StringBuilder();
this.parent.RenderHeader(sb);
return logEvent.AddCachedLayoutValue(this, sb.ToString());
return RenderAllocateBuilder(logEvent);
}

/// <summary>
Expand Down
40 changes: 24 additions & 16 deletions src/NLog/Layouts/JsonLayout.cs
Expand Up @@ -87,15 +87,32 @@ public JsonLayout()
public ISet<string> ExcludeProperties { get; set; }
#endif

/// <summary>
/// Formats the log event as a JSON document for writing.
/// </summary>
/// <param name="logEvent">The logging event.</param>
/// <param name="target">Initially empty <see cref="StringBuilder"/> for the result</param>
protected override void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
{
RenderJsonFormattedMessage(logEvent, target);
if (target.Length == 0 && RenderEmptyObject)
{
target.Append(SuppressSpaces ? "{}" : "{ }");
}
}

/// <summary>
/// Formats the log event as a JSON document for writing.
/// </summary>
/// <param name="logEvent">The log event to be formatted.</param>
/// <returns>A JSON string representation of the log event.</returns>
protected override string GetFormattedMessage(LogEventInfo logEvent)
{
StringBuilder sb = null;
return RenderAllocateBuilder(logEvent);
}

private void RenderJsonFormattedMessage(LogEventInfo logEvent, StringBuilder sb)
{
//Memory profiling pointed out that using a foreach-loop was allocating
//an Enumerator. Switching to a for-loop avoids the memory allocation.
for (int i = 0; i < this.Attributes.Count; i++)
Expand All @@ -104,10 +121,9 @@ protected override string GetFormattedMessage(LogEventInfo logEvent)
string text = attrib.LayoutWrapper.Render(logEvent);
if (!string.IsNullOrEmpty(text))
{
bool first = sb == null;
bool first = sb.Length == 0;
if (first)
{
sb = new StringBuilder(attrib.Name.Length + text.Length + 10);
sb.Append(SuppressSpaces ? "{" : "{ ");
}
AppendJsonAttributeValue(attrib, text, sb, first);
Expand All @@ -131,7 +147,7 @@ protected override string GetFormattedMessage(LogEventInfo logEvent)
if (prop.Value == null)
{
dynAttrib.Name = propName;
dynAttrib.Encode = false; // Don't put quotes around null values;
dynAttrib.Encode = false; // Don't put quotes around null values
dynAttrib.Layout = "null";
}
else
Expand All @@ -155,26 +171,18 @@ protected override string GetFormattedMessage(LogEventInfo logEvent)
string text = dynAttrib.LayoutWrapper.Render(logEvent);
if (!string.IsNullOrEmpty(text))
{
bool first = sb == null;
bool first = sb.Length == 0;
if (first)
{
sb = new StringBuilder(dynAttrib.Name.Length + text.Length + 10);
sb.Append(SuppressSpaces ? "{" : "{ ");
}
AppendJsonAttributeValue(dynAttrib, text, sb, first);
}
}
}

if (sb == null)
{
if (!RenderEmptyObject)
return string.Empty;
else
return SuppressSpaces ? "{}" : "{ }";
}
sb.Append(SuppressSpaces ? "}" : " }");
return sb.ToString();
if (sb.Length > 0)
sb.Append(SuppressSpaces ? "}" : " }");
}

private void AppendJsonAttributeValue(JsonAttribute attrib, string text, StringBuilder sb, bool first)
Expand Down Expand Up @@ -205,7 +213,7 @@ private void AppendJsonAttributeValue(JsonAttribute attrib, string text, StringB
{
//If encoding is disabled for current attribute, do not escape the value of the attribute.
//This enables user to write arbitrary string value (including JSON).
// "\"{0}\":{1}{2}";
// "\"{0}\":{1}{2}"
sb.Append(text);
}
}
Expand Down
45 changes: 42 additions & 3 deletions src/NLog/Layouts/Layout.cs
Expand Up @@ -32,7 +32,6 @@
//

using System;
using System.Collections.Generic;

namespace NLog.Layouts
{
Expand Down Expand Up @@ -144,7 +143,6 @@ public string Render(LogEventInfo logEvent)
this.InitializeLayout();
}


return this.GetFormattedMessage(logEvent);
}

Expand Down Expand Up @@ -201,14 +199,55 @@ internal void RenderAppendBuilder(LogEventInfo logEvent, StringBuilder target, b
}
}

/// <summary>
/// Valid default implementation of <see cref="GetFormattedMessage" />, when having implemented the optimized <see cref="RenderFormattedMessage"/>
/// </summary>
/// <param name="logEvent">The logging event.</param>
/// <param name="reusableBuilder">StringBuilder to help minimize allocations [optional].</param>
/// <param name="cacheLayoutResult">Should rendering result be cached on LogEventInfo</param>
/// <returns>The rendered layout.</returns>
internal string RenderAllocateBuilder(LogEventInfo logEvent, StringBuilder reusableBuilder = null, bool cacheLayoutResult = true)
{
if (!this.threadAgnostic)
{
string cachedValue;
if (logEvent.TryGetCachedLayoutValue(this, out cachedValue))
{
return cachedValue;
}
}

int initialLength = this.maxRenderedLength;
if (initialLength > MaxInitialRenderBufferLength)
{
initialLength = MaxInitialRenderBufferLength;
}

var sb = reusableBuilder ?? new StringBuilder(initialLength);
RenderFormattedMessage(logEvent, sb);
if (sb.Length > this.maxRenderedLength)
{
this.maxRenderedLength = sb.Length;
}

if (cacheLayoutResult && !this.threadAgnostic)
{
return logEvent.AddCachedLayoutValue(this, sb.ToString());
}
else
{
return sb.ToString();
}
}

/// <summary>
/// Renders the layout for the specified logging event by invoking layout renderers.
/// </summary>
/// <param name="logEvent">The logging event.</param>
/// <param name="target">Initially empty <see cref="StringBuilder"/> for the result</param>
protected virtual void RenderFormattedMessage(LogEventInfo logEvent, StringBuilder target)
{
target.Append(GetFormattedMessage(logEvent));
target.Append(GetFormattedMessage(logEvent) ?? string.Empty);
}

/// <summary>
Expand Down
9 changes: 1 addition & 8 deletions src/NLog/Layouts/Log4JXmlEventLayout.cs
Expand Up @@ -64,14 +64,7 @@ public Log4JXmlEventLayout()
/// <returns>The rendered layout.</returns>
protected override string GetFormattedMessage(LogEventInfo logEvent)
{
string cachedValue;

if (logEvent.TryGetCachedLayoutValue(this, out cachedValue))
{
return cachedValue;
}

return logEvent.AddCachedLayoutValue(this, this.Renderer.Render(logEvent));
return RenderAllocateBuilder(logEvent);
}

/// <summary>
Expand Down
24 changes: 1 addition & 23 deletions src/NLog/Layouts/SimpleLayout.cs
Expand Up @@ -56,9 +56,6 @@ namespace NLog.Layouts
[AppDomainFixedOutput]
public class SimpleLayout : Layout, IUsesStackTrace
{
private const int MaxInitialRenderBufferLength = 16384;
private int maxRenderedLength;

private string fixedText;
private string layoutText;
private ConfigurationItemFactory configurationItemFactory;
Expand Down Expand Up @@ -297,26 +294,7 @@ protected override string GetFormattedMessage(LogEventInfo logEvent)
return this.fixedText;
}

string cachedValue;
if (logEvent.TryGetCachedLayoutValue(this, out cachedValue))
{
return cachedValue;
}

int initialSize = this.maxRenderedLength;
if (initialSize > MaxInitialRenderBufferLength)
{
initialSize = MaxInitialRenderBufferLength;
}

var builder = new StringBuilder(initialSize);
RenderAllRenderers(logEvent, builder);
if (builder.Length > this.maxRenderedLength)
{
this.maxRenderedLength = builder.Length;
}

return logEvent.AddCachedLayoutValue(this, builder.ToString());
return RenderAllocateBuilder(logEvent);
}

private void RenderAllRenderers(LogEventInfo logEvent, StringBuilder target)
Expand Down
3 changes: 1 addition & 2 deletions src/NLog/Targets/Target.cs
Expand Up @@ -683,8 +683,7 @@ protected string RenderLogEvent(Layout layout, LogEventInfo logEvent)

using (var localTarget = ReusableLayoutBuilder.Allocate())
{
layout.RenderAppendBuilder(logEvent, localTarget.Result);
return localTarget.Result.ToString();
return layout.RenderAllocateBuilder(logEvent, localTarget.Result, false);
}
}
else
Expand Down
26 changes: 24 additions & 2 deletions tests/NLog.UnitTests/Layouts/JsonLayoutTests.cs
Expand Up @@ -182,6 +182,30 @@ public void JsonLayoutRenderingAndEncodingMessageAttribute()
Assert.Equal("{ \"date\": \"2010-01-01 12:34:56.0000\", \"level\": \"Info\", \"message\": \"{ \\\"hello\\\" : \\\"world\\\" }\" }", jsonLayout.Render(logEventInfo));
}

[Fact]
public void JsonAttributeThreadAgnosticTest()
{
var jsonLayout = new JsonLayout
{
Attributes =
{
new JsonAttribute("type", "${exception:format=Type}"),
new JsonAttribute("message", "${exception:format=Message}"),
new JsonAttribute("threadid", "${threadid}"),
}
};

var logEventInfo = CreateLogEventWithExcluded();
var result = jsonLayout.Render(logEventInfo);
string cachedLookup;
logEventInfo.TryGetCachedLayoutValue(jsonLayout, out cachedLookup);
Assert.NotNull(cachedLookup);
Assert.Equal(result, cachedLookup);

string cacheVerification = jsonLayout.Render(logEventInfo);
Assert.Equal(true, ReferenceEquals(cachedLookup, cacheVerification));
}

[Fact]
public void NestedJsonAttrTest()
{
Expand Down Expand Up @@ -350,9 +374,7 @@ public void IncludeAllJsonProperties()

var logEventInfo = CreateLogEventWithExcluded();


Assert.Equal(ExpectedIncludeAllPropertiesWithExcludes, jsonLayout.Render(logEventInfo));

}

/// <summary>
Expand Down

0 comments on commit 620bdc7

Please sign in to comment.