Semantic logging - local time

Nov 12, 2013 at 12:48 PM
I am using Semantic logging to log in flat file. It logs UTC timestamp. How can I log in local time?

My code is as follows :
ObservableEventListener listener = new ObservableEventListener();
listener.LogToFlatFile("C:\debug.log");
listener.EnableEvents(Log.Logger, EventLevel.LogAlways, Log.Keywords.Trace);

Thanks in advance.
Nov 17, 2013 at 1:09 AM
Yes, you can change the behavior to log the local time. It's not just a knob that you can turn but you can do it with a custom formatter. Here's an example I created by reusing some of the Enterprise Library code:
    /// <summary>
    /// A <see cref="IEventTextFormatter"/> implementation that writes out formatted text.
    /// </summary>
    /// <remarks>This class is not thread-safe.</remarks>
    public class CustomEventTextFormatter : IEventTextFormatter
    {
        private string dateTimeFormat;

        /// <summary>
        /// Initializes a new instance of the <see cref="EventTextFormatter" /> class.
        /// </summary>
        /// <param name="header">The header.</param>
        /// <param name="footer">The footer.</param>
        /// <param name="verbosityThreshold">The verbosity threshold.</param>
        /// <param name="dateTimeFormat">The date time format used for timestamp value.</param>
        public CustomEventTextFormatter(string header = null, string footer = null, EventLevel verbosityThreshold = EventTextFormatter.DefaultVerbosityThreshold, string dateTimeFormat = null)
        {
            this.Header = header;
            this.Footer = footer;
            this.VerbosityThreshold = verbosityThreshold;
            this.DateTimeFormat = dateTimeFormat;
        }

        /// <summary>
        /// Gets or sets the header.
        /// </summary>
        /// <value>The header of the text formatter.</value>
        public string Header { get; set; }

        /// <summary>
        /// Gets or sets the footer.
        /// </summary>
        /// <value>The footer of the text formatter.</value>
        public string Footer { get; set; }

        /// <summary>
        /// Gets or sets the lowest <see cref="System.Diagnostics.Tracing.EventLevel" /> value where the formatted output provides all the event entry information.
        /// Otherwise a summarized content of the event entry will be written.
        /// </summary>
        /// <value>The EventLevel.</value>
        public EventLevel VerbosityThreshold { get; set; }

        /// <summary>
        /// Gets or sets the date time format used for timestamp value.
        /// </summary>
        /// <value>The date time format value.</value>
        public string DateTimeFormat
        {
            get
            {
                return this.dateTimeFormat;
            }

            set
            {
                ValidDateTimeFormat(value, "DateTimeFormat");
                this.dateTimeFormat = value;
            }
        }

        public static void ValidDateTimeFormat(string format, string argumentName)
        {
            if (format == null)
            {
                return;
            }

            try
            {
                DateTime.Now.ToString(format, CultureInfo.InvariantCulture);
            }
            catch (FormatException e)
            {
                throw new ArgumentException(argumentName, "InvalidDateTimeFormatError", e);
            }
        }

        public static void ArgumentNotNull(object argumentValue, string argumentName)
        {
            if (argumentValue == null)
            {
                throw new ArgumentNullException(argumentName);
            }
        }

        /// <summary>
        /// Writes the event.
        /// </summary>
        /// <param name="eventEntry">The <see cref="EventEntry" /> instance containing the event data.</param>
        /// <param name="writer">The writer.</param>
        public void WriteEvent(EventEntry eventEntry, TextWriter writer)
        {
            ArgumentNotNull(eventEntry, "eventEntry");
            ArgumentNotNull(writer, "writer");

            // Write header
            if (!string.IsNullOrWhiteSpace(this.Header))
            {
                writer.WriteLine(this.Header);
            }

            if (eventEntry.Schema.Level <= this.VerbosityThreshold || this.VerbosityThreshold == EventLevel.LogAlways)
            {
                string format = "{0} : {1}";

                // Write with verbosityThreshold format 
                writer.WriteLine(format, PropertyNames.ProviderId, eventEntry.ProviderId);
                writer.WriteLine(format, PropertyNames.EventId, eventEntry.EventId);
                writer.WriteLine(format, PropertyNames.Keywords, eventEntry.Schema.Keywords);
                writer.WriteLine(format, PropertyNames.Level, eventEntry.Schema.Level);
                writer.WriteLine(format, PropertyNames.Message, eventEntry.FormattedMessage);
                writer.WriteLine(format, PropertyNames.Opcode, eventEntry.Schema.Opcode);
                writer.WriteLine(format, PropertyNames.Task, eventEntry.Schema.Task);
                writer.WriteLine(format, PropertyNames.Version, eventEntry.Schema.Version);
                writer.WriteLine(format, PropertyNames.Payload, FormatPayload(eventEntry));
                writer.WriteLine(format, PropertyNames.EventName, eventEntry.Schema.EventName);
                writer.WriteLine(format, PropertyNames.Timestamp, GetFormattedTimestamp(eventEntry.Timestamp.ToLocalTime(), this.DateTimeFormat));
            }
            else
            {
                // Write with summary format
                writer.WriteLine(
                    "{0} : {1}, {2} : {3}, {4} : {5}, {6} : {7}, {8} : {9}, {10} : {11}",
                    PropertyNames.EventId,
                    eventEntry.EventId,
                    PropertyNames.Level,
                    eventEntry.Schema.Level,
                    PropertyNames.Message,
                    eventEntry.FormattedMessage,
                    PropertyNames.Payload,
                    FormatPayload(eventEntry),
                    PropertyNames.EventName,
                    eventEntry.Schema.EventName,
                    PropertyNames.Timestamp,
                    GetFormattedTimestamp(eventEntry.Timestamp.ToLocalTime(), this.DateTimeFormat));
            }

            // Write footer
            if (!string.IsNullOrWhiteSpace(this.Footer))
            {
                writer.WriteLine(this.Footer);
            }

            writer.WriteLine();
        }

        private static string FormatPayload(EventEntry entry)
        {
            var eventSchema = entry.Schema;
            var sb = new StringBuilder();

            for (int i = 0; i < entry.Payload.Count; i++)
            {
                try
                {
                    sb.AppendFormat("[{0} : {1}] ", eventSchema.Payload[i], entry.Payload[i]);
                }
                catch (Exception e)
                {
                    //TODO: Log something
                    //SemanticLoggingEventSource.Log.EventEntryTextWriterFailed(e.ToString());
                    //sb.AppendFormat("[{0} : {1}] ", "Exception", string.Format(CultureInfo.CurrentCulture, "TextSerializationError", e.Message));
                }
            }

            return sb.ToString();
        }

        /// <summary>
        /// Gets the formatted timestamp.
        /// </summary>
        /// <param name="format">The format.</param>
        /// <returns>The formatted string.</returns>
        public string GetFormattedTimestamp(DateTimeOffset timestamp, string format)
        {
            return timestamp.ToString(string.IsNullOrWhiteSpace(format) ? "O" : format, CultureInfo.InvariantCulture);
        }
    }

    internal static class PropertyNames
    {
        internal const string ProviderId = "ProviderId";
        internal const string EventId = "EventId";
        internal const string Keywords = "Keywords";
        internal const string Level = "Level";
        internal const string Message = "Message";
        internal const string Opcode = "Opcode";
        internal const string Task = "Task";
        internal const string Version = "Version";
        internal const string Payload = "Payload";
        internal const string EventName = "EventName";
        internal const string Timestamp = "Timestamp";
    }

And then you can use it like this:
    MainLogger logger = MainLogger.Log;
    ObservableEventListener listener = new ObservableEventListener();
    listener.EnableEvents(logger, System.Diagnostics.Tracing.EventLevel.Informational);
    listener.LogToConsole(new CustomEventTextFormatter(), new DefaultConsoleColorMapper());
    listener.LogToFlatFile(@"C:\Logs\FlatFile.txt", new CustomEventTextFormatter());
~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Nov 20, 2013 at 11:28 AM
Thanks for the reply. It worked well.