我正在用C#.NET 3.5编写一个类库程序集,用于与其他应用程序集成,包括第三方商用现成(COTS)工具.因此,有时这个类库将由我控制的应用程序(EXE)调用,而有时它将被其他DLL或我无法控制的应用程序调用.
任何解决方案必须
要么
当我的独立类库由我无法控制的DLL或应用程序(例如第三方COTS工具)调用且未指定log4net配置信息时,我的类库无法执行任何日志记录.
如何为独立类库程序集配置和启用log4net,以便无论调用应用程序是否提供log4net配置,它都将记录?
Jac*_*cob 12
您可以在XmlConfigurator类周围编写代码:
public static class MyLogManager
{
// for illustration, you should configure this somewhere else...
private static string configFile = @"path\to\log4net.config";
public static ILog GetLogger(Type type)
{
if(log4net.LogManager.GetCurrentLoggers().Length == 0)
{
// load logger config with XmlConfigurator
log4net.Config.XmlConfigurator.Configure(configFile);
}
return LogManager.GetLogger(type);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的课程中,而不是:
private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));
Run Code Online (Sandbox Code Playgroud)
使用:
private static readonly ILog log = MyLogManager.GetLogger(typeof(MyApp));
Run Code Online (Sandbox Code Playgroud)
当然,最好将此类作为服务并使用您选择的IoC容器动态配置它,但您明白了吗?
编辑:修复注释中指出的Count()问题.
Zac*_*ame 12
第一组约束的解决方案是基本上将log4net.LogManager包装到您自己的自定义LogManager类中,如Jacob,Jeroen和McWafflestix所建议的(参见下面的代码).
不幸的是,log4net.LogManager类是静态的,C#不支持静态继承,因此您不能简单地继承它并覆盖GetLogger方法.但是,log4net.LogManager类中没有太多方法,所以这肯定是可能的.
这个解决方案的另一个缺点是,如果你有一个现有的代码库(我在我的情况下),你将不得不用你的包装类替换所有现有的log4net.LogManager调用.然而,今天的重构工具并没有什么大不了的.
对于我的项目,这些缺点超过了使用调用应用程序提供的日志记录配置的好处,因此,我选择了解决方案2.
首先,您需要一个LogManager包装类:
using System;
using System.IO;
using log4net;
using log4net.Config;
namespace MyApplication.Logging
{
//// TODO: Implement the additional GetLogger method signatures and log4net.LogManager methods that are not seen below.
public static class LogManagerWrapper
{
private static readonly string LOG_CONFIG_FILE= @"path\to\log4net.config";
public static ILog GetLogger(Type type)
{
// If no loggers have been created, load our own.
if(LogManager.GetCurrentLoggers().Length == 0)
{
LoadConfig();
}
return LogManager.GetLogger(type);
}
private void LoadConfig()
{
//// TODO: Do exception handling for File access issues and supply sane defaults if it's unavailable.
XmlConfigurator.ConfigureAndWatch(new FileInfo(LOG_CONFIG_FILE));
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的课程中,而不是:
private static readonly ILog log = LogManager.GetLogger(typeof(MyApp));
Run Code Online (Sandbox Code Playgroud)
使用:
private static readonly ILog log = LogManagerWrapper.GetLogger(typeof(MyApp));
Run Code Online (Sandbox Code Playgroud)
出于我的目的,我决定采用符合第二组约束的解决方案.请参阅下面的代码了解我的解决方案
"程序集可以选择使用命名的日志存储库而不是默认存储库.这会将程序集的日志记录与应用程序的其余部分完全分开.这对于希望将log4net用于其组件的组件开发人员非常有用.不希望要求所有使用其组件的应用程序都知道log4net.这也意味着他们的调试配置与应用程序配置分离.程序集应指定RepositoryAttribute来设置其日志存储库."
我将以下行放在我的类库的AssemblyInfo.cs文件中:
Run Code Online (Sandbox Code Playgroud)// Log4Net configuration file location [assembly: log4net.Config.Repository("CompanyName.IntegrationLibName")] [assembly: log4net.Config.XmlConfigurator(ConfigFile = "CompanyName.IntegrationLibName.config", Watch = true)]
在您的代码中,您可以检查是否有任何记录器通过
log4net.LogManager.GetCurrentLoggers().Count()
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用XmlConfigurator从文件加载默认配置:
log4net.Config.XmlConfigurator.Configure(configFile)
Run Code Online (Sandbox Code Playgroud)
您可以在静态或常规构造函数中进行初始化.
class Sample
{
private static readonly log4net.ILog LOG;
static Sample()
{
if (log4net.LogManager.GetCurrentLoggers().Count() == 0)
{
loadConfig();
}
LOG = log4net.LogManager.GetLogger(typeof(Sample));
}
private static void loadConfig()
{
/* Load your config file here */
}
public void YourMethod()
{
LOG.Info("Your messages");
}
}
Run Code Online (Sandbox Code Playgroud)