Skip to content
This repository has been archived by the owner on Jun 1, 2024. It is now read-only.

Commit

Permalink
Render message by default #158, Could disable MessageTemplate #159 + …
Browse files Browse the repository at this point in the history
…Tests (#160)
  • Loading branch information
klettier authored and mivano committed Apr 21, 2018
1 parent 19e0f38 commit 1960e2c
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public abstract class DefaultJsonFormatter : ITextFormatter
readonly bool _omitEnclosingObject;
readonly string _closingDelimiter;
readonly bool _renderMessage;
readonly bool _renderMessageTemplate;
readonly IFormatProvider _formatProvider;
readonly IDictionary<Type, Action<object, bool, TextWriter>> _literalWriters;

Expand All @@ -50,15 +51,19 @@ public abstract class DefaultJsonFormatter : ITextFormatter
/// <param name="renderMessage">If true, the message will be rendered and written to the output as a
/// property named RenderedMessage.</param>
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
/// <param name="renderMessageTemplate">If true, the message template will be rendered and written to the output as a
/// property named RenderedMessageTemplate.</param>
protected DefaultJsonFormatter(
bool omitEnclosingObject = false,
string closingDelimiter = null,
bool renderMessage = false,
IFormatProvider formatProvider = null)
bool renderMessage = true,
IFormatProvider formatProvider = null,
bool renderMessageTemplate = true)
{
_omitEnclosingObject = omitEnclosingObject;
_closingDelimiter = closingDelimiter ?? Environment.NewLine;
_renderMessage = renderMessage;
_renderMessageTemplate = renderMessageTemplate;
_formatProvider = formatProvider;

_literalWriters = new Dictionary<Type, Action<object, bool, TextWriter>>
Expand Down Expand Up @@ -102,7 +107,12 @@ public void Format(LogEvent logEvent, TextWriter output)
var delim = "";
WriteTimestamp(logEvent.Timestamp, ref delim, output);
WriteLevel(logEvent.Level, ref delim, output);
WriteMessageTemplate(logEvent.MessageTemplate.Text, ref delim, output);

if(_renderMessageTemplate)
{
WriteMessageTemplate(logEvent.MessageTemplate.Text, ref delim, output);
}

if (_renderMessage)
{
var message = logEvent.RenderMessage(_formatProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,27 @@ public class ElasticsearchJsonFormatter : DefaultJsonFormatter
readonly IElasticsearchSerializer _serializer;
readonly bool _inlineFields;

/// <summary>
/// Render message property name
/// </summary>
public const string RenderedMessagePropertyName = "message";
/// <summary>
/// Message template property name
/// </summary>
public const string MessageTemplatePropertyName = "messageTemplate";
/// <summary>
/// Exception property name
/// </summary>
public const string ExceptionPropertyName = "Exception";
/// <summary>
/// Level property name
/// </summary>
public const string LevelPropertyName = "level";
/// <summary>
/// Timestamp property name
/// </summary>
public const string TimestampPropertyName = "@timestamp";

/// <summary>
/// Construct a <see cref="ElasticsearchJsonFormatter"/>.
/// </summary>
Expand All @@ -47,13 +68,17 @@ public class ElasticsearchJsonFormatter : DefaultJsonFormatter
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
/// <param name="serializer">Inject a serializer to force objects to be serialized over being ToString()</param>
/// <param name="inlineFields">When set to true values will be written at the root of the json document</param>
public ElasticsearchJsonFormatter(bool omitEnclosingObject = false,
/// <param name="renderMessageTemplate">If true, the message template will be rendered and written to the output as a
/// property named RenderedMessageTemplate.</param>
public ElasticsearchJsonFormatter(
bool omitEnclosingObject = false,
string closingDelimiter = null,
bool renderMessage = false,
bool renderMessage = true,
IFormatProvider formatProvider = null,
IElasticsearchSerializer serializer = null,
bool inlineFields = false)
: base(omitEnclosingObject, closingDelimiter, renderMessage, formatProvider)
bool inlineFields = false,
bool renderMessageTemplate = true)
: base(omitEnclosingObject, closingDelimiter, renderMessage, formatProvider, renderMessageTemplate)
{
_serializer = serializer;
_inlineFields = inlineFields;
Expand Down Expand Up @@ -240,21 +265,20 @@ private void WriteStructuredExceptionMethod(string exceptionMethodString, ref st
delim = ",";
}


/// <summary>
/// (Optionally) writes out the rendered message
/// </summary>
protected override void WriteRenderedMessage(string message, ref string delim, TextWriter output)
{
WriteJsonProperty("message", message, ref delim, output);
WriteJsonProperty(RenderedMessagePropertyName, message, ref delim, output);
}

/// <summary>
/// Writes out the message template for the logevent.
/// </summary>
protected override void WriteMessageTemplate(string template, ref string delim, TextWriter output)
{
WriteJsonProperty("messageTemplate", template, ref delim, output);
WriteJsonProperty(MessageTemplatePropertyName, template, ref delim, output);
}

/// <summary>
Expand All @@ -263,15 +287,15 @@ protected override void WriteMessageTemplate(string template, ref string delim,
protected override void WriteLevel(LogEventLevel level, ref string delim, TextWriter output)
{
var stringLevel = Enum.GetName(typeof(LogEventLevel), level);
WriteJsonProperty("level", stringLevel, ref delim, output);
WriteJsonProperty(LevelPropertyName, stringLevel, ref delim, output);
}

/// <summary>
/// Writes out the log timestamp
/// </summary>
protected override void WriteTimestamp(DateTimeOffset timestamp, ref string delim, TextWriter output)
{
WriteJsonProperty("@timestamp", timestamp, ref delim, output);
WriteJsonProperty(TimestampPropertyName, timestamp, ref delim, output);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ public int QueueSizeLimit
/// <summary>
/// Configures the elasticsearch sink defaults
/// </summary>
protected ElasticsearchSinkOptions()
public ElasticsearchSinkOptions()
{
this.IndexFormat = "logstash-{0:yyyy.MM.dd}";
this.DeadLetterIndexName = "deadletter-{0:yyyy.MM.dd}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,27 +77,34 @@ private ElasticsearchSinkState(ElasticsearchSinkOptions options)

_client = new ElasticLowLevelClient(configuration);

_formatter = options.CustomFormatter ?? new ElasticsearchJsonFormatter(
_formatter = options.CustomFormatter ?? CreateDefaultFormatter(options);

_durableFormatter = options.CustomDurableFormatter ?? CreateDefaultDurableFormatter(options);

_registerTemplateOnStartup = options.AutoRegisterTemplate;
TemplateRegistrationSuccess = !_registerTemplateOnStartup;
}

public static ITextFormatter CreateDefaultFormatter(ElasticsearchSinkOptions options)
{
return new ElasticsearchJsonFormatter(
formatProvider: options.FormatProvider,
renderMessage: true,
closingDelimiter: string.Empty,
serializer: options.Serializer,
inlineFields: options.InlineFields
);
}

_durableFormatter = options.CustomDurableFormatter ?? new ElasticsearchJsonFormatter(
public static ITextFormatter CreateDefaultDurableFormatter(ElasticsearchSinkOptions options)
{
return new ElasticsearchJsonFormatter(
formatProvider: options.FormatProvider,
renderMessage: true,
closingDelimiter: Environment.NewLine,
serializer: options.Serializer,
inlineFields: options.InlineFields
);

_registerTemplateOnStartup = options.AutoRegisterTemplate;
TemplateRegistrationSuccess = !_registerTemplateOnStartup;
}


public string Serialize(object o)
{
return _client.Serializer.SerializeToString(o, SerializationFormatting.None);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using Serilog.Events;
using Serilog.Parsing;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Xunit;

namespace Serilog.Sinks.Elasticsearch.Tests
{
public class ElasticsearchJsonFormatterTests
{
#region Helpers
static LogEvent CreateLogEvent() =>
new LogEvent
(
DateTimeOffset.Now,
LogEventLevel.Debug,
exception: null,
messageTemplate: new MessageTemplate(Enumerable.Empty<MessageTemplateToken>()),
properties: Enumerable.Empty<LogEventProperty>()
);

static void CheckProperties(Func<LogEvent> logEventProvider, ElasticsearchJsonFormatter formatter, Action<string> assert)
{
string result = null;

var logEvent = logEventProvider();

using (var stringWriter = new StringWriter())
{
formatter.Format(logEvent, stringWriter);

result = stringWriter.ToString();
}

assert(result);
}

static void CheckProperties(ElasticsearchJsonFormatter formatter, Action<string> assert) =>
CheckProperties(CreateLogEvent, formatter, assert);

static void ContainsProperty(string propertyToCheck, string result) =>
Assert.Contains
(
propertyToCheck,
result,
StringComparison.CurrentCultureIgnoreCase
);
static void DoesNotContainsProperty(string propertyToCheck, string result) =>
Assert.DoesNotContain
(
propertyToCheck,
result,
StringComparison.CurrentCultureIgnoreCase
);

static string FormatProperty(string property) => $"\"{property}\":";
#endregion

[Theory]
[InlineData(ElasticsearchJsonFormatter.RenderedMessagePropertyName)]
[InlineData(ElasticsearchJsonFormatter.MessageTemplatePropertyName)]
[InlineData(ElasticsearchJsonFormatter.TimestampPropertyName)]
[InlineData(ElasticsearchJsonFormatter.LevelPropertyName)]
public void DefaultJsonFormater_Should_Render_default_properties(string propertyToCheck)
{
CheckProperties(
new ElasticsearchJsonFormatter(),
result => ContainsProperty(FormatProperty(propertyToCheck), result));
}

[Fact]
public void When_disabling_renderMessage_Should_not_render_message_but_others()
{
CheckProperties(
new ElasticsearchJsonFormatter(renderMessage: false),
result =>
{
DoesNotContainsProperty(FormatProperty(ElasticsearchJsonFormatter.RenderedMessagePropertyName), result);
ContainsProperty(FormatProperty(ElasticsearchJsonFormatter.MessageTemplatePropertyName), result);
ContainsProperty(FormatProperty(ElasticsearchJsonFormatter.TimestampPropertyName), result);
ContainsProperty(FormatProperty(ElasticsearchJsonFormatter.LevelPropertyName), result);
});
}

[Fact]
public void When_disabling_renderMessageTemplate_Should_not_render_message_template_but_others()
{
CheckProperties(
new ElasticsearchJsonFormatter(renderMessageTemplate: false),
result =>
{
DoesNotContainsProperty(FormatProperty(ElasticsearchJsonFormatter.MessageTemplatePropertyName), result);
ContainsProperty(FormatProperty(ElasticsearchJsonFormatter.RenderedMessagePropertyName), result);
ContainsProperty(FormatProperty(ElasticsearchJsonFormatter.TimestampPropertyName), result);
ContainsProperty(FormatProperty(ElasticsearchJsonFormatter.LevelPropertyName), result);
});
}

[Fact]
public void DefaultJsonFormater_Should_enclose_object()
{
CheckProperties(
new ElasticsearchJsonFormatter(),
result =>
{
Assert.StartsWith("{", result);
Assert.EndsWith($"}}{Environment.NewLine}", result);
});
}

[Fact]
public void When_omitEnclosingObject_should_not_enclose_object()
{
CheckProperties(
new ElasticsearchJsonFormatter(omitEnclosingObject: true),
result =>
{
Assert.StartsWith("\"", result);
Assert.EndsWith("\"", result);
});
}

[Fact]
public void When_provide_closing_delimiter_should_use_it()
{
CheckProperties(
new ElasticsearchJsonFormatter(closingDelimiter: "closingDelimiter"),
result =>
{
Assert.EndsWith("closingDelimiter", result);
});
}
}
}

0 comments on commit 1960e2c

Please sign in to comment.