timestamp format in log entry

Topics: Logging Application Block
May 11, 2007 at 4:53 AM
Hi,
I was just wondering if there was some way of specifiying the format of the timestamp in the log entries. I know that to get local time instead of the UTC time i have to specify the formatter as {timestamp(local)} which produces an entry like "10/05/2007 5:04:25 PM"

but I would prefer to have milliseconds in there as well. How do I go about doing this?

May 11, 2007 at 12:23 PM
Hi,

I've suffered from the same limitation, and as a real developer, I've created my own formatter that allows you to do so as in the following example:

<add dateTimeFormat="yyyy-MM-dd HH:mm:ss.ff" 
  template="[{timestamp} P{processId,-4} T{win32ThreadId,-4} {user,-10} {categories,-11} {logger,-20}] {message}" 
  type="MyNamespace.ExtendedFormatter, MyFrameWork, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 
  name="Text Formatter" />

The full code of my custom formatter:

    /// <summary>
    /// Provides similar text formatting services as the Enterprise Library <see cref="TextFormatter"/>, but 
    /// adds additional formatting options.
    /// </summary>
    /// <remarks>
    /// <list type="bullet">
    /// <item><see cref="string.Format(string,object)"/> specifiers for setting the layout. E.g. {tag, -1} or {tag, 20}</item>
    /// <item>The date-time format can be customized with the <i>dateTimeFormat</i> attribute</item>
    /// <item>A <i>user</i> tag for displaying the current identity name</item>
    /// </list>
    /// </remarks>
    [ConfigurationElementType(typeof(CustomFormatterData))]
    public class ExtendedFormatter : ILogFormatter
    {
        private string template = "";
        private string dateTimeFormat = "yyyy-MM-dd hh:mm:ss.ff";
 
        /// <summary>
        /// Initializes a new instance of the <see cref="ExtendedFormatter"/> class.
        /// </summary>
        /// <param name="attributes">The attributes.</param>
        public ExtendedFormatter(NameValueCollection attributes)
        {
            template = attributes["template"];
            if (string.IsNullOrEmpty(template))
            {
                throw new LoggingException("template is a required attribute");
            }
 
            if (attributes["dateTimeFormat"] != null)
            {
                dateTimeFormat = attributes["dateTimeFormat"];
            }
        }
 
        ///<summary>
        ///
        ///            Formats a log entry and return a string to be outputted.
        ///            
        ///</summary>
        ///
        ///<param name="log">Log entry to format.</param>
        ///<returns>
        ///String representing the log entry.
        ///</returns>
        ///
        public string Format(LogEntry log)
        {
            TextBuilder builder = new TextBuilder(template);
            
            builder.Replace("timestamp", log.TimeStamp.ToLocalTime().ToString(dateTimeFormat));
            builder.Replace("title", log.Title);
            builder.Replace("message", log.Message);
            builder.Replace("eventid", log.EventId);
            builder.Replace("priority", log.Priority);
            builder.Replace("severity", log.Severity);
            builder.Replace("machine", log.MachineName);
            builder.Replace("appDomain", log.AppDomainName);
            builder.Replace("processId", log.ProcessId);
            builder.Replace("processName", log.ProcessName);
            builder.Replace("win32ThreadId", log.Win32ThreadId);
            builder.Replace("threadName", log.ManagedThreadName);
            builder.Replace("user", Thread.CurrentPrincipal.Identity.Name);
            builder.Replace("categories", string.Join(" ", log.CategoriesStrings));
 
            return builder.ToString();
        }
 
        /// <summary>
        /// Helper class that ensures that the placeholders are properly used during replacement.
        /// </summary>
        internal class TextBuilder
        {
            private StringBuilder templateBuilder; 
            private int placeHolderIndex = 0;
            private List<object> values = new List<object>();
 
            /// <summary>
            /// Initializes a new instance of the <see cref="TextBuilder"/> class.
            /// </summary>
            /// <param name="template">The template.</param>
            public TextBuilder(string template)
            {
                templateBuilder  = new StringBuilder(template);
                templateBuilder.Replace("{newline}", Environment.NewLine);
                templateBuilder.Replace("{tab}", "\t");
            }
 
            /// <summary>
            /// Replaces the specified {tag} with a value, while preserving the formatting. 
            /// </summary>
            public void Replace(string tag, object value)
            {
                templateBuilder.Replace("{" + tag, "{" + placeHolderIndex);
                values.Add(value);
                ++placeHolderIndex;
            }
 
            ///<summary>
            ///Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
            ///</summary>
            ///
            ///<returns>
            ///A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
            ///</returns>
            ///<filterpriority>2</filterpriority>
            public override string ToString()
            {
                try
                {
                    return string.Format(templateBuilder.ToString(), values.ToArray());
                }
                catch (FormatException)
                {
                    throw new LoggingException("The template contains unknown tags or unbalanced parentheses");
                }
            }
        }
    }
