mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-20 10:16:13 +10:00
[임대현] [NOBTS] UI v2.0
git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-web/trunk@2203 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"directory": "main/webapp/components"
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "pinpoint",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"angular": "~1.0.7",
|
||||
"json3": "~3.2.4",
|
||||
"jquery": "~1.9.1",
|
||||
"es5-shim": "~2.0.8",
|
||||
"angular-resource": "~1.0.7",
|
||||
"angular-cookies": "~1.0.7",
|
||||
"select2": "~3.4.1",
|
||||
"underscore": "~1.5.1",
|
||||
"angular-bootstrap": "~0.5.0",
|
||||
"angular-bootstrap-datetimepicker": "~0.1.2",
|
||||
"moment": "*",
|
||||
"bootstrap-datetimepicker": "~0.0.11",
|
||||
"modernizr": "~2.6.2",
|
||||
"jquery-ui": "~1.10.3",
|
||||
"datejs": "*",
|
||||
"nvd3": "~1.0.0-beta",
|
||||
"d3": "~3.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-mocks": "~1.0.7",
|
||||
"angular-scenario": "~1.0.7"
|
||||
},
|
||||
"appPath": "main/webapp",
|
||||
"testPath": "test/webapp"
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Karma configuration
|
||||
|
||||
// base path, that will be used to resolve files and exclude
|
||||
basePath = '';
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files = [
|
||||
JASMINE,
|
||||
JASMINE_ADAPTER,
|
||||
'main/webapp/components/angular/angular.js',
|
||||
'main/webapp/components/angular-mocks/angular-mocks.js',
|
||||
'main/webapp/components/angular-resource/angular-resource.js',
|
||||
'main/webapp/scripts/*.js',
|
||||
'main/webapp/scripts/**/*.js',
|
||||
'test/webapp/**/*.js'
|
||||
];
|
||||
|
||||
// list of files to exclude
|
||||
exclude = [];
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: dots || progress || growl
|
||||
reporters = ['progress'];
|
||||
|
||||
// web server port
|
||||
port = 8080;
|
||||
|
||||
// cli runner port
|
||||
runnerPort = 9100;
|
||||
|
||||
// enable / disable colors in the output (reporters and logs)
|
||||
colors = true;
|
||||
|
||||
// level of logging
|
||||
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
|
||||
logLevel = LOG_INFO;
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch = true;
|
||||
|
||||
// Start these browsers, currently available:
|
||||
// - Chrome
|
||||
// - ChromeCanary
|
||||
// - Firefox
|
||||
// - Opera
|
||||
// - Safari (only Mac)
|
||||
// - PhantomJS
|
||||
// - IE (only Windows)
|
||||
browsers = ['Chrome'];
|
||||
|
||||
// If browser does not capture in given timeout [ms], kill it
|
||||
captureTimeout = 5000;
|
||||
|
||||
// Continuous Integration mode
|
||||
// if true, it capture browsers, run tests and exit
|
||||
singleRun = false;
|
||||
@@ -11,8 +11,8 @@ var showApplicationStatisticsSummary = function(data) {
|
||||
var chart = nv.models.discreteBarChart().x(function(d) {
|
||||
return d.label;
|
||||
}).y(function(d) {
|
||||
return d.value;
|
||||
}).staggerLabels(false).tooltips(false).showValues(true);
|
||||
return d.value;
|
||||
}).staggerLabels(false).tooltips(false).showValues(true);
|
||||
|
||||
chart.xAxis.tickFormat(function(d) {
|
||||
if($.isNumeric(d)) {
|
||||
@@ -20,17 +20,17 @@ var showApplicationStatisticsSummary = function(data) {
|
||||
}
|
||||
return d;
|
||||
});
|
||||
|
||||
|
||||
chart.yAxis.tickFormat(function(d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
|
||||
chart.valueFormat(function(d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
|
||||
chart.color(myColors);
|
||||
|
||||
|
||||
d3.select('#linkInfoDetails .linkInfoBarChart svg')
|
||||
.datum(data)
|
||||
.transition()
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+85
-370
@@ -1,383 +1,98 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>PINPOINT</title>
|
||||
<!doctype html>
|
||||
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
|
||||
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title></title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
|
||||
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="/components_v1/bootstrap/css/bootstrap.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/components_v1/bootstrap/css/bootstrap-responsive.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/components_v1/pinpoint/css/pinpoint.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/components_v1/pinpoint-scatter/css/scatter.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/components_v1/bootstrap-datepicker/bootstrap-datepicker.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/components_v1/nvd3/nv.d3.css" />
|
||||
<link type="text/css" rel="stylesheet" href="/components_v1/select2/select2.css" />
|
||||
|
||||
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<!-- build:css({.tmp,app}) styles/main.css -->
|
||||
<link rel="stylesheet" href="components/bootstrap/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="components/bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css"/>
|
||||
<link rel="stylesheet" href="components/select2/select2.css">
|
||||
<link rel="stylesheet" href="components/nvd3/src/nv.d3.css">
|
||||
<link rel="stylesheet" href="components/pinpoint-scatter/jquery.dragToSelect.css">
|
||||
<link rel="stylesheet" href="components/pinpoint-scatter/jquery.BigScatterChart.css">
|
||||
<link rel="stylesheet" href="styles/main.css">
|
||||
<!-- endbuild -->
|
||||
</head>
|
||||
<body ng-app="pinpointApp">
|
||||
<!--[if lt IE 7]>
|
||||
<p class="chromeframe">You are using an outdated browser. <a href="http://browsehappy.com/">Upgrade your browser today</a> or <a href="http://www.google.com/chromeframe/?redirect=true">install Google Chrome Frame</a> to better experience this site.</p>
|
||||
<![endif]-->
|
||||
|
||||
<!-- commons -->
|
||||
<script type="text/javascript" src="/components_v1/jquery/jquery-1.9.1.min.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/jquery-ui/jquery-ui-1.10.2.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/jquery-class/jquery.Class.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/jquery-template/jquery.tmpl.min.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/bootstrap-datepicker/bootstrap-datepicker.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/modernizer/modernizr-2.6.2.min.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/underscore/underscore-min.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/select2/select2.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/utils/date.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/pinpoint/pinpoint.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/pinpoint/navigationbar.js"></script>
|
||||
|
||||
<!-- scatter chart -->
|
||||
<script type="text/javascript" src="/components_v1/jquery-dragtoselect/jquery.dragToSelect.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/pinpoint-scatter/jquery.BigScatterChart.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/pinpoint/chart-scatter4.js"></script>
|
||||
|
||||
<!-- server map -->
|
||||
<script type="text/javascript" src="/components_v1/gojs/go.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/pinpoint-servermap/Point2D.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/pinpoint-servermap/intersection.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/pinpoint-servermap/canvas.roundRect.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/pinpoint-servermap/jquery.ServerMap.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/pinpoint/chart-servermap.js"></script>
|
||||
|
||||
<!-- link info chart -->
|
||||
<script type="text/javascript" src="/components_v1/d3/d3.v2.min.js"></script>
|
||||
<script type="text/javascript" src="/components_v1/nvd3/nv.d3.js"></script>
|
||||
|
||||
<!-- requests list -->
|
||||
<script type="text/javascript" src="/components_v1/pinpoint/chart-transactions.js"></script>
|
||||
|
||||
<!-- help -->
|
||||
<script type="text/javascript" src="/components_v1/pinpoint/message.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="bower_components/es5-shim/es5-shim.js"></script>
|
||||
<script src="bower_components/json3/lib/json3.min.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<img class="brand" src="/images/logo.png" width="116" height="18" />
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="">
|
||||
<form class="navbar-form pull-left">
|
||||
<select id="application" disabled>
|
||||
<option>Loading...</option>
|
||||
</select>
|
||||
<div id="period" class="btn-group" data-toggle="buttons-radio">
|
||||
<button type="button" value="5" class="btn btn-mini" disabled>Last 5m</button>
|
||||
<button type="button" value="20" class="btn btn-mini btn-inverse active" disabled>20m</button>
|
||||
<button type="button" value="60" class="btn btn-mini" disabled>1h</button>
|
||||
<button type="button" value="180" class="btn btn-mini" disabled>3h</button>
|
||||
<button type="button" value="360" class="btn btn-mini" disabled>6h</button>
|
||||
<button type="button" value="740" class="btn btn-mini" disabled>12h</button>
|
||||
<button type="button" value="1440" class="btn btn-mini" disabled>1d</button>
|
||||
<button type="button" value="2880" class="btn btn-mini" disabled>2d</button>
|
||||
<button type="button" value="4320" class="btn btn-mini" disabled>3d</button>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="">
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-mini dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
map options
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" id="mergeUnknown" data-selected="true"><i class="icon-ok"></i> Merge unknowns</a></li>
|
||||
<li><a href="#" id="hideIndirectAccess" data-selected="false"><i class="icon-ok icon-white"></i> Hide indirect access</a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Label text type</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" class="labelTextType" data-type="count" data-selected="true"><i class="icon-ok"></i> Total request count</a></li>
|
||||
<li><a href="#" class="labelTextType" data-type="tps" data-selected="false"><i class="icon-ok icon-white"></i> TPS</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="" id="queryTime"></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<!-- Add your site or application content here -->
|
||||
<navbar></navbar>
|
||||
|
||||
<!-- Add your site or application content here -->
|
||||
<div class="main-container" ng-view=""></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container" id="warningMessage"></div>
|
||||
<!-- ng-template -->
|
||||
<script id="warning" type="text/ng-template">
|
||||
<div class="warning" style="position:absolute;top:38%;width:100%;display:none;">
|
||||
<div class="alert alert-block">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
<h4>Warning!</h4>
|
||||
<div class="msg"></div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script id="loading" type="text/ng-template">
|
||||
<div class="progress progress-striped active" style="position:absolute;top:40%;width:100%">
|
||||
<div class="bar" style="width: 0%;"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<div id="progressbar" style="display:none;"><img src="/images/ajaxloader.gif" /></div>
|
||||
</div>
|
||||
<script src="components/jquery/jquery.js"></script>
|
||||
<script src="components/jquery-ui/ui/jquery-ui.js"></script>
|
||||
<script src="components/moment/moment.js"></script>
|
||||
<script src="components/angular/angular.js"></script>
|
||||
<script src="components/modernizr/modernizr.js"></script>
|
||||
<script src="components/datejs/build/date.js"></script>
|
||||
<script src="components/underscore/underscore-min.js"></script>
|
||||
<script src="components/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="components/gojs/go.js"></script>
|
||||
<script src="components/d3/d3.min.js"></script>
|
||||
<script src="components/nvd3/nv.d3.js"></script>
|
||||
|
||||
<!-- BODY -->
|
||||
<div class="chart-container">
|
||||
<div class="chart-left">
|
||||
<div id="servermap" class="servermap"></div>
|
||||
</div>
|
||||
<div class="chart-right">
|
||||
<div id="scatterChartContainer" style="display:none;">
|
||||
<span onclick="" style="text-decoration:underline;cursor:pointer">Show all transaction</span>
|
||||
|
||||
<i class="icon-fullscreen" onclick="expandScatter($(this));" onmouseover="$(this).tooltip('show');" title="Expand to new popup window." style="cursor:pointer;"></i>
|
||||
|
||||
<a href=""><i class="icon-download-alt" onmouseover="$(this).tooltip('show');" title="Download as PNG image format file." style="cursor:pointer;"></i></a>
|
||||
<div id="scatterchart"></div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div id="statisticsProgressbar" style="display:none;"><img src="/images/ajaxloader.gif" /></div>
|
||||
<div id="nodeInfoDetails">
|
||||
<div class='info'></div>
|
||||
</div>
|
||||
<div id="linkInfoDetails">
|
||||
<div class='info'></div>
|
||||
<div class='linkInfoChart' style='width:100%;display:none'>
|
||||
Response histogram
|
||||
<svg style='height:200px' />
|
||||
</div>
|
||||
<div class='linkInfoBarChart' style='width:100%;display:none'>
|
||||
Response histogram summary
|
||||
<svg style='height:150px' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END OF BODY -->
|
||||
<!-- build:js scripts/plugins.js -->
|
||||
<script src="components/select2/select2.min.js"></script>
|
||||
<script src="components/select2/select2_locale_ko.js"></script>
|
||||
<script src="components/jquery-class/jquery.Class.js"></script>
|
||||
<script src="components/pinpoint-servermap/js/jquery.ServerMap.js"></script>
|
||||
<script src="components/bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js"></script>
|
||||
<script src="components/pinpoint-scatter/jquery.dragToSelect.js"></script>
|
||||
<script src="components/pinpoint-scatter/jquery.BigScatterChart.js"></script>
|
||||
<!-- endbuild -->
|
||||
|
||||
<script type="text/javascript">
|
||||
var Nav;
|
||||
|
||||
$(document).ready(function () {
|
||||
Nav = new _PinpointNavigationBar();
|
||||
|
||||
$("#mergeUnknown").bind('click', toggleMergeUnknowns);
|
||||
$("#hideIndirectAccess").bind('click', toggleHideIndirectAccess);
|
||||
|
||||
$('#date').datepicker().on('changeDate', function(ev){
|
||||
updateCharts();
|
||||
});
|
||||
|
||||
$('#time').bind('focus', function(e){
|
||||
$(this).data("time", $(this).val());
|
||||
}).bind('blur', function(e){
|
||||
if ($(this).data("time") !== $(this).val()) {
|
||||
updateCharts();
|
||||
}
|
||||
});
|
||||
|
||||
$('#until').delegate("button", "click", function(){
|
||||
var $this = $(this);
|
||||
|
||||
$this.siblings(".btn-primary").removeClass("btn-primary");
|
||||
$this.addClass("btn-primary");
|
||||
|
||||
if ($this.attr("id") === "now") {
|
||||
$("#date").attr("disabled", "").val("");
|
||||
$("#time").attr("disabled", "").val("");
|
||||
updateCharts();
|
||||
} else {
|
||||
setQueryDateToNow();
|
||||
$("#date").attr("disabled", null);
|
||||
$("#time").attr("disabled", null);
|
||||
}
|
||||
});
|
||||
|
||||
$('#period').delegate("button", "click", function(){
|
||||
var $this = $(this);
|
||||
$this.siblings(".btn-inverse").removeClass("btn-inverse active");
|
||||
$this.addClass("btn-inverse active");
|
||||
updateCharts();
|
||||
});
|
||||
|
||||
// TODO 조회 버튼을 두 번 연속 눌렀을 때 앞서 수행되던 결과는 취소시켜야 함.
|
||||
// 예를 들어 1일치 조회하다가 모두 조회 되기 전에 30분 데이터 조회할 때...
|
||||
function updateCharts() {
|
||||
if(!Nav.isSelected()) {
|
||||
alert("\n\nSelect an application, please.\n\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
var f = formatDate(new Date(Nav.getQueryStartTime()), true);
|
||||
var e = formatDate(new Date(Nav.getQueryEndTime()), true);
|
||||
|
||||
$("#queryTime").html(f + ' ~ <br/>' + e);
|
||||
|
||||
$("#progressbar").show();
|
||||
|
||||
showServerMap(Nav.getApplicationName(), Nav.getServiceType(), Nav.getQueryStartTime(), Nav.getQueryEndTime(), Nav.getQueryPeriod(), Nav.isQueryFromNow(), null, Nav.isHideIndirectAccess(), function() { $("#progressbar").hide(); });
|
||||
showResponseScatter(Nav.getApplicationName(), Nav.getQueryStartTime(), Nav.getQueryEndTime(), Nav.getQueryPeriod(), Nav.isQueryFromNow());
|
||||
}
|
||||
|
||||
$.getJSON("/applications.pinpoint", function(json) {
|
||||
var target = $("#application");
|
||||
|
||||
if (json.length == 0) {
|
||||
$("#application OPTION:first").text("Application not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
target.empty();
|
||||
var optionsHTML = [];
|
||||
$(json).each(function(i, e) {
|
||||
var opt = $(document.createElement("option"));
|
||||
opt.attr("value", e.applicationName + "@" + e.code);
|
||||
if (json.length == 1) {
|
||||
opt.attr("selected", "selected");
|
||||
}
|
||||
opt.text(e.applicationName + "@" + e.serviceType);
|
||||
target.append(opt);
|
||||
});
|
||||
|
||||
target.attr("disabled", null);
|
||||
|
||||
var formatOptionText = function(state) {
|
||||
if (!state.id) return state.text;
|
||||
var chunk = state.text.split("@");
|
||||
if (chunk.length > 1) {
|
||||
var img = document.createElement("img");
|
||||
img.src = "/images/icons/" + chunk[1] + ".png";
|
||||
return img.outerHTML + chunk[0];
|
||||
} else {
|
||||
return state.text;
|
||||
}
|
||||
}
|
||||
|
||||
target.select2({
|
||||
placeholder: "Select an application.",
|
||||
formatResult: formatOptionText,
|
||||
formatSelection: formatOptionText,
|
||||
escapeMarkup: function(m) { return m; }
|
||||
});
|
||||
|
||||
// 임시.
|
||||
$(".select2-container").css("top", "4px");
|
||||
$("#until BUTTON").attr("disabled", null);
|
||||
$("#period BUTTON").attr("disabled", null);
|
||||
});
|
||||
|
||||
$("#application").bind("change", updateCharts);
|
||||
});
|
||||
</script>
|
||||
<script id="NodeInfoBox" type="text/x-jquery-tmpl">
|
||||
<div class="NodeInfoBox">
|
||||
{{if category != "UNKNOWN_GROUP" && category != "USER"}}
|
||||
<img src="/images/icons/{{= category}}.png" width="20" height="10" /> {{= text}} ({{= category}})
|
||||
{{if terminal == "false" && category != "UNKNOWN_CLOUD"}}
|
||||
<br/><a href="#" onclick="showRequests('{{= text}}', {{= query.from}}, {{= query.to}}, {{= query.period}}, {{= query.usePeriod}});">Passing transaction list</a>
|
||||
<br/><a href="#" onclick="showResponseScatter('{{= text}}', {{= query.from}}, {{= query.to}}, {{= query.period}}, {{= query.usePeriod}});">Passing transaction response scatter chart</a>
|
||||
{{/if}}
|
||||
<br/>
|
||||
{{/if}}
|
||||
|
||||
{{if category == "USER"}}
|
||||
<img src="/images/icons/USER.png" width="20" height="10" /> {{= category}}
|
||||
{{/if}}
|
||||
|
||||
{{if hosts.length > 0}}
|
||||
Hosts
|
||||
<ul>
|
||||
{{each(key, value) hosts}}
|
||||
<li>
|
||||
<span class="label label-success">OK</span>
|
||||
{{= value}}
|
||||
<a href="http://nsight.nhncorp.com/dashboard_server/{{= value.split(':')[0].replace('.nhnsystem.com','')}}" target="_blank" title="System resource monitoring site">(NSight)</a>
|
||||
{{if category == 'ARCUS' }}
|
||||
<a href="http://hubble.arcuscloud.nhncorp.com/" target="_blank" title="Arcus monitoring site">(Hubble)</a>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
|
||||
{{if agents.length > 0}}
|
||||
Server instances
|
||||
<ul>
|
||||
{{each(key, value) agents}}
|
||||
<li>
|
||||
<span class="label label-success">OK</span>
|
||||
{{= value.agentId}}
|
||||
<!--
|
||||
<a href="#" onclick="alert('Sorry. Not implemented.');">(Kuvasz)</a>
|
||||
<a href="#" onclick="alert('Sorry. Not implemented.');">(Tools)</a>
|
||||
-->
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</div>
|
||||
</script>
|
||||
<script id="LinkInfoBox" type="text/x-jquery-tmpl">
|
||||
<div class="LinkInfoBox">
|
||||
<img src="/images/icons/{{= sourceinfo.serviceType}}.png" width="20" height="10" /> {{= sourceinfo.applicationName}}
|
||||
<i class="icon-arrow-right"></i>
|
||||
<img src="/images/icons/{{= targetinfo.serviceType}}.png" width="20" height="10" /> {{= targetinfo.applicationName}}
|
||||
<!--
|
||||
<br/>
|
||||
Total requests : ???<br/>
|
||||
Failed : {{= error}}<br/>
|
||||
Response statistics
|
||||
<ul>
|
||||
{{var lastKey=''}}
|
||||
{{each(key, value) histogram}}
|
||||
<li><= {{= key}}ms : {{= value}}</li>
|
||||
{{eval lastKey=key}}
|
||||
{{/each}}
|
||||
<li> > {{= lastKey}}ms : {{= slow}}</li>
|
||||
</ul>
|
||||
-->
|
||||
<br/>
|
||||
<a href="#" onclick="filterPassingTransaction('{{= sourceinfo.applicationName}}', '{{= query.serviceType}}', {{= query.from}}, {{= query.to}}, '{{= sourceinfo.serviceType}}', '{{= sourceinfo.applicationName}}', '{{= targetinfo.serviceType}}', '{{= targetinfo.applicationName}}', null);">Passing transaction map</a><br/>
|
||||
{{if sourceinfo.serviceType == "CLIENT"}}
|
||||
<a href="#" onclick="showRequests('{{= targetinfo.applicationName}}', {{= query.from}}, {{= query.to}}, {{= query.period}}, {{= query.usePeriod}}, '{{= sourceinfo.serviceType}}|{{= targetinfo.applicationName}}|{{= targetinfo.serviceType}}|{{= targetinfo.applicationName}}');">Passing transaction list</a>
|
||||
{{/if}}
|
||||
{{if sourceinfo.serviceType != "CLIENT"}}
|
||||
<a href="#" onclick="showRequests('{{= sourceinfo.applicationName}}', {{= query.from}}, {{= query.to}}, {{= query.period}}, {{= query.usePeriod}}, '{{= sourceinfo.serviceType}}|{{= sourceinfo.applicationName}}|{{= targetinfo.serviceType}}|{{= targetinfo.applicationName}}');">Passing transaction list</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script id="UnknownNodeInfoBox" type="text/x-jquery-tmpl">
|
||||
<div class="UnknownNodeInfoBox">
|
||||
{{each(index, value) textArr}}
|
||||
<img src="/images/icons/UNKNOWN_CLOUD.png" width="20" height="10" /> {{= value.applicationName}}<br/>
|
||||
{{/each}}
|
||||
</div>
|
||||
</script>
|
||||
<script id="UnknownLinkInfoBox" type="text/x-jquery-tmpl">
|
||||
<div class="UnknownLinkInfoBox">
|
||||
{{each(index, value) targetinfo}}
|
||||
<img src="/images/icons/{{= sourceinfo[0].serviceType}}.png" width="20" height="10" /> {{= sourceinfo[0].applicationName}}
|
||||
<i class="icon-arrow-right"></i>
|
||||
<img src="/images/icons/{{= value.serviceType}}.png" width="20" height="10" /> {{= value.applicationName}}
|
||||
<a href="#" onclick="SERVERMAP_METHOD_CACHE['{{= value.applicationName}}']();" title="show details" style="text-decoration:none;">
|
||||
<i class="icon-search"></i>
|
||||
</a>
|
||||
<ul>
|
||||
<li>request count : {{= rawdata[value.applicationName].count}} /
|
||||
{{if rawdata[value.applicationName].error > 0}}
|
||||
<font color="#FF0000">{{= rawdata[value.applicationName].error}}</font>
|
||||
{{else}}
|
||||
{{= rawdata[value.applicationName].error}}
|
||||
{{/if}}
|
||||
</li>
|
||||
</ul>
|
||||
<br/>
|
||||
{{/each}}
|
||||
</div>
|
||||
</script>
|
||||
<!-- build:js scripts/modules.js -->
|
||||
<script src="components/angular-resource/angular-resource.js"></script>
|
||||
<script src="components/angular-cookies/angular-cookies.js"></script>
|
||||
<!-- endbuild -->
|
||||
|
||||
<!-- build:js({.tmp,app}) scripts/scripts.js -->
|
||||
<script src="scripts/app.js"></script>
|
||||
<script src="scripts/controllers/main.js"></script>
|
||||
<script src="scripts/directives/navbar.js"></script>
|
||||
<script src="scripts/directives/servermap.js"></script>
|
||||
<script src="scripts/directives/divider.js"></script>
|
||||
<script src="scripts/directives/scatter.js"></script>
|
||||
<script src="scripts/directives/nodeInfoDetails.js"></script>
|
||||
<script src="scripts/directives/linkInfoDetails.js"></script>
|
||||
<!-- endbuild -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
var pinpointApp = angular.module('pinpointApp', [ 'ngResource' ]);
|
||||
|
||||
pinpointApp.config(function($routeProvider, $locationProvider) {
|
||||
$locationProvider.html5Mode(false).hashPrefix(''); // 해쉬뱅을 사용 안할 수 있
|
||||
$routeProvider.when('/main', {
|
||||
templateUrl : 'views/ready.html',
|
||||
controller : 'MainCtrl',
|
||||
}).when('/main/:application/:period/:queryEndTime', {
|
||||
templateUrl : 'views/main.html',
|
||||
controller : 'MainCtrl',
|
||||
}).otherwise({
|
||||
redirectTo : '/main'
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
pinpointApp.controller('MainCtrl', [ '$scope', '$routeParams', function($scope, $routeParams) {
|
||||
|
||||
$scope.main = "";
|
||||
$scope.sidebar = "";
|
||||
|
||||
$scope.$on("dividerOpen", function(event) {
|
||||
$scope.main = "";
|
||||
$scope.sidebar = "";
|
||||
$(window).trigger('resize');
|
||||
});
|
||||
|
||||
$scope.$on("dividerClosed", function(event) {
|
||||
$scope.main = "fullsize";
|
||||
$scope.sidebar = "smallsize";
|
||||
$(window).trigger('resize');
|
||||
});
|
||||
|
||||
} ]);
|
||||
@@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
pinpointApp
|
||||
.directive('divider', ['$rootScope', function ($rootScope) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
templateUrl: 'views/divider.html',
|
||||
link: function postLink(scope, element, attrs) {
|
||||
scope.onoff = 'divider-open';
|
||||
scope.toggle = function(){
|
||||
if(scope.onoff === 'divider-open'){
|
||||
scope.onoff = 'divider-closed';
|
||||
$rootScope.$broadcast('dividerClosed');
|
||||
}else{
|
||||
scope.onoff = 'divider-open';
|
||||
$rootScope.$broadcast('dividerOpen');
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
@@ -0,0 +1,169 @@
|
||||
'use strict';
|
||||
|
||||
pinpointApp.constant('linkInfoDetailsConfig', {
|
||||
linkStatisticsUrl: '/linkStatistics.pinpoint',
|
||||
myColors : ["#008000", "#4B72E3", "#A74EA7", "#BB5004", "#FF0000"]
|
||||
});
|
||||
|
||||
pinpointApp
|
||||
.directive('linkInfoDetails', [ 'linkInfoDetailsConfig', function (config) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
templateUrl: 'views/linkInfoDetails.html',
|
||||
link: function postLink(scope, element, attrs) {
|
||||
|
||||
var reset = function () {
|
||||
scope.linkCategory = null;
|
||||
scope.rawdata = null;
|
||||
scope.query = null;
|
||||
scope.targetinfo = null;
|
||||
scope.sourceinfo = null;
|
||||
scope.showLinkInfoChart = false;
|
||||
scope.showLinkInfoBarChart = false;
|
||||
scope.$digest();
|
||||
};
|
||||
|
||||
var showDetailInformation = function (query, data) {
|
||||
if (data.rawdata) {
|
||||
scope.linkCategory = 'UnknownLinkInfoBox';
|
||||
} else {
|
||||
scope.linkCategory = 'LinkInfoBox';
|
||||
showApplicationStatistics(query.from,
|
||||
query.to,
|
||||
data.sourceinfo.serviceTypeCode,
|
||||
data.sourceinfo.applicationName,
|
||||
data.targetinfo.serviceTypeCode,
|
||||
data.targetinfo.applicationName);
|
||||
}
|
||||
|
||||
scope.rawdata = data.rawdata;
|
||||
scope.query = data.query;
|
||||
scope.targetinfo = data.targetinfo;
|
||||
scope.sourceinfo = data.sourceinfo;
|
||||
scope.$digest();
|
||||
};
|
||||
|
||||
var getLinkStatisticsData = function (query, callback) {
|
||||
jQuery.ajax({
|
||||
type : 'GET',
|
||||
url : config.linkStatisticsUrl,
|
||||
cache : false,
|
||||
dataType: 'json',
|
||||
data : {
|
||||
from : query.from,
|
||||
to : query.to,
|
||||
srcServiceType : query.srcServiceType,
|
||||
srcApplicationName : query.srcApplicationName,
|
||||
destServiceType : query.destServiceType,
|
||||
destApplicationName : query.destApplicationName
|
||||
},
|
||||
success : function (result) {
|
||||
callback(query, result);
|
||||
},
|
||||
error : function (xhr, status, error) {
|
||||
console.log("ERROR", status, error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var renderStatisticsTimeseriesHistogram = function (data) {
|
||||
nv.addGraph(function() {
|
||||
var chart = nv.models.multiBarChart().x(function (d) {
|
||||
return d[0];
|
||||
}).y(function(d) {
|
||||
return d[1];
|
||||
}).clipEdge(true).showControls(false);
|
||||
|
||||
chart.stacked(true);
|
||||
|
||||
chart.xAxis.tickFormat(function (d) {
|
||||
return d3.time.format('%H:%M')(new Date(d));
|
||||
});
|
||||
|
||||
chart.yAxis.tickFormat(function (d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
chart.color(config.myColors);
|
||||
|
||||
d3.select('.linkInfoDetails .infoChart svg')
|
||||
.datum(data)
|
||||
.transition()
|
||||
.duration(0)
|
||||
.call(chart);
|
||||
|
||||
nv.utils.windowResize(chart.update);
|
||||
|
||||
return chart;
|
||||
});
|
||||
};
|
||||
|
||||
var renderStatisticsSummary = function (data) {
|
||||
nv.addGraph(function() {
|
||||
var chart = nv.models.discreteBarChart().x(function (d) {
|
||||
return d.label;
|
||||
}).y(function (d) {
|
||||
return d.value;
|
||||
}).staggerLabels(false).tooltips(false).showValues(true);
|
||||
|
||||
chart.xAxis.tickFormat(function (d) {
|
||||
if(angular.isNumber(d)) {
|
||||
return (d >= 1000) ? d / 1000 + "s" : d + "ms";
|
||||
}
|
||||
return d;
|
||||
});
|
||||
|
||||
chart.yAxis.tickFormat(function (d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
chart.valueFormat(function (d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
chart.color(config.myColors);
|
||||
|
||||
d3.select('.linkInfoDetails .infoBarChart svg')
|
||||
.datum(data)
|
||||
.transition()
|
||||
.duration(0)
|
||||
.call(chart);
|
||||
|
||||
nv.utils.windowResize(chart.update);
|
||||
|
||||
return chart;
|
||||
});
|
||||
}
|
||||
|
||||
var showApplicationStatistics = function (begin, end, srcServiceType, srcApplicationName, destServiceType, destApplicationName) {
|
||||
var params = {
|
||||
"from" : begin,
|
||||
"to" : end,
|
||||
"srcServiceType" : srcServiceType,
|
||||
"srcApplicationName" : srcApplicationName,
|
||||
"destServiceType" : destServiceType,
|
||||
"destApplicationName" : destApplicationName
|
||||
};
|
||||
|
||||
getLinkStatisticsData(params, function(query, result) {
|
||||
scope.showLinkInfoChart = true;
|
||||
scope.showLinkInfoBarChart = true;
|
||||
scope.$digest();
|
||||
renderStatisticsTimeseriesHistogram(result.timeseriesHistogram);
|
||||
renderStatisticsSummary(result.histogramSummary);
|
||||
});
|
||||
}
|
||||
|
||||
scope.$on('servermap.nodeClicked', function (event, e, query, data, containerId) {
|
||||
reset();
|
||||
});
|
||||
scope.$on('servermap.linkClicked', function (event, e, query, data, containerId) {
|
||||
reset();
|
||||
showDetailInformation(query, data);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
} ]);
|
||||
@@ -0,0 +1,232 @@
|
||||
'use strict';
|
||||
|
||||
pinpointApp.constant('navbarConfig', {
|
||||
applicationUrl: '/applications.pinpoint'
|
||||
});
|
||||
|
||||
pinpointApp.directive('navbar', [ 'navbarConfig', '$rootScope', '$http',
|
||||
'$document', '$timeout', '$location', '$routeParams',
|
||||
function (navbarConfig, $rootScope, $http, $document, $timeout, $location, $routeParams) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
templateUrl: 'views/navbar.html',
|
||||
link: function (scope, element, attrs) {
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*/
|
||||
scope.applications = [
|
||||
{
|
||||
text: 'Loading...',
|
||||
value: ''
|
||||
}
|
||||
];
|
||||
|
||||
scope.application = '';
|
||||
scope.disableApplication = true;
|
||||
scope.period = '';
|
||||
var applicationElement = element.find('.application');
|
||||
applicationElement.width(200);
|
||||
$http.defaults.useXDomain = true;
|
||||
|
||||
$timeout(function () {
|
||||
if ($routeParams.period) {
|
||||
scope.period = $routeParams.period;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* date time picker
|
||||
*/
|
||||
var elDatetimepicker = element.find('#datetimepicker');
|
||||
elDatetimepicker.datetimepicker({
|
||||
pick12HourFormat: false,
|
||||
pickSeconds: false
|
||||
});
|
||||
$timeout(function () {
|
||||
setDateTime($routeParams.queryEndTime);
|
||||
});
|
||||
|
||||
/**
|
||||
* set DateTime
|
||||
*/
|
||||
var setDateTime = function (time) {
|
||||
var elDatetimepicker = element.find('#datetimepicker');
|
||||
var picker = elDatetimepicker.data('datetimepicker');
|
||||
var date = new Date();
|
||||
if (time) {
|
||||
date.setTime(date);
|
||||
}
|
||||
picker.setDate(date);
|
||||
};
|
||||
|
||||
/**
|
||||
* now
|
||||
*/
|
||||
scope.now = function() {
|
||||
setDateTime();
|
||||
broadcast();
|
||||
};
|
||||
|
||||
/**
|
||||
* _boardcast as applicationChanged with args
|
||||
*/
|
||||
var broadcast = scope.broadcast = function () {
|
||||
if (!scope.application || !scope.period || !getQueryEndTime()) {
|
||||
$location.path('/main');
|
||||
return;
|
||||
}
|
||||
var splitedApp = scope.application.split('@'),
|
||||
data = {
|
||||
application: scope.application,
|
||||
applicationName: splitedApp[0],
|
||||
serviceType: splitedApp[1],
|
||||
period: scope.period,
|
||||
queryPeriod: getQueryPeriod(),
|
||||
queryEndTime: getQueryEndTime()
|
||||
},
|
||||
url = '/main/' + scope.application + '/' + scope.period + '/' + getQueryEndTime();
|
||||
|
||||
$location.path(url);
|
||||
|
||||
$timeout(function () {
|
||||
$rootScope.$broadcast('navbar.applicationChanged', data);
|
||||
}, 100);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* get query period
|
||||
*/
|
||||
var getQueryPeriod = function () {
|
||||
return scope.period * 1000 * 60;
|
||||
};
|
||||
|
||||
var getQueryEndTime = function () {
|
||||
var date = elDatetimepicker.data('datetimepicker');
|
||||
var time = new Date(date.getDate());
|
||||
return time.getTime();
|
||||
};
|
||||
|
||||
/**
|
||||
* get Application List
|
||||
*/
|
||||
var getApplicationList = function () {
|
||||
$http.get(navbarConfig.applicationUrl).success(function (data, status) {
|
||||
|
||||
if (angular.isArray(data) === false || data.length === 0) {
|
||||
scope.applications[0].text = 'Application not found.';
|
||||
} else {
|
||||
parseApplicationList(data, function () {
|
||||
scope.disableApplication = false;
|
||||
$timeout(function () { // it should be apply after pushing data, so
|
||||
// it should work like nextTick
|
||||
applySelect2Plugnin();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}).error(function (data, status) {
|
||||
scope.applications[0].text = 'Application error.';
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* parse Application List
|
||||
*/
|
||||
var parseApplicationList = function (data, cb) {
|
||||
scope.applications = [
|
||||
{
|
||||
text: '',
|
||||
value: ''
|
||||
}
|
||||
];
|
||||
angular.forEach(data, function (value, key) {
|
||||
scope.applications.push({
|
||||
text: value.applicationName + "@" + value.serviceType,
|
||||
value: value.applicationName + "@" + value.code
|
||||
});
|
||||
});
|
||||
if (angular.isFunction(cb))
|
||||
cb.apply(scope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* apply Select2 Plugin
|
||||
*/
|
||||
var applySelect2Plugnin = function () {
|
||||
/**
|
||||
* formatOptionText
|
||||
*/
|
||||
var formatOptionText = function (state) {
|
||||
if (!state.id)
|
||||
return state.text;
|
||||
var chunk = state.text.split("@");
|
||||
if (chunk.length > 1) {
|
||||
var img = $document.get(0).createElement("img");
|
||||
img.src = "/images/icons/" + chunk[1] + ".png";
|
||||
return img.outerHTML + chunk[0];
|
||||
} else {
|
||||
return state.text;
|
||||
}
|
||||
};
|
||||
|
||||
applicationElement.select2({
|
||||
placeholder: "Select an application.",
|
||||
allowClear: false,
|
||||
formatResult: formatOptionText,
|
||||
formatSelection: formatOptionText,
|
||||
escapeMarkup: function (m) {
|
||||
return m;
|
||||
}
|
||||
});
|
||||
if ($routeParams.application) {
|
||||
applicationElement.select2('val', $routeParams.application);
|
||||
scope.application = $routeParams.application;
|
||||
broadcast();
|
||||
}
|
||||
applicationElement.on("change", function (e) {
|
||||
scope.application = e.val;
|
||||
broadcast();
|
||||
// 참고1 : http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
|
||||
// 참고2 : http://jsfiddle.net/CDvGy/2/
|
||||
scope.$digest();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* period click
|
||||
* @param val
|
||||
*/
|
||||
scope.periodClick = function (val) {
|
||||
if (scope.period !== val) {
|
||||
scope.period = val;
|
||||
broadcast();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* watches
|
||||
*/
|
||||
scope.$watch('useAnchorDate', function (newVal, oldVal) {
|
||||
scope.classAnchorDate = newVal ? 'input-append' : '';
|
||||
// if(newVal === false && oldVal === true){
|
||||
// var now = new Date();
|
||||
// 초단위 무시.
|
||||
// now.setSeconds(0);
|
||||
// 5분 단위로 조회
|
||||
// now.setMinutes(Math.floor(now.getMinutes() / 5 + 0.9) * 5);
|
||||
// elDatetimepicker.datetimepicker('setLocalDate', now);
|
||||
// broadcast();
|
||||
// }
|
||||
});
|
||||
|
||||
/**
|
||||
* executes
|
||||
*/
|
||||
getApplicationList();
|
||||
}
|
||||
};
|
||||
} ]);
|
||||
@@ -0,0 +1,124 @@
|
||||
'use strict';
|
||||
|
||||
pinpointApp.constant('nodeInfoDetailsConfig', {
|
||||
applicationStatisticsUrl: '/applicationStatistics.pinpoint',
|
||||
myColors : ["#008000", "#4B72E3", "#A74EA7", "#BB5004", "#FF0000"]
|
||||
});
|
||||
|
||||
pinpointApp
|
||||
.directive('nodeInfoDetails', [ 'nodeInfoDetailsConfig', '$rootScope', '$templateCache', function (config, $rootScope, $templateCache) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
templateUrl: 'views/nodeInfoDetails.html',
|
||||
link: function postLink(scope, element, attrs) {
|
||||
|
||||
var reset = function () {
|
||||
scope.nodeCategory = null;
|
||||
scope.unknownGroup = null;
|
||||
scope.hosts = null;
|
||||
scope.showHosts = false;
|
||||
scope.agents = null;
|
||||
scope.showAgents = false;
|
||||
scope.showNodeInfoBarChart = false;
|
||||
scope.$digest();
|
||||
};
|
||||
|
||||
var showDetailInformation = function (query, data) {
|
||||
scope.nodeCategory = data.category;
|
||||
scope.unknownGroup = data.textArr;
|
||||
scope.hosts = data.hosts;
|
||||
scope.showHosts = (scope.hosts.length > 0) ? true : false;
|
||||
scope.agents = data.agents;
|
||||
scope.showAgents = (scope.agents.length > 0) ? true : false;
|
||||
scope.$digest();
|
||||
};
|
||||
|
||||
var getApplicationStatisticsData = function (query, callback) {
|
||||
jQuery.ajax({
|
||||
type : 'GET',
|
||||
url : config.applicationStatisticsUrl,
|
||||
cache : false,
|
||||
dataType: 'json',
|
||||
data : {
|
||||
from : query.from,
|
||||
to : query.to,
|
||||
applicationName : query.applicationName,
|
||||
serviceType : query.serviceType
|
||||
},
|
||||
success : function (result) {
|
||||
callback(query, result);
|
||||
},
|
||||
error : function (xhr, status, error) {
|
||||
console.log("ERROR", status, error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var renderApplicationStatistics = function (data) {
|
||||
scope.showInfoBarChart = true;
|
||||
nv.addGraph(function () {
|
||||
var chart = nv.models.discreteBarChart().x(function (d) {
|
||||
return d.label;
|
||||
}).y(function(d) {
|
||||
return d.value;
|
||||
}).staggerLabels(false).tooltips(false).showValues(true);
|
||||
|
||||
chart.xAxis.tickFormat(function (d) {
|
||||
if(angular.isNumber(d)) {
|
||||
return (d >= 1000) ? d / 1000 + "s" : d + "ms";
|
||||
}
|
||||
return d;
|
||||
});
|
||||
|
||||
chart.yAxis.tickFormat(function (d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
chart.valueFormat(function (d) {
|
||||
return d;
|
||||
});
|
||||
|
||||
chart.color(config.myColors);
|
||||
|
||||
d3.select('.nodeInfoDetails .infoBarChart svg')
|
||||
.datum(data)
|
||||
.transition()
|
||||
.duration(0)
|
||||
.call(chart);
|
||||
|
||||
nv.utils.windowResize(chart.update);
|
||||
|
||||
return chart;
|
||||
});
|
||||
};
|
||||
|
||||
var showApplicationStatisticsSummary = function (begin, end, applicationName, serviceType) {
|
||||
var params = {
|
||||
"from" : begin,
|
||||
"to" : end,
|
||||
"applicationName" : applicationName,
|
||||
"serviceType" : serviceType
|
||||
};
|
||||
getApplicationStatisticsData(params, function (query, result) {
|
||||
scope.showNodeInfoBarChart = true;
|
||||
scope.$digest();
|
||||
renderApplicationStatistics(result.histogramSummary);
|
||||
});
|
||||
};
|
||||
|
||||
scope.$on('servermap.nodeClicked', function (event, e, query, data, containerId) {
|
||||
reset();
|
||||
showDetailInformation(query, data);
|
||||
if (!data.rawdata && data.category !== "USER" && data.category !== "UNKNOWN_GROUP") {
|
||||
showApplicationStatisticsSummary(query.from, query.to, data.text, data.serviceTypeCode);
|
||||
}
|
||||
});
|
||||
scope.$on('servermap.linkClicked', function (event, e, query, data, containerId) {
|
||||
reset();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
}]);
|
||||
@@ -0,0 +1,235 @@
|
||||
'use strict';
|
||||
|
||||
pinpointApp.constant('scatterConfig', {
|
||||
get: {
|
||||
scatterData: '/getScatterData.pinpoint',
|
||||
lastScatterData: '/getLastScatterData.pinpoint'
|
||||
}
|
||||
});
|
||||
|
||||
pinpointApp.directive('scatter',
|
||||
[ 'scatterConfig', '$rootScope', '$timeout', function (scatterConfig, $rootScope, $timeout) {
|
||||
return {
|
||||
template: '<div id="scatterchart"></div>',
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
link: function (scope, element, attrs) {
|
||||
|
||||
var oScatterChart = null;
|
||||
var selectdTracesBox = {};
|
||||
|
||||
scope.$on('navbar.applicationChanged', function (event, data) {
|
||||
console.log('got navbar.applicationChanged from scatter : ', data);
|
||||
|
||||
scope.data = data;
|
||||
|
||||
makeScatter(data.applicationName, data.queryEndTime - data.queryPeriod, data.queryEndTime, 'scatterchart', data.queryPeriod);
|
||||
});
|
||||
|
||||
var showScatter = function (applicationName, from, to, period, filter, w, h) {
|
||||
if (oScatterChart) {
|
||||
console.log('clear');
|
||||
// oScatterChart.clear();
|
||||
}
|
||||
|
||||
selectdTracesBox = {};
|
||||
// var fullscreenButton = $("#scatterChartContainer I.icon-fullscreen");
|
||||
// fullscreenButton.data("applicationName", applicationName);
|
||||
// fullscreenButton.data("from", from);
|
||||
// fullscreenButton.data("to", to);
|
||||
// fullscreenButton.data("period", period);
|
||||
// fullscreenButton.data("usePeriod", usePeriod);
|
||||
// fullscreenButton.data("filter", filter);
|
||||
|
||||
// var downloadButton = $("#scatterChartContainer A");
|
||||
|
||||
// var imageFileName = applicationName +
|
||||
// "_" +
|
||||
// new Date(from).toString("yyyyMMdd_HHmm") +
|
||||
// "~" +
|
||||
// new Date(to).toString("yyyyMMdd_HHmm") +
|
||||
// "_response_scatter.png";
|
||||
//
|
||||
// downloadButton.attr("download", imageFileName);
|
||||
// downloadButton.unbind("click");
|
||||
// downloadButton.bind("click", function() {
|
||||
// var sImageUrl = oScatterChart.getChartAsPNG();
|
||||
// $(this).attr('href', sImageUrl);
|
||||
// });
|
||||
|
||||
// $("#scatterChartContainer SPAN").unbind("click");
|
||||
// $("#scatterChartContainer SPAN").bind("click", function() {
|
||||
// showRequests(applicationName, from, to, period, usePeriod, filter);
|
||||
// });
|
||||
|
||||
// $("#scatterChartContainer").show();
|
||||
|
||||
var bDrawOnceAll = false,
|
||||
nInterval = 2000,
|
||||
fetchLimit = 2000;
|
||||
|
||||
var htDataSource = {
|
||||
sUrl: function (nFetchIndex) {
|
||||
// if (!usePeriod) {
|
||||
// return scatterConfig.get.scatterData;
|
||||
// }
|
||||
|
||||
// if (nFetchIndex === 0) {
|
||||
// return scatterConfig.get.lastScatterData;
|
||||
// } else {
|
||||
return scatterConfig.get.scatterData;
|
||||
// }
|
||||
},
|
||||
htParam: function (nFetchIndex, htLastFetchParam, htLastFetchedData) {
|
||||
// calculate parameter
|
||||
var htData;
|
||||
// console.log("htParam", nFetchIndex, htLastFetchParam, htLastFetchedData);
|
||||
|
||||
// if (nFetchIndex === 0 && !usePeriod) {
|
||||
if (nFetchIndex === 0) {
|
||||
return {
|
||||
'application': applicationName,
|
||||
'from': from,
|
||||
'to': to,
|
||||
'limit': fetchLimit,
|
||||
'filter': filter
|
||||
};
|
||||
}
|
||||
|
||||
// period만큼 먼저 조회해본다.
|
||||
if (nFetchIndex === 0 /*|| typeof(htLastFetchParam) === 'undefined' || typeof(htLastFetchedData) === 'undefined'*/) {
|
||||
htData = {
|
||||
'application': applicationName,
|
||||
'period': period,
|
||||
'limit': fetchLimit,
|
||||
'filter': filter
|
||||
};
|
||||
} else {
|
||||
if (bDrawOnceAll || htLastFetchedData.scatter.length == 0) {
|
||||
htData = {
|
||||
'application': applicationName,
|
||||
'from': htLastFetchParam.to + 1,
|
||||
'to': htLastFetchParam.to + 2000,
|
||||
'limit': fetchLimit,
|
||||
'filter': filter
|
||||
};
|
||||
} else {
|
||||
htData = {
|
||||
'application': applicationName,
|
||||
// array[0] 이 최근 값, array[len]이 오래된 이다.
|
||||
'from': from,
|
||||
'to': htLastFetchedData.scatter[htLastFetchedData.scatter.length - 1].x - 1,
|
||||
'limit': fetchLimit,
|
||||
'filter': filter
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return htData;
|
||||
},
|
||||
nFetch: function (htLastFetchParam, htLastFetchedData) {
|
||||
// -1 : stop, n = 0 : immediately, n > 0 : interval
|
||||
var useInterval = false;
|
||||
|
||||
// console.log("nFetch", htLastFetchedData);
|
||||
|
||||
if (useInterval && htLastFetchedData.scatter.length === 0) {
|
||||
// console.log("2A");
|
||||
bDrawOnceAll = true;
|
||||
return nInterval;
|
||||
}
|
||||
|
||||
if (htLastFetchedData.scatter.length !== 0) {
|
||||
// array[0] 이 최근 값, array[len]이 오래된 이다.
|
||||
if (htLastFetchedData.scatter[0].x > from) {
|
||||
// TO THE NEXT
|
||||
return 0;
|
||||
} else {
|
||||
// STOP
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (htLastFetchedData.scatter[htLastFetchedData.scatter.length - 1] &&
|
||||
htLastFetchedData.scatter[htLastFetchedData.scatter.length - 1].x < date.getTime()) {
|
||||
if (useInterval) {
|
||||
bDrawOnceAll = true;
|
||||
return nInterval;
|
||||
}
|
||||
// TO THE NEXT
|
||||
return 0;
|
||||
}
|
||||
|
||||
// STOP
|
||||
return -1;
|
||||
},
|
||||
htOption: {
|
||||
dataType: 'jsonp',
|
||||
jsonp: '_callback'
|
||||
}
|
||||
};
|
||||
oScatterChart.drawWithDataSource(htDataSource);
|
||||
};
|
||||
var makeScatter = function (title, start, end, targetId, period, w, h) {
|
||||
if(!Modernizr.canvas) {
|
||||
alert("Can't draw scatter. Not supported browser.");
|
||||
}
|
||||
|
||||
var yAxisMAX = 10000;
|
||||
var date = new Date();
|
||||
|
||||
if (oScatterChart !== null) {
|
||||
console.log('destory');
|
||||
// oScatterChart.destroy();
|
||||
// oScatterChart.updateXYAxis(start, end, 0, yAxisMAX);
|
||||
// oScatterChart.clear();
|
||||
// return;
|
||||
}
|
||||
|
||||
var options = {
|
||||
sContainerId : targetId,
|
||||
nWidth : w ? w : 400,
|
||||
nHeight : h ? h : 250,
|
||||
// nXMin: date.getTime() - 86400000, nXMax: date.getTime(),
|
||||
nXMin: start, nXMax: end,
|
||||
nYMin: 0, nYMax: yAxisMAX,
|
||||
nZMin: 0, nZMax: 5,
|
||||
nBubbleSize: 3,
|
||||
sXLabel : '',
|
||||
sYLabel : '(ms)',
|
||||
sTitle : title,
|
||||
htTypeAndColor : {
|
||||
// type name : color
|
||||
'Success' : '#2ca02c',
|
||||
// 'Warning' : '#f5d025',
|
||||
'Failed' : '#d62728'
|
||||
},
|
||||
fOnSelect : function(htPosition, htXY){
|
||||
var traces = this.getDataByXY(htXY.nXFrom, htXY.nXTo, htXY.nYFrom, htXY.nYTo);
|
||||
|
||||
if (traces.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (traces.length === 1) {
|
||||
// openTrace(traces[0].traceId, traces[0].x);
|
||||
return;
|
||||
}
|
||||
|
||||
var token = Math.random() * 10000 + 1;
|
||||
selectdTracesBox[token] = traces;
|
||||
|
||||
var popupwindow = window.open("/selectedScatter.pinpoint", token);
|
||||
}
|
||||
};
|
||||
|
||||
$timeout(function() {
|
||||
oScatterChart = new BigScatterChart(options);
|
||||
showScatter(scope.data.applicationName, start,end, period);
|
||||
}, 100);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
} ]);
|
||||
@@ -0,0 +1,459 @@
|
||||
'use strict';
|
||||
|
||||
pinpointApp.constant('servermapConfig', {
|
||||
applicationUrl: '/applications.pinpoint',
|
||||
options: {
|
||||
"sContainerId": 'servermap',
|
||||
"sImageDir": '/images/icons/',
|
||||
"sBigFont": "12pt calibri, Helvetica, Arial, sans-serif",
|
||||
"sSmallFont": "11pt calibri, Helvetica, Arial, sans-serif",
|
||||
"htIcons": {
|
||||
'APACHE': 'APACHE.png',
|
||||
'ARCUS': 'ARCUS.png',
|
||||
'CUBRID': 'CUBRID.png',
|
||||
'ETC': 'ETC.png',
|
||||
'MEMCACHED': 'MEMCACHED.png',
|
||||
'MYSQL': 'MYSQL.png',
|
||||
'QUEUE': 'QUEUE.png',
|
||||
'TOMCAT': 'TOMCAT.png',
|
||||
'UNKNOWN_CLOUD': 'UNKNOWN_CLOUD.png',
|
||||
'UNKNOWN_GROUP': 'UNKNOWN_CLOUD.png',
|
||||
'USER': 'USER.png',
|
||||
'ORACLE': 'ORACLE.png'
|
||||
},
|
||||
"htLinkTheme": {
|
||||
"default": {
|
||||
"background": { 0: "rgb(240, 240, 240)", 0.3: "rgb(240, 240, 240)", 1: "rgba(240, 240, 240, 1)"},
|
||||
"border": "gray",
|
||||
"font": "10pt calibri, helvetica, arial, sans-serif",
|
||||
"color": "#000000", // "#919191",
|
||||
"align": "center",
|
||||
"margin": 1
|
||||
},
|
||||
"good": {
|
||||
// "background" : { 0: "rgb(240, 1, 240)", 0.3: "rgb(240, 1,
|
||||
// 240)", 1: "rgba(240, 1, 240, 1)"},
|
||||
"background": { 0: "#2CA02C"},
|
||||
"border": "green",
|
||||
"font": "10pt calibri, helvetica, arial, sans-serif",
|
||||
"color": "#919191",
|
||||
"align": "center",
|
||||
"margin": 1
|
||||
},
|
||||
"bad": {
|
||||
// "background" : { 0: "rgb(214, 27, 28)", 0.3: "rgb(214, 27,
|
||||
// 28)", 1: "rgba(214, 27, 28, 1)"},
|
||||
// "background" : { 0: "#D62728" },
|
||||
"background": { 0: "rgba(200, 27, 28, 1)" },
|
||||
"border": "#FFFFFF",
|
||||
"font": "10pt calibri, helvetica, arial, sans-serif",
|
||||
"color": "#FFFFFF",
|
||||
"align": "center",
|
||||
"margin": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pinpointApp.directive('servermap', [ 'servermapConfig', '$rootScope', '$templateCache', '$compile', '$timeout', function (servermapConfig, $rootScope, $templateCache, $compile, $timeout) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
templateUrl: 'views/servermap.html',
|
||||
link: function postLink(scope, element, attrs) {
|
||||
var serverMapCachedQuery, serverMapCachedData;
|
||||
var oServerMap = null;
|
||||
var FILTER_DELIMETER = "^";
|
||||
var FILTER_ENTRY_DELIMETER = "|";
|
||||
var SERVERMAP_METHOD_CACHE = {};
|
||||
var myColors = ["#008000", "#4B72E3", "#A74EA7", "#BB5004", "#FF0000"];
|
||||
|
||||
/**
|
||||
* loading
|
||||
*/
|
||||
var startLoading = function () {
|
||||
setLoading(0);
|
||||
$timeout(function () {
|
||||
$('.servermap .progress').show();
|
||||
});
|
||||
};
|
||||
var stopLoading = function () {
|
||||
$timeout(function () {
|
||||
$('.servermap .progress').hide();
|
||||
}, 300);
|
||||
};
|
||||
var setLoading = function (p) {
|
||||
$('.servermap .progress .bar').width(p + '%');
|
||||
};
|
||||
|
||||
var showWarning = function (msg) {
|
||||
$timeout(function () {
|
||||
$('.servermap .warning').show();
|
||||
$('.servermap .warning .msg').text(msg);
|
||||
}, 300);
|
||||
};
|
||||
|
||||
var showServerMap = function (applicationName, serviceType, to, period, filterText, hideIndirectAccess) {
|
||||
startLoading();
|
||||
if (oServerMap) {
|
||||
oServerMap.clear();
|
||||
}
|
||||
setLoading(10);
|
||||
|
||||
var query = {
|
||||
applicationName: applicationName,
|
||||
serviceType: serviceType,
|
||||
from: to - period,
|
||||
to: to,
|
||||
period: period,
|
||||
filter: filterText,
|
||||
hideIndirectAccess: hideIndirectAccess
|
||||
};
|
||||
|
||||
if (filterText) {
|
||||
// getFilteredServerMapData(query, function(query, result) {
|
||||
// if (cb) {
|
||||
// cb(query, result);
|
||||
// }
|
||||
// serverMapCallback(query, result);
|
||||
// });
|
||||
} else {
|
||||
getServerMapData2(query, function (query, result) {
|
||||
serverMapCallback(query, result);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var getServerMapData2 = function (query, callback) {
|
||||
setLoading(50);
|
||||
jQuery.ajax({
|
||||
type: 'GET',
|
||||
url: '/getServerMapData2.pinpoint',
|
||||
cache: false,
|
||||
dataType: 'json',
|
||||
data: {
|
||||
application: query.applicationName,
|
||||
serviceType: query.serviceType,
|
||||
from: query.from,
|
||||
to: query.to,
|
||||
hideIndirectAccess: query.hideIndirectAccess
|
||||
},
|
||||
success: function (result) {
|
||||
setLoading(30);
|
||||
callback(query, result);
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
console.log("ERROR", status, error);
|
||||
stopLoading();
|
||||
showWarning('There is some error.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// var getFilteredServerMapData = function (query, callback) {
|
||||
// jQuery.ajax({
|
||||
// type: 'GET',
|
||||
// url: '/getFilteredServerMapData2.pinpoint',
|
||||
// cache: false,
|
||||
// dataType: 'json',
|
||||
// data: {
|
||||
// application: query.applicationName,
|
||||
// serviceType: query.serviceType,
|
||||
// from: query.from,
|
||||
// to: query.to,
|
||||
// filter: query.filter
|
||||
// },
|
||||
// success: function (result) {
|
||||
// callback(query, result);
|
||||
// },
|
||||
// error: function (xhr, status, error) {
|
||||
// console.log("ERROR", status, error);
|
||||
// }
|
||||
// });
|
||||
// };
|
||||
|
||||
var serverMapCallback = function (query, data, ignoreCache) {
|
||||
var containerId = servermapConfig.options.sContainerId;
|
||||
|
||||
serverMapCachedQuery = angular.copy(query);
|
||||
serverMapCachedData = angular.copy(data);
|
||||
setLoading(80);
|
||||
if (data.applicationMapData.nodeDataArray.length === 0) {
|
||||
stopLoading();
|
||||
showWarning('There is no data.');
|
||||
// warning("NO DATA", "");
|
||||
return;
|
||||
} else {
|
||||
// clearAllWarnings();
|
||||
// $("#" + containerId).show();
|
||||
}
|
||||
|
||||
// if ($('#mergeUnknown').data('selected')) {
|
||||
// // if ($('#mergeUnknown').is(':checked')) {
|
||||
// mergeUnknown(query, data);
|
||||
// }
|
||||
mergeUnknown(query, data);
|
||||
replaceClientToUser(data);
|
||||
setLoading(90);
|
||||
|
||||
var options = servermapConfig.options;
|
||||
options.fOnNodeContextClick = function (e, d) {
|
||||
// nodeContextClickHandler(e, query, d, "#" + containerId);
|
||||
console.log("servermap.nodeContextClicked", e, query, d, "#" + containerId);
|
||||
$rootScope.$broadcast("servermap.nodeContextClicked", e, query, d, "#" + containerId);
|
||||
};
|
||||
options.fOnLinkContextClick = function (e, d) {
|
||||
// linkContextClickHandler(e, query, d, "#" + containerId);
|
||||
console.log("servermap.linkContextClicked", e, query, d, "#" + containerId);
|
||||
$rootScope.$broadcast("servermap.linkContextClicked", e, query, d, "#" + containerId);
|
||||
};
|
||||
options.fOnLinkClick = function (e, d) {
|
||||
// linkClickHandler(e, query, d, data, "#" + containerId);
|
||||
console.log("servermap.linkClicked", e, query, d, "#" + containerId);
|
||||
$rootScope.$broadcast("servermap.linkClicked", e, query, d, "#" + containerId);
|
||||
};
|
||||
options.fOnNodeClick = function (e, d) {
|
||||
// nodeClickHandler(e, query, d, data, "#" + containerId);
|
||||
console.log("servermap.nodeClicked", e, query, d, "#" + containerId);
|
||||
$rootScope.$broadcast("servermap.nodeClicked", e, query, d, "#" + containerId);
|
||||
};
|
||||
|
||||
setLoading(100);
|
||||
oServerMap = new ServerMap(options);
|
||||
oServerMap.load(data.applicationMapData);
|
||||
stopLoading();
|
||||
|
||||
try {
|
||||
var selectedNode = (function () {
|
||||
for (var i = 0; i < data.applicationMapData.nodeDataArray.length; i++) {
|
||||
var e = data.applicationMapData.nodeDataArray[i];
|
||||
if (e.text === query.applicationName && e.serviceTypeCode === query.serviceType) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
})();
|
||||
oServerMap.highlightNodeByKey(selectedNode.key);
|
||||
// nodeClickHandler(null, query, selectedNode);
|
||||
$rootScope.$broadcast("servermap.nodeClicked", null, query, selectedNode);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
;
|
||||
};
|
||||
|
||||
// TODO 임시코드로 나중에 USER와 backend를 구분할 예정.
|
||||
var replaceClientToUser = function (data) {
|
||||
var nodes = data.applicationMapData.nodeDataArray;
|
||||
nodes.forEach(function (node) {
|
||||
if (node.category == "CLIENT") {
|
||||
node.category = "USER";
|
||||
node.text = "USER";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var mergeUnknown = function (query, data) {
|
||||
SERVERMAP_METHOD_CACHE = {};
|
||||
var nodes = data.applicationMapData.nodeDataArray;
|
||||
var links = data.applicationMapData.linkDataArray;
|
||||
|
||||
var inboundCountMap = {};
|
||||
nodes.forEach(function (node) {
|
||||
if (!inboundCountMap[node.key]) {
|
||||
inboundCountMap[node.key] = {
|
||||
"sourceCount": 0,
|
||||
"totalCallCount": 0
|
||||
};
|
||||
}
|
||||
|
||||
links.forEach(function (link) {
|
||||
if (link.to == node.key) {
|
||||
inboundCountMap[node.key].sourceCount++;
|
||||
inboundCountMap[node.key].totalCallCount += link.text;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var newNodeList = [];
|
||||
var newLinkList = [];
|
||||
|
||||
var removeNodeIdSet = {};
|
||||
var removeLinkIdSet = {};
|
||||
|
||||
nodes.forEach(function (node, nodeIndex) {
|
||||
if (node.category == "UNKNOWN_CLOUD") {
|
||||
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_CLOUD" &&
|
||||
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_CLOUD") {
|
||||
return;
|
||||
}
|
||||
if (inboundCountMap[link.to] && inboundCountMap[link.to].sourceCount > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// branch out from current node.
|
||||
if (link.from == node.key) {
|
||||
if (!newNode) {
|
||||
newNode = {
|
||||
"id": newNodeKey,
|
||||
"key": newNodeKey,
|
||||
"textArr": [],
|
||||
"text": "",
|
||||
"hosts": [],
|
||||
"category": "UNKNOWN_GROUP",
|
||||
"terminal": "true",
|
||||
"agents": [],
|
||||
"fig": "FramedRectangle"
|
||||
}
|
||||
}
|
||||
if (!newLink) {
|
||||
newLink = {
|
||||
"id": node.key + "-" + newNodeKey,
|
||||
"from": node.key,
|
||||
"to": newNodeKey,
|
||||
"sourceinfo": [],
|
||||
"targetinfo": [],
|
||||
"text": 0,
|
||||
"error": 0,
|
||||
"slow": 0,
|
||||
"rawdata": [],
|
||||
"histogram": {}
|
||||
};
|
||||
}
|
||||
|
||||
// fill the new node/link informations.
|
||||
newNode.textArr.push({ 'count': link.text, 'applicationName': link.targetinfo.applicationName});
|
||||
|
||||
newLink.text += link.text;
|
||||
newLink.error += link.error;
|
||||
newLink.slow += link.slow;
|
||||
newLink.sourceinfo.push(link.sourceinfo);
|
||||
newLink.targetinfo.push(link.targetinfo);
|
||||
|
||||
var newRawData = {
|
||||
"id": link.id,
|
||||
"from": link.from,
|
||||
"to": link.to,
|
||||
"sourceinfo": link.sourceinfo,
|
||||
"targetinfo": link.targetinfo,
|
||||
"text": 0,
|
||||
"count": link.text,
|
||||
"error": link.error,
|
||||
"slow": link.slow,
|
||||
"histogram": link.histogram
|
||||
};
|
||||
newLink.rawdata[link.targetinfo.applicationName] = newRawData;
|
||||
|
||||
/*
|
||||
* group된 노드에서 개별 노드의 정보를 조회할 때 사용됨.
|
||||
* onclick="SERVERMAP_METHOD_CACHE['{{=
|
||||
* value.applicationName}}']();" 으로 호출함.
|
||||
*/
|
||||
SERVERMAP_METHOD_CACHE[link.targetinfo.applicationName] = function () {
|
||||
linkClickHandler(null, query, newRawData);
|
||||
}
|
||||
|
||||
$.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.id] = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (newNode) {
|
||||
newNode.textArr.sort(function (e1, e2) {
|
||||
return e2.count - e1.count;
|
||||
});
|
||||
|
||||
var nodeCount = newNode.textArr.length - 1;
|
||||
$.each(newNode.textArr, function (i, e) {
|
||||
newNode.text += e.applicationName + " (" + e.count + ")" + (i < nodeCount ? "\n" : "");
|
||||
});
|
||||
|
||||
// console.log("newNode", newNode);
|
||||
newNodeList.push(newNode);
|
||||
}
|
||||
|
||||
if (newLink) {
|
||||
if ((newLink.error / newLink.text * 100) > 10) {
|
||||
newLink.category = "bad";
|
||||
} else {
|
||||
newLink.category = "default";
|
||||
}
|
||||
|
||||
// targetinfo 에러를 우선으로, 요청수 내림차순 정렬.
|
||||
newLink.targetinfo.sort(function (e1, e2) {
|
||||
var err1 = newLink.rawdata[e1.applicationName].error;
|
||||
var err2 = newLink.rawdata[e2.applicationName].error;
|
||||
|
||||
if (err1 + err2 > 0) {
|
||||
return err2 - err1;
|
||||
} else {
|
||||
return newLink.rawdata[e2.applicationName].count - newLink.rawdata[e1.applicationName].count;
|
||||
}
|
||||
});
|
||||
|
||||
// console.log("newLink", newLink);
|
||||
newLinkList.push(newLink);
|
||||
}
|
||||
});
|
||||
|
||||
newNodeList.forEach(function (newNode) {
|
||||
data.applicationMapData.nodeDataArray.push(newNode);
|
||||
});
|
||||
|
||||
newLinkList.forEach(function (newLink) {
|
||||
data.applicationMapData.linkDataArray.push(newLink);
|
||||
});
|
||||
|
||||
$.each(removeNodeIdSet, function (key, val) {
|
||||
nodes.forEach(function (node, i) {
|
||||
if (node.id == key) {
|
||||
nodes.splice(i, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$.each(removeLinkIdSet, function (key, val) {
|
||||
links.forEach(function (link, i) {
|
||||
if (link.id === key) {
|
||||
links.splice(i, 1);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
scope.$on('navbar.applicationChanged', function (event, data) {
|
||||
console.log('got navbar.applicationChanged from servermap : ', data);
|
||||
showServerMap(data.applicationName, data.serviceType, data.queryEndTime, data.queryPeriod, '', false);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}]);
|
||||
@@ -0,0 +1,136 @@
|
||||
@font-face{font-family:ng;src:url(../fonts/nanumgothic.eot);src:local('※'),url(../fonts/nanumgothic.woff) format('woff')}
|
||||
@font-face{font-family:nm;src:url(../fonts/nanummyeongjo.eot);src:local('※'),url(../fonts/nanummyeongjo.woff) format('woff')}
|
||||
@font-face{font-family:tjp;src:url(../fonts/trajanpro.eot);src:local('※'),url(../fonts/trajanpro.woff) format('woff')}
|
||||
@font-face{font-family:avn55;src:url(../fonts/avenir55.eot);src:local('※'),url(../fonts/avenir55.woff) format('woff')}
|
||||
@font-face{font-family:avn85;src:url(../fonts/avenir85.eot);src:local('※'),url(../fonts/avenir85.woff) format('woff')}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body,input,textarea,select,button,table{font-family:'나눔고딕',NanumGothic,ng,'돋움',dotum,AppleGothic,avn55,sans-serif}
|
||||
canvas {outline:none}
|
||||
|
||||
#wrapper {
|
||||
padding: 40px 0 0 0;
|
||||
position:absolute;
|
||||
top:0;
|
||||
bottom:0;
|
||||
left:0;
|
||||
right:0;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
position: absolute;
|
||||
margin: -40px 0 0 0;
|
||||
height: 40px;
|
||||
background-color: #252a3a;
|
||||
width: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
.navbar .brand {
|
||||
margin-left: 20px;
|
||||
}
|
||||
.navbar .nav>li {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.navbar .divider-vertical {
|
||||
min-height: 1px;
|
||||
margin: 0 9px;
|
||||
border: 0;
|
||||
}
|
||||
.navbar-form {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.navbar-form .datetimepicker {
|
||||
margin: 0;
|
||||
}
|
||||
.navbar-form .datetimepicker input[type="text"]{
|
||||
width: 120px;
|
||||
}
|
||||
.navbar-form .datetimepicker .checkbox input[type="checkbox"]{
|
||||
float: none;
|
||||
}
|
||||
.navbar-form .datetimepicker .icon-calendar {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.mt8 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.navbar .btn-group > .btn > input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main {
|
||||
margin-right: 430px;
|
||||
height: 100%;
|
||||
}
|
||||
.main.fullsize {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
/* sidebar */
|
||||
.sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding-left: 12px;
|
||||
width: 410px;
|
||||
height: 100%;
|
||||
}
|
||||
.sidebar.smallsize {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.divider {
|
||||
position: absolute;
|
||||
top: 45%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.onoff-ico {
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 54px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('../images/onoff.png');
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
/* divider */
|
||||
.divider-open {
|
||||
background-position: 0 0;
|
||||
}
|
||||
.onoff-ico.divider-open:hover,
|
||||
.onoff-ico.divider-open:focus {
|
||||
background-position: 0 -56px;
|
||||
}
|
||||
|
||||
.divider-closed {
|
||||
background-position: -12px 0;
|
||||
}
|
||||
.onoff-ico.divider-closed:hover,
|
||||
.onoff-ico.divider-closed:focus {
|
||||
background-position: -12px -56px;
|
||||
}
|
||||
|
||||
/* info-details */
|
||||
.info-details {
|
||||
border-top: 1px solid #ddd;
|
||||
border-left: 1px solid #ddd;
|
||||
position: absolute;
|
||||
top: 250px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: auto;
|
||||
padding: 5px;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<a class="divider" href ng-click="toggle()">
|
||||
<i class="onoff-ico" ng-class="onoff"></i>
|
||||
</a>
|
||||
@@ -0,0 +1,58 @@
|
||||
<div class="linkInfoDetails">
|
||||
<div class='info' ng-switch="linkCategory">
|
||||
|
||||
<div ng-switch-when="UnknownLinkInfoBox">
|
||||
<div ng-repeat="target in targetinfo">
|
||||
<img ng-src="/images/icons/{{sourceinfo[0].serviceType}}.png" width="20" height="10" /> {{sourceinfo[0].applicationName}}
|
||||
<i class="icon-arrow-right"></i>
|
||||
<img ng-src="/images/icons/{{target.serviceType}}.png" width="20" height="10" /> {{target.applicationName}}
|
||||
<a href="#" onclick="SERVERMAP_METHOD_CACHE['{{target.applicationName}}']();" title="show details" style="text-decoration:none;">
|
||||
<i class="icon-search"></i>
|
||||
</a>
|
||||
<ul>
|
||||
<li>request count : {{rawdata[target.applicationName].count}} /
|
||||
<span ng-style="rawdata[target.applicationName].error && 'color:#FF0000'">{{rawdata[target.applicationName].error}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-switch-when="LinkInfoBox">
|
||||
<img ng-src="/images/icons/{{sourceinfo.serviceType}}.png" width="20" height="10" /> {{sourceinfo.applicationName}}
|
||||
<i class="icon-arrow-right"></i>
|
||||
<img ng-src="/images/icons/{{targetinfo.serviceType}}.png" width="20" height="10" /> {{targetinfo.applicationName}}
|
||||
<!--
|
||||
<br/>
|
||||
Total requests : ???<br/>
|
||||
Failed : {{= error}}<br/>
|
||||
Response statistics
|
||||
<ul>
|
||||
{{var lastKey=''}}
|
||||
{{each(key, value) histogram}}
|
||||
<li><= {{= key}}ms : {{= value}}</li>
|
||||
{{eval lastKey=key}}
|
||||
{{/each}}
|
||||
<li> > {{= lastKey}}ms : {{= slow}}</li>
|
||||
</ul>
|
||||
-->
|
||||
<br/>
|
||||
<a href="#" onclick="filterPassingTransaction('{{sourceinfo.applicationName}}', '{{query.serviceType}}', {{query.from}}, {{query.to}}, '{{sourceinfo.serviceType}}', '{{sourceinfo.applicationName}}', '{{targetinfo.serviceType}}', '{{targetinfo.applicationName}}', null);">Passing transaction map</a><br/>
|
||||
|
||||
<a ng-if="sourceinfo.serviceType == 'CLIENT'" href="#" ng-click="showRequests('{{targetinfo.applicationName}}', {{query.from}}, {{query.to}}, {{query.period}}, {{query.usePeriod}}, '{{sourceinfo.serviceType}}|{{targetinfo.applicationName}}|{{targetinfo.serviceType}}|{{targetinfo.applicationName}}');">Passing transaction list</a>
|
||||
<a ng-if="sourceinfo.serviceType != 'CLIENT'" href="#" ng-click="showRequests('{{sourceinfo.applicationName}}', {{query.from}}, {{query.to}}, {{query.period}}, {{query.usePeriod}}, '{{sourceinfo.serviceType}}|{{sourceinfo.applicationName}}|{{targetinfo.serviceType}}|{{targetinfo.applicationName}}');">Passing transaction list</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class='infoChart' ng-show="showLinkInfoChart">
|
||||
Response histogram
|
||||
<svg style='height:200px' />
|
||||
</div>
|
||||
|
||||
<div class='infoBarChart' ng-show="showLinkInfoBarChart">
|
||||
Response histogram summary
|
||||
<svg style='height:150px' />
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<div class="main" ng-class="main">
|
||||
<servermap></servermap>
|
||||
</div>
|
||||
<div class="sidebar" ng-class="sidebar">
|
||||
<scatter></scatter>
|
||||
<div class="info-details">
|
||||
<node-info-details></node-info-details>
|
||||
<link-info-details></link-info-details>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,73 @@
|
||||
<div class="navbar bs-docs-nav">
|
||||
<div class="nav-container">
|
||||
<a href="/" class="navbar-brand"><img class="brand" src="/images/logo2.png" width="116" height="18"></a>
|
||||
|
||||
<div class="nav-collapse collapse">
|
||||
<form class="navbar-form pull-left">
|
||||
<ul class="nav navbar-nav">
|
||||
<li>
|
||||
<select class="application" ng-disabled="disableApplication">
|
||||
<option ng-repeat="app in applications" value="{{app.value}}">{{app.text}}</option>
|
||||
</select>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li>
|
||||
<div class="btn-group">
|
||||
<label class="btn btn-primary btn-mini" ng-class="{active: period == 5}">
|
||||
<input type="radio" ng-click="periodClick(5)">Last 5m
|
||||
</label>
|
||||
<label class="btn btn-primary btn-mini" ng-class="{active: period == 20}">
|
||||
<input type="radio" ng-click="periodClick(20)">20m
|
||||
</label>
|
||||
<label class="btn btn-success btn-mini" ng-class="{active: period == 60}">
|
||||
<input type="radio" ng-click="periodClick(60)">1h
|
||||
</label>
|
||||
<label class="btn btn-success btn-mini" ng-class="{active: period == 180}">
|
||||
<input type="radio" ng-click="periodClick(180)">3h
|
||||
</label>
|
||||
<label class="btn btn-success btn-mini" ng-class="{active: period == 360}">
|
||||
<input type="radio" ng-click="periodClick(360)">6h
|
||||
</label>
|
||||
<label class="btn btn-success btn-mini" ng-class="{active: period == 740}">
|
||||
<input type="radio" ng-click="periodClick(740)">12h
|
||||
</label>
|
||||
<label class="btn btn-info btn-mini" ng-class="{active: period == 1440}">
|
||||
<input type="radio" ng-click="periodClick(1440)">1d
|
||||
</label>
|
||||
<label class="btn btn-info btn-mini" ng-class="{active: period == 2880}">
|
||||
<input type="radio" ng-click="periodClick(2880)">2d
|
||||
</label>
|
||||
<label class="btn btn-info btn-mini" ng-class="{active: period == 4320}">
|
||||
<input type="radio" ng-click="periodClick(4320)">3d
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li style="{{useAnchorDate && 'width:194px' || 'width:168px'}}">
|
||||
<div class="datetimepicker input-prepend date" ng-class="classAnchorDate">
|
||||
<span class="add-on pull-left">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" ng-model="useAnchorDate" ng-init="useAnchorDate = false">
|
||||
</label>
|
||||
</span>
|
||||
|
||||
<div id="datetimepicker">
|
||||
<input data-format="yyyy.MM.dd hh:mm" type="text" ng-disabled="!useAnchorDate"></input>
|
||||
<span class="add-on" ng-show="useAnchorDate">
|
||||
<i data-time-icon="icon-time" data-date-icon="icon-calendar">
|
||||
</i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li style="margin-top:0;" ng-show="useAnchorDate" >
|
||||
<button class="btn" type="button" ng-click="broadcast()">Apply</button>
|
||||
</li>
|
||||
<li style="margin-top:0;" ng-show="!useAnchorDate" >
|
||||
<button class="btn" type="button" ng-click="now()">Now</button>
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,52 @@
|
||||
<div class="nodeInfoDetails">
|
||||
<div class='info' ng-switch="nodeCategory">
|
||||
|
||||
<div ng-switch-when="UNKNOWN_GROUP">
|
||||
<ul>
|
||||
<li ng-repeat="node in unknownGroup">
|
||||
<img src="/images/icons/UNKNOWN_CLOUD.png" width="20" height="10" /> {{node.applicationName}}<br/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div ng-switch-when="USER">
|
||||
<img src="/images/icons/USER.png" width="20" height="10" /> USER
|
||||
</div>
|
||||
|
||||
<div ng-switch-default>
|
||||
<div ng-show="showHosts">
|
||||
Hosts
|
||||
<ul>
|
||||
<li ng-repeat="host in hosts">
|
||||
<span class="label label-success">OK</span>
|
||||
{{host}}
|
||||
<a href="http://nsight.nhncorp.com/dashboard_server/{{host.split(':')[0].replace('.nhnsystem.com','')}}" target="_blank" title="System resource monitoring site">(NSight)</a>
|
||||
<a href="http://hubble.arcuscloud.nhncorp.com/" target="_blank" title="Arcus monitoring site" ng-if="category == 'ARCUS'">(Hubble)</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div ng-show="showAgents">
|
||||
Server instances
|
||||
<ul>
|
||||
<li ng-repeat="agent in agents">
|
||||
<span class="label label-success">OK</span>
|
||||
{{agent.agentId}}
|
||||
<!--
|
||||
<a href="#" onclick="alert('Sorry. Not implemented.');">(Kuvasz)</a>
|
||||
<a href="#" onclick="alert('Sorry. Not implemented.');">(Tools)</a>
|
||||
-->
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class='infoBarChart' ng-show="showNodeInfoBarChart">
|
||||
Response histogram summary
|
||||
<svg style='height:150px;' />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div style="display:table;height:100%;width:100%;">
|
||||
<div style="display:table-cell;text-align:center;vertical-align:middle;">
|
||||
<div class="input-prepend">
|
||||
<span class="add-on"><i class="icon-warning-sign"></i></span>
|
||||
<span class="uneditable-input span2" style="width:294px;cursor:auto">Please select an application and period above.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="servermap" style="width:100%;height:100%;position: relative;">
|
||||
<div id="servermap" style="width:100%;height:100%;position: relative;">
|
||||
</div>
|
||||
<div ng-include=" 'warning' "></div>
|
||||
<div ng-include=" 'loading' "></div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user