Visual Rx – Part 5

2012/08/19

Visual Rx – Part 5

this post is part of the Visual Rx series and it will focus on controlling the Visual Rx publication on the coding part.

you can see this series TOC in here.

I was talking about enabling / disabling the Visual Rx publication (through the predefine publication channel), using the VirtualRxSettings.Enable property, in part 1 of this series.

Enable / Disable

let look at a Enable / Disable snippet:

Code Snippet
  1. Task<VisualRxInitResult> info = VisualRxSettings.Initialize(
  2.     VisualRxWcfDiscoveryProxy.Create());
  3.  
  4. VisualRxInitResult infos = info.Result;
  5. Trace.WriteLine(infos);
  6.  
  7. var xs = Observable.Interval(TimeSpan.FromSeconds(0.5))
  8.     .Take(10);
  9. xs = xs.Monitor("Enable / Disable", 1);
  10. xs.Subscribe(
  11.     v => VisualRxSettings.Enable = v < 3 || v > 6);

lines 1,2 define the publication channel to Wcf Discovery.
lines 4,5 is waiting to the channel construction completion and log it to the Trace.
lines 7,8 create a datum stream.
line 9 is monitoring the stream.

line 11, within the Subscribe method I toggle the publication (on / off), you should be aware that the current value has been already sent by the time that the toggling logic took place, which mean that the toggling will affect the next value.

the toggle state for values 4-7 is off therefore the Visual Rx Viewer will show the stream as follow:

Rx, Visual Rx, Trace, Monitor, Monitoring, IObservable, IOserver

enabling or disabling the publication is totally at your control.

Partial publication
real-life scenario may demand a finer control over the datum’s publication. 
you may want to enable or disable a partial publication based on the datum’s stream name, keywords, channel key or even the datum itself.

this can be achieved by using the VisualRxSetting.AddFilter API.

the following snippet is showing how to split different streams into different channels:

Code Snippet
  1. Task<VisualRxInitResult> info = VisualRxSettings.Initialize(
  2.     VisualRxWcfDiscoveryProxy.Create(),
  3.     VisualRxWcfQueuedProxy.Create(),
  4.     VisualRxTraceSourceProxy.Create());
  5.  
  6. VisualRxSettings.AddFilter((marble, channelKey) =>
  7.     {
  8.         bool enable = false;
  9.         switch (marble.Name)
  10.         {
  11.             case "Stream A":
  12.                 enable = channelKey == VisualRxWcfDiscoveryProxy.KIND;
  13.                 break;
  14.             case "Stream B":
  15.                 enable = channelKey == VisualRxTraceSourceProxy.KIND;
  16.                 break;
  17.             default:
  18.                 enable = channelKey == VisualRxWcfQueuedProxy.KIND;
  19.                 break;
  20.         }
  21.         return enable;
  22.     });
  23.  
  24. VisualRxInitResult infos = info.Result;
  25. Trace.WriteLine(infos);
  26.  
  27. var xs = Observable.Interval(TimeSpan.FromSeconds(0.5))
  28.    .Take(10);
  29. xs = xs.Monitor("Stream A", 1);
  30. var ys = Observable.Interval(TimeSpan.FromSeconds(1))
  31.    .Take(10);
  32. ys = ys.Monitor("Stream B", 2);
  33.  
  34. xs.Subscribe();
  35. ys.Subscribe();

the result will be that the Visual Rx Viewer will monitor "Stream A" while "Stream B" will be log to the TraceSource under the "Visual Rx" setting.

the Viewer will present the following:

Rx, Visual Rx, Trace, Monitor, Monitoring, IObservable, IOserver

while the TraceSource output is going to the default listener (therefore it will go to the output window on debugging).
the output will look as follow:

Code Snippet
  1. <MarbleBase z:Id="i1" i:type="MarbleNext">
  2.   <BinaryValue i:nil="true" />
  3.   <DateCreatedUtc>2012-08-13T12:07:31.8190414Z</DateCreatedUtc>
  4.   <FormattedValue>0</FormattedValue>
  5.   <IndexOrder>2</IndexOrder>
  6.   <Keywords />
  7.   <Kind>OnNext</Kind>
  8.   <MachineName i:nil="true" />
  9.   <Name>Stream B</Name>
  10.   <Offset>PT0.4960332S</Offset>
  11.   <Options>None</Options>
  12.   <StringValue>0</StringValue>
  13.   <ThreadId>14</ThreadId>
  14. </MarbleBase>
  15.  
  16.  
  17. VisualRx Information: 0 :
  18. <MarbleBase z:Id="i1" i:type="MarbleComplete">
  19.   <BinaryValue i:nil="true" />
  20.   <DateCreatedUtc>2012-08-13T12:07:40.9455634Z</DateCreatedUtc>
  21.   <FormattedValue i:nil="true" />
  22.   <IndexOrder>2</IndexOrder>
  23.   <Keywords />
  24.   <Kind>OnCompleted</Kind>
  25.   <MachineName i:nil="true" />
  26.   <Name>Stream B</Name>
  27.   <Offset>PT9.6220625S</Offset>
  28.   <Options>None</Options>
  29.   <StringValue i:nil="true" />
  30.   <ThreadId>14</ThreadId>
  31. </MarbleBase>

if you want you can even filter by the actual data,
for example you can omit item that doesn’t relevant to the current monitoring session.

the following code omit publication for datum that doesn’t belong to the "Extreme" category.

first I will use the following declarations:

Code Snippet
  1. public enum Category
  2. {
  3.     BallGame,
  4.     Snow,
  5.     Extreme,
  6.     Water,
  7.     Weapon
  8. }
  9.  
  10. public class Item
  11. {
  12.     public Item(long value)
  13.     {
  14.         Value = value;
  15.         this.Category = (Category)(value % 5);
  16.     }
  17.     public long Value { get; private set; }
  18.     public Category Category { get; private set; }
  19. }

