我正在使用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);
}
答案 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));
}
这里发生的是DateLayoutRenderer
从TimeStamp
对象获取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
属性的自动设置应该可以正常工作。它仅依赖于LogEventInfo
,TimeStamp
以及重用最后Environment.Ticks
值的逻辑。
您是否可能正在创建DateTime.Now
对象,然后将其DateTime.Now
属性设置为LogEventInfo
?我问,因为记录的日期是TimeStamp
。
我能想到的唯一其他解释是,如果DateTime.MinValue
由于某种原因返回-1。如果是,那么DateTime.MinValue
将始终返回lastDateTime私有成员变量的初始值。我无法想象Environment.Ticks
会返回-1的情况。