Visual Rx – Part 1


Visual Rx – Part 1

this post is the first of series about Visual Rx.
this post series also stand as the official help of Visual Rx.

you can see this series TOC in here.

Visual Rx is a bundle of API and a Viewer which can monitor and visualize Rx datum stream (at run-time).

Profile, Rx, Diagnostic, Contrib, Marble, Bnaya, Dubug, Trace, Visual Rx

one of the challenge of any Rx solution is reasoning about the datum flow at run-time, the Visual Rx bundle is a perfect solution for this problem.

Visual Rx was design for minimal performance penalty, which make it a perfect candidate for production time monitoring.

Supported functionality :
  • Activation: monitoring can be enable and disable at runtime (at the code side).
  • Transport: different transport strategy can be apply (including WCF, Queue, and Trace Source).
  • Plug-ins: custom behaviors can be hook on different aspect of the monitoring or UI functionality, including a custom transport channel, UI painting and more (more about this one on letter post).

the architecture of the Visual Rx bundle is separate into two main components groups (those groups is having a loosely couple connection though a common contract and DTOs):

  • Coding extension which is responsible to the settings and the transmission of the datum information on the Rx code side.
  • Viewer component which is responsible to visualize the Rx datum stream.

Coding extension

Visual Rx settings

the Visual Rx setting is responsible to setup the transmission channels which will be used to submit the Rx datum stream toward the viewer (or any other end point).

out of the box Visual Rx come with the followings built-in channels:

  • Wcf discovery – will try to locate the end point of the viewer service (or any other discoverable service which apply to the Visual Rx contract).
    this is the easiest proxy and it is recommended to local network scenarios. 
  • Wcf queued – which submit the datum though MSMQ channel (the default viewer is compatible with this channel).
  • Trace Source – publish the data though the standard .NET Trace Source. using the "VisualRx" trace source name (for internal messages it use "VisualRx.Log"). 
    the app.config setting will be discuss on latter posts.

you can define the channel by using VirtualRxSettings Initialize static method.

Code Snippet
  1. Task<VisualRxInitResult> info = VisualRxSettings.Initialize(
  2.     VisualRxWcfDiscoveryProxy.Create(),
  3.     VisualRxWcfQueuedProxy.Create(),
  4.     VisualRxTraceSourceProxy.Create());
  6. VisualRxInitResult infos = info.Result;
  7. Trace.WriteLine(infos);

lines 1-4 setup the transmission channels to all 3 built-in channels.
it is a non blocking API which return a Task which you can either wait until the channels construction or use a ContinueWith / await for a callback operations (this sample is blocking until the channels are ready).

through the Task result you can log the channels state (lines 6-8).

this is the Initialize method signature:

Code Snippet
  1. Task<VisualRxInitResult> Initialize(
  2.             params IVisualRxProxy[] proxies)

as you can see, you can initialize any number of proxies including a custom proxies that implement IVisualRxProxy (the proxy responsibility is to send the data though a channel).
you can call the Initialize method multiple time, each call will override the settings of the previous one.


at any time you can turn on / off the profiling operation by assigning the Enable property.

Code Snippet
  1. VirtualRxSettings.Enable = false;

this is one of the way you can avoid performance penalty. you can activate the data publication only when you need to actively monitor the it.
you can expose this functionality by any standard service (in letter version I will supply a tool for remote activation and deactivate the publication).

other advance setting will be discuss on latter posts.

Monitoring an IObservable<T>

for any observable you can use a Monitor extension methods in order to publish the the observable’s datum information though a predefine channels.

Code Snippet
  1. var xs = Observable.Interval(TimeSpan.FromSeconds(1)).Take(5);
  2. xs = xs.Monitor("Interval 1 second", 1);
  3. xs.Subscribe();

the minimal overload of the Monitor method is getting 2 parameters

  • marble diagram name
  • marble diagram index order (which is handle by the viewer).

IMPORTANT: you should define the transmission channel (see Visual Rx Setting) in order to actually send the datum through the publication channel (it is you’re responsibility to define the publication channel).

for example the following code snippet is setting a Wcf Discovery proxy in order of monitoring 2 observables:

Code Snippet
  1. Task<VisualRxInitResult> info = VisualRxSettings.Initialize(
  2.     VisualRxWcfDiscoveryProxy.Create(),
  3.     VisualRxWcfQueuedProxy.Create(),
  4.     VisualRxTraceSourceProxy.Create());
  6. VisualRxInitResult infos = info.Result;
  7. Trace.WriteLine(infos);
  9. var xs = Observable.Interval(TimeSpan.FromSeconds(1)).Take(5);
  10. xs = xs.Monitor("Interval 1 second", 1);
  11. var ys = Observable.Interval(TimeSpan.FromSeconds(0.5)).Take(10);
  12. ys = ys.Monitor("Interval 0.5 second", 2);
  14. xs.Subscribe();
  15. ys.Subscribe();

