Date 为什么可以';t nlog读取当前日期

Date 为什么可以';t nlog读取当前日期,date,formatting,nlog,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}"/> 更新: @edosoft我认为问题在于您使用LogEv

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

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


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

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

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

DateLayoutRenderer
(From)的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));
    }
这里发生的事情是,
DateLayoutRenderer
正在从
LogEventInfo
对象中获取
TimeStamp
值(每次使用
Logger.Trace
Logger.Debug
Logger.Info
等方法时,NLog都会创建其中一个对象。您也可以自己创建
LogEventInfo
对象,并使用
Logger.log
方法记录它们)

默认情况下,当创建
LogEventInfo
对象时,其
时间戳
字段设置如下(从
LogEventInfo
的源代码中)(请注意
CurrentTimeGetter.Now
)的用法:

使用
TimeSource.Current.Now
属性在
LogEventInfo
构造函数中设置
TimeStamp
字段,可以看到其实现

(更新-在某一点上,NLog从使用
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;
            }
        }
    }
}
公共抽象类CachedTimeSource:TimeSource
{
private int lastTicks=-1;
private DateTime lastTime=DateTime.MinValue;
/// 
///从派生的时间源获取原始未缓存时间。
/// 
受保护的抽象DateTime FreshTime{get;}
/// 
///获取为一个系统刻度(15.6毫秒)缓存的当前时间。
/// 
公共覆盖日期时间
{
得到
{
int tickCount=Environment.tickCount;
如果(滴答声=最后滴答声)
上次返回;
其他的
{
日期时间=新鲜时间;
lastTicks=滴答声计数;
lastTime=时间;
返回时间;
}
}
}
}
此类的目的是使用相对便宜的操作(
Environment.Ticks
)来限制对相对昂贵的操作(
DateTime.Now
)的访问。如果Ticks的值在调用之间(从一条记录的消息到下一条消息)没有变化,然后是
DateTime的值。现在
this time检索到的值将与DateTime的值相同。现在是这次检索到的值,所以只需使用上次检索到的值

所有这些代码都在发挥作用(日期/时间记录显然适用于大多数其他人),对您的问题的一种可能解释是,您正在使用
Logger.Log
方法记录消息,并且您自己正在构建
LogEventInfo
对象。默认情况下,如果您刚刚新建一个
LogEventInfo
对象,
TimeStamp
属性的自动设置应该可以正常工作。它只是dep依赖于
环境。勾号
日期时间.Now
,以及重用上一个
日期时间.Now
值的逻辑(如果适用)

您是否可能正在创建一个
LogEventInfo
对象,然后将其
时间戳
属性设置为
DateTime.MinValue
?我这样问是因为记录的日期是
DateTime.MinValue


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

你是不是被一个有没有可能使用Log方法和LogEventInfo类来生成您的消息?@wageoghe我希望是这样,但我没有atm代码。我一看就会更新。我想问题是您使用LogEventInfo的默认构造函数。我在回答中添加了更多细节。谢谢,我会更新代码并重新测试,但似乎有问题你说得对,看着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));
    }
    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();
        }
    }
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;
            }
        }
    }
}