This project is read-only.

Extend token/property reader architecture

Aug 27, 2010 at 5:32 PM

Extending the architecture might be too strong of a term.  Let me describe my thought.  Currently, many tokens (and the supporting property readers) access fields in the TraceEventCache (e.g. date, time, event id, etc) or the static Trace object (activity id, LogicalOperationStack, etc).  It is also possible to have somewhat arbitrary functions that can retrieve information from any "well known" location (like Environment.MachineName), calculate a value, etc.

I wonder if it would be reasonable to extend the token/property reader system by making it possible to pass in a "Ukadc.Diagnostics-known" object to the TraceSource.TraceEvent overload that takes a single parameter.  For example, if there were an interface (or a class) like ILogEntry (like the LogEntry class in LAB or the similar classes/structures in log4net and NLog) that an application could populate, then property readers could be implemented in terms of that interface/class. 

Already, it should be possible for an application to create its own application-specific property readers by having the reader be aware of an application's special object.  Using the LAB's LogEntry class as an example, an application could implement its logging as a wrapper/layer over TraceSource objects (again, similar to LAB).  Each "Log" method would build the LogEntry, populating fields with information that might not be easily derivable otherwise from within the context of the TraceDataCore method(s) - maybe some custom app data, location info like calling method/class, custom level (MostLogging, MoreLogging, AverageLogging, LessLogging, LeastLogging rather than Critical, Error, Warning, Info, Verbose), etc.

