Skip to content

Commit

Permalink
Double quotes management. Fixes #2
Browse files Browse the repository at this point in the history
  • Loading branch information
eiximenis committed May 27, 2021
1 parent 33f99e7 commit b19cf85
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Serilog.Logfmt/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<PackageProjectUrl>https://github.com/eiximenis/Serilog.Logfmt/</PackageProjectUrl>
<RepositoryUrl>https://github.com/eiximenis/Serilog.Logfmt</RepositoryUrl>
<Package>Serilog.Logfmt</Package>
<Version>1.0.1$(VersionSuffix)</Version>
<Version>1.0.2$(VersionSuffix)</Version>
<Authors>Eiximenis</Authors>
<Company>Lo Crestià</Company>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
Expand Down
14 changes: 14 additions & 0 deletions Serilog.Logfmt/DoubleQuotesAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Serilog.Logfmt
{
enum DoubleQuotesAction
{
None,
ConvertToSingle,
Escape,
Remove
}
}
14 changes: 14 additions & 0 deletions Serilog.Logfmt/IDoubleQuotesOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace Serilog.Logfmt
{
public interface IDoubleQuotesOptions
{
void Escape();
void ConvertToSingle();
void Preserve();
void Remove();
}
}
17 changes: 17 additions & 0 deletions Serilog.Logfmt/LogfmtFormatProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;

namespace Serilog.Logfmt
{
internal class LogfmtFormatProvider : IFormatProvider, ICustomFormatter
{
public string Format(string format, object arg, IFormatProvider formatProvider)
{
return arg.ToString();
}

public object GetFormat(Type formatType)
{
return this;
}
}
}
5 changes: 3 additions & 2 deletions Serilog.Logfmt/LogfmtFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Serilog.Formatting;
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
Expand Down Expand Up @@ -46,8 +47,8 @@ public void Format(LogEvent logEvent, TextWriter output)
var msg = "";
using (var sw = new StringWriter())
{
logEvent.RenderMessage(sw);
msg = sw.ToString();
sw.WriteMessage(logEvent); // Don't use logEvent.RenderMessage(sw) due to extra quotes added.
msg = sw.ToLogfmtQuotedString(_options.DoubleQuotesAction);
}

output.WriteLine("{1}{0}{1} ", msg, msg.Contains(" ") ? "\"" : "");
Expand Down
30 changes: 28 additions & 2 deletions Serilog.Logfmt/LogfmtOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@

namespace Serilog.Logfmt
{
public class LogfmtOptions
public class LogfmtOptions : IDoubleQuotesOptions
{

internal bool NormalizeCase { get; private set; }
internal bool GrafanaLevels { get; private set; }

internal LogExceptionOptions ExceptionOptions {get;}

internal DoubleQuotesAction DoubleQuotesAction { get; private set; }

internal Func<string, bool> PropertyKeyFilter { get; private set; }

public LogfmtOptions()
Expand All @@ -22,6 +24,7 @@ public LogfmtOptions()
GrafanaLevels = true;
PropertyKeyFilter = k => false;
ExceptionOptions = new LogExceptionOptions();
DoubleQuotesAction = DoubleQuotesAction.ConvertToSingle;
}

public LogfmtOptions PreserveCase()
Expand All @@ -30,6 +33,12 @@ public LogfmtOptions PreserveCase()
return this;
}

public LogfmtOptions OnDoubleQuotes(Action<IDoubleQuotesOptions> optionsAction)
{
optionsAction?.Invoke(this);
return this;
}

public LogfmtOptions PreserveSerilogLogLevels()
{
GrafanaLevels = false;
Expand All @@ -46,7 +55,24 @@ public LogfmtOptions OnException(Action<LogExceptionOptions> optionsAction)
{
optionsAction?.Invoke(ExceptionOptions);
return this;
}
}

void IDoubleQuotesOptions.Escape()
{
DoubleQuotesAction = DoubleQuotesAction.Escape;
}

