Skip to content

Commit

Permalink
Moved colored console sink
Browse files Browse the repository at this point in the history
  • Loading branch information
merbla committed Jan 21, 2016
1 parent 0d49b19 commit 7abaafc
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2013-2016 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Events;
using Serilog.Sinks.SystemConsole;

namespace Serilog
{
public static class ColoredConsoleLoggerConfigurationExtensions
{
const string DefaultConsoleOutputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}";

/// <summary>
/// Writes log events to <see cref="System.Console"/>, using color to differentiate
/// between levels.
/// </summary>
/// <param name="sinkConfiguration">Logger sink configuration.</param>
/// <param name="restrictedToMinimumLevel">The minimum level for
/// events passed through the sink. Ignored when <paramref name="levelSwitch"/> is specified.</param>
/// <param name="levelSwitch">A switch allowing the pass-through minimum level
/// to be changed at runtime.</param>
/// <param name="outputTemplate">A message template describing the format used to write to the sink.
/// the default is "{Timestamp} [{Level}] {Message}{NewLine}{Exception}".</param>
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
/// <returns>Configuration object allowing method chaining.</returns>
public static LoggerConfiguration ColoredConsole(
this LoggerSinkConfiguration sinkConfiguration,
LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
string outputTemplate = DefaultConsoleOutputTemplate,
IFormatProvider formatProvider = null,
LoggingLevelSwitch levelSwitch = null)
{
if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration));
if (outputTemplate == null) throw new ArgumentNullException(nameof(outputTemplate));
return sinkConfiguration.Sink(new ColoredConsoleSink(outputTemplate, formatProvider), restrictedToMinimumLevel, levelSwitch);
}
}
}
18 changes: 18 additions & 0 deletions src/Serilog.Sinks.SystemConsole/Serilog.Sinks.SystemConsole.xproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>50b24aca-d8f0-4268-a477-871b0a92a04a</ProjectGuid>
<RootNamespace>Serilog</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// Copyright 2013-2016 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.IO;
using Serilog.Core;
using Serilog.Events;
using System.Collections.Generic;
using Serilog.Formatting.Display;
using Serilog.Parsing;

using IPropertyDictionary = System.Collections.Generic.IReadOnlyDictionary<string, Serilog.Events.LogEventPropertyValue>;

namespace Serilog.Sinks.SystemConsole
{
class ColoredConsoleSink : ILogEventSink
{
readonly IFormatProvider _formatProvider;

class Palette
{
public ConsoleColor Base { get; set; }
public ConsoleColor BaseText { get; set; }
public ConsoleColor Highlight { get; set; }
public ConsoleColor HighlightText { get; set; }
}

static readonly Palette DefaultPalette = new Palette
{
Base = ConsoleColor.Black,
BaseText = ConsoleColor.Gray,
Highlight = ConsoleColor.DarkGray,
HighlightText = ConsoleColor.Gray
};

static readonly IDictionary<LogEventLevel, Palette> LevelPalettes = new Dictionary<LogEventLevel, Palette>
{
{ LogEventLevel.Verbose, new Palette { Base = ConsoleColor.Black, BaseText = ConsoleColor.DarkGray,
Highlight = ConsoleColor.Black, HighlightText = ConsoleColor.Gray } },
{ LogEventLevel.Debug, new Palette { Base = ConsoleColor.Black, BaseText = ConsoleColor.Gray,
Highlight = ConsoleColor.Black, HighlightText = ConsoleColor.White } },
{ LogEventLevel.Information, new Palette { Base = ConsoleColor.Black, BaseText = ConsoleColor.White,
Highlight = ConsoleColor.DarkBlue, HighlightText = ConsoleColor.White } },
{ LogEventLevel.Warning, new Palette { Base = ConsoleColor.Black, BaseText = ConsoleColor.Yellow,
Highlight = ConsoleColor.DarkYellow, HighlightText = ConsoleColor.White } },
{ LogEventLevel.Error, new Palette { Base = ConsoleColor.Black, BaseText = ConsoleColor.Red,
Highlight = ConsoleColor.Red, HighlightText = ConsoleColor.White } },
{ LogEventLevel.Fatal, new Palette { Base = ConsoleColor.DarkRed, BaseText = ConsoleColor.White,
Highlight = ConsoleColor.Red, HighlightText = ConsoleColor.White } }
};

readonly object _syncRoot = new object();
readonly MessageTemplate _outputTemplate;

public ColoredConsoleSink(string outputTemplate, IFormatProvider formatProvider)
{
if (outputTemplate == null) throw new ArgumentNullException(nameof(outputTemplate));
_outputTemplate = new MessageTemplateParser().Parse(outputTemplate);
_formatProvider = formatProvider;
}

const string StackFrameLinePrefix = " ";

public void Emit(LogEvent logEvent)
{
if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));

var outputProperties = OutputProperties.GetOutputProperties(logEvent);
var palette = GetPalette(logEvent.Level);
var output = Console.Out;

lock (_syncRoot)
{
try
{
foreach (var outputToken in _outputTemplate.Tokens)
{
var propertyToken = outputToken as PropertyToken;
if (propertyToken == null)
{
RenderOutputToken(palette, outputToken, outputProperties, output);
}
else switch (propertyToken.PropertyName)
{
case OutputProperties.MessagePropertyName:
RenderMessageToken(logEvent, palette, output);
break;
case OutputProperties.ExceptionPropertyName:
RenderExceptionToken(palette, propertyToken, outputProperties, output);
break;
default:
RenderOutputToken(palette, outputToken, outputProperties, output);
break;
}
}
}
finally { Console.ResetColor(); }
}
}

