如何从头开始以编程方式配置 log4net(无配置)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/769983/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to configure log4net programmatically from scratch (no config)
提问by John M Gant
This is a Bad Idea, I know, but... I want to configure log4net programmatically from scratch with no config file. I'm working on a simple logging application for me and my team to use for a bunch of relatively small departmental applications we're responsible for. I want them to all log to the same database. The logging application is just a wrapper around log4net with the AdoNetAppender preconfigured.
这是一个坏主意,我知道,但是......我想从头开始以编程方式配置 log4net,没有配置文件。我正在为我和我的团队开发一个简单的日志记录应用程序,用于我们负责的一系列相对较小的部门应用程序。我希望他们都登录到同一个数据库。日志应用程序只是预配置了 AdoNetAppender 的 log4net 的包装器。
All of the applications are ClickOnce deployed, which presents a small problem with deploying the config file. If the config file were part of the core project, I could set its properties to deploy with the assembly. But it's part of a linked application, so I don't have the option of deploying it with the main application. (If that's not true, somebody please let me know).
所有应用程序都是 ClickOnce 部署的,这在部署配置文件时存在一个小问题。如果配置文件是核心项目的一部分,我可以设置它的属性以与程序集一起部署。但它是链接应用程序的一部分,因此我无法选择将它与主应用程序一起部署。(如果这不是真的,请有人告诉我)。
Probably because it's a Bad Idea, there doesn't seem to be much sample code available for programmatically configruating log4net from scratch. Here's what I have so far.
可能是因为这是一个坏主意,似乎没有多少示例代码可用于从头开始以编程方式配置 log4net。这是我到目前为止所拥有的。
Dim apndr As New AdoNetAppender()
apndr.CommandText = "INSERT INTO LOG_ENTRY (LOG_DTM, LOG_LEVEL, LOGGER, MESSAGE, PROGRAM, USER_ID, MACHINE, EXCEPTION) VALUES (@log_date, @log_level, @logger, @message, @program, @user, @machine, @exception)"
apndr.ConnectionString = connectionString
apndr.ConnectionType = "System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
apndr.CommandType = CommandType.Text
Dim logDate As New AdoNetAppenderParameter()
logDate.ParameterName = "@log_date"
logDate.DbType = DbType.DateTime
logDate.Layout = New RawTimeStampLayout()
apndr.AddParameter(logDate)
Dim logLevel As New AdoNetAppenderParameter()
logLevel.ParameterName = "@log_level"
'And so forth...
After configuring all the parameters for apndr, I at first tried this...
在为 配置了所有参数后apndr,我首先尝试了这个...
Dim hier As Hierarchy = DirectCast(LogManager.GetRepository(), Hierarchy)
hier.Root.AddAppender(apndr)
It didn't work. Then, as a shot in the dark, I tried this instead.
它没有用。然后,作为在黑暗中的一个镜头,我尝试了这个。
BasicConfigurator.Configure(apndr)
That didn't work either. Does anybody have any good references on how to configure log4net programmatically from scratch with no config file?
那也没有用。有人对如何在没有配置文件的情况下从头开始以编程方式配置 log4net 有任何好的参考吗?
采纳答案by Jonathan Rupp
One way I've done this in the past is to include the configuration file as an embedded resource, and just used log4net.Config.Configure(Stream).
我过去这样做的一种方法是将配置文件作为嵌入式资源包含在内,并且只使用log4net.Config.Configure(Stream)。
That way, I could use the configuration syntax I was familiar with, and didn't have to worry about getting a file deployed.
这样,我可以使用我熟悉的配置语法,而不必担心部署文件。
回答by Todd Stout
Here's an example class that creates log4net config completely in code. I should mention that creating a logger via a static method is generally viewed as bad, but in my context, this is what I wanted. Regardless, you can carve up the code to meet your needs.
这是一个示例类,它完全在代码中创建 log4net 配置。我应该提到通过静态方法创建记录器通常被认为是不好的,但在我的上下文中,这就是我想要的。无论如何,您可以分割代码以满足您的需求。
using log4net;
using log4net.Repository.Hierarchy;
using log4net.Core;
using log4net.Appender;
using log4net.Layout;
namespace dnservices.logging
{
public class Logger
{
private PatternLayout _layout = new PatternLayout();
private const string LOG_PATTERN = "%d [%t] %-5p %m%n";
public string DefaultPattern
{
get { return LOG_PATTERN; }
}
public Logger()
{
_layout.ConversionPattern = DefaultPattern;
_layout.ActivateOptions();
}
public PatternLayout DefaultLayout
{
get { return _layout; }
}
public void AddAppender(IAppender appender)
{
Hierarchy hierarchy =
(Hierarchy)LogManager.GetRepository();
hierarchy.Root.AddAppender(appender);
}
static Logger()
{
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
TraceAppender tracer = new TraceAppender();
PatternLayout patternLayout = new PatternLayout();
patternLayout.ConversionPattern = LOG_PATTERN;
patternLayout.ActivateOptions();
tracer.Layout = patternLayout;
tracer.ActivateOptions();
hierarchy.Root.AddAppender(tracer);
RollingFileAppender roller = new RollingFileAppender();
roller.Layout = patternLayout;
roller.AppendToFile = true;
roller.RollingStyle = RollingFileAppender.RollingMode.Size;
roller.MaxSizeRollBackups = 4;
roller.MaximumFileSize = "100KB";
roller.StaticLogFileName = true;
roller.File = "dnservices.txt";
roller.ActivateOptions();
hierarchy.Root.AddAppender(roller);
hierarchy.Root.Level = Level.All;
hierarchy.Configured = true;
}
public static ILog Create()
{
return LogManager.GetLogger("dnservices");
}
}
}
}
回答by Pavel Chuchuva
More concise solution:
更简洁的解决方案:
var layout = new PatternLayout("%-4timestamp [%thread] %-5level %logger %ndc - %message%newline");
var appender = new RollingFileAppender {
File = "my.log",
Layout = layout
};
layout.ActivateOptions();
appender.ActivateOptions();
BasicConfigurator.Configure(appender);
Don't forget to call ActivateOptionsmethod:
不要忘记调用ActivateOptions方法:
The ActivateOptions method must be called on this object after the configuration properties have been set. Until ActivateOptions is called this object is in an undefined state and must not be used.
设置配置属性后,必须在此对象上调用 ActivateOptions 方法。在调用 ActivateOptions 之前,此对象处于未定义状态,不得使用。
回答by Joe
As Jonathansays, using a resource is a good solution.
正如乔纳森所说,使用资源是一个很好的解决方案。
It's a bit restrictive in that the embedded resource contents will be fixed at compile time. I have a logging component that generates an XmlDocument with a basic Log4Net configuration, using variables defined as appSettings (e.g. filename for a RollingFileAppender, default logging level, maybe connection string name if you want to use an AdoNetAppender). And then I call log4net.Config.XmlConfigurator.Configureto configure Log4Net using the root element of the generated XmlDocument.
这有点限制,因为嵌入的资源内容将在编译时固定。我有一个日志组件,它使用定义为 appSettings 的变量(例如,RollingFileAppender 的文件名、默认日志记录级别,如果您想使用 AdoNetAppender,可能是连接字符串名称)生成具有基本 Log4Net 配置的 XmlDocument。然后我调用log4net.Config.XmlConfigurator.Configure使用生成的 XmlDocument 的根元素来配置 Log4Net。
Then administrators can customise the "standard" configuration by modifying a few appSettings (typically level, filename, ...) or can specify an external configuration file to get more control.
然后管理员可以通过修改一些 appSettings(通常是级别、文件名等)来自定义“标准”配置,或者可以指定外部配置文件以获得更多控制。
回答by RodKnee
I can't tell in the question's code snippet if the "'And so forth..." includes the very important apndr.ActivateOptions() which is indicated in Todd Stout's answer. Without ActivateOptions() the Appender is inactive and will not do anything which could explain why it is failing.
我无法在问题的代码片段中判断“'等等...”是否包含非常重要的 apndr.ActivateOptions(),这在 Todd Stout 的回答中有所说明。如果没有 ActivateOptions(),Appender 是不活动的,并且不会做任何可以解释它为什么失败的事情。
回答by oleksii
A bit late for the party. But here is a minimal config that worked for me.
聚会有点晚了。但这里有一个对我有用的最小配置。
Sample class
示例类
public class Bar
{
private readonly ILog log = LogManager.GetLogger(typeof(Bar));
public void DoBar() { log.Info("Logged"); }
}
Minimal log4net trace config (inside NUnit test)
最小的 log4net 跟踪配置(在 NUnit 测试中)
[Test]
public void Foo()
{
var tracer = new TraceAppender();
var hierarchy = (Hierarchy)LogManager.GetRepository();
hierarchy.Root.AddAppender(tracer);
var patternLayout = new PatternLayout {ConversionPattern = "%m%n"};
tracer.Layout = patternLayout;
hierarchy.Configured = true;
var bar = new Bar();
bar.DoBar();
}
Prints to the trace listener
打印到跟踪侦听器
Namespace+Bar: Logged
回答by Jeroen K
Dr. Netjeshas this for setting the connectionstring programmatically:
// Get the Hierarchy object that organizes the loggers
log4net.Repository.Hierarchy.Hierarchy hier =
log4net.LogManager.GetLoggerRepository() as log4net.Repository.Hierarchy.Hierarchy;
if (hier != null)
{
//get ADONetAppender
log4net.Appender.ADONetAppender adoAppender =
(log4net.Appender.ADONetAppender)hier.GetLogger("MyProject",
hier.LoggerFactory).GetAppender("ADONetAppender");
if (adoAppender != null)
{
adoAppender.ConnectionString =
System.Configuration.ConfigurationSettings.AppSettings["MyConnectionString"];
adoAppender.ActivateOptions(); //refresh settings of appender
}
}
回答by zeb ula
// I've embedded three config files as an Embedded Resource and access them like this:
// 我已经将三个配置文件作为嵌入式资源嵌入并像这样访问它们:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Resources;
using System.IO;
namespace Loader
{
class Program
{
private static log4net.ILog CustomerLog = log4net.LogManager.GetLogger("CustomerLogging");
private static log4net.ILog OrderLog = log4net.LogManager.GetLogger("OrderLogging");
private static log4net.ILog DetailsLog = log4net.LogManager.GetLogger("OrderDetailLogging");
static void Main(string[] args)
{
// array of embedded log4net config files
string[] configs = { "Customer.config", "Order.config", "Detail.config"};
foreach (var config in configs)
{
// build path to assembly config
StringBuilder sb = new StringBuilder();
sb.Append(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
sb.Append(".");
sb.Append(config);
// convert to a stream
Stream configStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(sb.ToString());
// configure logger with ocnfig stream
log4net.Config.XmlConfigurator.Configure(configStream);
// test logging
CustomerLog.Info("Begin logging with: " + config);
OrderLog.Info("Begin logging with: " + config);
DetailsLog.Info("Begin logging with: " + config);
for (int iX = 0; iX < 10; iX++)
{
CustomerLog.Info("iX=" + iX);
OrderLog.Info("iX=" + iX);
DetailsLog.Info("iX=" + iX);
}
CustomerLog.Info("Ending logging with: " + config);
OrderLog.Info("Ending logging with: " + config);
DetailsLog.Info("Ending logging with: " + config);
}
}
}
}
回答by Mel Padden
I ended up using this:
我最终使用了这个:
http://www.mikebevers.be/blog/2010/09/log4net-custom-adonetappender/
http://www.mikebevers.be/blog/2010/09/log4net-custom-adonetappender/
After 4 hours fiddling with the config and getting progressively more frustrated.
摆弄配置 4 小时后,越来越沮丧。
Hope it helps someone.
希望它可以帮助某人。
回答by vlad2135
It is strange that BasicConfigurator.Configure(apndr)did not work. In my case it did its job... But, anyway, here goes the answer - you should've wrote hier.Configured = true;(c# code) after you've finished all setup.
奇怪的是BasicConfigurator.Configure(apndr)没有用。在我的情况下,它完成了它的工作......但是,无论如何,答案就在这里 - 你应该hier.Configured = true;在完成所有设置后编写(c# 代码)。