the above code will be present on the VisualRx viewer as follow:Profile, Rx, Diagnostic, Contrib, Marble, Bnaya, Dubug, Trace, Visual Rx

the viewer is having 2 tabs (All and Grid),
the All tab is the selected tab which present the data stream as a sequence of marbles, the distance between marble present the duration.
as you can see the 1 second interval is less intensive then the 0.5 second interval.

the Grid representation will present each datum as a line in a grid:

Profile, Rx, Diagnostic, Contrib, Marble, Bnaya, Dubug, Trace, Visual Rx

in real-life you may have more then a few Rx data streams which may have inter relation (you may want to have separate tab for each of those sub groups).

for this scenario Visual Rx support a keywords.

the following code snippet is setting different keywords to different datum streams:

Code Snippet
  1. var inputA1 = Observable.Interval(TimeSpan.FromSeconds(1.5)).Take(7);
  2. inputA1 = inputA1.Monitor("Input A1", 1, "ScenarioA", "Input");
  3. var inputA2 = Observable.Interval(TimeSpan.FromSeconds(2)).Take(5);
  4. inputA2 = inputA2.Monitor("Input A2", 2, "ScenarioA", "Input");
  5. var outputA = Observable.Merge(inputA1, inputA2);
  6. outputA = outputA.Monitor("Output A", 3, "ScenarioA", "Output");
  8. var inputB = Observable.Interval(TimeSpan.FromSeconds(1)).Take(10);
  9. inputB = inputB.Monitor("Input B", 4, "ScenarioB", "Input");
  10. var outputB = from item in inputB
  11.               group item by item % 3 into g
  12.               select g;
  13. outputB = outputB.MonitorGroup("Output B", 5, "ScenarioB", "Output");
  15. outputA.Subscribe();
  16. outputB.Subscribe(g => g.Subscribe());

line 1-6 is constructing the first scenario (Scenario A) where 2 input stream are merged into a single output stream (Output A).

you can see at line 2,4 that the monitoring is specify both "ScenarioA" and "Input" keywords,
while on line 6, the monitoring is specify "ScenarioA" and "Output" keywords.

lines 8-13 is constructing the second scenario (Scenario B) which is having a single input stream and group by manipulation for the output stream.

as you can see at line 9 the keywords for the input stream is"ScenarioB" and "Input" and
at line 13 you can see a group monitoring using the MonitorGroup extension method, which is using the "ScenarioB" and "Output" keywords.
(shortly we will survey the output of the MonitorGroup extension).

summarizing, we was attaching different keywords at different stage on the pipeline of scenario A and B.
as you will see shortly, it will help us to stay in focus about each scenario, the inputs or the outputs streams.

the Visual Rx viewer will present it as follow:

Profile, Rx, Diagnostic, Contrib, Marble, Bnaya, Dubug, Trace, Visual Rx

you can easily see the monitoring of the first scenario in the first 3 marble’s lines, while the second scenario is present in the last 5 marble’s line.

as you can record, we was using the MonitorGroup extension method. using this kind of monitoring results with one marble’s line for the group’s keys (the "Output B (keys)" line).
and a marble’s line for each group output (because our group key was item % 3 there is only 3 group’s lines Output B 1,2,3).

but in real life monitoring this tab can become a bit over packed with to much marble’s line.

by using the keywords you can focus on different aspects of overall execution like each scenario, input or outputs.

you can see that except of the Grid and the All tabs the viewer has create a new tab for each keyword.

for example: the Scenario B  tab will show the marble’s line which was attached to the "ScenarioB" keyword:

Profile, Rx, Diagnostic, Contrib, Marble, Bnaya, Dubug, Trace, Visual Rx

while the Output tab will focus on the "Output" keyword:

Profile, Rx, Diagnostic, Contrib, Marble, Bnaya, Dubug, Trace, Visual Rx

this can really help us to stay in focus on what we actually monitoring.

More extensions:

just like the MonitorGroup which can represent a group by monitoring, there is a MonitorMany that can monitor a IObservable<IObservable<T>> (which is the result of the Window operator).
in the future I may add other monitoring operators.


another future API will be the ability to attach a Category which will act as a scope where the Viewer can be subscribe to specific categories.
this feature will enable to open multiple viewers for different monitoring scenario.
this feature is still on the design table and in general you can vote for feature in here.


this is part one of the series which give you the basics instruction for monitoring a data stream using the Monitor extension.

you can download the Viewer and the SDK from codeplex and the SDK can also be download from NuGet (search for VisualRx).

you can vote for feature at the CodePlex site under the Issue Tracker tab.

kick it on Shout it

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

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>