From 5aabf6b5cbb37be49763c9479d7f494875754df1 Mon Sep 17 00:00:00 2001 From: sand Date: Mon, 30 Jul 2012 20:42:46 +0800 Subject: [PATCH] StatViewServlet: add activeConnectionStackTrace support, refactor js --- .../druid/support/http/StatViewServlet.java | 37 ++++ .../com/alibaba/druid/util/MapComparator.java | 24 ++- .../resources/activeConnectionStackTrace.html | 31 +++ .../resources/activeConnectionStackTrace.js | 23 ++ .../resources/support/http/resources/api.html | 23 +- .../support/http/resources/basicStat.js | 23 ++ .../support/http/resources/common.js | 60 ++++++ .../support/http/resources/datasource.html | 4 +- .../http/resources/{js.js => datasource.js} | 201 ++---------------- .../support/http/resources/index.html | 4 +- .../resources/support/http/resources/sql.html | 68 ++++-- .../resources/support/http/resources/sql.js | 127 +++++++++++ .../support/http/resources/style.css | 13 +- .../support/http/resources/template.html | 3 +- 14 files changed, 424 insertions(+), 217 deletions(-) create mode 100644 src/main/resources/support/http/resources/activeConnectionStackTrace.html create mode 100644 src/main/resources/support/http/resources/activeConnectionStackTrace.js create mode 100644 src/main/resources/support/http/resources/basicStat.js create mode 100644 src/main/resources/support/http/resources/common.js rename src/main/resources/support/http/resources/{js.js => datasource.js} (60%) create mode 100644 src/main/resources/support/http/resources/sql.js diff --git a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java index 4c8f819160..8111617fa3 100644 --- a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java +++ b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java @@ -102,6 +102,16 @@ public class StatViewServlet extends HttpServlet { return; } + if (path.startsWith("/activeConnectionStackTrace-")) { + Integer id = StringUtils.subStringToInteger(path, "activeConnectionStackTrace-", "."); + DruidDataSource datasource = getDruidDataSourceById(id); + + if (path.endsWith(".json")) returnJSONActiveConnectionStackTrace(datasource, request, response); + if (path.endsWith(".html")) returnViewActiveConnectionStackTrace(datasource, request, response); + + return; + } + if (path.equals("/sql.json")) { returnJSONResult(request, response, RESULT_CODE_SUCCESS, getSqlStatDataList(request)); return; @@ -127,6 +137,30 @@ public class StatViewServlet extends HttpServlet { returnResourceFile(path, response); } + private void returnJSONActiveConnectionStackTrace(DruidDataSource datasource, HttpServletRequest request, + HttpServletResponse response) throws IOException { + if (datasource.isRemoveAbandoned()) { + List result = datasource.getActiveConnectionStackTrace(); + returnJSONResult(request, response, RESULT_CODE_SUCCESS, result); + } else { + returnJSONResult(request, response, RESULT_CODE_ERROR, "require set removeAbandoned=true"); + } + } + + private void returnViewActiveConnectionStackTrace(DruidDataSource datasource, HttpServletRequest request, + HttpServletResponse response) throws IOException { + if (datasource == null) return; + + if (!datasource.isRemoveAbandoned()) { + response.getWriter().print(mergeTemplatePage("ERROR", "require set removeAbandoned=true")); + return; + } + + String text = IOUtils.readFromResource(RESOURCE_PATH + "/activeConnectionStackTrace.html"); + text = text.replaceAll("\\{datasourceId\\}", String.valueOf(System.identityHashCode(datasource))); + response.getWriter().print(text); + } + private void returnViewSqlStat(JdbcSqlStat sqlStat, HttpServletResponse response) throws IOException { if (sqlStat == null) return; @@ -343,6 +377,9 @@ public class StatViewServlet extends HttpServlet { dataMap.put("StartTransactionCount", dataSource.getStartTransactionCount()); dataMap.put("TransactionHistogramValues", dataSource.getTransactionHistogramValues()); + + dataMap.put("RemoveAbandoned", dataSource.isRemoveAbandoned()); + return dataMap; } diff --git a/src/main/java/com/alibaba/druid/util/MapComparator.java b/src/main/java/com/alibaba/druid/util/MapComparator.java index 21ab0f2052..b41af0a756 100644 --- a/src/main/java/com/alibaba/druid/util/MapComparator.java +++ b/src/main/java/com/alibaba/druid/util/MapComparator.java @@ -1,5 +1,6 @@ package com.alibaba.druid.util; +import java.lang.reflect.Array; import java.text.Collator; import java.util.Comparator; import java.util.Date; @@ -11,9 +12,9 @@ import java.util.Map; public class MapComparator implements Comparator> { private boolean isDesc; - private String orderByKey; + private K orderByKey; - public MapComparator(String orderByKey, boolean isDesc) { + public MapComparator(K orderByKey, boolean isDesc) { this.orderByKey = orderByKey; this.isDesc = isDesc; } @@ -39,9 +40,24 @@ public class MapComparator implements Compar return result; } + private Object getValueByKey(Map map, K key) { + if (key instanceof String) { + String keyStr = (String) key; + if (keyStr.matches(".+\\[[0-9]+\\]")) { + Object value = map.get(keyStr.substring(0, keyStr.indexOf("["))); + Integer index = StringUtils.subStringToInteger(keyStr, "[", "]"); + if (value.getClass().isArray() && Array.getLength(value) >= index) { + return Array.get(value, index); + } + return null; + } + } + return map.get(key); + } + public int compare_0(Map o1, Map o2) { - Object v1 = o1.get(orderByKey); - Object v2 = o2.get(orderByKey); + Object v1 = getValueByKey(o1, orderByKey); + Object v2 = getValueByKey(o2, orderByKey); if (v1 == null && v2 == null) return 0; if (v1 == null) return -1; diff --git a/src/main/resources/support/http/resources/activeConnectionStackTrace.html b/src/main/resources/support/http/resources/activeConnectionStackTrace.html new file mode 100644 index 0000000000..3c73713d64 --- /dev/null +++ b/src/main/resources/support/http/resources/activeConnectionStackTrace.html @@ -0,0 +1,31 @@ + + + + Druid ActiveConnection StackTrace + + + + + + + +
+ +
+
+

ActiveConnection StackTrace [View JSON API]

+
+ +
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/support/http/resources/activeConnectionStackTrace.js b/src/main/resources/support/http/resources/activeConnectionStackTrace.js new file mode 100644 index 0000000000..0b813d2349 --- /dev/null +++ b/src/main/resources/support/http/resources/activeConnectionStackTrace.js @@ -0,0 +1,23 @@ +function ajaxRequestForActiveConnectionStackTrace(datasourceId) { + var xmlHttpForActiveConnectionStackTrace=getRequestObject(); + sendRequest(xmlHttpForActiveConnectionStackTrace,'activeConnectionStackTrace-' + datasourceId + '.json', function() { + ajaxResponseForActiveConnectionStackTrace(xmlHttpForActiveConnectionStackTrace, datasourceId); + }); +} + +function ajaxResponseForActiveConnectionStackTrace(xmlHttpForActiveConnectionStackTrace, datasourceId) { + var conntionStackTraceList = getJSONResponseContent(xmlHttpForActiveConnectionStackTrace); + if (conntionStackTraceList == null) + return; + + var activeConnectionStackTraceTable = document.getElementById("activeConnectionStackTraceTable"); + while (activeConnectionStackTraceTable.rows.length > 0) { + activeConnectionStackTraceTable.deleteRow(0); + } + for ( var i = 0; i < conntionStackTraceList.length; i++) { + var conntionStackTrace = conntionStackTraceList[i]; + var newRow = activeConnectionStackTraceTable.insertRow(-1); + newRow.insertCell(-1).innerHTML = conntionStackTrace; + } + +} \ No newline at end of file diff --git a/src/main/resources/support/http/resources/api.html b/src/main/resources/support/http/resources/api.html index 1b09db4edb..08a9fc71ee 100644 --- a/src/main/resources/support/http/resources/api.html +++ b/src/main/resources/support/http/resources/api.html @@ -3,7 +3,7 @@ Druid Stat JSON API - + @@ -43,17 +43,27 @@ DatasourceStat for id={id},id is DatsSourceStat.ID
Example: druid/datasource-1.json + + + + activeConnectionStackTrace-{datasourceId}.json + + + StrackTrace for activeConnection in datasource which datasource.id={datasourceId},id is DatsSourceStat.ID
+ Required: set removeAbandoned=true
+ Example: druid/activeConnectionStackTrace-1.json + sql.json -

SqlStat info List.

-

orderBy=[ID|ExecuteCount|...|](every property without histogram in sqlstat object)

-

orderType=[asc|desc] default is desc

-

page=page count start with 1

-

perPageCount=item count in one page,default is IN

+ SqlStat info List.
+ orderBy=[ID|ExecuteCount|...|](every property without histogram in sqlstat object)
+ orderType=[asc|desc] default is desc
+ page=page count start with 1
+ perPageCount=item count in one page,default is INTEGER.MAX_VALUE @@ -75,5 +85,6 @@ + \ No newline at end of file diff --git a/src/main/resources/support/http/resources/basicStat.js b/src/main/resources/support/http/resources/basicStat.js new file mode 100644 index 0000000000..38cdfc288d --- /dev/null +++ b/src/main/resources/support/http/resources/basicStat.js @@ -0,0 +1,23 @@ +var xmlHttpForBasicInfo; + +function ajaxRequestForBasicInfo() { + xmlHttpForBasicInfo = getRequestObject(); + sendRequest(xmlHttpForBasicInfo,'basic.json',ajaxResponseForBasicInfo); +} + +function ajaxResponseForBasicInfo() { + var jsonContent = getJSONResponseContent(xmlHttpForBasicInfo); + if(jsonContent==null) return; + + document.getElementById("DruidVersion").innerHTML = jsonContent.Version; + + var driversList = jsonContent.Drivers; + if (driversList) { + var driverHtml = ''; + for ( var i = 0; i < driversList.length; i++) { + var driver = driversList[i]; + driverHtml += driver + ' , '; + } + document.getElementById("DruidDrivers").innerHTML = driverHtml; + } +} diff --git a/src/main/resources/support/http/resources/common.js b/src/main/resources/support/http/resources/common.js new file mode 100644 index 0000000000..3a8dc01ab2 --- /dev/null +++ b/src/main/resources/support/http/resources/common.js @@ -0,0 +1,60 @@ +function changeInnerHtml(id, divHtml) { + var divObj = document.getElementById(id); + if (divHtml == undefined) + divHtml = ''; + if (divObj) { + divObj.innerHTML = divHtml; + } +} + +function checkResoponse(xmlHttpForRequest){ + if (xmlHttpForRequest.readyState != 4) { + return false; + } + if (xmlHttpForRequest.status != 200) { + return false; + } + return true; +} + +function getJSONResponseContent(xmlHttpForRequest){ + if(checkResoponse(xmlHttpForRequest)){ + var jsonResp = eval("(" + xmlHttpForRequest.responseText + ")"); + if (jsonResp.ResultCode == 1) { + return jsonResp.Content; + } + } + return null; +} + +function sendRequest(requestObject,url,callBack){ + requestObject.onreadystatechange = callBack; + requestObject.open("GET", url, true); + requestObject.send(null); +} + +function getRequestObject(){ + var requestObject; + if (window.XMLHttpRequest) + requestObject = new XMLHttpRequest(); + else if (window.ActiveXObject) + requestObject = new ActiveXObject("Microsoft.XMLHTTP"); + return requestObject; +} + + +function ajaxRequestForReset() { + xmlHttpForReset = getRequestObject(); + sendRequest(xmlHttpForReset,'reset-all.json',ajaxResponseForReset) +} + +function ajaxResponseForReset() { + if (!checkResoponse(xmlHttpForReset)) { + return; + } + var jsonResp = eval("(" + xmlHttpForReset.responseText + ")"); + if (jsonResp.ResultCode == 1) { + alert("already reset all stat"); + } + +} \ No newline at end of file diff --git a/src/main/resources/support/http/resources/datasource.html b/src/main/resources/support/http/resources/datasource.html index b64f986ddc..6e5b47f54c 100644 --- a/src/main/resources/support/http/resources/datasource.html +++ b/src/main/resources/support/http/resources/datasource.html @@ -4,7 +4,8 @@ Druid DataSourceStat - + + + + + + \ No newline at end of file diff --git a/src/main/resources/support/http/resources/sql.js b/src/main/resources/support/http/resources/sql.js new file mode 100644 index 0000000000..02172ba557 --- /dev/null +++ b/src/main/resources/support/http/resources/sql.js @@ -0,0 +1,127 @@ + +var xmlHttpForDataSourceSqlStatInfo; + +var sqlViewOrderBy = ''; +var sqlViewOrderBy_old = ''; +var sqlViewOrderType = 'asc'; + +// only one page for now +var sqlViewPage = 1; +var sqlViewPerPageCount = 1000000; + +function resetSortMark() { + var divObj = document.getElementById('th-' + sqlViewOrderBy); + var old_divObj = document.getElementById('th-' + sqlViewOrderBy_old); + var replaceToStr = ''; + if (old_divObj) { + var html = old_divObj.innerHTML; + if (sqlViewOrderBy_old.indexOf('[') > 0) + replaceToStr = '-'; + html = html.replace('↑', replaceToStr); + html = html.replace('↓', replaceToStr); + old_divObj.innerHTML = html + } + if (divObj) { + var html = divObj.innerHTML; + if (sqlViewOrderBy.indexOf('[') > 0) + html = ''; + + if (sqlViewOrderType == 'asc') { + html += '↑'; + } else if (sqlViewOrderType == 'desc') { + html += '↓'; + } + divObj.innerHTML = html; + } +} + +function setOrderBy(orderBy) { + if (sqlViewOrderBy != orderBy) { + sqlViewOrderBy_old = sqlViewOrderBy; + sqlViewOrderBy = orderBy; + sqlViewOrderType = 'desc'; + resetSortMark(); + return; + } + + sqlViewOrderBy_old = sqlViewOrderBy; + + if (sqlViewOrderType == 'asc') + sqlViewOrderType = 'desc' + else + sqlViewOrderType = 'asc'; + + resetSortMark(); + +} + +function getSqlViewJsonUrl() { + var result = 'sql.json?'; + + if (sqlViewOrderBy != undefined) + result += 'orderBy=' + sqlViewOrderBy + '&'; + + if (sqlViewOrderType != undefined) + result += 'orderType=' + sqlViewOrderType + '&'; + + if (sqlViewPage != undefined) + result += 'page=' + sqlViewPage + '&'; + + if (sqlViewPerPageCount != undefined) + result += 'perPageCount=' + sqlViewPerPageCount + '&'; + + return result; +} + +function ajaxRequestForDataSourceSqlStatInfo() { + xmlHttpForDataSourceSqlStatInfo = getRequestObject(); + sendRequest(xmlHttpForDataSourceSqlStatInfo,getSqlViewJsonUrl(),ajaxResponseForDataSourceSqlStatInfo) +} + +function subSqlString(sql, len) { + if (sql.length <= len) + return sql; + return sql.substr(0, len) + '...'; +} +function ajaxResponseForDataSourceSqlStatInfo() { + var sqlStatList = getJSONResponseContent(xmlHttpForDataSourceSqlStatInfo); + if(sqlStatList==null) return; + + var sqlStatTable = document.getElementById("SqlStatTable"); + while (sqlStatTable.rows.length > 1) { + sqlStatTable.deleteRow(1); + } + for ( var i = 0; i < sqlStatList.length; i++) { + var sqlStat = sqlStatList[i]; + var newRow = sqlStatTable.insertRow(-1); + newRow.insertCell(-1).innerHTML = '' + subSqlString(sqlStat.SQL, 25) + ''; + // if (sqlStat.File) + // newRow.insertCell(-1).innerHTML = sqlStat.File; + // else + // newRow.insertCell(-1).innerHTML = ''; + // if (sqlStat.Name) + // newRow.insertCell(-1).innerHTML = sqlStat.Name; + // else + // newRow.insertCell(-1).innerHTML = ''; + newRow.insertCell(-1).innerHTML = sqlStat.ExecuteCount; + newRow.insertCell(-1).innerHTML = sqlStat.TotalTime; + newRow.insertCell(-1).innerHTML = sqlStat.MaxTimespan; + newRow.insertCell(-1).innerHTML = sqlStat.InTransactionCount; + newRow.insertCell(-1).innerHTML = sqlStat.ErrorCount; + newRow.insertCell(-1).innerHTML = sqlStat.EffectedRowCount; + newRow.insertCell(-1).innerHTML = sqlStat.FetchRowCount; + newRow.insertCell(-1).innerHTML = sqlStat.RunningCount; + newRow.insertCell(-1).innerHTML = sqlStat.ConcurrentMax; + // hiHtml += 'ExecHistogram |'; + // hiHtml += 'FetchRow | '; + // hiHtml += 'UpdateCount | '; + // hiHtml += 'ExecAndRsHold'; + newRow.insertCell(-1).innerHTML = '[' + sqlStat.Histogram + ']'; + newRow.insertCell(-1).innerHTML = '[' + sqlStat.FetchRowCountHistogram + ']'; + newRow.insertCell(-1).innerHTML = '[' + sqlStat.EffectedRowCountHistogram + ']'; + newRow.insertCell(-1).innerHTML = '[' + sqlStat.ExecuteAndResultHoldTimeHistogram + ']'; + } +} \ No newline at end of file diff --git a/src/main/resources/support/http/resources/style.css b/src/main/resources/support/http/resources/style.css index 4b9d779251..e86f051143 100644 --- a/src/main/resources/support/http/resources/style.css +++ b/src/main/resources/support/http/resources/style.css @@ -8,10 +8,19 @@ body{ height:50px; } - #menu a{ +#menu a{ color: #0082FF; font: 18px 'Microsoft YaHei','Microsoft JhengHei',STHeiti,Georgia,'Times New Roman',Times,serif; - } +} +#footer { + height: 50px; + border-top: 1px solid #A8C7CE; + margin-top: 20px; + width: 99%; + text-align: center; + line-height: 26px; + padding-top: 15px; +} tr{ background-color:white; } diff --git a/src/main/resources/support/http/resources/template.html b/src/main/resources/support/http/resources/template.html index 36d5b4ce3b..a6e145b412 100644 --- a/src/main/resources/support/http/resources/template.html +++ b/src/main/resources/support/http/resources/template.html @@ -4,7 +4,7 @@ {title} - +
@@ -15,5 +15,6 @@
{content}
+ \ No newline at end of file