So, for an app-specific property reader, it would be easy enough to do something like this:

    /// <summary>
    /// Can compare against and get the value of LogEntry's EventType
    /// </summary>
    public class LogEntryEventTypePropertyReader : PropertyReader
    {
        /// <summary>
        /// Return the property type
        /// </summary>
        public override Type PropertyType
        {
            get { return typeof (LogEntryEventType); }
        }

        /// <summary>
        /// Return the comparator
        /// </summary>
        public override IComparator Comparator
        {
            get { return NumericComparator.Instance; }
        }

        /// <summary>
        /// Return the event type
        /// </summary>
        /// <param name="value">The eventType</param>
        /// <param name="cache">Unused</param>
        /// <param name="source">Unused</param>
        /// <param name="eventType">Unused</param>
        /// <param name="id">Unused</param>
        /// <param name="formatOrMessage">Unused</param>
        /// <param name="data">Unused</param>
        /// <returns>True</returns>
        public override bool TryGetValue(out object value, TraceEventCache cache, string source,
                                         TraceEventType eventType, int id, string formatOrMessage, object[] data)
        {
            if (data != null && data.Count == 1 && data[0] Is LogEntry)
            {
              value = ((LogEntry)data[0]).EventType;
              return true;
            }
            else
            {
              // What if not LogEntry?  Don't know, for sample code
              // just return TraceEventCache's event type.
              value = eventType;
              return true;
            }
        }

To log a message with the LogEntry approach, a wrapper around TraceSource might look something like this:

    public override void Log(LogLevel lvl, string fmt, params object[] data)
    {
      if (!ShouldLog(lvl)) return;

      LogEntry le = new LogEntry(lvl, string.Format(fmt,data), GetEventId(), LoggingContext.DictionaryOfExtendedDataLikeLABAllows);
      ts.TraceEvent(lvl.ToTraceEventType(), le.EventId, le);
      ts.Flush();
    }

Ultimately, the LogEntry will get passed into to TraceListener and passed as one of the parameters to the property reader.

That might be good enough for an app that wants to create logging data using the LogEntry class/struct approach and is satisfied with implementing custom readers to read the LogEntry. 

Would it be a good idea for Ukadc.Diagnostics to try to provide a LogEntry class (or ILogEntry interface that an app could implement)?  That way, the property readers that could read the LogEntry/ILogEntry could be provided with Ukadc.Diagnostics.  On the down side, to use the class/interface in application code would require a reference to the Ukadc.Diagnostics project, which I think is not required today (unless using the ExtendedTraceSource).

Aug 31, 2010 at 9:42 AM

Hi wageoghe,

I think what you’re describing is pretty close to the scenario we were aiming for with the dynamic property reader (check out the docs on codeplex).

The idea here is that you can pass in ‘any object’ as data to a TraceEvent / TraceData call and then use a DynamicPropertyReader (DPR) to access properties of this class with tokens. So if you log ILogEvent and it has a TaskId or something property – you could access that using a DPR. If elsewhere you log a different object that doesn’t have this property then you would just get ‘null’ for that token’s value.

HTH – let me know if I’m off the mark.

Ta

Josh

From: wageoghe [mailto:notifications@codeplex.com]
Sent: 27 August 2010 17:32
To: Josh Twist
Subject: Extend token/property reader architecture [UkadcDiagnostics:225085]

From: wageoghe

Extending the architecture might be too strong of a term. Let me describe my thought. Currently, many tokens (and the supporting property readers) access fields in the TraceEventCache (e.g. date, time, event id, etc) or the static Trace object (activity id, LogicalOperationStack, etc). It is also possible to have somewhat arbitrary functions that can retrieve information from any "well known" location (like Environment.MachineName), calculate a value, etc.

I wonder if it would be reasonable to extend the token/property reader system by making it possible to pass in a "Ukadc.Diagnostics-known" object to the TraceSource.TraceEvent overload that takes a single parameter. For example, if there were an interface (or a class) like ILogEntry (like the LogEntry class in LAB or the similar classes/structures in log4net and NLog) that an application could populate, then property readers could be implemented in terms of that interface/class.

Already, it should be possible for an application to create its own application-specific property readers by having the reader be aware of an application's special object. Using the LAB's LogEntry class as an example, an application could implement its logging as a wrapper/layer over TraceSource objects (again, similar to LAB). Each "Log" method would build the LogEntry, populating fields with information that might not be easily derivable otherwise from within the context of the TraceDataCore method(s) - maybe some custom app data, location info like calling method/class, custom level (MostLogging, MoreLogging, AverageLogging, LessLogging, LeastLogging rather than Critical, Error, Warning, Info, Verbose), etc.

So, for an app-specific property reader, it would be easy enough to do something like this:

    /// <summary>
    /// Can compare against and get the value of LogEntry's EventType
    /// </summary>
    public class LogEntryEventTypePropertyReader : PropertyReader
    {
        /// <summary>
        /// Return the property type
        /// </summary>
        public override Type PropertyType
        {
            get { return typeof (LogEntryEventType); }
        }
 
        /// <summary>
        /// Return the comparator
        /// </summary>
        public override IComparator Comparator
        {
            get { return NumericComparator.Instance; }
        }
 
        /// <summary>
        /// Return the event type
        /// </summary>
        /// <param name="value">The eventType</param>
        /// <param name="cache">Unused</param>
        /// <param name="source">Unused</param>
        /// <param name="eventType">Unused</param>
        /// <param name="id">Unused</param>
        /// <param name="formatOrMessage">Unused</param>
        /// <param name="data">Unused</param>
        /// <returns>True</returns>
        public override bool TryGetValue(out object value, TraceEventCache cache, string source,
                                         TraceEventType eventType, int id, string formatOrMessage, object[] data)
        {
            if (data != null && data.Count == 1 && data[0] Is LogEntry)
            {
              value = ((LogEntry)data[0]).EventType;
              return true;
            }
            else
            {
              // What if not LogEntry?  Don't know, for sample code
              // just return TraceEventCache's event type.
              value = eventType;
              return true;
            }
        }
 

To log a message with the LogEntry approach, a wrapper around TraceSource might look something like this:

    public override void Log(LogLevel lvl, string fmt, params object[] data)
    {
      if (!ShouldLog(lvl)) return;
 
      LogEntry le = new LogEntry(lvl, string.Format(fmt,data), GetEventId(), LoggingContext.DictionaryOfExtendedDataLikeLABAllows);
      ts.TraceEvent(lvl.ToTraceEventType(), le.EventId, le);
      ts.Flush();
    }
 

Ultimately, the LogEntry will get passed into to TraceListener and passed as one of the parameters to the property reader.

That might be good enough for an app that wants to create logging data using the LogEntry class/struct approach and is satisfied with implementing custom readers to read the LogEntry.

Would it be a good idea for Ukadc.Diagnostics to try to provide a LogEntry class (or ILogEntry interface that an app could implement)? That way, the property readers that could read the LogEntry/ILogEntry could be provided with Ukadc.Diagnostics. On the down side, to use the class/interface in application code would require a reference to the Ukadc.Diagnostics project, which I think is not required today (unless using the ExtendedTraceSource).

Read the full discussion online.

To add a post to this discussion, reply to this email (UkadcDiagnostics@discussions.codeplex.com)

To start a new discussion for this project, email UkadcDiagnostics@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

Sep 1, 2010 at 3:21 PM

Thanks for the info.  I had seen the DynamicPropertyReader, but I had not read closely enough to see that it would probably fit my situation.