Skip to content

Commit

Permalink
#45: Initial spike of Camel profile view.
Browse files Browse the repository at this point in the history
  • Loading branch information
davsclaus committed Apr 8, 2013
1 parent 1dc31b0 commit da1ab81
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 3 deletions.
4 changes: 1 addition & 3 deletions hawtio-web/pom.xml
Expand Up @@ -658,10 +658,8 @@

<profile>
<id>camelSnapshot</id>

<!-- when using the exec:java target this will try to auto-connect to a local fuse fabric -->
<properties>
<camel-version>2.11-SNAPSHOT</camel-version>
<camel-version>2.12-SNAPSHOT</camel-version>
</properties>
</profile>

Expand Down
20 changes: 20 additions & 0 deletions hawtio-web/src/main/webapp/app/camel/html/profileRoute.html
@@ -0,0 +1,20 @@
<div class="row-fluid" ng-controller="Camel.ProfileRouteController">

<div class="row-fluid">
<div class="pull-right">
<form class="form-inline no-bottom-margin">
<fieldset>
<div class="control-group inline-block">
<input type="text" class="search-query" placeholder="Filter..." ng-model="search">
</div>
</fieldset>
</form>
</div>
</div>

<div class="row-fluid">
<div class="gridStyle" ng-grid="gridOptions"></div>
</div>

</div>

