我有一个启动较小程序或任务的程序,现在我希望每个任务都动态地记录到自己的文件名,最好使用任务名称。
我已经挖了一下,似乎有一个漂亮的%property
可以用于Log4Net。所以我试过了。但似乎Log4Net在初始化后没有对此进行拾取更改。
我写了一个小测试程序来玩。 我宁愿只构建一次windsor容器,但Log4Net不会重新初始化"并创建一个新的日志文件。所以现在我必须在开始任务之前构建容器,以确保我在日志文件中获得正确的文件名。
有没有人知道在运行时是否有更好/更智能的方法来更改日志的文件名?
这是我的测试代码:
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
答案 0 :(得分:0)
我希望每个任务都动态记录到自己的文件名,最好使用任务名称
执行此操作的唯一方法 - 假设您的任务同时运行 - 每个任务都有一个记录器,其中每个记录器都有自己的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);
}
答案 1 :(得分:-1)
在log4net.config
中定义的appender中,您可以指定文件名的输出格式。例如<file value="fixedName"/>
。您还可以使用<staticLogFileName value="false"/>
和模式使用动态文件名,例如
<file type="log4net.Util.PatternString" value="somePrefix-%property{SomePropertyName}-%utcdate{yyMMdd}.trace.log" />.
这将根据日期和您的"SomePropertyName"
属性路由到不同的文件。
您必须在任务中设置该属性,例如log4net.ThreadContext.Properties["SomePropertyName"] = "someValue";
。
我想一个好的开关将是生成日志记录事件(%t
或%thread
)的线程的名称。如果没有可用名称,则输出线程编号。但您可以在ITask
s。