This project is read-only.

FileTraceListener and DateTime formatting

Jun 11, 2010 at 10:35 PM
Edited Jun 14, 2010 at 11:31 PM

I have just downloaded Ukadc.Diagnostics and started testing it and I have to say that it is pretty cool.

Currently I am using the FileTraceListener using {Year}-{Month}-{Day}.txt as the filePath parameter.  Every time I run my test program, the file only contains the diagnostics for that run, not the prior runs.  Is it supposed to work this way?  Also, sometimes (often?) the last few lines of the output file will be from a prior run of the program.  This seems to happen whether running from within VisualStudio or from a console window (my test program is a simple console app).

Another question...  When I format my diagnostic output using the output option, I specify that the DateTime should be included.  When the DateTime is logged, it is, apparently, in UTC.  Is it possible to specify that the DateTime should be logged in local time?


Later ... responding to my own post ...

It looks like one idea for logging the DateTime in local time (if desired) would be to simply implement a "LocalDateTime" token.

Something like this.  I guess this works, but it might be nice to have an option for the DateTime to be local or not.


public class LocalDateTime : StringPropertyReader
  public override bool TryGetValue(out object value,  TraceEventCache cache, string source, TraceEventType eventType, int id, string formatOrMessage, object [] data) 
    value = (cache == null) ? DateTime.Now.ToString() : cache.DateTime.ToLocalTime().ToString(); 
    return true ; 


















Jun 15, 2010 at 10:17 AM


Firstly, you found a little bug in the File Listener - if you get the latest code this has now been fixed (thank you!). Note that I've upgraded the projects to Visual Studio 2010 now also - although the .NET version is still .NET 3.0.

Yes, you absolutely could add your own token - in fact this seems like a reasonable thing to want to do so I've added a LocalTimePropertyReader and a {LocalTime} token into the core - it should just work for you. Note that the implementation is slightly different to yours. I would avoid a StringPropertyReader unless the value is actually a string. Much better to keep the logging data in it's native format. Especially with the new Property:Format syntax in tokens. So you can write:

{LocalTime.Year} and because 'Year' is a property of the DateTime object it will just write out the year. You can also write {LocalTime:yyyy} which will apply the formatstring 'yyyy' to the DateTime object which will give you the current year. You can do this withy any token now and FormatString and Properties can be combined, e.g.

{DateTime.Year:c} Which should format the current year as a currency (I think that's what 'c' does anyway :)).


Jun 15, 2010 at 2:56 PM
Edited Jun 15, 2010 at 3:10 PM

Thanks for the quick response!  I will pull the latest source.

I will also mention that I was confused trying to get my property reader to be recognized at first.  It was recognized as a literal token.  So, if my token was LocalTime, then {LocalTime} was written out rather than the value of the property.  I was following the examples on the Tokens page that show how to add tokens to the app.config file.  For example, here is one example:

    <token name="{CustomToken}" type="YourNamespace.ProcessNamePropertyReader, YourAssembly" />

Apparently now the {} are no longer required (or valid) when defining the token name.  I changed my app.config to define my token like this:

    <token name="CustomToken" type="YourNamespace.ProcessNamePropertyReader, YourAssembly" />

And it fixed my problem.  I did find a mention of this change either in your blog or in one of the changelist descriptions.

Thanks again!


As long as I am here, I had another thought.  In our homegrown logging package that we are using in a C++/COM/VB environment, we have a field that contains the elapsed time since the process started.  Technically, it is the elapsed time since the logging object (singleton) was created with is pretty close to the time the process started.  Anyway, I was fooling around with implementing similar capability as a property reader.  It is probably not a great implementation, but is is similar to our existing capability.  Anyway, here is the implementation.  Essentially it takes a snapshot of the QPC when the ElapsedTime reader is created.  It also gets the frequency so that the timespans can be converted to milliseconds.  Each time the property reader's value is retrieved, the current value of the QPC is retrieved and the delta from the original value and the current value, converted to milliseconds, is logged.  It wasn't obvious to me how to achieve the same effect in completely managed code, but maybe there is a way.  If nothing else, I think it is another interesting example of what can be achieved with the property readers.  Note that it is still a string property reader as I had implemented it before seeing your earlier response.

public class ElapsedTime : StringPropertyReader
    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool QueryPerformanceFrequency(out long lpFrequency);

    private long _start;
    private long _freq;
    private double _clicksPerMillisecond;

    public ElapsedTime()
      QueryPerformanceCounter(out _start);
      QueryPerformanceFrequency(out _freq);
      _clicksPerMillisecond = _freq / 1000.0;

    public override bool TryGetValue(out object value, TraceEventCache cache, string source, TraceEventType eventType, int id, string formatOrMessage, object[] data)
      long _now;
      QueryPerformanceCounter(out _now);

      //string s = (cache.DateTime.ToLocalTime() - p.StartTime).Milliseconds.ToString();
      value = ((long)((_now - _start) / _clicksPerMillisecond)).ToString();

      return true;

Jun 15, 2010 at 3:03 PM

Good spot about token configuration - I'll update the sample. This change allows the {Token.Property:Format} system to work (which we think is pretty cool!) :)