Open Lukino2000 opened 6 years ago
Hi @Lukino2000 - no, this isn't possible in the current version of the sink. SystemConsoleTheme.Colored
is the best replacement available for the old "colored" console theme.
Just to gauge interest - how important is the line coloring for you/your app? It's possible we could extend the theming system to support it, but there aren't all that many possible themes that can be created using this mechanism so we've held off on attempting this so far.
While I personally don't have a need for coloring lines, I'd like to be able to change the output color for an individual log event, such as coloring certain currency logs different colors (for example -- to make it easier to distinguish between GBP and USD), without having to create a theme.
I'd love to see this, i.e. the whole line using the color of the level used, it would make the output much easier to read. I would never use the ability to customize the color of a single line, but colorizing parameters would be great, e.g. highlighting the exception class, a correlation ID, a server IP etc. Off topic, it would also be nice to have a theme for consoles with white background.
This is a nice to have feature for a console application currently under development: I'm using Serilog to write execution status info to the output console with this simple template: {Message}{NewLine}{Exception}
; I don't want to show the log level to the user, but nonetheless I need to make him aware if there are any anomalies or errors, and the best way to do it is by coloring the entire line.
This is a nice to have feature for a console application currently under development: I'm using Serilog to write execution status info to the output console with this simple template:
{Message}{NewLine}{Exception}
; I don't want to show the log level to the user, but nonetheless I need to make him aware if there are any anomalies or errors, and the best way to do it is by coloring the entire line.
This is exactly my use case too. For short-running applications this makes sense - esp. when you want to use a single framework to logging into file and having a nice formatted console output for the user.
I haven’t been back for a while, but I did a spike on making the template token renderer public. I was attempting to see how a few different proposed features might work here:
https://github.com/serilog/serilog-sinks-console/compare/dev...adamchester:spike-themed-exception
Edit: this has an example of how to colour lines by log level
Righto, thanks for all the input! If anyone's keen to discuss design options, with a view to submitting a PR, I can help figure out how we can get this in :+1:
I'd like to take a look at that @nblumhardt
First I'd rework ConsoleThemeStyle
to be extensible (reason will be later) and to have support for hierarchy.
With that I would add new properties for template variables (e.g. Message
, Exception
, etc). Which could also be more specific by adding level (e.g. Message.Verbose
, Exception.Fatal
, etc)
Because of the specific by level and extensibility there must be some hierarchy, so that when something isn't specified, it has to have some fallback value. (e.g. Message.Verbose
not present -> use Message
, Message.Verbose
not present -> Message
not present -> use Text
)
And by extensibility I mean, that it would also support variables from enrichers like ThreadId
from Serilog.Enrichers.Thread
.
This extensibility would be for a user of serilog, which want to have custom theme, so he could set color for everything in template.
I am still thinking what algorithm and data structure to use for it internally so that it is most efficient. It has to have possibly O(1) speed access with as little constant coeficient as possible.
May I... up this? :eyes:
One more up vote from me! We are using serilog for a dotnet global tool so we can write to multiple sinks and it'd be useful to colorize the entire log line, in addition the background color of a log line when writing to the console.
For those watching, we were able to implement a naive version that supports structure and full line colorization that meets our requirements using the following code. To support customized colorization at just the level or just the log line, you'd likely need your own implementation(s) of ITextFormatter which colorize the variety of parts.
I'm certain that someone could generalize this to make it more broadly applicable using a them instead of hardcoding colorization requirements.
Hope this helps the next person who needs this!
public class ColoredConsoleSink : ILogEventSink
{
private readonly ConsoleColor _defaultForeground = Console.ForegroundColor;
private readonly ConsoleColor _defaultBackground = Console.BackgroundColor;
private readonly ITextFormatter _formatter;
public ColoredConsoleSink(ITextFormatter formatter)
{
_formatter = formatter;
}
public void Emit(LogEvent logEvent)
{
if (logEvent.Level >= LogEventLevel.Fatal)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.BackgroundColor = ConsoleColor.Red;
}
else if (logEvent.Level >= LogEventLevel.Error)
{
Console.ForegroundColor = ConsoleColor.Red;
}
else if (logEvent.Level >= LogEventLevel.Warning)
{
Console.ForegroundColor = ConsoleColor.Yellow;
}
_formatter.Format(logEvent, Console.Out);
Console.Out.Flush();
Console.ForegroundColor = _defaultForeground;
Console.BackgroundColor = _defaultBackground;
}
}
And the extension method to enable it:
public static class ColoredConsoleSinkExtensions
{
public static LoggerConfiguration ColoredConsole(
this LoggerSinkConfiguration loggerConfiguration,
LogEventLevel minimumLevel = LogEventLevel.Verbose,
string outputTemplate = "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}",
IFormatProvider formatProvider = null)
{
return loggerConfiguration.Sink(new ColoredConsoleSink(new MessageTemplateTextFormatter(outputTemplate, formatProvider)), minimumLevel);
}
}
I wrote an extension to accomplish this. I don't know if this is better or worse than the code above, but anyone is free to use it. It will accept colors. As written it only supports logging at information level. Output looks like this:
using System;
using System.Collections.Generic;
using Serilog;
using Serilog.Sinks.SystemConsole.Themes;
namespace main1
{
static class LoggerExtensions
{
public const string BackgroundBlack = "\u001b[40m";
public const string BackgroundRed = "\u001b[41m";
public const string BackgroundGreen = "\u001b[42m";
public const string BackgroundYellow = "\u001b[43m";
public const string BackgroundBlue = "\u001b[44m";
public const string BackgroundMagenta = "\u001b[45m";
public const string BackgroundCyan = "\u001b[46m";
public const string BackgroundWhite = "\u001b[47m";
public const string BackgroundBrightBlack = "\u001b[40;1m";
public const string BackgroundBrightRed = "\u001b[41;1m";
public const string BackgroundBrightGreen = "\u001b[42;1m";
public const string BackgroundBrightYellow = "\u001b[43;1m";
public const string BackgroundBrightBlue = "\u001b[44;1m";
public const string BackgroundBrightMagenta = "\u001b[45;1m";
public const string BackgroundBrightCyan = "\u001b[46;1m";
public const string BackgroundBrightWhite = "\u001b[47;1m";
public static List<int> AllIndexesOf(this string str, string value)
{
if (String.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", "value");
List<int> indexes = new List<int>();
for (int index = 0; ; index += value.Length)
{
index = str.IndexOf(value, index);
if (index == -1)
return indexes;
indexes.Add(index);
}
}
public static void BkColor(
this ILogger logger,
string messageTemplate,
params object[] args)
{
// Get the color they chose
string CurrentColor = (string)args[args.GetLength(0)-1];
// Get rid of the color parameter now as it will break the Serilog parser
args[args.GetLength(0)-1] = "";
// Prepend our color code to every argument (tested with strings and numbers)
for (int i = 0; i < args.GetLength(0); i++)
{
args[i] = CurrentColor + args[i];
}
// Find all the arguments looking for the close bracket
List<int> indexes = messageTemplate.AllIndexesOf("}");
int iterations = 0;
// rebuild messageTemplate with our color-coded arguments
// Note: we have to increase the index on each iteration based on the previous insertion of
// a color code
foreach (var i in indexes)
{
messageTemplate = messageTemplate.Insert(i + 1 + (iterations++ * CurrentColor.Length), CurrentColor);
}
// Prefix the entire message template with color code
string bkg = CurrentColor + messageTemplate;
// Log it with a context
logger.ForContext("IsImportant", true)
.Information(bkg, args);
}
}
class Program
{
static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Async(a => a.Console(theme: AnsiConsoleTheme.Code))
.CreateLogger();
Log.Information("Hello, Async Serilog!");
Log.Fatal("This is really bad!");
Log.Logger.BkColor("Hello, {Name}! How are you {Today}? Pi is {Pi}", "World", "Today", 3.14159,LoggerExtensions.BackgroundBrightRed);
Log.Logger.BkColor("Hello World", LoggerExtensions.BackgroundBrightGreen);
Log.Logger.BkColor("Hello World. Today is {date}", DateTime.Now, LoggerExtensions.BackgroundBrightMagenta);
Log.CloseAndFlush();
Console.ReadKey();
}
}
}
Complete code at this gist: https://gist.github.com/bwedding/fd12e1ae1a4045b6c797e9d13319d751
is there anyway to obtain an output like this using theme?