为什么nlog不能读取当前日期

时间:2012-11-12 13:19:03

标签: date formatting nlog

我正在使用Nlog将一些日志记录写入文本文件。部分nlog.config:

 <target name="file" xsi:type="File" fileName="${basedir}/MBWRunner_log.txt"
             layout="${date} (${level}): ${message}
Exception: ${exception:format=Method, ToString}"/>

日志文件中的行如下所示:

  

0001-01-01 00:00:00(追踪):MBWRunner已启动

正如您所看到的,日期和时间都是0.我已经测试了{longdate}和{date:format = yyyyMMddHHmmss},结果相同。

该应用程序是一个控制台应用程序,从提升的命令行运行。

任何线索?

[编辑]我在组织内的2台机器上测试了这个,结果相同。请帮忙!

使用的代码:

  static Logger _logger = LogManager.GetCurrentClassLogger();

public static void Log(string message, LogLevel priority)
    {
      LogEventInfo eventinfo = new LogEventInfo(); ;
      eventinfo.Message = message;
      eventinfo.Level = priority;
      Log(eventinfo);
    }

static void Log(LogEventInfo logentry)
{     
  _logger.Log(logentry);
}

1 个答案:

答案 0 :(得分:5)

更新:

@edosoft我认为问题是你使用LogEventInfo的默认构造函数。如果你在这里查看LogEventInfo的源代码

https://github.com/NLog/NLog/blob/master/src/NLog/LogEventInfo.cs

您将看到使用默认构造函数不会填充.TimeStamp字段,因此该字段可能只是默认为DateTime的默认值,我假设它是DateTime.MinValue。您应该使用其他构造函数之一或Create方法之一。由于您只设置了消息和级别字段,我建议:

var logEvent = new LogEventInfo(priority, "", message); //Second param is logger name.

或者

var logEvent = LogEventInfo.Create(priority, "", message);

DateLayoutRenderer(来自here)的NLog源我们可以看到,作为记录流的一部分写入的日期值计算如下:

    protected override void Append(StringBuilder builder, LogEventInfo logEvent)
    {
        var ts = logEvent.TimeStamp;
        if (this.UniversalTime)
        {
            ts = ts.ToUniversalTime();
        }

        builder.Append(ts.ToString(this.Format, this.Culture));
    }

这里发生的是DateLayoutRendererTimeStamp对象获取LogEventInfo值(每次使用Logger.Trace时,NLog都会创建其中一个,{ {1}},Logger.Debug等方法。您也可以自己创建Logger.Info个对象,并使用LogEventInfo方法记录它们。

默认情况下,创建Logger.Log对象时,其LogEventInfo字段设置如下(来自TimeStamp here的来源)(请注意{的使用{1}}):

LogEventInfo

使用CurrentTimeGetter.Now属性在 public LogEventInfo(LogLevel level, string loggerName, IFormatProvider formatProvider, [Localizable(false)] string message, object[] parameters, Exception exception) { this.TimeStamp = CurrentTimeGetter.Now; this.Level = level; this.LoggerName = loggerName; this.Message = message; this.Parameters = parameters; this.FormatProvider = formatProvider; this.Exception = exception; this.SequenceID = Interlocked.Increment(ref globalSequenceId); if (NeedToPreformatMessage(parameters)) { this.CalcFormattedMessage(); } } 构造函数中设置了TimeStamp字段,可以看到here的实现。

(更新 - 在某些时候,NLog从使用LogEventInfo变为更通用的方法,即拥有一个具有多种风格的TimeSource.Current.Now对象(其中一个,CurrentTimeGetter,基本上是与TimeSource))相同。

为了省去导航链接的麻烦,以下是CachedTimeSource的来源:

CurrentTimeGetter

此类的目的是使用相对便宜的操作(CachedTimeSource)来限制对相对昂贵的操作(public abstract class CachedTimeSource : TimeSource { private int lastTicks = -1; private DateTime lastTime = DateTime.MinValue; /// <summary> /// Gets raw uncached time from derived time source. /// </summary> protected abstract DateTime FreshTime { get; } /// <summary> /// Gets current time cached for one system tick (15.6 milliseconds). /// </summary> public override DateTime Time { get { int tickCount = Environment.TickCount; if (tickCount == lastTicks) return lastTime; else { DateTime time = FreshTime; lastTicks = tickCount; lastTime = time; return time; } } } } )的访问。如果Ticks的值在调用之间没有变化(从一个记录的消息到下一个消息),则此时检索的Environment.Ticks的值将与DateTime.Now的值相同,此时检索到,所以只需使用最后检索的值。

使用所有这些代码(并且日期/时间日志记录显然适用于大多数其他人),对您的问题的一个可能的解释是您使用DateTime.Now方法来记录您的消息,而您是自己构建DateTime.Now个对象。默认情况下,如果您刚刚创建了一个Logger.Log对象,LogEventInfo属性的自动设置应该可以正常工作。它仅依赖于LogEventInfoTimeStamp以及重用最后Environment.Ticks值的逻辑。

您是否可能正在创建DateTime.Now对象,然后将其DateTime.Now属性设置为LogEventInfo?我问,因为记录的日期是TimeStamp

我能想到的唯一其他解释是,如果DateTime.MinValue由于某种原因返回-1。如果是,那么DateTime.MinValue将始终返回lastDateTime私有成员变量的初始值。我无法想象Environment.Ticks会返回-1的情况。