diff --git a/web/src/main/webapp/components/pinpoint-servermap/js/jquery.ServerMap2.js b/web/src/main/webapp/components/pinpoint-servermap/js/jquery.ServerMap2.js index e8d365554..4b3c9195f 100644 --- a/web/src/main/webapp/components/pinpoint-servermap/js/jquery.ServerMap2.js +++ b/web/src/main/webapp/components/pinpoint-servermap/js/jquery.ServerMap2.js @@ -20,7 +20,8 @@ * @method $init * @param {Hash Table} options */ - $init: function (htOption) { + $init: function (htOption, $location) { + this._query = ""; this.option({ "sContainerId": '', "sOverviewId": '', @@ -39,7 +40,9 @@ 'MEMCACHED': 'MEMCACHED.png', 'MONGODB': 'MONGODB.png', 'MSSQLSERVER': 'MSSQLSERVER.png', + 'MSSQLSERVER_GROUP': 'MSSQLSERVER.png', 'MYSQL': 'MYSQL.png', + 'MYSQL_GROUP': 'MYSQL.png', 'NBASE': 'NBASE.png', 'NGINX': 'NGINX.png', 'ORACLE': 'ORACLE.png', @@ -47,6 +50,7 @@ 'STAND_ALONE': 'STAND_ALONE.png', 'TOMCAT': 'TOMCAT.png', 'UNDEFINED': 'UNDEFINED.png', + 'UNDEFINED_GROUP': 'UNDEFINED.png', 'UNKNOWN': 'UNKNOWN.png', 'UNKNOWN_GROUP': 'UNKNOWN_GROUP.png', 'REDIS': 'REDIS.png', @@ -58,12 +62,13 @@ "backgroundColor": "#ffffff", "borderColor": "#C5C5C5", "borderWidth": 1, - "fontColor": "#1F1F21" + "fontColor": "#000000" }, "bold": { "backgroundColor": "#f2f2f2", "borderColor": "#666975", - "borderWidth": 2 + "borderWidth": 2, + "fontColor": "#000000" } }, "htLinkType": { @@ -94,7 +99,8 @@ //"borderColor": "#25AFF4", "borderColor": "#53069B", "backgroundColor": "#289E1D", - "fontColor": "#ffffff" + //"fontColor": "#5cb85c" + "fontColor": "#53069B" }, "htHighlightLink": { "fontFamily": "bold 12pt avn55,NanumGothic,ng,dotum,AppleGothic,sans-serif", @@ -130,7 +136,7 @@ this._initNodeTemplates(); this._initLinkTemplates(); this._initDiagramEnvironment(); - this._initOverview(); + this._initOverview( $location ); }, /** @@ -202,7 +208,7 @@ click: function (e, obj) { self._onNodeClicked(e, obj); }, - contextClick: self._onNodeContextClicked.bind(this) + contextClick: self._onNodeContextClicked.bind(self) }, self.$( go.Shape, @@ -388,6 +394,7 @@ self.$( go.TextBlock, { + name: "NODE_APPLICATION_NAME", margin: new go.Margin(1, 2), column: 2, font: self.option('sSmallFont'), @@ -430,7 +437,7 @@ self._onNodeClicked(e, obj); } }, - contextClick: self._onNodeContextClicked.bind(this) + contextClick: self._onNodeContextClicked.bind(self) }, self.$( go.Shape, @@ -452,11 +459,13 @@ go.Panel, go.Panel.Spot, { + name: "NODE_1SUB_PANEL", }, self.$( go.Panel, go.Panel.Vertical, { + name: "NODE_2SUB_PANEL", alignment: go.Spot.TopLeft, alignmentFocus: go.Spot.TopLeft, minSize: new go.Size(130, NaN) @@ -483,12 +492,51 @@ new go.Binding("itemArray", "unknownNodeGroup") ) ) + ), + self.$( + go.Panel, + go.Panel.Auto, + { + alignment: go.Spot.TopRight, + alignmentFocus: go.Spot.TopRight, + visible: false + }, + new go.Binding("visible", "instanceCount", function (v) { + return v > 1 ? true : false; + }), + self.$( + go.Shape, + { + figure: "RoundedRectangle", + fill: "#848484", + strokeWidth: 1, + stroke: "#848484" + } + ), + self.$( + go.Panel, + go.Panel.Auto, + { + margin: new go.Margin(0, 3, 0, 3) + }, + self.$( + go.TextBlock, + new go.Binding("text", "instanceCount"), + { + stroke: "#FFFFFF", + textAlign: "center", + height: 16, + font: self.option('sSmallFont'), + editable: false + } + ) + ) ) ); }; _.each(htIcons, function (sVal, sKey) { - if (sKey === "UNKNOWN_GROUP") { + if ( sKey.indexOf( "_GROUP" ) != -1 ) { this._oDiagram.nodeTemplateMap.add(sKey, getUnknownGroupTemplate(sVal)); } else { this._oDiagram.nodeTemplateMap.add(sKey, getNodeTemplate(sVal)); @@ -711,14 +759,19 @@ * * @method _initOverview */ - _initOverview: function () { - this._oOverview = this.$( go.Overview, - this.option('sOverviewId'), - { observed: this._oDiagram } - ); - this._oOverview.box.elt(0).figure = "RoundedRectangle"; - this._oOverview.box.elt(0).stroke = "#53069B"; - this._oOverview.box.elt(0).strokeWidth = 4; + _initOverview: function ( $location ) { + + if ( /^\/main/.test( $location.path() ) ) { + this._oOverview = this.$( go.Overview, + this.option('sOverviewId'), + { observed: this._oDiagram } + ); + this._oOverview.box.elt(0).figure = "RoundedRectangle"; + this._oOverview.box.elt(0).stroke = "#53069B"; + this._oOverview.box.elt(0).strokeWidth = 4; + } else { + $( "#" + this.option('sOverviewId') ).hide(); + } }, /** @@ -787,7 +840,7 @@ // nodes, including groups while (allNodes.next()) { - this._hightlightNode(allNodes.value.findObject("NODE_SHAPE"), allNodes.value.findObject("NODE_TEXT"), allNodes.value.highlight); + this._highlightNode(allNodes.value.findObject("NODE_SHAPE"), allNodes.value.findObject("NODE_TEXT"), allNodes.value.highlight); } // links while (allLinks.next()) { @@ -853,18 +906,43 @@ * @param theme * @private */ - _hightlightNode: function (nodeShape, nodeText, theme) { + _highlightNode: function (nodeShape, nodeText, theme) { if (nodeShape === null || nodeText === null) { return; } if (theme) { nodeShape.stroke = this.option('htHighlightNode').borderColor; nodeShape.strokeWidth = 2; + nodeShape.part.isShadowed = true; + + if ( this._query != "" ) { + if ( nodeText.type === go.Panel.Table ) { + for( var i = 0 ; i < nodeText.rowCount ; i++ ) { + if ( new RegExp( this._query, "i" ).test( nodeText.elt(i).elt(1).text ) ) { + nodeText.elt(i).elt(1).stroke = this.option('htHighlightNode').fontColor; + } + } + } else { + if ( new RegExp( this._query, "i" ).test( nodeText.text ) ) { + nodeText.stroke = this.option('htHighlightNode').fontColor; + } + } + } // nodeText.stroke = this.option('htHighlightNode')[theme].fontColor; } else { var type = (nodeShape.key === this.option('sBoldKey')) ? 'bold' : 'default'; nodeShape.stroke = this.option('htNodeTheme')[type].borderColor; nodeShape.strokeWidth = 1; + nodeShape.part.isShadowed = false; + + if ( nodeText.type === go.Panel.Table ) { + for( var i = 0 ; i < nodeText.rowCount ; i++ ) { + nodeText.elt(i).elt(1).stroke = this.option('htNodeTheme')[type].fontColor; + } + } else { + nodeText.stroke = this.option('htNodeTheme')[type].fontColor; + } + // nodeText.stroke = this.option('htNodeTheme').default.fontColor; } }, @@ -987,12 +1065,12 @@ * @param {ojb} ojb * @param {String} unknownKey */ - _onNodeClicked: function (e, obj, unknownKey) { + _onNodeClicked: function (e, obj, unknownKey, query) { var node = obj.part, htData = node.data, fOnNodeClicked = this.option('fOnNodeClicked'); if (_.isFunction(fOnNodeClicked)) { - fOnNodeClicked.call(this, e, htData, unknownKey); + fOnNodeClicked.call(this, e, htData, unknownKey, query); } // node.diagram.startTransaction("onNodeClick"); // node.diagram.commitTransaction("onNodeClick"); @@ -1070,10 +1148,14 @@ this._oDiagram.contentAlignment = go.Spot.Center; this._oDiagram.contentAlignment = go.Spot.None; }, + clearQuery: function() { + this._query = ""; + }, /** * search node */ - searchNode: function( nodeName, nodeServiceType ) { + searchNode: function( query, nodeServiceType ) { + this._query = query; var allNodes = this._oDiagram.nodes, selectedNode = null, selectedIndex = 0, @@ -1082,17 +1164,17 @@ while (allNodes.next()) { var node = allNodes.value; - if ( node.data.serviceType == this.option("unknownGroupName") && ( nodeServiceType == this.option("unknownGroupName") || nodeServiceType == null ) ) { + if ( node.data.unknownNodeGroup ) { var unknownNodeGroup = node.data.unknownNodeGroup; for( var i = 0; i < unknownNodeGroup.length ; i++ ) { - if ( new RegExp( nodeName, "i" ).test( unknownNodeGroup[i].applicationName ) ) { + if ( new RegExp( query, "i" ).test( unknownNodeGroup[i].applicationName ) ) { this._addNodeToTemporaryList( similarNodeList, returnNodeDataList, node, unknownNodeGroup[i], this.option("unknownGroupName") ); break; } } } else { if ( !angular.isUndefined( node.data.applicationName ) ) { - if ( new RegExp( nodeName, "i" ).test( node.data.applicationName ) ) { + if ( new RegExp( query, "i" ).test( node.data.applicationName ) ) { this._addNodeToTemporaryList( similarNodeList, returnNodeDataList, node, node.data ); if ( new RegExp( nodeServiceType, "i" ).test( node.data.serviceType ) ) { selectedIndex = similarNodeList.length - 1; @@ -1119,7 +1201,7 @@ _selectAndHighlight : function( selectedNode ) { this._oDiagram.select( selectedNode ); this._oDiagram.centerRect( selectedNode.actualBounds ); - this._onNodeClicked(null, selectedNode ); + this._onNodeClicked(null, selectedNode, null, this._query ); } }); diff --git a/web/src/main/webapp/images/icons/CUBRID_GROUP.png b/web/src/main/webapp/images/icons/CUBRID_GROUP.png new file mode 100644 index 000000000..2521c7948 Binary files /dev/null and b/web/src/main/webapp/images/icons/CUBRID_GROUP.png differ diff --git a/web/src/main/webapp/images/icons/MONGODB_GROUP.png b/web/src/main/webapp/images/icons/MONGODB_GROUP.png new file mode 100644 index 000000000..f7faabfaa Binary files /dev/null and b/web/src/main/webapp/images/icons/MONGODB_GROUP.png differ diff --git a/web/src/main/webapp/images/icons/MSSQLSERVER_GROUP.png b/web/src/main/webapp/images/icons/MSSQLSERVER_GROUP.png new file mode 100644 index 000000000..49e0e7703 Binary files /dev/null and b/web/src/main/webapp/images/icons/MSSQLSERVER_GROUP.png differ diff --git a/web/src/main/webapp/images/icons/MYSQL_GROUP.png b/web/src/main/webapp/images/icons/MYSQL_GROUP.png new file mode 100644 index 000000000..5c7133f28 Binary files /dev/null and b/web/src/main/webapp/images/icons/MYSQL_GROUP.png differ diff --git a/web/src/main/webapp/images/icons/ORACLE_GROUP.png b/web/src/main/webapp/images/icons/ORACLE_GROUP.png new file mode 100644 index 000000000..77044a3a2 Binary files /dev/null and b/web/src/main/webapp/images/icons/ORACLE_GROUP.png differ diff --git a/web/src/main/webapp/index.html b/web/src/main/webapp/index.html index 580b976da..149fd0c25 100644 --- a/web/src/main/webapp/index.html +++ b/web/src/main/webapp/index.html @@ -88,6 +88,7 @@ + diff --git a/web/src/main/webapp/scripts/controllers/filteredMap.js b/web/src/main/webapp/scripts/controllers/filteredMap.js index 70b31656d..577c3cd0e 100644 --- a/web/src/main/webapp/scripts/controllers/filteredMap.js +++ b/web/src/main/webapp/scripts/controllers/filteredMap.js @@ -185,7 +185,7 @@ pinpointApp.controller('FilteredMapCtrl', [ 'filterConfig', '$scope', '$routePar oSidebarTitleVo.setTitle(node.applicationName); $scope.$broadcast('scatter.showByNode', node); } else if (node.unknownNodeGroup) { - oSidebarTitleVo.setTitle('Unknown Group'); + oSidebarTitleVo.setTitle( node.serviceType.replace( "_", " " ) ); $scope.hasScatter = false; } else { oSidebarTitleVo.setTitle(node.applicationName); diff --git a/web/src/main/webapp/scripts/controllers/main.js b/web/src/main/webapp/scripts/controllers/main.js index 9e6a331a2..06c411152 100644 --- a/web/src/main/webapp/scripts/controllers/main.js +++ b/web/src/main/webapp/scripts/controllers/main.js @@ -146,7 +146,7 @@ pinpointApp.controller('MainCtrl', [ 'filterConfig', '$scope', '$timeout', '$rou /** * scope event on serverMap.nodeClicked */ - $scope.$on('serverMap.nodeClicked', function (event, e, query, node, data) { + $scope.$on('serverMap.nodeClicked', function (event, e, query, node, data, searchQuery) { bNodeSelected = true; var oSidebarTitleVo = new SidebarTitleVo; oSidebarTitleVo.setImageType(node.serviceType); @@ -156,7 +156,7 @@ pinpointApp.controller('MainCtrl', [ 'filterConfig', '$scope', '$timeout', '$rou oSidebarTitleVo.setTitle(node.applicationName); $scope.$broadcast('scatter.initializeWithNode', node); } else if (node.unknownNodeGroup) { - oSidebarTitleVo.setTitle('Unknown Group'); + oSidebarTitleVo.setTitle( node.serviceType.replace( "_", " " ) ); $scope.hasScatter = false; } else { oSidebarTitleVo.setTitle(node.applicationName); @@ -164,7 +164,7 @@ pinpointApp.controller('MainCtrl', [ 'filterConfig', '$scope', '$timeout', '$rou } $scope.hasFilter = false; $scope.$broadcast('sidebarTitle.initialize.forMain', oSidebarTitleVo); - $scope.$broadcast('nodeInfoDetails.initialize', e, query, node, data, oNavbarVo); + $scope.$broadcast('nodeInfoDetails.initialize', e, query, node, data, oNavbarVo, null, searchQuery); $scope.$broadcast('linkInfoDetails.hide'); $scope.refreshHelpIcons(); @@ -261,7 +261,7 @@ pinpointApp.controller('MainCtrl', [ 'filterConfig', '$scope', '$timeout', '$rou oSidebarTitleVo .setImageType(node.serviceType); if (node.unknownNodeGroup) { - oSidebarTitleVo.setTitle('Unknown Group'); + oSidebarTitleVo.setTitle( node.serviceType.replace( "_", " " ) ); $scope.hasScatter = false; } else { oSidebarTitleVo.setTitle(node.applicationName); diff --git a/web/src/main/webapp/scripts/controllers/transactionDetail.js b/web/src/main/webapp/scripts/controllers/transactionDetail.js index c12eba46e..e5dd008aa 100644 --- a/web/src/main/webapp/scripts/controllers/transactionDetail.js +++ b/web/src/main/webapp/scripts/controllers/transactionDetail.js @@ -96,6 +96,10 @@ pinpointApp.controller('TransactionDetailCtrl', ['TransactionDetailConfig', '$sc $scope.openTransactionView = function () { $window.open('/#/transactionView/' + $scope.transactionDetail.agentId + '/' + $scope.transactionDetail.transactionId + '/' + $scope.transactionDetail.callStackStart); }; + $scope.$on("transactionDetail.selectDistributedCallFlowRow", function( event, rowId ) { + $("#traceTabs li:nth-child(1) a").trigger("click"); + $scope.$broadcast('distributedCallFlow.selectRow.forTransactionDetail', rowId); + }); // events binding $("#traceTabs li a").bind("click", function (e) { diff --git a/web/src/main/webapp/scripts/controllers/transactionList.js b/web/src/main/webapp/scripts/controllers/transactionList.js index 62307c04e..df333181d 100644 --- a/web/src/main/webapp/scripts/controllers/transactionList.js +++ b/web/src/main/webapp/scripts/controllers/transactionList.js @@ -54,7 +54,7 @@ pinpointApp.controller('TransactionListCtrl', ['TransactionListConfig', '$scope' $timeout(function () { $("#main-container").layout({ north__minSize: 20, - north__size: 200, + north__size: (window.innerHeight - 40) / 2, // north__spacing_closed: 20, // north__togglerLength_closed: 100, // north__togglerAlign_closed: "top", diff --git a/web/src/main/webapp/scripts/directives/distributedCallFlow.js b/web/src/main/webapp/scripts/directives/distributedCallFlow.js index 83ebeaf98..5a6331022 100644 --- a/web/src/main/webapp/scripts/directives/distributedCallFlow.js +++ b/web/src/main/webapp/scripts/directives/distributedCallFlow.js @@ -23,11 +23,11 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', /** * get color by string - * @param str + * @param idx * @returns {string} */ getColorByString = function(str) { - // str to hash + // str to hash for (var i = 0, hash = 0; i < str.length; hash = str.charCodeAt(i++) + ((hash << 5) - hash)); // int/hash to hex for (var i = 0, colour = "#"; i < 3; colour += ("00" + ((hash >> i++ * 8) & 0xFF).toString(16)).slice(-2)); @@ -59,8 +59,10 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', } else if (!item.isMethod) { divClass += ' not-method'; } + + html.push('
'); - html.push("
"); + html.push("
"); html.push(""); if (window.callStacks[idx + 1] && window.callStacks[idx + 1].indent > window.callStacks[idx].indent) { @@ -210,6 +212,7 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', isMethod: val[index['isMethod']] , logLink : val[index['logPageUrl']], logButtonName : val[index['logButtonName']], + isFocused : val[index['isFocused']] }); }); return result; @@ -248,6 +251,17 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', // }; // } // }; + dataView.getItemMetadata = function( row ) { + var item = dataView.getItemByIdx(row); + var o = { cssClasses: "" }; + if ( item.isFocused === true ) { + o.cssClasses += " entry-point"; + } + if ( item.execTime !== null ) { + o.cssClasses += " id_" + (row+1); + } + return o; + }; dataView.endUpdate(); var columns = [ @@ -268,6 +282,7 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', } grid = new Slick.Grid(element.get(0), dataView, columns, options); + grid.setSelectionModel(new Slick.RowSelectionModel()); var isSingleClick = true, clickTimeout = false; grid.onClick.subscribe(function (e, args) { @@ -376,6 +391,11 @@ pinpointApp.directive('distributedCallFlow', [ '$filter', '$timeout', scope.$on('distributedCallFlow.resize.' + scope.namespace, function (event) { grid.resizeCanvas(); }); + scope.$on("distributedCallFlow.selectRow." + scope.namespace, function( event, rowId ) { + var gridRow = rowId - 1; + grid.setSelectedRows( [gridRow] ); + grid.scrollRowToTop( gridRow ); + }); } }; } diff --git a/web/src/main/webapp/scripts/directives/nodeInfoDetails.js b/web/src/main/webapp/scripts/directives/nodeInfoDetails.js index 380072ac0..719422825 100644 --- a/web/src/main/webapp/scripts/directives/nodeInfoDetails.js +++ b/web/src/main/webapp/scripts/directives/nodeInfoDetails.js @@ -29,7 +29,7 @@ pinpointApp scope.htLastUnknownNode = false; angular.element($window).bind('resize',function(e) { - if (bShown && htLastNode.category === 'UNKNOWN_GROUP') { + if (bShown && /_GROUP$/.test( htLastNode.category ) ) { renderAllChartWhichIsVisible(htLastNode); } }); @@ -84,13 +84,13 @@ pinpointApp scope.showNodeServers = _.isEmpty(scope.serverList) ? false : true; scope.agentHistogram = node.agentHistogram; - if (node.serviceType !== "UNKNOWN_GROUP") { + if ( /_GROUP$/.test( node.serviceType ) === false ) { scope.showNodeResponseSummary = true; scope.showNodeLoad = true; renderResponseSummary('forNode', node.applicationName, node.histogram, '100%', '150px'); renderLoad('forNode', node.applicationName, node.timeSeriesHistogram, '100%', '220px', true); - } else if (node.serviceType === 'UNKNOWN_GROUP'){ + } else if ( /_GROUP$/.test( node.serviceType ) ){ scope.showNodeResponseSummaryForUnknown = (scope.oNavbarVo.getPeriod() <= cfg.maxTimeToShowLoadAsDefaultForUnknown) ? false : true; renderAllChartWhichIsVisible(node); // scope.htLastUnknownNode = angular.copy(node); @@ -308,7 +308,7 @@ pinpointApp /** * scope event on nodeInfoDetails.initialize */ - scope.$on('nodeInfoDetails.initialize', function (event, e, query, node, mapData, navbarVo, reloadOnly) { + scope.$on('nodeInfoDetails.initialize', function (event, e, query, node, mapData, navbarVo, reloadOnly, searchQuery) { show(); // DISABLE node Cache //if (angular.equals(sLastKey, node.key) && !reloadOnly) { @@ -323,6 +323,7 @@ pinpointApp htLastNode = node; scope.htLastUnknownNode = false; scope.oNavbarVo = navbarVo; + scope.nodeSearch = searchQuery || ""; htServermapData = mapData; showDetailInformation(node); }); diff --git a/web/src/main/webapp/scripts/directives/serverMap.js b/web/src/main/webapp/scripts/directives/serverMap.js index dbd102030..7fce64f20 100644 --- a/web/src/main/webapp/scripts/directives/serverMap.js +++ b/web/src/main/webapp/scripts/directives/serverMap.js @@ -34,8 +34,8 @@ pinpointApp.constant('serverMapConfig', { } }); -pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts', 'ProgressBar', 'SidebarTitleVo', '$filter', 'ServerMapFilterVo', 'encodeURIComponentFilter', 'filteredMapUtil', '$base64', 'ServerMapHintVo', '$timeout', - function (cfg, ServerMapDao, Alerts, ProgressBar, SidebarTitleVo, $filter, ServerMapFilterVo, encodeURIComponentFilter, filteredMapUtil, $base64, ServerMapHintVo, $timeout) { +pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts', 'ProgressBar', 'SidebarTitleVo', '$filter', 'ServerMapFilterVo', 'encodeURIComponentFilter', 'filteredMapUtil', '$base64', 'ServerMapHintVo', '$timeout', '$location', + function (cfg, ServerMapDao, Alerts, ProgressBar, SidebarTitleVo, $filter, ServerMapFilterVo, encodeURIComponentFilter, filteredMapUtil, $base64, ServerMapHintVo, $timeout, $location) { return { restrict: 'EA', replace: true, @@ -50,7 +50,7 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' // define private variables of methods var showServerMap, setNodeContextMenuPosition, reset, emitDataExisting, setLinkContextMenuPosition, setBackgroundContextMenuPosition, serverMapCallback, setLinkOption, - zoomToFit, updateLastSelection, openFilterWizard, searchNode; + zoomToFit, updateLastSelection, openFilterWizard, searchNode, getMergeArray, extractMergeTypeList; // bootstrap @@ -73,12 +73,12 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' htLastLink = {}; htLastNode = {}; scope.oNavbarVo = null; - scope.mergeUnknowns = true; + //scope.mergeUnknowns = true; scope.totalRequestCount = true; scope.bShowServerMapStatus = false; scope.linkRouting = cfg.options.htLinkType.sRouting; scope.linkCurve = cfg.options.htLinkType.sCurve; - scope.searchNodeName = ""; + scope.searchNodeQuery = ""; scope.searchNodeIndex = 0; scope.searchNodeList = []; $fromAgentName = element.find('.fromAgentName'); @@ -86,7 +86,23 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' $fromAgentName.select2(); $toAgentName.select2(); bIsFilterWizardLoaded = false; - + scope.mergeTypeList = [];//[ 'APACHE', 'ARCUS', 'BACKEND', 'BLOC', 'CASSANDRA', 'CUBRID', 'JAVA', 'MEMCACHED', 'MONGODB', 'MSSQLSERVER', 'MYSQL', 'NBASE', 'NGINX', 'ORACLE', 'QUEUE', 'STAND_ALONE', 'TOMCAT', 'UNKNOWN', 'REDIS', 'NBASE_ARC' ]; + scope.mergeStatus = {}; + + /** + * extract node serviceType info + * @param serverMapData + */ + extractMergeTypeList = function( serverMapData ) { + serverMapData.nodeDataArray.forEach( function( o ) { + if ( o.isWas == false && o.serviceType !== "USER" ) { + if ( angular.isUndefined( scope.mergeStatus[o.serviceType] ) ) { + scope.mergeTypeList.push( o.serviceType ); + scope.mergeStatus[o.serviceType] = true; + } + } + }); + }; /** * reset */ @@ -117,11 +133,10 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' * @param period * @param filterText * @parma hintText - * @param mergeUnknowns * @param linkRouting * @param linkCurve */ - showServerMap = function (applicationName, serviceTypeCode, to, period, filterText, hintText, mergeUnknowns, linkRouting, linkCurve) { + showServerMap = function (applicationName, serviceTypeCode, to, period, filterText, hintText, linkRouting, linkCurve) { oProgressBar.startLoading(); oAlert.hideError(); oAlert.hideWarning(); @@ -160,9 +175,14 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' htLastMapData.applicationMapData = ServerMapDao.mergeFilteredMapData(htLastMapData.applicationMapData, result.applicationMapData); var serverMapData = ServerMapDao.extractDataFromApplicationMapData(htLastMapData.applicationMapData); serverMapData = ServerMapDao.addFilterProperty(filters, serverMapData); - if (filteredMapUtil.doFiltersHaveUnknownNode(filters)) scope.mergeUnknowns = mergeUnknowns = false; + extractMergeTypeList( serverMapData ); + if (filteredMapUtil.doFiltersHaveUnknownNode(filters)) { + for( var key in scope.mergeStatus ) { + scope.mergeStatus[key] = false; + } + } emitDataExisting(htLastMapData); - serverMapCallback(query, serverMapData, mergeUnknowns, linkRouting, linkCurve); + serverMapCallback(query, serverMapData, linkRouting, linkCurve); }); } else { ServerMapDao.getServerMapData(htLastQuery, function (err, query, mapData) { @@ -176,7 +196,8 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' emitDataExisting(mapData); htLastMapData = mapData; var serverMapData = ServerMapDao.extractDataFromApplicationMapData(mapData.applicationMapData); - serverMapCallback(query, serverMapData, mergeUnknowns, linkRouting, linkCurve); + extractMergeTypeList( serverMapData ); + serverMapCallback(query, serverMapData, linkRouting, linkCurve); }); } }; @@ -237,21 +258,31 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' }; scope.$digest(); }; + getMergeArray = function() { + var a = []; + for( var key in scope.mergeStatus ) { + if ( scope.mergeStatus[key] === true ) { + a.push( key ); + } + } + return a; + }; /** * server map callback * @param query * @param applicationMapData - * @param mergeUnknowns * @param linkRouting * @param linkCurve */ - serverMapCallback = function (query, applicationMapData, mergeUnknowns, linkRouting, linkCurve) { + serverMapCallback = function (query, applicationMapData, linkRouting, linkCurve) { console.log( applicationMapData ); - var lastCopiedData = applicationMapData; - if (mergeUnknowns) { - lastCopiedData = ServerMapDao.mergeUnknown(applicationMapData); - } + //var lastCopiedData = applicationMapData; + + //if (mergeUnknowns) { + //lastCopiedData = ServerMapDao.mergeUnknown(applicationMapData, mergeTypeList); + var lastCopiedData = ServerMapDao.mergeGroup(applicationMapData, getMergeArray()); + //} console.log( lastCopiedData ); // ServerMapDao.removeNoneNecessaryDataForHighPerformance(lastCopiedData); @@ -290,7 +321,7 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' oProgressBar.setLoading(90); var options = cfg.options; - options.fOnNodeClicked = function (e, node, unknownKey) { + options.fOnNodeClicked = function (e, node, unknownKey, searchQuery) { var originalNode; if (angular.isDefined(node.unknownNodeGroup) && !unknownKey) { node.unknownNodeGroup = ServerMapDao.getUnknownNodeDataByUnknownNodeGroup(htLastMapData.applicationMapData, node.unknownNodeGroup); @@ -302,7 +333,7 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' } sLastSelection = 'node'; htLastNode = node; - scope.$emit("serverMap.nodeClicked", e, htLastQuery, node, lastCopiedData); + scope.$emit("serverMap.nodeClicked", e, htLastQuery, node, lastCopiedData, searchQuery); reset(); }; options.fOnNodeContextClicked = function (e, node) { @@ -391,7 +422,7 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' oProgressBar.setLoading(100); if (oServerMap === null) { - oServerMap = new ServerMap(options); + oServerMap = new ServerMap(options, $location); } else { oServerMap.option(options); } @@ -609,7 +640,16 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' */ scope.toggleMergeUnknowns = function () { scope.mergeUnknowns = (scope.mergeUnknowns) ? false : true; - serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.mergeUnknowns, scope.linkRouting, scope.linkCurve); + serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.linkRouting, scope.linkCurve); + reset(); + }; + /** + * toggle merge group + */ + scope.toggleMergeGroup = function ( mergeType ) { + scope.mergeStatus[ mergeType ] = !scope.mergeStatus[ mergeType ]; + //scope.mergeUnknowns = (scope.mergeUnknowns) ? false : true; + serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.linkRouting, scope.linkCurve); reset(); }; @@ -620,7 +660,7 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' scope.toggleLinkLableTextType = function (type) { scope.totalRequestCount = (type !== 'tps') ? true : false; scope.tps = (type === 'tps') ? true : false; - serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.mergeUnknowns, scope.linkRouting, scope.linkCurve); + serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.linkRouting, scope.linkCurve); reset(); }; @@ -630,7 +670,7 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' */ scope.toggleLinkRouting = function (type) { scope.linkRouting = cfg.options.htLinkType.sRouting = type; - serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.mergeUnknowns, scope.linkRouting, scope.linkCurve); + serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.linkRouting, scope.linkCurve); reset(); }; @@ -640,7 +680,7 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' */ scope.toggleLinkCurve = function (type) { scope.linkCurve = cfg.options.htLinkType.sCurve = type; - serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.mergeUnknowns, scope.linkRouting, scope.linkCurve); + serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.linkRouting, scope.linkCurve); reset(); }; @@ -665,14 +705,14 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' scope.bShowServerMapStatus = true; bUseLinkContextMenu = bUseBackgroundContextMenu = true; bUseNodeContextMenu = false; - showServerMap(navbarVo.getApplicationName(), navbarVo.getServiceTypeCode(), navbarVo.getQueryEndTime(), navbarVo.getQueryPeriod(), navbarVo.getFilter(), navbarVo.getHint(), scope.mergeUnknowns, scope.linkRouting, scope.linkCurve); + showServerMap(navbarVo.getApplicationName(), navbarVo.getServiceTypeCode(), navbarVo.getQueryEndTime(), navbarVo.getQueryPeriod(), navbarVo.getFilter(), navbarVo.getHint(), scope.linkRouting, scope.linkCurve); }); /** * scope event on serverMap.fetch */ scope.$on('serverMap.fetch', function (event, queryPeriod, queryEndTime) { - showServerMap(scope.oNavbarVo.getApplicationName(), scope.oNavbarVo.getServiceTypeCode(), queryEndTime, queryPeriod, scope.oNavbarVo.getFilter(), scope.oNavbarVo.getHint(), scope.mergeUnknowns, scope.linkRouting, scope.linkCurve); + showServerMap(scope.oNavbarVo.getApplicationName(), scope.oNavbarVo.getServiceTypeCode(), queryEndTime, queryPeriod, scope.oNavbarVo.getFilter(), scope.oNavbarVo.getHint(), scope.linkRouting, scope.linkCurve); }); /** @@ -687,7 +727,7 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' applicationName: mapData.applicationId }; htLastMapData = mapData; - serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.mergeUnknowns, scope.linkRouting, scope.linkCurve); + serverMapCallback(htLastQuery, htLastMapData.applicationMapData, scope.linkRouting, scope.linkCurve); }); /** @@ -714,14 +754,15 @@ pinpointApp.directive('serverMap', [ 'serverMapConfig', 'ServerMapDao', 'Alerts' } } scope.searchNode = function() { - if (oServerMap && scope.searchNodeName !== "" ) { + if (oServerMap && scope.searchNodeQuery !== "" ) { scope.searchNodeIndex = 0; - scope.searchNodeList = oServerMap.searchNode( scope.searchNodeName ); + scope.searchNodeList = oServerMap.searchNode( scope.searchNodeQuery ); } }; scope.clearSearchNode = function() { + oServerMap.clearQuery(); scope.searchNodeIndex = 0; - scope.searchNodeName = ""; + scope.searchNodeQuery = ""; scope.searchNodeList = []; } } diff --git a/web/src/main/webapp/scripts/directives/timeline.js b/web/src/main/webapp/scripts/directives/timeline.js index f9a919fc0..9ae9dba2c 100644 --- a/web/src/main/webapp/scripts/directives/timeline.js +++ b/web/src/main/webapp/scripts/directives/timeline.js @@ -28,6 +28,9 @@ pinpointApp.directive('timeline', function () { scope.$on('timeline.initialize', function (event, transactionDetail) { initialize(transactionDetail); }); + scope.moveCallFlow = function( item ) { + scope.$emit( "transactionDetail.selectDistributedCallFlowRow", item[6] ); + }; } }; }); diff --git a/web/src/main/webapp/scripts/directives/transactionTable.js b/web/src/main/webapp/scripts/directives/transactionTable.js index 30a38b39d..8bb0e97c2 100644 --- a/web/src/main/webapp/scripts/directives/transactionTable.js +++ b/web/src/main/webapp/scripts/directives/transactionTable.js @@ -32,6 +32,9 @@ pinpointApp.directive('transactionTable', ['$window', function ($window) { scope.transactionReverse = false; element.find('table tbody tr:last-child')[0].scrollIntoView(true); // $(".transaction-table_wrapper").animate({ scrollTop: element.find('table tbody tr:last-child').offset().top }, 500); + } else { + scope.transactionOrderBy = 'elapsed'; + scope.transactionReverse = true; } scope.transactionList = scope.transactionList.concat(transactionList); resetIndexToTransactionList(); diff --git a/web/src/main/webapp/scripts/services/ServerMapDao.js b/web/src/main/webapp/scripts/services/ServerMapDao.js index 2b1ab9373..0b604a925 100644 --- a/web/src/main/webapp/scripts/services/ServerMapDao.js +++ b/web/src/main/webapp/scripts/services/ServerMapDao.js @@ -447,35 +447,30 @@ pinpointApp.service('ServerMapDao', [ 'serverMapDaoConfig', function ServerMapDa * @param applicationMapData * @returns {*} */ - this.mergeUnknown = function (mapData) { + this.mergeGroup = function (mapData, mergeTypeList) { // SERVERMAP_METHOD_CACHE = {}; var applicationMapData = angular.copy(mapData); var nodes = applicationMapData.nodeDataArray; var links = applicationMapData.linkDataArray; var inboundCountMap = {}; + // 1. 각 노드 별로 인입되는 노드의 갯수와 request 합을 저장해 둠. + // > sourceCount == 0 인 경우 root node 라고 생각 할 수 있습니다. + // > sourceCount == 1 인 경우 아마도 merging을 대상이 아님. nodes.forEach(function (node) { - if (!inboundCountMap[node.key]) { - inboundCountMap[node.key] = { - "sourceCount": 0, - "totalCallCount": 0 - }; - } - - links.forEach(function (link) { + var sourceCount = 0; + var totalCallCount = 0; + links.forEach(function (link) { if (link.to === node.key) { - inboundCountMap[node.key].sourceCount++; - inboundCountMap[node.key].totalCallCount += link.totalCount; + sourceCount++; + totalCallCount += link.totalCount; } }); + inboundCountMap[node.key] = { + "sourceCount": sourceCount, + "totalCallCount": totalCallCount + }; }); - - var newNodeList = []; - var newLinkList = []; - - var removeNodeIdSet = {}; - var removeLinkIdSet = {}; - function getNodeByApplicationName(applicationName) { for(var k in nodes) { if (applicationName === nodes[k].applicationName) { @@ -485,128 +480,150 @@ pinpointApp.service('ServerMapDao', [ 'serverMapDaoConfig', function ServerMapDa return false; } - nodes.forEach(function (node, nodeIndex) { - if (node.category === "UNKNOWN") { - return; - } - - var newNode; - var newLink; - var newNodeKey = "UNKNOWN_GROUP_" + node.key; - - var unknownCount = 0; - links.forEach(function (link, linkIndex) { - if (link.from == node.key && - link.targetInfo.serviceType == "UNKNOWN" && - inboundCountMap[link.to] && inboundCountMap[link.to].sourceCount == 1) { - unknownCount++; - } - }); - if (unknownCount < 2) { - return; - } - - // for each children. - links.forEach(function (link, linkIndex) { - if (link.targetInfo.serviceType != "UNKNOWN") { - return; - } - if (inboundCountMap[link.to] && inboundCountMap[link.to].sourceCount > 1) { - return; - } - - // branch out from current node. - if (link.from == node.key) { - if (!newNode) { - newNode = { - "key": newNodeKey, - "unknownNodeGroup": [], - "serviceType": "UNKNOWN_GROUP", - "category": "UNKNOWN_GROUP" - }; - } - if (!newLink) { - newLink = { - "key": node.key + "-" + newNodeKey, - "from": node.key, - "to": newNodeKey, - "sourceInfo": {}, - "targetInfo": [], - "totalCount": 0, - "errorCount": 0, - "slowCount": 0, - "hasAlert": false, - "unknownLinkGroup": [], - "histogram": {} - }; - } - - var thisNode = getNodeByApplicationName(link.targetInfo.applicationName); - delete thisNode.category; - newNode.unknownNodeGroup.push(thisNode); - - link.targetInfo['totalCount'] = link.totalCount; - newLink.totalCount += link.totalCount; - newLink.errorCount += link.errorCount; - newLink.slowCount += link.slowCount; - newLink.sourceInfo = link.sourceInfo; - if (link.hasAlert) { - newLink.hasAlert = link.hasAlert; - } - newLink.unknownLinkGroup.push(link); - -// $.each(link.histogram, function (key, value) { -// if (newLink.histogram[key]) { -// newLink.histogram[key] += value; -// } else { -// newLink.histogram[key] = value; -// } -// }); - - removeNodeIdSet[link.to] = null; - removeLinkIdSet[link.key] = null; - } - }); - - if (newNode) { - newNode.unknownNodeGroup.sort(function (e1, e2) { - return e2.totalCount - e1.totalCount; - }); - newNodeList.push(newNode); - } - - if (newLink) { - newLink.unknownLinkGroup.sort(function (e1, e2) { - return e2.totalCount - e1.totalCount; - }); - newLinkList.push(newLink); - } + mergeTypeList.forEach( function( mergeType ) { + var mergeTypeGroup = mergeType + "_GROUP"; + + var newNodeList = []; + var newLinkList = []; + var removeNodeIdSet = {}; + var removeLinkIdSet = {}; + + nodes.forEach(function (node, nodeIndex) { + if (node.category === mergeType) { + return; + } + + var newNode; + var newLink; + var newNodeKey = mergeTypeGroup + "_" + node.key; + + var unknownCount = 0; + // 현재 확인 중인 node가 "UNKNOWN"으로 요청을 보내는 Node인지 확인하고 그렇다면 갯수를 count 함. + // 또한 "UNKNOWN"의 sourceCount는 1인 것 만 대상으로 함. + // > 즉 두 개 이상의 노드로 부터 request를 받는 "UNKNOWN"은 mergeing 대상이 아님. + // from은 같고 to가 두 개 이상인 노드와 unknown을 골라 냄. + links.forEach(function (link, linkIndex) { + if (link.from == node.key && + link.targetInfo.serviceType == mergeType && + inboundCountMap[link.to] && inboundCountMap[link.to].sourceCount == 1) { + unknownCount++; + } + }); + // merging을 해야 하닌 2개 이하는 의미없음. + if (unknownCount < 2) { + return; + } + + // @@여기까지 오면 현재 노드는 두 개 이상의 UNKNOWN 으로 요청을 보내는 노드가 됨.( 것두 혼자서 보냄 ) + // 고로 현재 노드의 to 가 되는 Unknown 노드들은 merging을 대상이 됨. + links.forEach(function (link, linkIndex) { + // 검증 + if (link.targetInfo.serviceType != mergeType) { + return; + } + // 검증 + if (inboundCountMap[link.to] && inboundCountMap[link.to].sourceCount > 1) { + return; + } + + // 다시 현재 노드로 부터 나가는 링크들을 골라냄. + if (link.from == node.key) { + if (!newNode) { + newNode = { + "key": newNodeKey, + "unknownNodeGroup": [], + "serviceType": mergeTypeGroup, + "category": mergeTypeGroup, + "instanceCount": 0 + }; + } + if (!newLink) { + newLink = { + "key": node.key + "-" + newNodeKey, + "from": node.key, + "to": newNodeKey, + "sourceInfo": {}, + "targetInfo": [], + "totalCount": 0, + "errorCount": 0, + "slowCount": 0, + "hasAlert": false, + "unknownLinkGroup": [], + "histogram": {} + }; + } + + // 자 링크의 target이 되는 unknown 노드를 가져옴. + var thisNode = getNodeByApplicationName(link.targetInfo.applicationName); + delete thisNode.category; + newNode.instanceCount += thisNode.instanceCount; + newNode.unknownNodeGroup.push(thisNode); + + // 각종 count 정보를 합산함. + link.targetInfo['totalCount'] = link.totalCount; + newLink.totalCount += link.totalCount; + newLink.errorCount += link.errorCount; + newLink.slowCount += link.slowCount; + newLink.sourceInfo = link.sourceInfo; + if (link.hasAlert) { + newLink.hasAlert = link.hasAlert; + } + newLink.unknownLinkGroup.push(link); + + // $.each(link.histogram, function (key, value) { + // if (newLink.histogram[key]) { + // newLink.histogram[key] += value; + // } else { + // newLink.histogram[key] = value; + // } + // }); + + // merging으로 인해 삭제할 원 노드와 원 링크의 정보를 저장해 둠.( 나중에 몰아서 삭제하도록 ). + removeNodeIdSet[link.to] = null; + removeLinkIdSet[link.key] = null; + } + }); + + if (newNode) { + newNode.unknownNodeGroup.sort(function (e1, e2) { + return e2.totalCount - e1.totalCount; + }); + newNodeList.push(newNode); + } + + if (newLink) { + newLink.unknownLinkGroup.sort(function (e1, e2) { + return e2.totalCount - e1.totalCount; + }); + newLinkList.push(newLink); + } + }); + + newNodeList.forEach(function (newNode) { + applicationMapData.nodeDataArray.push(newNode); + }); + + newLinkList.forEach(function (newLink) { + applicationMapData.linkDataArray.push(newLink); + }); + + $.each(removeNodeIdSet, function (key, val) { + nodes.forEach(function (node, i) { + if (node.key == key) { + nodes.splice(i, 1); + } + }); + }); + + $.each(removeLinkIdSet, function (key, val) { + links.forEach(function (link, i) { + if (link.key === key) { + links.splice(i, 1); + } + }); + }); }); - - newNodeList.forEach(function (newNode) { - applicationMapData.nodeDataArray.push(newNode); - }); - - newLinkList.forEach(function (newLink) { - applicationMapData.linkDataArray.push(newLink); - }); - - $.each(removeNodeIdSet, function (key, val) { - nodes.forEach(function (node, i) { - if (node.key == key) { - nodes.splice(i, 1); - } - }); - }); - - $.each(removeLinkIdSet, function (key, val) { - links.forEach(function (link, i) { - if (link.key === key) { - links.splice(i, 1); - } - }); - }); - + return applicationMapData; }; diff --git a/web/src/main/webapp/styles/distributedCallFlow.css b/web/src/main/webapp/styles/distributedCallFlow.css index 3f05385ea..9fcc4adb8 100644 --- a/web/src/main/webapp/styles/distributedCallFlow.css +++ b/web/src/main/webapp/styles/distributedCallFlow.css @@ -60,6 +60,11 @@ .slick-row.active { background: #DFE8F6; } +.slick-row.entry-point { + background: #DFF0D8; + color: #1469EB; +} + .slick-cell { padding: 0 4px; diff --git a/web/src/main/webapp/styles/serverMap.css b/web/src/main/webapp/styles/serverMap.css index c7114633a..b9d8097ca 100644 --- a/web/src/main/webapp/styles/serverMap.css +++ b/web/src/main/webapp/styles/serverMap.css @@ -61,9 +61,9 @@ width: 15%; height: 15%; position: absolute; - left: 0px; + right: 16px; bottom: 16px; - background-color: rgba(255, 203, 39, 0.5); + background-color: rgba(44, 160, 44, 0.2); z-index: 2; - border: 1px solid rgb(255, 203, 39); + border: 1px solid rgb(44, 160, 44); } \ No newline at end of file diff --git a/web/src/main/webapp/views/linkInfoDetails.html b/web/src/main/webapp/views/linkInfoDetails.html index 43d403c6d..510a4df3c 100644 --- a/web/src/main/webapp/views/linkInfoDetails.html +++ b/web/src/main/webapp/views/linkInfoDetails.html @@ -1,6 +1,6 @@
-
+
@@ -65,7 +65,7 @@
-