#1
|
|||
|
|||
![]()
Hi,
Oftentimes, I have a lot of complicated channels deployed from the same Mirth installation and I loose track of what's doing what. I was thinking it would be nice to have a script that would generate a directed graph indicating which channels fed into which. So, I decided to write one this afternoon and here it is: Code:
#!/usr/bin/perl use Graph::Easy; use XML::Smart; #open the directory specified in the parameter and read the files opendir(DIR, $ARGV[0]); @files = readdir DIR; foreach $file (@files){ $path = $ARGV[0]."/".$file; if ($file ne "." && $file ne ".."){ push(@channels, XML::Smart->new($path)); } } #loop through the channels and make a hash where the keys are channel id's and the values are channel names foreach $channel (@channels){ $channel = $channel->cut_root; $idNameHash{$channel->{id}} = $channel->{name}; } #loop again, but this time make an array of destination, name pairings foreach $channel (@channels){ $i = 0; while ($channel->{destinationConnectors}{'com.webreach.mirth.model.Connector'}[$i]){ @properties = @{$channel->{destinationConnectors}{'com.webreach.mirth.model.Connector'}[$i]{properties}{property}}; if ($properties[3] ne "sink"){ @edge = [$channel->{name}, $idNameHash{$properties[3]}]; push(@edges, @edge); } $i++; } } #generate the directed graph my $graph = Graph::Easy->new(); $i=0; while($edges[$i]){ $first = sprintf("%s",$edges[$i]->[0]); $second = sprintf("%s",$edges[$i]->[1]); $graph->add_edge($first, $second); $i++; } print $graph->as_ascii( ); If you run the script against the attached collection of test Mirth channels, you'll see the following graph rendered in ASCII: Code:
+---+ | E | +---+ ^ | | +---+ +---+ +---+ | A | --> | B | --> | C | +---+ +---+ +---+ | | v +---+ | D | +---+ The script doesn't recognize the situation when a channel feeds another by virtue of the javascript call 'router.routeMessage', but it could be made to do so. Also, if you want a webpage as output instead, try $graph->as_html_page() instead of $graph->as_ascii(). If people think this is useful, maybe something like it could be made part of admin interface someday. Thanks and Happy Mirthing! Last edited by csmith; 05-25-2010 at 10:24 AM. Reason: clarification |
#2
|
|||
|
|||
![]()
Nice work!
__________________
Jon Bartels Zen is hiring!!!! http://consultzen.com/careers/ Talented healthcare IT professionals wanted. Engineers to sales to management. Good benefits, great working environment, genuinely interesting work. |
#3
|
|||
|
|||
![]()
Wow, nice work indeed!
__________________
Jacob Brauer Director, Software Development NextGen Healthcare |
#4
|
|||
|
|||
![]()
Hi,
Thanks for the interest! I've modified the code to find destination channels specified by calls to 'router.routeMessage' in javascript source transformers. See below: Code:
#!/usr/bin/perl use Graph::Easy; use XML::Smart; #open the directory specified in the parameter and read the files opendir(DIR, $ARGV[0]); @files = readdir DIR; foreach $file (@files){ $path = $ARGV[0]."/".$file; if ($file ne "." && $file ne ".."){ push(@channels, XML::Smart->new($path)); } } #loop through the channels and make a hash where the keys are channel id's and the values are channel names foreach $channel (@channels){ $channel = $channel->cut_root; $idNameHash{$channel->{id}} = $channel->{name}; } #loop again, but this time make an array of destination, name pairings foreach $channel (@channels){ #loop for destination connectors first $i = 0; while ($channel->{destinationConnectors}{'com.webreach.mirth.model.Connector'}[$i]){ @properties = @{$channel->{destinationConnectors}{'com.webreach.mirth.model.Connector'}[$i]{properties}{property}}; if ($idNameHash{$properties[3]}){ @edge = [$channel->{name}, $idNameHash{$properties[3]}]; push(@edges, @edge); } $i++; } #now, loop for destinations specified in javascript source transformers $i = 0; while ($codeText = $channel->{sourceConnector}{transformer}{steps}[$i]{'com.webreach.mirth.model.Step'}{script}){ while ($codeText =~ /(routeMessage\(\'.+\')/g ){ $processed = $1; $processed =~ s/routeMessage\(//; $processed =~ s/'//g; @edge = [$channel->{name}, $processed]; push(@edges, @edge); } $i++; } } #generate the directed graph my $graph = Graph::Easy->new(); $i=0; while($edges[$i]){ $first = sprintf("%s",$edges[$i]->[0]); $second = sprintf("%s",$edges[$i]->[1]); $graph->add_edge_once($first, $second); $i++; } print $graph->as_ascii( ); Code:
+--------------+ | | | | | +---------+---------+ | | | v | +---+ +---+ +---+ | | A | --> | B | --> | C | | +---+ +---+ +---+ | | | | | | | v v | +---+ +---+ +> | E | | D | +---+ +---+ Note that the script doesn't output channels that don't feed into other channels. It could be modified to do so, however. |
#5
|
|||
|
|||
![]()
Even better.
Now if you could only do it using a Java charting/graphing tool by looking through the Channel model...then we could include it in Mirth Connect. ![]()
__________________
Jacob Brauer Director, Software Development NextGen Healthcare |
#6
|
|||
|
|||
![]()
Hi,
You mean write a plug-in? Like one that would reside here, http://www.mirthcorp.com/community/f...onnect/plugins , in the source? I've modified the script slightly so that now it outputs channels that are 'orphaned', i.e., those that don't explicitly feed into (or out of) any of the others in the installation. Code:
#!/usr/bin/perl use Graph::Easy; use XML::Smart; #open the directory specified in the parameter and read the files opendir(DIR, $ARGV[0]); @files = readdir DIR; foreach $file (@files){ $path = $ARGV[0]."/".$file; if ($file ne "." && $file ne ".."){ push(@channels, XML::Smart->new($path)); } } #loop through the channels and make a hash where the keys are channel id's and the values are channel names foreach $channel (@channels){ $channel = $channel->cut_root; $idNameHash{$channel->{id}} = $channel->{name}; $nameUsageHash{$channel->{name}} = 0; } #loop again, but this time make an array of destination, name pairings foreach $channel (@channels){ #loop for destination connectors first $i = 0; while ($channel->{destinationConnectors}{'com.webreach.mirth.model.Connector'}[$i]){ @properties = @{$channel->{destinationConnectors}{'com.webreach.mirth.model.Connector'}[$i]{properties}{property}}; if ($idNameHash{$properties[3]}){ @edge = [$channel->{name}, $idNameHash{$properties[3]}]; push(@edges, @edge); } $i++; } #now, loop for destinations specified in javascript source transformers $i = 0; while ($codeText = $channel->{sourceConnector}{transformer}{steps}[$i]{'com.webreach.mirth.model.Step'}{script}){ while ($codeText =~ /(routeMessage\(\'.+\')/g ){ $processed = $1; $processed =~ s/routeMessage\(//; $processed =~ s/'//g; @edge = [$channel->{name}, $processed]; push(@edges, @edge); } $i++; } } #generate the directed graph my $graph = Graph::Easy->new(); $i=0; while($edges[$i]){ $first = sprintf("%s",$edges[$i]->[0]); $second = sprintf("%s",$edges[$i]->[1]); $counter = $nameUsageHash{$first}; $nameUsageHash{$first} = $counter + 1; $counter = $nameUsageHash{$second}; $nameUsageHash{$second} = $counter + 1; $graph->add_edge_once($first, $second); $i++; } #output orphaned channels as unconnected nodes while (($key, $value) = each (%nameUsageHash)){ if ($value == 0){ $graph->add_node($key); } } print $graph->as_ascii( ); Code:
+-------------------+ | v +---+ +---+ +---+ | A | --> | B | --> | C | +---+ +---+ +---+ | | | | v | +---+ | | E | <-----+ +---+ +---+ | D | +---+ Thanks |
#7
|
|||
|
|||
![]()
Yeah, some sort of plugin would be great. It might just be in the core client, though, because it would be nice to really integrate it into the channel viewer. It would also help if it graphed out transformers and destinations so that you could double click those and jump directly to them in the channel. It's definitely something we've wanted to have as an option for a long time.
__________________
Jacob Brauer Director, Software Development NextGen Healthcare |
#8
|
|||
|
|||
![]()
this is awesome!
|
#9
|
|||
|
|||
![]()
I agree. This looks great. I was in the process of testing it myself and am having trouble exporting my channels from the mirth shell. I can export one at a time, but I can not seem to export all.
I am using: export * "/tmp/channels" but it throws an Invocation error and kicks me out of the shell. I know I can export all through the GUI but I would then need to put all of those into a file on the Linux box the shell is running on. Any ideas? |
#10
|
|||
|
|||
![]()
Hi,
Thanks for your interest! This version picks up destinations specified in javascript destination writers: Code:
#!/usr/bin/perl use Graph::Easy; use XML::Smart; #open the directory specified in the parameter and read the files opendir(DIR, $ARGV[0]); @files = readdir DIR; foreach $file (@files){ $path = $ARGV[0]."/".$file; if ($file ne "." && $file ne ".."){ push(@channels, XML::Smart->new($path)); } } #loop through the channels and make a hash where the keys are channel id's and the values are channel names foreach $channel (@channels){ $channel = $channel->cut_root; $idNameHash{$channel->{id}} = $channel->{name}; $nameUsageHash{$channel->{name}} = 0; } #loop again, but this time make an array of destination, name pairings foreach $channel (@channels){ #loop for destination connectors first $i = 0; while ($channel->{destinationConnectors}{'com.webreach.mirth.model.Connector'}[$i]){ @properties = @{$channel->{destinationConnectors}{'com.webreach.mirth.model.Connector'}[$i]{properties}{property}}; if ($idNameHash{$properties[3]}){ @edge = [$channel->{name}, $idNameHash{$properties[3]}]; push(@edges, @edge); } $i++; } #now, loop for destinations specified in javascript source transformers $i = 0; while ($codeText = $channel->{sourceConnector}{transformer}{steps}[$i]{'com.webreach.mirth.model.Step'}{script}){ while ($codeText =~ /(routeMessage\(\'.+\')/g ){ $processed = $1; $processed =~ s/routeMessage\(//; $processed =~ s/'//g; @edge = [$channel->{name}, $processed]; push(@edges, @edge); } $i++; } #now, loop for destinations specified in javascript destination writers $i = 0; while ($codeText = $channel->{destinationConnectors}{'com.webreach.mirth.model.Connector'}[$i]{properties}{property}){ while ($codeText =~ /(routeMessage\(\'.+\')/g ){ $processed = $1; $processed =~ s/routeMessage\(//; $processed =~ s/'//g; @edge = [$channel->{name}, $processed]; push(@edges, @edge); } $i++; } } #generate the directed graph my $graph = Graph::Easy->new(); $i=0; while($edges[$i]){ $first = sprintf("%s",$edges[$i]->[0]); $second = sprintf("%s",$edges[$i]->[1]); $counter = $nameUsageHash{$first}; $nameUsageHash{$first} = $counter + 1; $counter = $nameUsageHash{$second}; $nameUsageHash{$second} = $counter + 1; $graph->add_edge_once($first, $second); $i++; } #output orphaned channels as unconnected nodes while (($key, $value) = each (%nameUsageHash)){ if ($value == 0){ $graph->add_node($key); } } print $graph->as_ascii( ); It looks like it would be a tough job though. Thanks again! |
![]() |
Thread Tools | |
Display Modes | |
|
|