Is it possible with NLog to emit a multi-line message such that each line is formatted according to the current layout? E.g.
2015-12-17 11:37:38.0845 | 64 | INFO | -----------------------------------
2015-12-17 11:37:38.0845 | 64 | INFO | Statistics:
2015-12-17 11:37:38.0845 | 64 | INFO | Crawling Requests 46887 /min
2015-12-17 11:37:38.0845 | 64 | INFO | Stored Documents 9910 /min
2015-12-17 11:37:38.0845 | 64 | INFO | -----------------------------------
Alternatively, is it possible with NLog to emit multiple messages as a single, non-interrupted block in a multithreaded environment?
You can do all this from your config.
<variable name="statData" value="${longdate} | 64 | ${level} | "/>
<variable name="line" value="-----------------------------------"/>
<targets>
<target xsi:type="Console"
name="Console"
layout="
${statData}${line}${newline}
${statData}Statistics:${newline}
${statData} Crawling Requests 46887 /min ${newline}
${statData} Stored Documents 9910 /min ${newline}
${statData}${line}${newline}"/>
Wasn't exactly sure what your 64 was or where you were getting your per minute data. Probably a variable or something your inserting.This should also work if you are logging to a file not the console.
As for your second question, if you are wanting a single log message from multiple threads I think you would have to do that on the code side. You would have to collect your threads, get your log data you want and send it 1 time to nLog. I might be misunderstanding though
There does not appear to be existing functionally to do this yet (as of NLog 4.2.3). A potential solution is to create your own wrapper layout renderer to improve the functionality of the replace-newlines renderer.
So replace-newlines and replace wrappers will not take layout renderers in their replacement strings. Looking at the NLog source for other wrappers, renderers, and targets, a Layout
type property can be used to accept a string with (or without) layout renderers. The built in replace wrappers fail when provided a layout renderer because their Replacement
property type is string
. The xml parser is only looking for plain text but the } of a provided layout renderer prematurely ends the replace-newline wrapper.
The following custom wrapper changes the replacement type from string
to Layout
. The replacement layout then needs to be rendered by calling its Render
method with some context (LogEventInfo
). This can be done in the overridden Append
method where LogEventInfo
is available. The rendered output can be saved off for later usage in the Transform
method.
using System;
using System.Text;
using NLog.Config;
using NLog.LayoutRenderers;
using NLog.LayoutRenderers.Wrappers;
using NLog.Layouts;
namespace My.Namespace
{
[LayoutRenderer("replace-newlines-withlayout")]
[ThreadAgnostic]
public class ReplaceNewLinesFormatLayoutRendererWrapper : WrapperLayoutRendererBase
{
private string m_replacementString = " ";
public ReplaceNewLinesFormatLayoutRendererWrapper()
{
// Changed from
// Replacement = " ";
Replacement = Layout.FromString(" ");
}
// Changed from
// public string Replacement { get; set; }
public Layout Replacement { get; set; }
// Override Append in order to render the replacement.
protected override void Append(StringBuilder builder, NLog.LogEventInfo logEvent)
{
// Render...
m_replacementString = Replacement.Render(logEvent);
// The base functionality of append is fine.
base.Append(builder, logEvent);
}
// Called from base.Append()
protected override string Transform(string text)
{
// Changed from
// return text.Replace(Environment.NewLine, Replacement);
// Now just put in the rendered replacement string.
return text.Replace(Environment.NewLine, m_replacementString);
}
}
}
And then, for example, use it as
<target
...
layout=${replace-newlines-withlayout:replacement=${newline}${time}:${message}}
...
/>
In this simplified case, assuming ${message} has line breaks, each new line will be prefixed with a time stamp. Just replace ${time} with the desired prefix layout.