为什么不能读取当前日期 [英] Why can't nlog read the current date

查看:158
本文介绍了为什么不能读取当前日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用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));
}

这里发生的是 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 属性设置,其实现可以是这里



(更新 - 在某些时候,NLog从使用 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。


I'm using Nlog to write some logging to a textfile. Partial nlog.config:

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

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:

  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);
}

解决方案

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 .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.

Or

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

From the NLog source for 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));
    }

What is happening here is that the 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).

By default, when a 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();
        }
    }

The TimeStamp field is set in the LogEventInfo constructor using the TimeSource.Current.Now property, whose implementation can be seen here.

(UPDATE - At some point NLog changed from using 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)).

To save the trouble of navigating the link, here is the source for 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;
            }
        }
    }
}

The purpose of this class is to use a relatively cheap operation (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.

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 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.

Is it possible that you are creating a LogEventInfo object and then setting its TimeStamp property to DateTime.MinValue? I ask because the date that is being logged is DateTime.MinValue.

The only other explanation that I can think of would be if 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.

这篇关于为什么不能读取当前日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