背景
我正在 C# .NET 3.5 中编写一个类库程序集,用于与其他应用程序集成,包括第三方商业现成 (COTS) 工具。 因此,有时这个类库会被我控制的应用程序(EXE)调用,而有时它会被我不控制的其他DLL或应用程序调用。
假设
- 我使用的是 C# 3.0、.NET 3.5 SP1 和 Visual Studio 2008 SP1
- 我使用的是 log4net 1.2.10.0 或更高
版本 限制
任何解决方案都必须:
- 允许类库通过其自己的配置文件启用和配置日志记录(如果调用)应用程序未配置 log4net。
- 允许类库通过调用应用程序配置启用和配置日志记录,
如果指定了 log4net 信息,则
- 或者允许类库始终使用其自己的配置文件启用和配置日志记录。
问题
当我的独立类库由我无法控制的 DLL 或应用程序(例如第三方 COTS 工具)调用并且未指定 log4net 配置信息时,我的类库无法执行任何操作记录。
问题
如何为独立类库程序集配置和启用 log4net,以便无论调用应用程序是否提供 log4net 配置它都会记录日志?
Background
I am writing a class library assembly in C# .NET 3.5 which is used for integration with other applications including third-party Commercial-Off-The-Shelf (COTS) tools. Therefore, sometimes this class library will be called by applications (EXEs) that I control while other times it will be called by other DLLs or applications that I do not control.
Assumptions
- I am using C# 3.0, .NET 3.5 SP1, and Visual Studio 2008 SP1
- I am using log4net 1.2.10.0 or greater
Constraints
Any solution must:
- Allow for the class library to enable and configure logging via it's own configuration file, if the calling application does not configure log4net.
- Allow for the class library to enable and configuring logging via the calling applications configuration, if it specifies log4net information
OR
- Allow for the class library to enable and configuring logging using it's own configuration file at all times.
Problem
When my stand-alone class library is called by a DLL or application that I do not control (such as a third-party COTS tool) and which doesn't specify log4net configuration information, my class library is unable to do any of it's logging.
Question
How do you configure and enable log4net for a stand-alone class library assembly so that it will log regardless if the calling application provides log4net configuration?
发布评论
评论(6)
您可以在这里找到一个很好的描述:
log4net:快速入门指南
该文章描述了,要分别在每个程序集之前配置它,请为名为
AssemblyName.dll.log4net
的程序集创建一个 XML 文件,并将以下 XML 代码放入其中:它进一步描述了实例化新记录器,只需将其声明为整个类的变量,如下所示:
然后您可以在类中使用私有变量
Log
,例如:同样,您可以使用
Log.Error(“运行时发生错误” myMethod", ex)
来记录错误以及异常详细信息。我发现的是以下内容:
不要忘记调用
log4net.Config.XmlConfigurator.Configure();
来激活您的配置如果您需要知道写入文件的路径,这里一些代码如何从Log4Net获取它
我希望这有帮助。
You can find a good description here:
log4net: A quick start guide
As the article describes, to configure it fore each assembly separately, create an XML file for your assembly named
AssemblyName.dll.log4net
and place the following XML code into it:It further describes, to instantiate a new logger, simply declare it as a variable for the entire class as follows:
You can then use the private variable
Log
inside your class like:Likewise you can use
Log.Error("Error occurred while running myMethod", ex)
to log errors along with the exception details.What I found is the following:
Don't forget to call
log4net.Config.XmlConfigurator.Configure();
to activate your configurationIf you need to know the path of the file(s) written, here some code how to obtain it from Log4Net
I hope this helps.
这对我来说适用于共享库
This works for me for a shared library
解决方案 1
第一组约束的解决方案基本上是包装 log4net。 LogManager 到您自己的自定义 LogManager 类中,例如 雅各布,Jeroen,和 McWafflestix 已建议(请参阅下面的代码)。
不幸的是,log4net.LogManager 类是静态的,C# 不支持静态继承,因此您不能简单地继承它并重写 GetLogger 方法。
log4net.LogManager 类,所以这当然是可能的。
此解决方案的另一个缺点是,如果您有现有的代码库(在我的例子中就是这样做的),您将必须用包装类替换对 log4net.LogManager 的所有现有调用。 然而对于今天的重构工具来说这没什么大不了的。
对于我的项目,这些缺点超过了使用调用应用程序提供的日志配置的好处,因此,我选择了解决方案 2。
代码
首先,您需要一个 LogManager 包装类:
然后在您的类中,而不是:
使用:
方案 2
解决 根据我的目的,我决定采用满足第二组约束的解决方案。 请参阅下面的代码了解我的解决方案。
来自 Apache log4net 文档:
“程序集可以选择使用命名的日志存储库而不是默认存储库,这将程序集的日志记录与应用程序的其余部分完全分开,这对于希望为其组件使用 log4net 但又不想要求所有这些的组件开发人员非常有用。使用其组件的应用程序知道 log4net。这也意味着它们的调试配置与应用程序配置分开。程序集应指定 RepositoryAttribute 来设置其日志记录存储库。”
代码
我将以下几行放在了我的类库的 AssemblyInfo.cs 文件:
参考文献
Solution 1
A solution for the first set of constraints is to basically wrap the log4net.LogManager into your own custom LogManager class like Jacob, Jeroen, and McWafflestix have suggested (see code below).
Unfortunately, the log4net.LogManager class is static and C# doesn't support static inheritance, so you couldn't simply inherit from it and override the GetLogger method.
There aren't too many methods in the log4net.LogManager class however, so this is certainly a possibility.
The other drawback to this solution is that if you have an existing codebase (which I do in my case) you would have to replace all existing calls to log4net.LogManager with your wrapper class. Not a big deal with today's refactoring tools however.
For my project, these drawbacks outweighed the benefits of using a logging configuration supplied by the calling application so, I went with Solution 2.
Code
First, you need a LogManager wrapper class:
Then in your classes, instead of:
Use:
Solution 2
For my purposes, I have decided to settle on a solution that meets the second set of constraints. See the code below for my solution.
From the Apache log4net document:
"An assembly may choose to utilize a named logging repository rather than the default repository. This completely separates the logging for the assembly from the rest of the application. This can be very useful to component developers that wish to use log4net for their components but do not want to require that all the applications that use their component are aware of log4net. It also means that their debugging configuration is separated from the applications configuration. The assembly should specify the RepositoryAttribute to set its logging repository."
Code
I placed the following lines in the AssemblyInfo.cs file of my class library:
References
您可以围绕 XmlConfigurator 类编写一些代码:
然后在你的类中,而不是:
使用:
当然,最好让这个类成为一个服务并使用你选择的 IoC 容器动态配置它,但是你明白了吗?
编辑:修复了评论中指出的 Count() 问题。
You can probably code something around the XmlConfigurator class:
Then in your classes, instead of:
Use:
Of course, it would be preferable to make this class a service and dynamically configure it with the IoC container of your choice, but you get the idea?
EDIT: Fixed Count() problem pointed out in comments.
在代码中,您可以通过检查是否有任何记录器,
然后您可以使用 XmlConfigurator 从文件加载默认配置:
您可以在静态或常规构造函数中进行初始化。
In your code you can check if there are any loggers via
You could then for example use an XmlConfigurator to load a default configuration from a file:
You could do the initialization in a static or regular constructor.
在独立类库中,有一个使用
log4net.Config.XmlConfigurator
加载log4net
配置文件的单例。具体来说,您可以定义所有代码以使用您自己的自定义日志记录类; 这个类可以只是 log4net 日志记录调用的简单包装,但有一个补充; 创建一个静态成员,其中包含您要记录的日志信息; 通过调用该类的静态构造函数中的 XmlConfigurator 来初始化它。 这就是你所要做的。
In your standalone class library, have a singleton which loads the
log4net
configuration file using thelog4net.Config.XmlConfigurator
.Specifically, you can define all of your code to use your own custom logging class; this class can just be a simple wrapper of the log4net logging calls, with one addition; make a static member which contains the log information you want to log to; initialize that with a call to the XmlConfigurator in the static constructor for that class. That's all you have to do.