Logging in a C# library
What is the best pra开发者_运维知识库ctise regarding logging inside a library?
I am creating a C# library to be used by users and at some points I want to log an error or a warning. Is it a good practice to use log4net and log in a file?
I use log4net in my own library but I would not do this if my library should be used by others (i.e. outside of my organization). In that case I would use an interface for logging, provide a default implementation based on log4net in separate assembly and use one way or another to allow the users of the library to inject their own implementation.
Having said this: I really like log4net and would not use anything else, but I think it is wrong to force others to have to use the logging framework of your choice.
Edit:
- I would also not consider it good practice having the library log to a file by default. The users of your library should be able to decide where log messages end-up.
- I would also provide a "no-operation" implementation that can be used if no logging at all is required. This probably should be default behavior an not require any additional assemblies or steps to implement.
All the answers here seems outdated. I will make a new one:
My library asks for an optional Microsoft.Extensions.Logging.ILogger
object to write log messsages. Without the ILogger
object then it simply won't log anything.
The consumer application can create this ILogger
object using NLog, Log4Net or SeriLog.. and my library can be used in ASP.NET core application with no log framework lock-in.
Example creating a Microsoft ILogger using other lggging framework
private static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddNLog(); //=>install NLog.Extensions.Logging nuget
//or builder.AddSerilog(); => install Serilog.Extensions.Logging nuget
//or builder.AddLog4Net() //=> Microsoft.Extensions.Logging.Log4Net.AspNetCore
});
private static readonly ILogger<Program> log = loggerFactory.CreateLogger<Program>();
//configure nlog/serilog/log4net normally then
log.LogInformation("Hello");
In case Log4Net, you can also
ILoggerFactory loggerFactory = new LoggerFactory();
loggerFactory.AddLog4Net(); //load log4net.config by default
The beauty of using log4net is that your library doesn't have to specify where something is logged. The destination (log appenders) of the log messages is determined by the configuration, which is specified by the application (typically in a config file).
So yes, use log4net following their recommended patterns (a unique "logger" per class) and inform your users that your library uses log4net. Any log messages that your library code generates will be routed according to the consumers configuration (file, database, console, trace, etc).
EDIT: Here is a good short primer on log4net that explains the basic concepts.
I would be wary of introducing a dependency on a 3rd party library such as log4net in a general-purpose class library: I would prefer to leave it to the caller to decide how to do logging. What if the user of the library is already using a different logging framework?
Some alternatives are:
For errors, throw an
Exception
or allow one to propagate, and let the caller handle it and do any logging.For warnings (e.g. an Exception that you handle in the library), you could consider raising an event that the caller can handle if he wants to log it. For example, you could raise an
Error
event that takes aSystem.IO.ErrorEventArgs
(or a similar customEventArgs
) with details of the error.If you feel the library needs more instrumentation, you could raise more events at strategic points in your library that the caller can handle to do logging.
Alternatively, you could define an interface in your class library (
ILogging
or similar) that callers have to implement if they want logging. Have callers pass an instance of this interface to a class constructor to enable logging.You can do something similar to logging in the AWS SDK for .NET, i.e. support multiple logging frameworks, but load 3rd party frameworks using reflection so as not to create a dependency. I personally don't like this, but it's a valid approach, especially if your library is big enough to justify detailed instrumentation.
Practice vise a good way to do it is to introduce a Logging facade, so you don't care about the logger you use, you have a consistent common interface for the logger.
for e.g you could try this or simply write your own.
log4net is just a 3rd party library, its not best practice that you must use that as your logging library when using C#. My advice would be always persist the log to somewhere (most common being a text file). However, there is also the event log (requires a little extra setup).
I tend to use NLog which I find is very easy to use and simple to setup. As for logging inside your class libraries its really just which ever approach you feel is best for your application. Some people would create 1 logger and pass it down into the classes, others would create a separate logger per loggable
class. I tend to create a static logger per class and it works fine.
In my opinion, it never hurts to wrap logging in your own small adapter, for example, to later easily strip logging from production. I created a small logging wrapper for this, its API looks like this:
Log.d("I'm a log message");
Log.w("I'm a warning with parmas", "param 1", 2, "..");
Log.e("I'm an error");
Log.e(new Exception("I'm an exception"));
AssertV2.IsTrue(1 + 1 == 3, "This assertion will fail");
See https://github.com/cs-util-com/cscore#logging for more examples
You can log to the console, a file, Unity and can easily add more complex logging targets like e.g. Serilog
Let me know if you have suggestions or other feedback, I want to keep it as small as possible but want to learn about use cases it would not cover yet
精彩评论