StatViewServlet:add sql view page; fix JdbcSqlStat for id init.

This commit is contained in:
sand
2012-07-21 23:38:30 +08:00
parent f9be1c795d
commit 6cb0395f08
9 changed files with 236 additions and 154 deletions
@@ -1,17 +1,10 @@
/*
* Copyright 1999-2011 Alibaba Group Holding Ltd.
*
* Licensed 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.
* Copyright 1999-2011 Alibaba Group Holding Ltd. Licensed 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 com.alibaba.druid.proxy;
@@ -55,6 +48,7 @@ public class DruidDriver implements Driver, DruidDriverMBean {
private final static ConcurrentMap<String, DataSourceProxyImpl> proxyDataSources = new ConcurrentHashMap<String, DataSourceProxyImpl>();
private final static AtomicInteger dataSourceIdSeed = new AtomicInteger(0);
private final static AtomicInteger sqlStatIdSeed = new AtomicInteger(0);
public final static String DEFAULT_PREFIX = "jdbc:wrap-jdbc:";
public final static String DRIVER_PREFIX = "driver=";
@@ -100,7 +94,7 @@ public class DruidDriver implements Driver, DruidDriverMBean {
return false;
}
public DruidDriver(){
public DruidDriver() {
}
@@ -112,6 +106,10 @@ public class DruidDriver implements Driver, DruidDriverMBean {
return dataSourceIdSeed.incrementAndGet();
}
public static int createSqlStatId() {
return sqlStatIdSeed.incrementAndGet();
}
@Override
public boolean acceptsURL(String url) throws SQLException {
if (url == null) {
@@ -1,17 +1,10 @@
/*
* Copyright 1999-2011 Alibaba Group Holding Ltd.
*
* Licensed 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.
* Copyright 1999-2011 Alibaba Group Holding Ltd. Licensed 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 com.alibaba.druid.stat;
@@ -27,6 +20,7 @@ import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
import com.alibaba.druid.proxy.DruidDriver;
import com.alibaba.druid.proxy.jdbc.StatementExecuteType;
import com.alibaba.druid.util.Histogram;
import com.alibaba.druid.util.IOUtils;
@@ -42,63 +36,57 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
private String dataSource;
private long executeLastStartTime;
private final AtomicLong executeBatchSizeTotal = new AtomicLong();
private final AtomicLong executeBatchSizeMax = new AtomicLong();
private final AtomicLong executeBatchSizeTotal = new AtomicLong();
private final AtomicLong executeBatchSizeMax = new AtomicLong();
private final AtomicLong executeSuccessCount = new AtomicLong();
private final AtomicLong executeSpanNanoTotal = new AtomicLong();
private final AtomicLong executeSpanNanoMax = new AtomicLong();
private final AtomicLong runningCount = new AtomicLong(0L);
private final AtomicLong concurrentMax = new AtomicLong();
private final AtomicLong resultSetHoldTimeNano = new AtomicLong();
private final AtomicLong executeAndResultSetHoldTime = new AtomicLong();
private final AtomicLong executeSuccessCount = new AtomicLong();
private final AtomicLong executeSpanNanoTotal = new AtomicLong();
private final AtomicLong executeSpanNanoMax = new AtomicLong();
private final AtomicLong runningCount = new AtomicLong(0L);
private final AtomicLong concurrentMax = new AtomicLong();
private final AtomicLong resultSetHoldTimeNano = new AtomicLong();
private final AtomicLong executeAndResultSetHoldTime = new AtomicLong();
private String name;
private String file;
private String dbType;
private long executeNanoSpanMaxOccurTime;
private final AtomicLong executeErrorCount = new AtomicLong();
private final AtomicLong executeErrorCount = new AtomicLong();
private Throwable executeErrorLast;
private long executeErrorLastTime;
private final AtomicLong updateCount = new AtomicLong();
private final AtomicLong fetchRowCount = new AtomicLong();
private final AtomicLong updateCount = new AtomicLong();
private final AtomicLong fetchRowCount = new AtomicLong();
private final AtomicLong inTransactionCount = new AtomicLong();
private final AtomicLong inTransactionCount = new AtomicLong();
private String lastSlowParameters;
private final Histogram histogram = new Histogram(new long[] { //
//
private final Histogram histogram = new Histogram(new long[] { //
//
1, 10, 100, 1000, 10 * 1000, //
100 * 1000, 1000 * 1000
//
});
private final Histogram executeAndResultHoldTimeHistogram = new Histogram(new long[] { //
//
1, 10, 100, 1000, 10 * 1000, //
100 * 1000, 1000 * 1000
//
});
//
});
private final Histogram fetchRowCountHistogram = new Histogram(new long[] { //
1, 10, 100, 1000, 10 * 1000
});
private final Histogram executeAndResultHoldTimeHistogram = new Histogram(new long[] { //
//
1, 10, 100, 1000, 10 * 1000, //
100 * 1000, 1000 * 1000
//
});
private final Histogram updateCountHistogram = new Histogram(new long[] { //
1, 10, 100, 1000, 10 * 1000
});
public JdbcSqlStat(String sql){
private final Histogram fetchRowCountHistogram = new Histogram(new long[] { //
1, 10, 100, 1000, 10 * 1000 });
private final Histogram updateCountHistogram = new Histogram(new long[] { //
1, 10, 100, 1000, 10 * 1000 });
public JdbcSqlStat(String sql) {
this.sql = sql;
this.id = DruidDriver.createSqlStatId();
}
public String getLastSlowParameters() {
@@ -164,7 +152,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
context.setFile(val);
}
public final static void setContextSql(String val) {
JdbcStatContext context = JdbcStatManager.getInstance().getStatContext();
if (context == null) {
@@ -233,10 +221,10 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
if (delta > 0) {
this.updateCount.addAndGet(delta);
}
this.updateCountHistogram.record(delta);
this.fetchRowCountHistogram.record(0);
}
public long getUpdateCount() {
@@ -288,7 +276,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
public void addFetchRowCount(long delta) {
this.fetchRowCount.addAndGet(delta);
this.fetchRowCountHistogram.record(delta);
}
public void addExecuteBatchCount(long batchSize) {
@@ -333,7 +321,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
}
}
}
public void decrementRunningCount() {
runningCount.decrementAndGet();
}
@@ -345,12 +333,12 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
public long getExecuteSuccessCount() {
return executeSuccessCount.get();
}
public void addExecuteTime(StatementExecuteType executeType, long nanoSpan) {
if (StatementExecuteType.ExecuteQuery != executeType) {
executeAndResultHoldTimeHistogram.record((nanoSpan)/1000/1000);
}
addExecuteTime(nanoSpan);
if (StatementExecuteType.ExecuteQuery != executeType) {
executeAndResultHoldTimeHistogram.record((nanoSpan) / 1000 / 1000);
}
addExecuteTime(nanoSpan);
}
public void addExecuteTime(long nanoSpan) {
@@ -454,12 +442,12 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
SimpleType.LONG, //
SimpleType.LONG, //
new ArrayType<Long>(SimpleType.LONG, true), //
// 30 -
// 30 -
new ArrayType<Long>(SimpleType.LONG, true), //
new ArrayType<Long>(SimpleType.LONG, true), //
};
String[] indexNames = {
@@ -500,17 +488,11 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
// 25 - 29
"Histogram", //
"LastSlowParameters",
"ResultSetHoldTime",
"ExecuteAndResultSetHoldTime",
"FetchRowCountHistogram",
"LastSlowParameters", "ResultSetHoldTime", "ExecuteAndResultSetHoldTime", "FetchRowCountHistogram",
// 30
"EffectedRowCountHistogram",
"ExecuteAndResultHoldTimeHistogram"
"EffectedRowCountHistogram", "ExecuteAndResultHoldTimeHistogram"
//
};
String[] indexDescriptions = indexNames;
@@ -575,15 +557,13 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
map.put("ResultSetHoldTime", getResultSetHoldTimeMilis()); // 27
map.put("ExecuteAndResultSetHoldTime", this.getExecuteAndResultSetHoldTimeMilis()); // 28
map.put("FetchRowCountHistogram", this.getFetchRowCountHistogram().toArray()); // 29
map.put("EffectedRowCountHistogram", this.getUpdateCountHistogram().toArray()); // 30
map.put("ExecuteAndResultHoldTimeHistogram", this.getExecuteAndResultHoldTimeHistogram().toArray()); // 30
return map;
}
public Histogram getHistogram() {
return this.histogram;
}
@@ -606,25 +586,23 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
public long getResultSetHoldTimeMilis() {
return getResultSetHoldTimeNano() / (1000 * 1000);
}
public long getExecuteAndResultSetHoldTimeMilis() {
return getExecuteAndResultSetHoldTimeNano() / (1000 * 1000);
}
public Histogram getFetchRowCountHistogram() {
return this.fetchRowCountHistogram;
}
public Histogram getUpdateCountHistogram() {
return this.updateCountHistogram;
}
public Histogram getExecuteAndResultHoldTimeHistogram() {
return this.executeAndResultHoldTimeHistogram;
}
public long getResultSetHoldTimeNano() {
return resultSetHoldTimeNano.get();
}
@@ -632,15 +610,15 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
public long getExecuteAndResultSetHoldTimeNano() {
return executeAndResultSetHoldTime.get();
}
public void addResultSetHoldTimeNano(long nano) {
resultSetHoldTimeNano.addAndGet(nano);
}
public void addResultSetHoldTimeNano(long statementExecuteNano, long resultHoldTimeNano) {
resultSetHoldTimeNano.addAndGet(resultHoldTimeNano);
executeAndResultSetHoldTime.addAndGet(statementExecuteNano+resultHoldTimeNano);
executeAndResultHoldTimeHistogram.record((statementExecuteNano+resultHoldTimeNano)/1000/1000);
updateCountHistogram.record(0);
resultSetHoldTimeNano.addAndGet(resultHoldTimeNano);
executeAndResultSetHoldTime.addAndGet(statementExecuteNano + resultHoldTimeNano);
executeAndResultHoldTimeHistogram.record((statementExecuteNano + resultHoldTimeNano) / 1000 / 1000);
updateCountHistogram.record(0);
}
}
@@ -1,7 +1,6 @@
package com.alibaba.druid.support.http;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Driver;
import java.sql.DriverManager;
@@ -18,32 +17,50 @@ import javax.servlet.http.HttpServletResponse;
import com.alibaba.druid.VERSION;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.stat.DruidDataSourceStatManager;
import com.alibaba.druid.stat.JdbcSqlStat;
import com.alibaba.druid.stat.JdbcStatManager;
import com.alibaba.druid.util.IOUtils;
import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
/**
* @author sandzhang<sandzhangtoo@gmail.com>
*/
public class StatServlet extends HttpServlet {
public class StatViewSerlvet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
private final static int RESULT_CODE_SUCCESS = 1;
private final static int RESULT_CODE_ERROR = -1;
private final static int RESULT_CODE_SUCCESS = 1;
private final static int RESULT_CODE_ERROR = -1;
private final static String RESOURCE_PATH = "support/http/resources";
private final static String TEMPLATE_PAGE_RESOURCE_PATH = RESOURCE_PATH + "/template.html";
public String templatePage;
public void init() throws ServletException {
try {
templatePage = IOUtils.readFromResource(TEMPLATE_PAGE_RESOURCE_PATH);
} catch (IOException e) {
throw new ServletException("error read templatePage:" + TEMPLATE_PAGE_RESOURCE_PATH, e);
}
}
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String contextPath = request.getContextPath();
String servletPath = request.getServletPath();
String requestURI = request.getRequestURI();
response.setCharacterEncoding("utf-8");
if (contextPath == null) { // root context
contextPath = "";
}
@@ -59,7 +76,7 @@ public class StatServlet extends HttpServlet {
returnJSONBasicStat(request, response);
return;
}
if (path.equals("/reset-all.json")) {
resetAllStat();
returnJSONResult(request, response, RESULT_CODE_SUCCESS, null);
@@ -70,7 +87,7 @@ public class StatServlet extends HttpServlet {
returnJSONResult(request, response, RESULT_CODE_SUCCESS, getJSONDataSourceStatList());
return;
}
if (path.startsWith("/datasource-")) {
Integer id = StringUtils.subStringToInteger(path, "datasource-", ".");
Object result = getJSONDataSourceStat(id);
@@ -82,11 +99,20 @@ public class StatServlet extends HttpServlet {
returnJSONResult(request, response, RESULT_CODE_SUCCESS, getJSONSqlStat());
return;
}
if (path.startsWith("/sql-")) {
Integer id = StringUtils.subStringToInteger(path, "sql-", ".");
Object result = getJSONSqlStat(id);
returnJSONResult(request, response, result == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, result);
if (path.endsWith(".json")) {
Object result = getJSONSqlStat(id);
returnJSONResult(request, response, result == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, result);
return;
}
if (path.endsWith(".html")) {
JdbcSqlStat sqlStat = getSqlStatById(id);
returnViewSqlStat(sqlStat, response);
return;
}
return;
}
@@ -94,6 +120,67 @@ public class StatServlet extends HttpServlet {
returnResourceFile(path, response);
}
private void returnViewSqlStat(JdbcSqlStat sqlStat, HttpServletResponse response) throws IOException {
if (sqlStat == null) return;
StringBuilder content = new StringBuilder();
content.append("<h2>FULL SQL</br></h2> <h4>" + sqlStat.getSql() + "</h4>");
content.append("<h2>Format View:</h2>");
content.append("<textarea style='width:99%;height:120px;;border:1px #A8C7CE solid;line-height:20px;font-size:12px;'>");
content.append(SQLUtils.format(sqlStat.getSql(), sqlStat.getDbType()));
content.append("</textarea><br>");
content.append("<p>API:com.alibaba.druid.sql.SQLUtils.format(sql,DBType);</p>");
content.append("<br>");
SQLStatementParser parser = new SQLStatementParser(sqlStat.getSql());
List<SQLStatement> statementList = parser.parseStatementList();
if (!statementList.isEmpty()) {
content.append("<h2>Parse View:</h2>");
SQLStatement statemen = statementList.get(0);
SchemaStatVisitor visitor = new SchemaStatVisitor();
statemen.accept(visitor);
content.append("<table cellpadding='5' cellspacing='1' width='99%'>");
content.append("<tr>");
content.append("<td class='td_lable' width='130'>Tables</td>");
content.append("<td>" + visitor.getTables() + "</td>");
content.append("</tr>");
content.append("<tr>");
content.append("<td class='td_lable'>Fields</td>");
content.append("<td>" + visitor.getColumns() + "</td>");
content.append("</tr>");
content.append("<tr>");
content.append("<td class='td_lable'>Coditions</td>");
content.append("<td>" + visitor.getConditions() + "</td>");
content.append("</tr>");
content.append("<tr>");
content.append("<td class='td_lable'>Relationships</td>");
content.append("<td>" + visitor.getRelationships() + "</td>");
content.append("</tr>");
content.append("</table>");
content.append("<br>");
content.append("<p>API:</p>");
content.append("<p>");
content.append("SQLStatementParser parser = new SQLStatementParser(sqlStat.getSql());</br>");
content.append("List<SQLStatement> statementList = parser.parseStatementList();</br>");
content.append("SQLStatement statemen = statementList.get(0);</br>");
content.append("SchemaStatVisitor visitor = new SchemaStatVisitor();</br>");
content.append("SchemaStatVisitor visitor = new SchemaStatVisitor();</br>");
content.append("statemen.accept(visitor);</br>");
content.append("visitor.getTables() / visitor.getColumns() / visitor.getConditions() / visitor.getRelationships()</br>");
content.append("</p>");
content.append("<br>");
}
response.getWriter().print(mergeTemplatePage("Druid Sql View", content.toString()));
}
private void resetAllStat() {
JdbcStatManager.getInstance().reset();
DruidDataSourceStatManager.getInstance().reset();
@@ -174,6 +261,7 @@ public class StatServlet extends HttpServlet {
private Map<String, Object> toJSONSqlStat(JdbcSqlStat sqlStat) {
Map<String, Object> json = new LinkedHashMap<String, Object>();
json.put("ID", sqlStat.getId());
json.put("SQL", sqlStat.getSql());
json.put("File", sqlStat.getFile());
json.put("Name", sqlStat.getName());
@@ -241,19 +329,11 @@ public class StatServlet extends HttpServlet {
}
private void returnResourceFile(String fileName, HttpServletResponse response) throws ServletException, IOException {
InputStream in = null;
try {
in = Thread.currentThread().getContextClassLoader().getResourceAsStream("support/http/resources" + fileName);
if (in == null) {
return;
}
String text = IOUtils.readFromResource(RESOURCE_PATH + fileName);
response.getWriter().write(text);
}
String text = IOUtils.read(in);
response.getWriter().write(text);
} catch (IOException e) {
throw new ServletException("error when response static file: " + fileName, e);
} finally {
JdbcUtils.close(in);
}
private String mergeTemplatePage(String title, String content) {
return templatePage.replaceAll("\\{title\\}", title).replaceAll("\\{content\\}", content);
}
}