运行时更改log4net文件名
我有一个启动较小程序或任务的程序,现在我希望每个任务都动态地记录到它们自己的文件名,最好使用任务名称。 我已经挖掘了一点,似乎有一个漂亮的%property
事情,你可以使用Log4Net。所以我试了一下。但似乎Log4Net在初始化之后没有为此获取更改。运行时更改log4net文件名
我写了一个小测试程序来玩。 我宁愿只构建windsor容器一次,但是Log4Net不会“重新初始化”,并创建一个新的日志文件。所以现在我必须在开始任务之前构建容器,以确保我在日志文件中获得了正确的文件名。
有谁知道是否有更好/更聪明的方法来改变运行时的日志文件名?
这里是我的testcode:
public class Program
{
static void Main(string[] args)
{
GlobalContext.Properties["LogName"] = "default";
XmlConfigurator.ConfigureAndWatch(new FileInfo("log4net.config"));
while (true)
{
Console.WriteLine();
Console.Write("> ");
string cmd = (Console.ReadLine() ?? string.Empty);
if (string.IsNullOrWhiteSpace(cmd)) continue;
if (cmd.ToLower() == "exit") Environment.Exit(0);
ExecuteTask(Regex.Split(cmd, @"\s+"));
}
}
private static void ExecuteTask(string[] args)
{
//This changes the filename Log4Net logs to, but Log4Net only picks it up if I rebuild my container
GlobalContext.Properties["LogName"] = args[0];
//This should only be run once. No real need to build the container before each run, except to reinitialize Log4Net
var container = BuildContainer();
try
{
var task = container.Resolve<ITask>(args[0]);
task.DoLog();
}
catch (Exception)
{
// This doesn't work as expected, Log4Net logs to the file specified outside of the trycatch
GlobalContext.Properties["LogName"] = "default";
var logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
logger.Info("Could not find "+args[0]);
}
}
private static WindsorContainer BuildContainer()
{
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
var container = new WindsorContainer();
container.Install(
FromAssembly.This());
return container;
}
}
public interface ITask
{
void DoLog();
}
public class TwoTask : ITask
{
private readonly ILogger _logger;
public TwoTask(ILogger logger)
{
_logger = logger;
}
public void DoLog()
{
_logger.Info("Hello!");
}
}
public class OneTask : ITask
{
private readonly ILogger _logger;
public OneTask(ILogger logger)
{
_logger = logger;
}
public void DoLog()
{
_logger.Info("Hello!");
}
}
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn(typeof(ITask))
.Configure(c => c.LifeStyle.Transient.Named(c.Implementation.Name)));
container.AddFacility<LoggingFacility>(f => f.UseLog4Net("log4net.config"));
}
}
Nugets使用: Castle.Core,Castle.Core-log4net的,Castle.LoggingFacility,Castle.Windsor
在你的appender在log4net.config
定义,你可以指定一个输出格式为文件名。例如<file value="fixedName"/>
。您还可以使用<staticLogFileName value="false"/>
以及一个图案(例如,
<file type="log4net.Util.PatternString" value="somePrefix-%property{SomePropertyName}-%utcdate{yyMMdd}.trace.log" />.
这将路线基于日期不同的文件和"SomePropertyName"
财产。
你将不得不在你的任务中设置这个propery,如log4net.ThreadContext.Properties["SomePropertyName"] = "someValue";
。
我想一个好的开关将是生成记录事件(%t
或%thread
)的线程的名称。如果没有名称可用,则输出线程号。但是你可以在你的ITask
中明确地设置线名。
我想每个任务登录到自己的文件名动态,最好使用任务
的名称要做到这一点的唯一方法 - 假设你的任务同时运行 - 就是有一个记录器每个任务,其中每个记录器有它自己的appender。
正如您已经注意到的那样,更改属性并不会更改日志文件,因为这是在配置时设置的。一个常见的解决方案是在运行时以编程方式修补appender文件名 - 这很容易,但是由于记录器共享appender,您会看到一个任务登录到另一个任务的文件。
所以,你将不得不construct loggers and appenders at runtime - 从后摘录:
// Create a new file appender
public static log4net.Appender.IAppender CreateFileAppender(string name,
string fileName)
{
log4net.Appender.FileAppender appender = new
log4net.Appender.FileAppender();
appender.Name = name;
appender.File = fileName;
appender.AppendToFile = true;
log4net.Layout.PatternLayout layout = new
log4net.Layout.PatternLayout();
layout.ConversionPattern = "%d [%t] %-5p %c [%x] - %m%n";
layout.ActivateOptions();
appender.Layout = layout;
appender.ActivateOptions();
return appender;
}
和:
// Add an appender to a logger
public static void AddAppender(string loggerName,log4net.Appender.IAppender appender)
{
log4net.ILog log = log4net.LogManager.GetLogger(loggerName);
log4net.Repository.Hierarchy.Logger l =
(log4net.Repository.Hierarchy.Logger)log.Logger;
l.AddAppender(appender);
}
所有你真的做的是使用'ThreadContext',而不是'GlobalContext'但这仍然不起作用 - 文件名在配置时设置。您可以尽可能多地更改属性的值,但它不会起作用。 – stuartd