7 changes: 7 additions & 0 deletions hawtio-web/src/main/webapp/app/camel/js/camelPlugin.ts
Expand Up @@ -19,6 +19,7 @@ module Camel {
when('/camel/sendMessage', {templateUrl: 'app/camel/html/sendMessage.html'}).
when('/camel/source', {templateUrl: 'app/camel/html/source.html'}).
when('/camel/traceRoute', {templateUrl: 'app/camel/html/traceRoute.html'}).
when('/camel/profileRoute', {templateUrl: 'app/camel/html/profileRoute.html'}).
when('/camel/properties', {templateUrl: 'app/camel/html/properties.html'});
}).
filter('camelIconClass', () => iconClass).
Expand Down Expand Up @@ -141,6 +142,12 @@ module Camel {
isValid: (workspace: Workspace) => workspace.isRoute() && Camel.getSelectionCamelTraceMBean(workspace),
href: () => "#/camel/traceRoute"
});
workspace.subLevelTabs.push({
content: '<i class="icon-bar-chart"></i> Profile',
title: "Profile the messages flowing through the Camel route",
isValid: (workspace: Workspace) => workspace.isRoute() && Camel.getSelectionCamelTraceMBean(workspace),
href: () => "#/camel/profileRoute"
});
workspace.subLevelTabs.push({
content: '<i class="icon-pencil"></i> Send',
title: "Send a message to this endpoint",
Expand Down
26 changes: 26 additions & 0 deletions hawtio-web/src/main/webapp/app/camel/js/helpers.ts
Expand Up @@ -304,4 +304,30 @@ module Camel {
}
return selectedRouteId;
}

/**
* Returns the selected camel route mbean for the given route id
*/
// TODO Should be a service
export function getSelectionRouteMBean(workspace: Workspace, routeId: String) {
if (workspace) {
var contextId = getContextId(workspace);
var selection = workspace.selection;
var tree = workspace.tree;
if (tree && selection) {
var domain = selection.domain;
if (domain && contextId) {
var result = tree.navigate(domain, contextId, "routes");
if (result && result.children) {
var mbean = result.children.find(m => m.title === routeId);
if (mbean) {
return mbean.objectName;
}
}
}
}
}
return null;
}

}
221 changes: 221 additions & 0 deletions hawtio-web/src/main/webapp/app/camel/js/profile.ts
@@ -0,0 +1,221 @@
module Camel {

export function ProfileRouteController($scope, $location, workspace:Workspace, jolokia) {

$scope.data = [];
$scope.search = "";

var columnDefs: any[] = [
{
field: 'id',
displayName: 'Id',
cellFilter: null,
width: "*",
resizable: true
},
{
field: 'count',
displayName: 'Count',
cellFilter: null,
width: "*",
resizable: true
},
{
field: 'last',
displayName: 'Last',
cellFilter: null,
width: "*",
resizable: true
},
{
field: 'delta',
displayName: 'Delta',
cellFilter: null,
width: "*",
resizable: true
},
{
field: 'mean',
displayName: 'Mean',
cellFilter: null,
width: "*",
resizable: true
},
{
field: 'min',
displayName: 'Min',
cellFilter: null,
width: "*",
resizable: true
},
{
field: 'max',
displayName: 'Max',
cellFilter: null,
width: "*",
resizable: true
},
{
field: 'total',
displayName: 'Total',
cellFilter: null,
width: "*",
resizable: true
},
{
field: 'self',
displayName: 'Self',
cellFilter: null,
width: "*",
resizable: true
}
];

$scope.gridOptions = {
data: 'data',
displayFooter: true,
displaySelectionCheckbox: false,
canSelectRows: false,
enableSorting: false,
columnDefs: columnDefs,
filterOptions: {
filterText: 'search'
}
};


var populateProfileMessages = function (response) {
var updatedData = [];

// its xml structure so we need to parse it
var xml = response.value;
if (angular.isString(xml)) {

// lets parse the XML DOM here...
var doc = $.parseXML(xml);

var routeMessages = $(doc).find("routeStat");

routeMessages.each((idx, message) => {
var messageData = {
id: {},
count: {},
last: {},
delta: {},
mean: {},
min: {},
max: {},
total: {},
self: {}
};

// compare counters, as we only update if we have new data
messageData.id = message.getAttribute("id");

var total = 0;
total += +message.getAttribute("exchangesCompleted");
total += +message.getAttribute("exchangesFailed");
messageData.count = total;
messageData.last = message.getAttribute("lastProcessingTime");
// delta is only avail from Camel 2.11 onwards
var delta = message.getAttribute("deltaProcessingTime");
if (delta) {
messageData.delta = delta;
} else {
messageData.delta = 0;
}
messageData.mean = message.getAttribute("meanProcessingTime");
messageData.min = message.getAttribute("minProcessingTime");
messageData.max = message.getAttribute("maxProcessingTime");
messageData.total = message.getAttribute("totalProcessingTime");
// self is pre calculated from Camel 2.11 onwards
var self = message.getAttribute("selfProcessingTime");
if (self) {
messageData.self = self;
} else {
messageData.self = "TODO";
}

updatedData.push(messageData);
});

console.log("Updating processor stats...");
var processorMessages = $(doc).find("processorStat");

processorMessages.each((idx, message) => {
var messageData = {
id: {},
count: {},
last: {},
delta: {},
mean: {},
min: {},
max: {},
total: {},
self: {}
};

messageData.id = message.getAttribute("id");
var total = 0;
total += +message.getAttribute("exchangesCompleted");
total += +message.getAttribute("exchangesFailed");
messageData.count = total;
messageData.last = message.getAttribute("lastProcessingTime");
// delta is only avail from Camel 2.11 onwards
var delta = message.getAttribute("deltaProcessingTime");
if (delta) {
messageData.delta = delta;
} else {
messageData.delta = 0;
}
messageData.mean = message.getAttribute("meanProcessingTime");
messageData.min = message.getAttribute("minProcessingTime");
messageData.max = message.getAttribute("maxProcessingTime");
// total time for processors is pre calculated as accumulated from Camel 2.11 onwards
var total = message.getAttribute("accumulatedProcessingTime");
if (total) {
messageData.total = total;
} else {
messageData.total = "TOOD"
}
// self time for processors is their total time
messageData.self = message.getAttribute("totalProcessingTime");

updatedData.push(messageData);
});
}

// replace data with updated data
$scope.data = updatedData;
Core.$apply($scope);
};

// function to trigger reloading page
$scope.onResponse = function (response) {
//console.log("got response: " + response);
loadData();
};

$scope.$watch('workspace.tree', function () {
// if the JMX tree is reloaded its probably because a new MBean has been added or removed
// so lets reload, asynchronously just in case
setTimeout(loadData, 50);
});

function loadData() {
console.log("Loading Camel route profile data...");
var selectedRouteId = getSelectedRouteId(workspace);
var routeMBean = getSelectionRouteMBean(workspace, selectedRouteId);
console.log("Selected route is " + selectedRouteId)

// schedule update the profile data, based on the configured interval
// TODO: trigger loading data first time page is viewed so we dont have to wait or show a loading... page
// TODO: show eips in the table/tree
// TODO: have cellFilter with bar grey-scale for highlighting the scales between the numbers

var query = {type: 'exec', mbean: routeMBean, operation: 'dumpRouteStatsAsXml(boolean,boolean)', arguments: [false, true]};
scopeStoreJolokiaHandle($scope, jolokia, jolokia.register(populateProfileMessages, query));
}

}
}

0 comments on commit da1ab81

Please sign in to comment.