Jun 6, 2007 at 8:40 AM
Hi,

you can provide a format string for the class TimeStampToken like this:
{timestamp(yyyy-MM-dd HH:mm:ss.fff)}

For information on which format strings you can use for DateTime values have a look at the .net framework documentation http://msdn2.microsoft.com/en-us/library/az4se3k1.aspx

Hope this helps.
Rainer
Dec 4, 2007 at 10:05 PM
If you are like me and do not want UTC time but local your format will look like:

{timestamp(local:yyyy-MM-dd HH:mm:ss.fff)}

This will get you your local format too:

{timestamp(local)}
Dec 29, 2007 at 1:02 AM
Edited Dec 29, 2007 at 1:03 AM
Thanks, dionysos1973 for putting that together.

Were you able to get the Config GUI to recognize your custom formatter?

I was not.

When I clicked on the Type property in the Properties editor for the Custom Formatter, it could not find any "classes that inherit from Microsoft.Practices.EnterpriseLibrary.Formatters.LogFormatters and have a ConfigurationElementType of 'CustomFormatterData'"

I even tried loading the dll specifically and got the same notice, that it could not find any suitable classes.

However, by editing the App.config by hand (ie not using the Configuration editor) it seemed to work fine, and I could edit it from thereon out via the Configuration GUI.

Just wondering if this is maybe a bug, or something (else) is missing from the documentation.

Thanks,

Jesse
Feb 5, 2008 at 1:05 PM
Thanks to dionysos1973 for a sample of a custom formatter. I got this formatter recognized by the Config Gui and here's how.

1) The custom formatter needs to inherit from the LogFormatter abstract class, in the example in implements the ILogFormatter interface.
2) If you have your own builds of EntLib, make sure that the Config UI is of the same build you are referencing in your projects, (this one got me a few times).
3) If you have the EntLib confug UI open, and the app.config loaded and you make changes to any types your are trying to have recognized by the UI, then you may have to close the Config UI first - it is kind of squirelly at times.

Aside from inheriting from LogFormatter, the example was good.

Thanks,

Mike

May 8, 2009 at 9:04 PM

Having the same probelm:

When I clicked on the Type property in the Properties editor for the Custom Formatter, it could not find any "classes that inherit from Microsoft.Practices.EnterpriseLibrary.Formatters.LogFormatters and have a ConfigurationElementType of 'CustomFormatterData'

I think I'm inhereting from the LogFormatter i.e. public class LogXmlFormatter LogFormatter  but when I go to the definition for LogFormatter I get this

 

 

 

 

<font size="2">

 

</font>

 

// Summary:

<font size="2">

 

</font>

 

// Abstract implememtation of the Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.ILogFormatter

<font size="2">

 

</font>

 

// interface.

<font size="2">

 

</font>

 

public abstract class LogFormatter :

ILogFormatter

{

how sould I be inhereting it?

 

May 11, 2009 at 7:26 AM

Maybe this would help, http://entlib.codeplex.com/Wiki/View.aspx?title=How%20do%20I%20create%20a%20custom%20formatter%3f&referringTitle=Home ,.

Valiant Dudan
Global Technology & Solutions
Avanade, Inc.

entlib.support@avanade.com