Example in-memory queue console logger, part of the ASP.NET core Logging Extensions library. Referenced in Logging in .NET Core and ASP.NET Core, No asynchronous logger methods.
// ----------------------------------------------------------------------------
// ConsoleLoggerProcessor.cs
// https://github.com/aspnet/Logging/blob/master/src/Microsoft.Extensions.Logging.Console/Internal/ConsoleLoggerProcessor.cs
// ----------------------------------------------------------------------------
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace Microsoft.Extensions.Logging.Console.Internal
{
public class ConsoleLoggerProcessor : IDisposable
{
private const int _maxQueuedMessages = 1024;
private readonly BlockingCollection<LogMessageEntry> _messageQueue = new BlockingCollection<LogMessageEntry>(_maxQueuedMessages);
private readonly Thread _outputThread;
public IConsole Console;
public IConsole ErrorConsole;
public ConsoleLoggerProcessor()
{
// Start Console message queue processor
_outputThread = new Thread(ProcessLogQueue)
{
IsBackground = true,
Name = "Console logger queue processing thread"
};
_outputThread.Start();
}
public virtual void EnqueueMessage(LogMessageEntry message)
{
if (!_messageQueue.IsAddingCompleted)
{
try
{
_messageQueue.Add(message);
return;
}
catch (InvalidOperationException) { }
}
// Adding is completed so just log the message
WriteMessage(message);
}
// for testing
internal virtual void WriteMessage(LogMessageEntry message)
{
var console = message.LogAsError ? ErrorConsole : Console;
if (message.TimeStamp != null)
{
console.Write(message.TimeStamp, message.MessageColor, message.MessageColor);
}
if (message.LevelString != null)
{
console.Write(message.LevelString, message.LevelBackground, message.LevelForeground);
}
console.Write(message.Message, message.MessageColor, message.MessageColor);
console.Flush();
}
private void ProcessLogQueue()
{
try
{
foreach (var message in _messageQueue.GetConsumingEnumerable())
{
WriteMessage(message);
}
}
catch
{
try
{
_messageQueue.CompleteAdding();
}
catch { }
}
}
public void Dispose()
{
_messageQueue.CompleteAdding();
try
{
_outputThread.Join(1500); // with timeout in-case Console is locked by user input
}
catch (ThreadStateException) { }
}
}
}
// ----------------------------------------------------------------------------
// IConsole.cs
// https://github.com/aspnet/Logging/blob/master/src/Microsoft.Extensions.Logging.Console/Internal/IConsole.cs
// ----------------------------------------------------------------------------
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.Extensions.Logging.Console.Internal
{
public interface IConsole
{
void Write(string message, ConsoleColor? background, ConsoleColor? foreground);
void WriteLine(string message, ConsoleColor? background, ConsoleColor? foreground);
void Flush();
}
}
// ----------------------------------------------------------------------------
// LogMessageEntry.cs
// https://github.com/aspnet/Logging/blob/master/src/Microsoft.Extensions.Logging.Console/Internal/LogMessageEntry.cs
// ----------------------------------------------------------------------------
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.Extensions.Logging.Console.Internal
{
public struct LogMessageEntry
{
public string TimeStamp;
public string LevelString;
public ConsoleColor? LevelBackground;
public ConsoleColor? LevelForeground;
public ConsoleColor? MessageColor;
public string Message;
public bool LogAsError;
}
}