运行时更改log4net文件名

时间:2016-08-25 05:45:41

标签: c# log4net

我有一个启动较小程序或任务的程序,现在我希望每个任务都动态地记录到自己的文件名,最好使用任务名称。 我已经挖了一下,似乎有一个漂亮的%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

2 个答案:

答案 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。

中明确设置线程名称