log4net的RollingFileAppender需要在每次记录日志时调用Configure()函数。

3
我不太确定发生了什么,但是我的日志记录代码只有在每次调用XmlConfigurator.Configure()后才能写入rollingFileAppender。我已经在以下代码中打开了调试功能,并确认当Configure仅在构造函数中被调用一次时,它确实在读取我的配置文件,但是当Log()实际被调用时,日志文件上没有任何反应或者在调试窗口中显示。
如果我取消Log()中的那个Configure()调用并让其在每次调用时重新配置,则可以正常工作,但我认为这不是预期的用法。
额外加分!- 我注意到第一次调用log.Info()时不会记录日志,但是在每次进程运行中的所有后续调用都很好。
谢谢!
  public static class LogToFile
{
    public const string RollingFileAppenderName = "RollingFileLogger";

    static LogToFile()
    {
        log4net.Config.XmlConfigurator.Configure();
    }

    public static void Log(string fileNameBase, string message, string context)
    {
        if (fileNameBase == null) throw new ArgumentNullException("fileNameBase");
        if (message == null) throw new ArgumentNullException("message");
        if (context == null) throw new ArgumentNullException("context");

        //log4net.Config.XmlConfigurator.Configure();

        string fileName = string.Format("{0}_{1}.log", fileNameBase, context);
        string fullFileName = Path.Combine(Properties.Settings.Default.LogFilePath, fileName);

        if (!Directory.Exists(Properties.Settings.Default.LogFilePath)) Directory.CreateDirectory(Properties.Settings.Default.LogFilePath);

        LogicalThreadContext.Properties["LogName"] = string.Format(fullFileName);
        ILog log = LogManager.GetLogger(RollingFileAppenderName);

        log.Info(message);
    }
}

    <appender name="rollingFileAppender" type="log4net.Appender.RollingFileAppender">
  <file type="log4net.Util.PatternString" value="%property{LogName}" />
  <appendToFile value="true" />
  <rollingStyle value="Size" />
  <maxSizeRollBackups value="10" />
  <maximumFileSize value="2MB" />
  <countDirection value="-1"/>
  <LockingModel value="log4net.Appender.FileAppender+MinimalLock"/>
  <staticLogFileName value="false" />
  <immediateFlush value="true" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="AlertMessageHandler Message : %-25date [%thread] - %newline%message%newline" />
  </layout>
</appender>
3个回答

2
你的配置文件中指定了日志文件名使用LogName属性,但是你在运行时改变了它。我一直认为在不重新初始化appender(通过调用ActivateOptions)或调用XmlConfigurator.Configure()(更简单但会做更多工作)的情况下无法在运行时更改appender的属性。 此外,在你的日志方法中,如果你在设置LogName之前调用XmlConfigurator.Configure(),那么我会怀疑你的第一次调用会失败(尝试写入null),而你的第二次调用将会写入到应该与第一次调用一起使用的文件中。 如果你将XmlConfigurator.Configure()移动到设置LogName之后,则应该可以正常工作。

你说的很有道理。:) 我尝试获取我的RollingFileAppender并调用ActivateOptions(),但那行不通。也许设置LogName属性的某些内容超出了ActivateOptions()可以刷新的范围。所以我只能调用configure...但是你确实引导我在更改属性后调用Configure(),这意味着我不再错过第一条消息或将其写入错误的文件中。谢谢! - Bob
如果您有一个对appender的引用,那么您应该能够直接将其File属性设置为fullFileName,然后调用ActivateOptions,这可能意味着您不需要LogName属性。 - sgmoore
1
我看到你已经得出了那个结论 -) - sgmoore
是的,我做了。但这只是因为你让我更多地思考了如何在代码中搞定 appender。谢谢! - Bob

1

尝试在方法外声明日志变量:

private static readonly ILog log = LogManager.GetLogger(typeof(LogToFile));

这是我的使用方式,我没有问题。然而,在我的情况下,我不会登录一个静态类。

此外,我的appender信息在我在XmlConfigurator.Configure()函数中指定的文件中。

log4net.Config.XmlConfigurator.Configure(new FileInfo(configFile));

1
我试着将ILog移出,但并没有改变任何东西。我确实注意到我不需要在每个日志调用上调用Configure,但我需要调用它直到第一条成功消息。这可能解释了为什么在构造函数中调用它不起作用(即log4net没有记录第一条消息)。 - Bob

1

实际上,sgmoore的建议让我找到了解决方案。如果我只是在Appender对象上命名日志文件,而不是操纵配置文件属性,那么调用ActivateOptions就可以正常工作。以下是可行的代码。谢谢!

public static class LogToFile
{
    public const string RollingFileLoggerName = "RollingFileLogger";

    public const string RollingFileAppenderName = "rollingFileAppender";

    private static readonly ILog Logger = LogManager.GetLogger(RollingFileLoggerName);

    /// <summary>
    /// Logs to log4net rollingFileAppender
    /// </summary>
    /// <param name="fileNameBase">prefix of log filename</param>
    /// <param name="message">log4net message property</param>
    /// <param name="context">files grouped by context</param>
    public static void Log(string fileNameBase, string message, string context)
    {
        if (fileNameBase == null) throw new ArgumentNullException("fileNameBase");
        if (message == null) throw new ArgumentNullException("message");
        if (context == null) throw new ArgumentNullException("context");

        string fileName = string.Format("{0}_{1}.log", fileNameBase, context);
        string fullFileName = Path.Combine(Properties.Settings.Default.LogFilePath, fileName);

        if (!Directory.Exists(Properties.Settings.Default.LogFilePath)) Directory.CreateDirectory(Properties.Settings.Default.LogFilePath);

        ActivateAppenderOptions(string.Format(fullFileName));

        Logger.Info(message);
    }

    /// <summary>
    /// Update the appender in log4net after setting the log file path
    /// </summary>
    /// <param name="filename"></param>
    private static void ActivateAppenderOptions(string filename)
    {
        var hierarchy = (Hierarchy)LogManager.GetRepository();
        var appenders = hierarchy.GetAppenders();
        foreach (
            var rfa in appenders.OfType<RollingFileAppender>().Where(rfa => rfa.Name == RollingFileAppenderName))
        {
            rfa.File = filename;
            rfa.ActivateOptions();
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接