void IDoubleQuotesOptions.ConvertToSingle()
{
DoubleQuotesAction = DoubleQuotesAction.ConvertToSingle;
}
void IDoubleQuotesOptions.Preserve()
{
DoubleQuotesAction = DoubleQuotesAction.None;
}
void IDoubleQuotesOptions.Remove()
{
DoubleQuotesAction = DoubleQuotesAction.Remove;
}
}
}
17 changes: 17 additions & 0 deletions Serilog.Logfmt/LogfmtValueFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.IO;
using System.Linq.Expressions;
using System.Text;

namespace Serilog.Logfmt
Expand Down Expand Up @@ -31,6 +32,22 @@ protected override bool VisitScalarValue(TextWriter state, ScalarValue scalar)
{
var svalue = scalar.Value?.ToString() ?? "";
var needQuotes = svalue.Contains(" ");
if (needQuotes)
{
switch (_options.DoubleQuotesAction)
{
case DoubleQuotesAction.ConvertToSingle:
svalue = svalue.Replace('"', '\'');
break;
case DoubleQuotesAction.Remove:
svalue = svalue.Replace(@"""", "");
break;
case DoubleQuotesAction.Escape:
svalue = svalue.Replace(@"""", @"\""");
break;
default: break;
}
}
state.Write("{1}{0}{1}", svalue, needQuotes ? "\"" : "");
return false;
}
Expand Down
59 changes: 59 additions & 0 deletions Serilog.Logfmt/StringWriterExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using Serilog.Events;
using Serilog.Parsing;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;

namespace Serilog.Logfmt
{
static class StringWriterExtensions
{
public static string ToLogfmtQuotedString(this StringWriter sw, DoubleQuotesAction action)
{
var sb = sw.GetStringBuilder();
switch (action)
{
case DoubleQuotesAction.ConvertToSingle:
sb.Replace('"', '\'');
break;
case DoubleQuotesAction.Escape:
sb.Replace(@"""", @"\""");
break;
case DoubleQuotesAction.Remove:
sb.Replace(@"""", "");
break;
default: // None
break;
}

return sb.ToString();
}

// From https://github.com/serilog/serilog/issues/936 for avoiding extra quotes on strings
public static void WriteMessage(this TextWriter tw, LogEvent logEvent)
{
Predicate<LogEventPropertyValue> isString = pv =>
{
var sv = pv as ScalarValue;
return (sv != null) && (sv.Value as string) != null;
};
foreach (var t in logEvent.MessageTemplate.Tokens)
{
var pt = t as PropertyToken;
LogEventPropertyValue propVal;
if (pt != null &&
logEvent.Properties.TryGetValue(pt.PropertyName, out propVal) &&
isString(propVal))
{
tw.Write(((ScalarValue)propVal).Value);
}
else
{
t.Render(logEvent.Properties, tw, null);
}
}
}
}
}
4 changes: 3 additions & 1 deletion TestApi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Logfmt;
using Serilog.Sinks.SystemConsole.Themes;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -25,7 +26,8 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
{
config.MinimumLevel.Verbose()
.Enrich.FromLogContext()
.WriteTo.Console(new LogfmtFormatter());
// .WriteTo.Console()
.WriteTo.Console(formatter: new LogfmtFormatter());
})
.ConfigureWebHostDefaults(webBuilder =>
{
Expand Down
6 changes: 5 additions & 1 deletion TestApi/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
Expand All @@ -19,7 +20,7 @@ public void ConfigureServices(IServiceCollection services)
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory lf)
{
if (env.IsDevelopment())
{
Expand All @@ -32,6 +33,9 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
endpoints.MapGet("/", async context =>
{
var logger = lf.CreateLogger("Startup");
logger.LogInformation(@"Message with ""double quotes"" :) ");

await context.Response.WriteAsync("Hello World!");
});
});
Expand Down

0 comments on commit b19cf85

Please sign in to comment.