It is possible for developers to log objects (or even an array of objects) of any type to the System.Diagnostics plumbing using either of these methods (members of TraceSource):

public void TraceData(TraceEventType eventType, int id, object data);
public void TraceData(TraceEventType eventType, int id, params object[] data);

The DynamicPropertyReader was created to allow Listeners and Filters to access the properties of these objects (which are unknown at design-time, i.e. now) at run-time. However, typically this requires reflection which has always been considered taboo to most logging libraries because of the relatively slow performance of reflection when compared to a static method call. However, to overcome this problem the DynamicPropertyReader uses a FastPropertyGetter (Ukadc.Diagnostics.Utils.FastPropertyGetter) which uses LCG (Lighweight Code Generation) to emit IL and create a DynamicMethod that retrieves the data in a much more performant manner.

The FastPropertyGetter uses reflection the very first time it is used to read the metadata that allows it to generate the IL necessary to call the Property's getter. However, this DynamicMethod is then stored statically and so compilation and reflection only occurs once per appdomain.

Of course, the DynamicPropertyReader is still marginally slower than a static call so you should always consider just creating your own PropertyReader if you're that concerned with performance (or turn logging of altogether!).

In use...

The DynamicPropertyReader can typically be used on any configuration element that specifies a propertyToken (such as parameter from the SqlTraceListener in this example):

<parameter name="@ActivityId" propertyToken="{ActivityId}" />

Instead of specifying the propertyToken we can provide a nested <dynamicProperty /> node:

<parameter name="@DynamicValue">
  <dynamicProperty sourceType="System.TimeSpan, mscorlib" propertyName="TotalMilliseconds" />

In this instance, the DynamicPropertyReader is configured to check the data object to see if it is a TimeSpan (from the System namespace in mscorlib) and if it is, return the TotalMilliseconds property.

Note: If an object is passed to the data parameter that is not of type System.Timespan the TryGetValue of the DynamicPropertyReader would return false (i.e. value not found) and set it's out value parameter to null. Also, if an array of objects are passed to the latter TraceData method (above), the SqlTraceListener will loop through each item in the object array looking for an object of the appropriate type (note, once a matching type has been found the filter does not continue to loop through any remaining items).

Note: It is invalid to specify a propertyToken value on the propertyFilter element and a dynamicProperty element. Doing so will result in a ConfigurationErrorsException the first time the filter is used.

Last edited Apr 8, 2008 at 4:30 AM by joshtwist, version 4


No comments yet.