void RenderExceptionToken(Palette palette, MessageTemplateToken outputToken, IPropertyDictionary outputProperties, TextWriter output)
{
var sw = new StringWriter();
outputToken.Render(outputProperties, sw, _formatProvider);
var lines = new StringReader(sw.ToString());
string nextLine;
while ((nextLine = lines.ReadLine()) != null)
{
if (nextLine.StartsWith(StackFrameLinePrefix))
SetBaseColors(palette);
else
SetHighlightColors(palette);
output.WriteLine(nextLine);
}
}

void RenderMessageToken(LogEvent logEvent, Palette palette, TextWriter output)
{
foreach (var messageToken in logEvent.MessageTemplate.Tokens)
{
var messagePropertyToken = messageToken as PropertyToken;
if (messagePropertyToken != null)
{
SetHighlightColors(palette);
messageToken.Render(logEvent.Properties, output, _formatProvider);
}
else
{
SetBaseColors(palette);
messageToken.Render(logEvent.Properties, output, _formatProvider);
}
}
}

void RenderOutputToken(Palette palette, MessageTemplateToken outputToken, IPropertyDictionary outputProperties, TextWriter output)
{
SetBaseColors(palette);
outputToken.Render(outputProperties, output, _formatProvider);
}

static Palette GetPalette(LogEventLevel level)
{
Palette palette;
if (!LevelPalettes.TryGetValue(level, out palette))
palette = DefaultPalette;

return palette;
}

static void SetBaseColors(Palette palette)
{
SetColors(palette.Base, palette.BaseText);
}

static void SetHighlightColors(Palette palette)
{
SetColors(palette.Highlight, palette.HighlightText);
}

static void SetColors(ConsoleColor background, ConsoleColor foreground)
{
Console.BackgroundColor = background;
Console.ForegroundColor = foreground;
}
}
}
24 changes: 24 additions & 0 deletions src/Serilog.Sinks.SystemConsole/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"version": "2.0.0-beta-*",
"description": "The colored console sink for Serilog",
"authors": [ "Serilog Contributors" ],
"tags": [ "serilog", "console", "coloredconsole" ],
"projectUrl": "http://serilog.net",
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0",
"iconUrl": "http://serilog.net/images/serilog-sink-nuget.png",
"dependencies": {
"Serilog": { "target": "project" }
},
"compilationOptions": {
"keyFile": "../../assets/Serilog.snk"
},
"frameworks": {
"net45": {
},
"dotnet5.1": {
"dependencies": {
"System.Console": "4.0.0-beta-23516"
}
}
}
}
26 changes: 0 additions & 26 deletions src/Serilog/LoggerConfigurationFullNetFxExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,32 +44,6 @@ public static class LoggerConfigurationFullNetFxExtensions
public const string DefaultOutputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}";
public const long DefaultFileSizeLimitBytes = 1L * 1024 * 1024 * 1024;
const string DefaultConsoleOutputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}";

/// <summary>
/// Writes log events to <see cref="System.Console"/>, using color to differentiate
/// between levels.
/// </summary>
/// <param name="sinkConfiguration">Logger sink configuration.</param>
/// <param name="restrictedToMinimumLevel">The minimum level for
/// events passed through the sink. Ignored when <paramref name="levelSwitch"/> is specified.</param>
/// <param name="levelSwitch">A switch allowing the pass-through minimum level
/// to be changed at runtime.</param>
/// <param name="outputTemplate">A message template describing the format used to write to the sink.
/// the default is "{Timestamp} [{Level}] {Message}{NewLine}{Exception}".</param>
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
/// <returns>Configuration object allowing method chaining.</returns>
public static LoggerConfiguration ColoredConsole(
this LoggerSinkConfiguration sinkConfiguration,
LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
string outputTemplate = DefaultConsoleOutputTemplate,
IFormatProvider formatProvider = null,
LoggingLevelSwitch levelSwitch = null)
{
if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration));
if (outputTemplate == null) throw new ArgumentNullException(nameof(outputTemplate));
return sinkConfiguration.Sink(new ColoredConsoleSink(outputTemplate, formatProvider), restrictedToMinimumLevel, levelSwitch);
}


#if LOGCONTEXT
/// <summary>
Expand Down

0 comments on commit 7abaafc

Please sign in to comment.