为什么不能读取当前日期 [英] Why can't nlog read the current date
问题描述
我正在使用Nlog将一些日志记录写入文本文件。部分nlog.config:
< target name =filexsi:type =FilefileName =$ {basedir } /MBWRunner_log.txt
layout =$ {date}($ {level}):$ {message}
异常:$ {exception:format = Method,ToString}/>
日志文件中的行如下所示:
< blockquote>
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);
}
更新:
@edosoft我认为问题是您使用LogEventInfo的默认构造函数。如果您在这里查看LogEventInfo的源代码,请执行以下操作:
https://github.com/NLog/NLog/blob/master/src/NLog/LogEventInfo.cs
您将看到,使用默认构造函数不会填充 .TimeStamp
字段,因此该字段可能默认为DateTime的默认值,我假设为code> DateTime.MinValue 。您应该使用其他构造函数之一或创建方法之一。由于您只设置了消息和级别字段,我建议:
var logEvent = new LogEventInfo(priority, , 信息); //第二个参数是记录器名称。
或
var logEvent = LogEventInfo.Create(priority,,message);
从 DateLayoutRenderer的NLog源
(from 这里),我们可以看到日期值作为日志流的一部分写入的值是这样计算的:
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));
}
这里发生的是 默认情况下,当创建一个 (更新 - 在某些时候,NLog从使用 为了节省导航链接的麻烦,以下是 这个课程的目的是使用相对便宜的操作( 所有这些代码都在播放(并且日期/时间记录显然工作对于大多数其他人来说),一个可能的解释是您正在使用 有可能您正在创建一个 我可以想到的唯一其他解释如果 I'm using Nlog to write some logging to a textfile. Partial nlog.config: Lines in the logfile look like this: 0001-01-01 00:00:00 (Trace): MBWRunner started As you can see the date and time are all 0. I have tested {longdate} and {date:format=yyyyMMddHHmmss} with the same result. The application is a console app, run from an elevated commandline. Any clues? [EDIT] I have tested this on 2 machine's within the organisation with the same result. Please help! Code used:
UPDATE: @edosoft I think the problem is your use of the default constructor for LogEventInfo. If you look at the source for LogEventInfo here https://github.com/NLog/NLog/blob/master/src/NLog/LogEventInfo.cs You will see that using the default constructor does not populate the Or From the NLog source for What is happening here is that the By default, when a The (UPDATE - At some point NLog changed from using To save the trouble of navigating the link, here is the source for The purpose of this class is to use a relatively cheap operation ( With all of this code in play (and with Date/Time logging apparently working for most other people), one possible explanation of your problem is that you are using the Is it possible that you are creating a The only other explanation that I can think of would be if 这篇关于为什么不能读取当前日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! DateLayoutRenderer
从
LogEventInfo
对象中获取 TimeStamp
值(NLog在每次使用时创建其中一个 Logger.Trace
, Logger.Debug
, Logger.Info
等方法,您还可以自己创建 LogEventInfo
对象,并使用 Logger.Log
方法)进行登录。 / p>
LogEventInfo
对象时,它的 TimeStamp
字段设置为(来自 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 =参数;
this.FormatProvider = formatProvider;
this.Exception = exception;
this.SequenceID = Interlocked.Increment(ref globalSequenceId);
if(NeedToPreformatMessage(parameters))
{
this.CalcFormattedMessage();
}
}
TimeStamp
字段在 LogEventInfo
构造函数中使用 TimeSource.Current.Now
属性设置,其实现可以是这里。
CurrentTimeGetter
更改为一个更通用的方法来获取一个 TimeSource
对象具有多种风格(其中之一, CachedTimeSource
,与 CurrentTimeGetter
基本相同) )
CachedTimeSource
的源代码:
public abstract class CachedTimeSource:TimeSource
{
private int lastTicks = -1;
private DateTime lastTime = DateTime.MinValue;
///< summary>
///从派生时间源获取原始未缓存的时间。
///< / summary>
protected Abstract DateTime FreshTime {get; }
///< summary>
///获取缓存一个系统的当前时间(15.6毫秒)。
///< / summary>
public override DateTime Time
{
get
{
int tickCount = Environment.TickCount;
if(tickCount == lastTicks)
返回lastTime;
else
{
DateTime time = FreshTime;
lastTicks = tickCount;
lastTime = 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。 <target name="file" xsi:type="File" fileName="${basedir}/MBWRunner_log.txt"
layout="${date} (${level}): ${message}
Exception: ${exception:format=Method, ToString}"/>
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);
}
.TimeStamp
field, so the field will probably just default to the default value for DateTime, which I assume is DateTime.MinValue
. You should use one of the other constructors or one of the Create methods. Since you are setting only the Message and Level fields, I would suggest either:var logEvent = new LogEventInfo(priority, "", message); //Second param is logger name.
var logEvent = LogEventInfo.Create(priority, "", message);
DateLayoutRenderer
(from here) we can see that the date value that gets written as part of the logging stream is calculated like this: 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
is getting the TimeStamp
value from the LogEventInfo
object (NLog creates one of these each time you use the Logger.Trace
, Logger.Debug
, Logger.Info
, etc methods. You can also create LogEventInfo
objects yourself and log them with the Logger.Log
method).LogEventInfo
object is created, its TimeStamp
field is set like this (from the source for LogEventInfo
here) (note the use of 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
field is set in the LogEventInfo
constructor using the TimeSource.Current.Now
property, whose implementation can be seen here.CurrentTimeGetter
to a more generic approach of having a TimeSource
object that has several flavors (one of which, CachedTimeSource
, is essentially the same as 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
) to limit access to a relatively expensive operation (DateTime.Now
). If the value of Ticks does not change from call to call (from one logged message to the next), then the value of DateTime.Now
retrieved the this time will be the same as the value of DateTime.Now retrieved this time, so just use the last retrieved value.Logger.Log
method to log your messages and you are building the LogEventInfo
objects yourself. By default, if you just new a LogEventInfo
object, the automatic setting of the TimeStamp
property should work fine. It is only dependent on Environment.Ticks
, DateTime.Now
, and the logic that reuses the last DateTime.Now
value, if appropriate.LogEventInfo
object and then setting its TimeStamp
property to DateTime.MinValue
? I ask because the date that is being logged is DateTime.MinValue
.Environment.Ticks
returns -1 for some reason. If it did, then CurrentTimeGetter
would always return the initial value of the lastDateTime private member variable. I can't imagine a scenario where Environment.Ticks
would return -1.