the following snippet does the filtering:

Code Snippet
  1. Task<VisualRxInitResult> info = VisualRxSettings.Initialize(
  2.     VisualRxWcfDiscoveryProxy.Create());
  3.  
  4. VisualRxSettings.AddFilter((marble, channelKey) =>
  5.     {
  6.         Item item = marble.RawValue as Item;
  7.         if (item != null && marble.Name == "Items")
  8.             return item.Category == Category.Extreme;
  9.         return true; // it is best practice to return true
  10.                      // because this way you don't
  11.                      // interfere with other filters
  12.     });
  13.  
  14. VisualRxInitResult infos = info.Result;
  15. Trace.WriteLine(infos);
  16.  
  17. var xs = Observable.Interval(TimeSpan.FromSeconds(0.5))
  18.     .Select(v => new Item(v))
  19.    .Take(10);
  20. xs = xs.Monitor("Items", 1);
  21. xs = xs.Monitor("Other monitoring", 1); // actually monitor the same aspect
  22.  
  23. xs.Subscribe();

focusing on the filtering at lines 4-12, you can see that I filtered out datum that belong to the "Items" monitor and doesn’t have the "Extreme" category.
in order to show the differences in the Visual Rx Viewer,
I was monitoring twice (lines 20, 21) once with the "Items" name which will be filtered and the second time is actually monitoring the same data but this time with "Other monitoring" name.
the result will be as follow:

Rx, Visual Rx, Trace, Monitor, Monitoring, IObservable, IOserver

you can download the source code and check the tests App.Config file to see how can you set the configuration for the TraceSource channel.

the following is one option where most of the listener are disabled:

Code Snippet
  1. <system.diagnostics>
  2.   <sources>
  3.     <!– Visual Rx TraceSource publication –>
  4.     <source name="VisualRx" switchName="defaultswitch">
  5.       <listeners>
  6.         <!–<remove name="Default"/>–>
  7.         <!–<add name="consoleListener" />–>
  8.         <!–<add name="xmlFileMonitorListener"/>–>
  9.         <!–<add name="customListener"/>–>
  10.       </listeners>
  11.     </source>
  12.   </sources>
  13.   <switches>
  14.     <!– Critical, Error, Warning, Information, Verbose
  15.          ActivityTracing: Start, Stop, Suspend, Resume, Transfer
  16.     –>
  17.     <add name="defaultswitch" value="Verbose"/>
  18.   </switches>
  19.   <sharedListeners>
  20.     <add name="customListener"
  21.         type="System.Reactive.Contrib.TestMonitor.CustomTraceListener,System.Reactive.Contrib.TestMonitor"
  22.          traceOutputOptions="ProcessId, DateTime"/>
  23.     <add name="consoleListener"
  24.         type="System.Diagnostics.ConsoleTraceListener"
  25.          traceOutputOptions="ProcessId, DateTime"/>
  26.     <add name="eventlogListener"
  27.         type="System.Diagnostics.EventLogTraceListener"
  28.         initializeData="Application">
  29.       <filter type="System.Diagnostics.EventTypeFilter"
  30.         initializeData="Error"/>
  31.     </add>
  32.     <add name="textFileListener"
  33.         type="System.Diagnostics.TextWriterTraceListener"
  34.         initializeData="RxContrib.log" />
  35.     <add name="xmlFileMonitorListener"
  36.         type="System.Diagnostics.XmlWriterTraceListener"
  37.         initializeData="Monitor.xml" />
  38.     <add name="defaultListener"
  39.         type="System.Diagnostics.DefaultTraceListener" traceOutputOptions="ProcessId"/>
  40.     <!–<add name="nlog" type="NLog.NLogTraceListener, NLog" />–>
  41.   </sharedListeners>
  42. </system.diagnostics>

if you want to filter by keyword just ask about the marble.Keywords:

Code Snippet
  1. VisualRxSettings.AddFilter((marble, channelKey) =>
  2.     marble.Keywords.Contains("Key1"));

the following snippet:

Code Snippet
  1. Task<VisualRxInitResult> info = VisualRxSettings.Initialize(
  2.     VisualRxWcfDiscoveryProxy.Create());
  3.  
  4. VisualRxSettings.AddFilter((marble, channelKey) =>
  5.     marble.Keywords.Contains("Key1"));
  6.  
  7. VisualRxInitResult infos = info.Result;
  8. Trace.WriteLine(infos);
  9.  
  10. var xs = Observable.Interval(TimeSpan.FromSeconds(0.5))
  11.    .Take(10);
  12. xs = xs.Monitor("Stream A", 1, "Key1", "Key3", "Key4");
  13. var ys = Observable.Interval(TimeSpan.FromSeconds(1))
  14.    .Take(10);
  15. ys = ys.Monitor("Stream B", 2, "Key2", "Key3");
  16.  
  17. xs.Subscribe();
  18. ys.Subscribe();

will be present in the viewer where only the "Stream A" will be shown on the Visual Rx Viewer because "Stream B" doesn’t have the "Key1" keyword:

Rx, Visual Rx, Trace, Monitor, Monitoring, IObservable, IOserver

Clear Filters

at any time you can wipe-out all the filters by using the ClearFilters API (this one can help for testability).

Code Snippet
  1. VirtualRxSettings.ClearFilters();

Summary

the filtering capability can keep a real-life system performance unaffected by data that doesn’t relevant to the current monitoring session.

Future Feature

one of the feature that I want to add in the future is a remote tool that will control simple filtering like which keywords is actively monitored.

Shout it kick it on DotNetKicks.com

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>