更新:
@edosoft 我认为问题在于您使用了 LogEventInfo 的默认构造函数。如果您在此处查看 LogEventInfo 的来源
https://github.com/NLog/NLog/blob/master/src/NLog/LogEventInfo.cs
您将看到使用默认构造函数不会填充该.TimeStamp
字段,因此该字段可能只是默认为 DateTime 的默认值,我假设它是DateTime.MinValue
. 您应该使用其他构造函数之一或 Create 方法之一。由于您只设置 Message 和 Level 字段,我建议:
var logEvent = new LogEventInfo(priority, "", message); //Second param is logger name.
或者
var logEvent = LogEventInfo.Create(priority, "", message);
DateLayoutRenderer
从(从这里)的 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
是从对象中获取TimeStamp
值LogEventInfo
(NLog 每次使用Logger.Trace
, Logger.Debug
,Logger.Info
等方法时都会创建其中一个。您也可以LogEventInfo
自己创建对象并使用该Logger.Log
方法记录它们)。
默认情况下,当一个LogEventInfo
对象被创建时,它的TimeStamp
字段是这样设置的(来自LogEventInfo
here的源代码)(注意使用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
字段是LogEventInfo
使用属性在构造函数中设置的TimeSource.Current.Now
,其实现可以在这里看到。
(更新 - 在某些时候,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;
}
}
}
}
此类的目的是使用相对便宜的操作 ( Environment.Ticks
) 来限制对相对昂贵的操作 ( DateTime.Now
) 的访问。如果 Ticks 的值在每次调用(从一条记录的消息到下一条)中没有变化,那么这次DateTime.Now
检索的值将与这次检索的 DateTime.Now 的值相同,所以只需使用最后一次检索到的值。
使用所有这些代码(并且日期/时间日志显然适用于大多数其他人),您的问题的一种可能解释是您正在使用该Logger.Log
方法来记录您的消息并且您正在LogEventInfo
自己构建对象。默认情况下,如果您只是新建一个LogEventInfo
对象,该TimeStamp
属性的自动设置应该可以正常工作。它仅取决于Environment.Ticks
、DateTime.Now
和重用最后一个DateTime.Now
值的逻辑(如果适用)。
您是否有可能正在创建一个LogEventInfo
对象,然后将其TimeStamp
属性设置为DateTime.MinValue
?我问是因为记录的日期是DateTime.MinValue
.
我能想到的唯一其他解释是如果Environment.Ticks
出于某种原因返回 -1。如果是这样,那么CurrentTimeGetter
将始终返回 lastDateTime 私有成员变量的初始值。我无法想象Environment.Ticks
会返回-1的场景。