Consider This New Logging Framework
This article corresponds with the MSDN article: Essential .NET – Logging with .NET Core. This GitHub repo contains the code referenced in the article. Not, in particular, the unit test LogCritical_Exception_Success
for an example of handling an exception using the custom logger.
public void LogCritical_Exception_Success()
{
string message = "The amount of caffeine has reach critical levels.";
CustomLogger.CustomLogger customLogger = null;
CustomLoggerProvider logProvider =
new CustomLoggerProvider((sender, eventArgs) => customLogger = eventArgs.CustomLogger);
ApplicationLogging.LoggerFactory.AddProvider(logProvider);
Logger.LogCritical(message, new Exception("Sample exception."));
Assert.AreEqual($"{message}\r\nSystem.Exception: Sample exception.", customLogger.LogDataQueue.Dequeue());
}
The Custom Logger implementation is straightforward:
public class CustomLogger : ILogger
{
public Queue LogDataQueue = new Queue();
public IDisposable BeginScopeImpl(object state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
{
string message = string.Empty;
if (formatter != null)
{
message = formatter(state, exception);
}
else
{
message = LogFormatter.Formatter(state, exception);
}
LogDataQueue.Enqueue(message);
}
}
Here is the the extension method for adding a custom logger provider:
public static class CustomLoggerFactoryExtensions
{
public static ILoggerFactory AddCustomLogger(
this ILoggerFactory factory, out CustomLoggerProvider logProvider)
{
logProvider = new CustomLoggerProvider();
factory.AddProvider(logProvider);
return factory;
}
}
The custom logger provider:
public class CustomLoggerProvider : ILoggerProvider
{
public CustomLoggerProvider() { }
public CustomLoggerProvider(EventHandler onCreateLogger)
{
OnCreateLogger = onCreateLogger;
}
public ConcurrentDictionary<string, customlogger=""> Loggers { get; set; } = new ConcurrentDictionary<string, customlogger="">();
public ILogger CreateLogger(string categoryName)
{
CustomLogger customLogger = Loggers.GetOrAdd(categoryName, new CustomLogger());
OnCreateLogger?.Invoke(this, new CustomLoggerProviderEventArgs(customLogger));
return customLogger;
}
public void Dispose() { }
public event EventHandler OnCreateLogger = delegate { };
}
</string,></string,>
The provider event args:
public class CustomLoggerProviderEventArgs
{
public CustomLogger CustomLogger { get; }
public CustomLoggerProviderEventArgs(CustomLogger logger)
{
CustomLogger = logger;
}
}
One uses the ApplicationLogging static class to set up the custom logger with the following pattern:
public static class ApplicationLogging
{
public static ILoggerFactory LoggerFactory { get; } = new LoggerFactory();
public static ILogger CreateLogger() =>
LoggerFactory.CreateLogger();
}
* The following pattern will set up the custom logger
CustomLogger.CustomLogger customLogger = null;
CustomLoggerProvider logProvider =
new CustomLoggerProvider((sender, eventArgs) => customLogger = eventArgs.CustomLogger);
ApplicationLogging.LoggerFactory.AddProvider(logProvider);
*/
Have a Question?
Check out my other tutorials and leave any questions in the comment section below!
thank you so much for articulating everything at one place, i just downloaded from git and started debugging and able to understand fully
Hi,
Thanks for the nice article,
I have one question, i want to pass caller method name to log, how can i do that?
Dilip,
Mark said the approach, starting with C# 10, would be to use the CallerArgumentExpressionAttribute. He’s writing a blog about this very subject that you should see on our blog in the near future. Thanks for the read!
How do I pass and read custom object in the log method implementation of my custom logger?
// Write log message
myCustomLogger.LogError(“My Message”, customDataObject);
// Log method implementation
public void Log(…)
In other words, How do I read customDataObject in above Log method?
Thanks in advance.
string formatter(Message msg, Exception ex)
{
var content = $”[{logLevel}]\r\n{msg.Title}\r\n{msg.Body}\r\n{msg.Author}\r\n{msg.CreatedDate}\r\n\r\n”;
return content;
}
log.Log(logLevel, new EventId(), message, null, (msg, ex) => formatter(msg, ex));
where Message is a custom object -> in yout custom provider, “TState state” parameter of Log method will be your passed object
How does this handle exceptions? I was kind of thinking that CustomLogger.Log() would implement try/catch logic to handle exceptions.
Agreed.. this doesn’t actually improve on the original at all.
I’m interested to learn coustom logger stored at mongodb
I want to implement Ilogger for any third party logger such as Nlog or Log4net
I need to learn about Ilogger