/*
* Copyright 2014 mango.jfaster.org
*
* The Mango Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.jfaster.mango.plugin.stats;
import org.jfaster.mango.stat.OperatorStat;
import java.util.Map;
/**
* @author ash
*/
public class Template {
public static String render(String beginTime, String endTime, Map<String, OperatorStat> osMap, Map<String, ExtendStat> esMap, boolean isFetchAll) {
StringBuilder sb = new StringBuilder();
for (String c1 : c1s) {
sb.append(c1).append("\n");
}
for (String sKey : osMap.keySet()) {
OperatorStat os = osMap.get(sKey);
ExtendStat es = esMap.get(sKey);
if (isFetchAll || os.getDatabaseExecuteCount() > 0 || os.getHitCount() > 0) {
sb.append(" <tr>").append("\n");
buildTD(sb, os.isCacheable() ? "yes" : "no");
buildTD(sb, es.getSimpleClassName());
buildTD(sb, es.getSimpleMethodName());
buildTD(sb, div(os.getDatabaseExecuteAveragePenalty(), 1000000));
buildTD(sb, os.getDatabaseExecuteCount());
buildTD(sb, os.getDatabaseExecuteExceptionCount());
buildTD(sb, mul(os.getDatabaseExecuteExceptionRate(), 100));
buildTD(sb, os.getInitCount());
buildTD(sb, os.getHitCount());
buildTD(sb, os.getMissCount());
buildTD(sb, mul(os.getHitRate(), 100));
buildTD(sb, div(os.getCacheGetAveragePenalty(), 1000000));
buildTD(sb, os.getCacheGetCount());
buildTD(sb, os.getCacheGetExceptionCount());
buildTD(sb, mul(os.getCacheGetExceptionRate(), 100));
buildTD(sb, div(os.getCacheGetBulkAveragePenalty(), 1000000));
buildTD(sb, os.getCacheGetBulkCount());
buildTD(sb, os.getCacheGetBulkExceptionCount());
buildTD(sb, mul(os.getCacheGetBulkExceptionRate(), 100));
buildTD(sb, div(os.getCacheSetAveragePenalty(), 1000000));
buildTD(sb, os.getCacheSetCount());
buildTD(sb, os.getCacheSetExceptionCount());
buildTD(sb, mul(os.getCacheSetExceptionRate(), 100));
buildTD(sb, div(os.getCacheAddAveragePenalty(), 1000000));
buildTD(sb, os.getCacheAddCount());
buildTD(sb, os.getCacheAddExceptionCount());
buildTD(sb, mul(os.getCacheAddExceptionRate(), 100));
buildTD(sb, div(os.getCacheDeleteAveragePenalty(), 1000000));
buildTD(sb, os.getCacheDeleteCount());
buildTD(sb, os.getCacheDeleteExceptionCount());
buildTD(sb, mul(os.getCacheDeleteExceptionRate(), 100));
buildTD(sb, div(os.getCacheBatchDeleteAveragePenalty(), 1000000));
buildTD(sb, os.getCacheBatchDeleteCount());
buildTD(sb, os.getCacheBatchDeleteExceptionCount());
buildTD(sb, mul(os.getCacheBatchDeleteExceptionRate(), 100));
buildTD(sb, es.getSql());
StringBuilder types = new StringBuilder();
for (String type : es.getStrParameterTypes()) {
types.append(type.replaceAll("<", "<").replaceAll(">", ">")).append(" ");
}
buildTD(sb, types);
buildTD(sb, es.getType());
buildTD(sb, os.isUseMultipleKeys() ? "yes" : "no");
buildTD(sb, os.isCacheNullObject() ? "yes" : "no");
sb.append(" </tr>").append("\n");
}
}
for (String c2 : c2s) {
sb.append(c2).append("\n");
}
String data = sb.toString();
data = data.replace("${beginTime}", beginTime).replace("${endTime}", endTime);
return data;
}
private static void buildTD(StringBuilder sb, Object data) {
sb.append(" <td>" + data + "</td>").append("\n");
}
private static String div(long a, long b) {
double c = ((double) a / (double) b);
double d = (double) (Math.round(c * 10)) / 10;
return String.valueOf(d);
}
private static String mul(double a, long b) {
double c = a * b;
double d = (double) (Math.round(c * 10)) / 10;
return String.valueOf(d) + "%";
}
private final static String[] c1s = new String[] {
"<html>",
"",
"<head>",
" <title>mango统计信息</title>",
" <script src='http://static.jfaster.org/jquery/1.11.1/jquery.min.js' type='text/javascript' charset='utf-8'></script>",
" <link href='http://static.jfaster.org/bootstrap/3.2.0/css/bootstrap.min.css' rel='stylesheet' >",
" <script src='http://static.jfaster.org/bootstrap/3.2.0/js/bootstrap.min.js' type='text/javascript' charset='utf-8'></script>",
" <link href='http://static.jfaster.org/bootstrap-table/1.8.1/bootstrap-table.min.css' rel='stylesheet' >",
"<script src='http://static.jfaster.org/bootstrap-table/1.8.1/bootstrap-table.min.js' type='text/javascript' charset='utf-8'></script>",
"</head>",
"",
"<body>",
"",
"<div id='custom-toolbar'>",
" <span style='font-size: 16px;margin-left: 10px;color:#666;'>",
" <span style='color:#000'>${beginTime}</span> 到",
" <span style='color:#000'>${endTime}</span>",
" </span>",
"</div>",
"",
"<table id='mango-stats-table'",
" data-toggle='table'",
" data-show-columns='true'",
" data-toolbar='#custom-toolbar'",
" data-sort-name='databaseExecuteCount'",
" data-sort-order='desc'",
" data-detail-view='true'",
" data-detail-formatter='detailFormatter'>",
" <thead>",
" <tr>",
" <th data-field='cacheable' data-sortable='true' data-switchable='false'>缓存</th>",
" <th data-field='simpleClassName' data-sortable='true' data-switchable='false'>类</th>",
" <th data-field='simpleMethodName' data-sortable='true' data-switchable='false'>方法</th>",
" <th data-field='averageDatabaseExecutePenalty' data-sortable='true' data-sorter='floatSorter' data-switchable='false'>db平均速率(毫秒)</th>",
" <th data-field='databaseExecuteCount' data-sortable='true' data-sorter='intSorter' data-switchable='false'>db总次数</th>",
" <th data-field='databaseExecuteExceptionCount' data-sortable='true' data-sorter='intSorter' data-switchable='false'>db失败次数</th>",
" <th data-field='databaseExecuteExceptionRate' data-sortable='true' data-sorter='rateSorter' data-switchable='false'>db失败率</th>",
" <th data-field='initCount' data-sortable='true' data-sorter='intSorter'>对象数</th>",
" <th data-field='hitCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache命中数</th>",
" <th data-field='missCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache丢失数</th>",
" <th data-field='hitRate' data-sortable='true' data-sorter='rateSorter' data-visible='false'>cache命中率</th>",
" <th data-field='averageCacheGetPenalty' data-sortable='true' data-sorter='floatSorter' data-visible='false'>cache[get]平均速率(毫秒)</th>",
" <th data-field='cacheGetCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[get]总次数</th>",
" <th data-field='cacheGetExceptionCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[get]失败次数</th>",
" <th data-field='cacheGetExceptionRate' data-sortable='true' data-sorter='rateSorter' data-visible='false'>cache[get]失败率</th>",
" <th data-field='averageCacheGetBulkPenalty' data-sortable='true' data-sorter='floatSorter' data-visible='false'>cache[getBulk]平均速率(毫秒)</th>",
" <th data-field='cacheGetBulkCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[getBulk]总次数</th>",
" <th data-field='cacheGetBulkExceptionCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[getBulk]失败次数</th>",
" <th data-field='cacheGetBulkExceptionRate' data-sortable='true' data-sorter='rateSorter' data-visible='false'>cache[getBulk]失败率</th>",
" <th data-field='averageCacheSetPenalty' data-sortable='true' data-sorter='floatSorter' data-visible='false'>cache[set]平均速率(毫秒)</th>",
" <th data-field='cacheSetCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[set]总次数</th>",
" <th data-field='cacheSetExceptionCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[set]失败次数</th>",
" <th data-field='cacheSetExceptionRate' data-sortable='true' data-sorter='rateSorter' data-visible='false'>cache[set]失败率</th>",
" <th data-field='averageCacheAddPenalty' data-sortable='true' data-sorter='floatSorter' data-visible='false'>cache[add]平均速率(毫秒)</th>",
" <th data-field='cacheAddCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[add]总次数</th>",
" <th data-field='cacheAddExceptionCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[add]失败次数</th>",
" <th data-field='cacheAddExceptionRate' data-sortable='true' data-sorter='rateSorter' data-visible='false'>cache[add]失败率</th>",
" <th data-field='averageCacheDeletePenalty' data-sortable='true' data-sorter='floatSorter' data-visible='false'>cache[delete]平均速率(毫秒)</th>",
" <th data-field='cacheDeleteCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[delete]总次数</th>",
" <th data-field='cacheDeleteExceptionCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[delete]失败次数</th>",
" <th data-field='cacheDeleteExceptionRate' data-sortable='true' data-sorter='rateSorter' data-visible='false'>cache[delete]失败率</th>",
" <th data-field='averageCacheBatchDeletePenalty' data-sortable='true' data-sorter='floatSorter' data-visible='false'>cache[batchDelete]平均速率(毫秒)</th>",
" <th data-field='cacheBatchDeleteCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[batchDelete]总次数</th>",
" <th data-field='cacheBatchDeleteExceptionCount' data-sortable='true' data-sorter='intSorter' data-visible='false'>cache[batchDelete]失败次数</th>",
" <th data-field='cacheBatchDeleteExceptionRate' data-sortable='true' data-sorter='rateSorter' data-visible='false'>cache[batchDelete]失败率</th>",
" <th data-field='sql' data-visible='false' data-switchable='false'>sql</th>",
" <th data-field='strParameterTypes' data-visible='false' data-switchable='false'>参数类型</th>",
" <th data-field='type' data-visible='false' data-switchable='false'>操作类型</th>",
" <th data-field='useMultipleKeys' data-visible='false' data-switchable='false'>缓存是否操作多个key</th>",
" <th data-field='cacheNullObject' data-visible='false' data-switchable='false'>是否缓存null对象</th>",
" </tr>",
" </thead>",
" <tbody>",
};
private final static String[] c2s = new String[] {
" </tbody>",
"</table>",
"",
"<script>",
" var $table = $('#mango-stats-table');",
" $table.on('expand-row.bs.table', function (e, index, row, $detail) {",
" });",
" function intSorter(s1, s2) {",
" var n1 = parseInt(s1);",
" var n2 = parseInt(s2);",
" if (n1 > n2) return 1;",
" if (n1 < n2) return -1;",
" return 0;",
" }",
" function floatSorter(s1, s2) {",
" var n1 = parseFloat(s1);",
" var n2 = parseFloat(s2);",
" if (n1 > n2) return 1;",
" if (n1 < n2) return -1;",
" return 0;",
" }",
" function rateSorter(s1, s2) {",
" s1 = s1.substring(0, s1.length - 1);",
" s2 = s2.substring(0, s2.length - 1);",
" var n1 = parseFloat(s1);",
" var n2 = parseFloat(s2);",
" if (n1 > n2) return 1;",
" if (n1 < n2) return -1;",
" return 0;",
" }",
" function detailFormatter(index, row) {",
" var html = [];",
" html.push('<p><b>SQL:</b> ' + row['sql'] + '</p>');",
" html.push('<p><b>参数类型:</b> ' + row['strParameterTypes'] + '</p>');",
" var isCacheable = row['cacheable'] == 'yes';",
" var isUseMultipleKeys = row['useMultipleKeys'] == 'yes';",
" var isCacheNullObject = row['cacheNullObject'] == 'yes';",
" var isQuery = row['type'] == 'query';",
" var isUpdate = row['type'] == 'update';",
" var isBatchUpdate = row['type'] == 'batchupdate';",
" if (isCacheable) {",
" html.push('<br>');",
" if (isQuery) {",
" html.push('<p><b>cache命中数:</b> ' + row['hitCount'] + '</p>');",
" html.push('<p><b>cache丢失数:</b> ' + row['missCount'] + '</p>');",
" html.push('<p><b>cache命中率:</b> ' + row['hitRate'] + '</p>');",
" html.push('<br>');",
" }",
" if (isQuery && !isUseMultipleKeys) {",
" html.push('<p><b>cache[get]平均速率(毫秒):</b> ' + row['averageCacheGetPenalty'] + '</p>');",
" html.push('<p><b>cache[get]总次数:</b> ' + row['cacheGetCount'] + '</p>');",
" html.push('<p><b>cache[get]失败次数:</b> ' + row['cacheGetExceptionCount'] + '</p>');",
" html.push('<p><b>cache[get]失败率:</b> ' + row['cacheGetExceptionRate'] + '</p>');",
" html.push('<br>');",
" }",
" if (isQuery && isUseMultipleKeys) {",
" html.push('<p><b>cache[getBulk]平均速率(毫秒):</b> ' + row['averageCacheGetBulkPenalty'] + '</p>');",
" html.push('<p><b>cache[getBulk]总次数:</b> ' + row['cacheGetBulkCount'] + '</p>');",
" html.push('<p><b>cache[getBulk]失败次数:</b> ' + row['cacheGetBulkExceptionCount'] + '</p>');",
" html.push('<p><b>cache[getBulk]失败率:</b> ' + row['cacheGetBulkExceptionRate'] + '</p>');",
" html.push('<br>');",
" }",
" if (isQuery) {",
" html.push('<p><b>cache[set]平均速率(毫秒):</b> ' + row['averageCacheSetPenalty'] + '</p>');",
" html.push('<p><b>cache[set]总次数:</b> ' + row['cacheSetCount'] + '</p>');",
" html.push('<p><b>cache[set]失败次数:</b> ' + row['cacheSetExceptionCount'] + '</p>');",
" html.push('<p><b>cache[set]失败率:</b> ' + row['cacheSetExceptionRate'] + '</p>');",
" html.push('<br>');",
" }",
" if (isQuery && isCacheNullObject) {",
" html.push('<p><b>cache[add]平均速率(毫秒):</b> ' + row['averageCacheAddPenalty'] + '</p>');",
" html.push('<p><b>cache[add]总次数:</b> ' + row['cacheAddCount'] + '</p>');",
" html.push('<p><b>cache[add]失败次数:</b> ' + row['cacheAddExceptionCount'] + '</p>');",
" html.push('<p><b>cache[add]失败率:</b> ' + row['cacheAddExceptionRate'] + '</p>');",
" html.push('<br>');",
" }",
" if (isUpdate && !isUseMultipleKeys) {",
" html.push('<p><b>cache[delete]平均速率(毫秒):</b> ' + row['averageCacheDeletePenalty'] + '</p>');",
" html.push('<p><b>cache[delete]总次数:</b> ' + row['cacheDeleteCount'] + '</p>');",
" html.push('<p><b>cache[delete]失败次数:</b> ' + row['cacheDeleteExceptionCount'] + '</p>');",
" html.push('<p><b>cache[delete]失败率:</b> ' + row['cacheDeleteExceptionRate'] + '</p>');",
" html.push('<br>');",
" }",
" if ((isUpdate && isUseMultipleKeys) || isBatchUpdate) {",
" html.push('<p><b>cache[batchDelete]平均速率(毫秒):</b> ' + row['averageCacheBatchDeletePenalty'] + '</p>');",
" html.push('<p><b>cache[batchDelete]总次数:</b> ' + row['cacheBatchDeleteCount'] + '</p>');",
" html.push('<p><b>cache[batchDelete]失败次数:</b> ' + row['cacheBatchDeleteExceptionCount'] + '</p>');",
" html.push('<p><b>cache[batchDelete]失败率:</b> ' + row['cacheBatchDeleteExceptionRate'] + '</p>');",
" html.push('<br>');",
" }",
" }",
" return html.join('');",
" }",
"</script>",
"</body>",
"</html>"
};
}