diff --git a/pom.xml b/pom.xml index 9cf18e9825..6e3a3a52c4 100644 --- a/pom.xml +++ b/pom.xml @@ -213,7 +213,7 @@ - + javax.servlet @@ -252,18 +252,18 @@ true - org.mybatis - mybatis - 3.1.1 - provided - true + org.mybatis + mybatis + 3.1.1 + provided + true - org.mybatis - mybatis-spring - 1.1.1 - provided - true + org.mybatis + mybatis-spring + 1.1.1 + provided + true @@ -321,6 +321,7 @@ 10.2.0.2 provided + com.microsoft.sqlserver sqljdbc4 diff --git a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java index 615097cdff..0e88e16577 100644 --- a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java +++ b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java @@ -81,6 +81,8 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean { // 3 seconds is slow sql protected long slowSqlMillis = 3 * 1000; + protected boolean logSlowSql = false; + private String dbType; private boolean mergeSql = false; @@ -182,6 +184,15 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean { } } } + + { + String property = properties.getProperty("druid.stat.logSlowSql"); + if ("true".equals(property)) { + this.logSlowSql = true; + } else if ("false".equals(property)) { + this.logSlowSql = false; + } + } } @Override @@ -507,6 +518,10 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean { } buf.append(']'); sqlStat.setLastSlowParameters(buf.toString()); + + if (logSlowSql) { + LOG.error("slow sql " + millis + " millis. \n" + statement.getLastExecuteSql() + "\n" + buf.toString()); + } } } } diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index 630dca4658..a05d04f77d 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -16,14 +16,18 @@ import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor; import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLExprParser; +import com.alibaba.druid.sql.parser.SQLParseException; import com.alibaba.druid.sql.parser.SQLParserUtils; import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.parser.Token; import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.util.JdbcUtils; public class SQLUtils { + private final static Log LOG = LogFactory.getLog(SQLUtils.class); public static String toSQLString(SQLObject sqlObject, String dbType) { if (JdbcUtils.MYSQL.equals(dbType)) { @@ -118,16 +122,22 @@ public class SQLUtils { } public static String format(String sql, String dbType) { - List statementList = toStatementList(sql, dbType); + try { + List statementList = toStatementList(sql, dbType); - StringBuilder out = new StringBuilder(); - SQLASTOutputVisitor visitor = createFormatOutputVisitor(out, statementList, dbType); + StringBuilder out = new StringBuilder(); + SQLASTOutputVisitor visitor = createFormatOutputVisitor(out, statementList, dbType); - for (SQLStatement stmt : statementList) { - stmt.accept(visitor); + for (SQLStatement stmt : statementList) { + stmt.accept(visitor); + } + + return out.toString(); + } catch (SQLParseException ex) { + LOG.warn("format error", ex); + + return sql; } - - return out.toString(); } public static SQLASTOutputVisitor createFormatOutputVisitor(Appendable out, List statementList, 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 90119e8075..df9fb7b460 100644 --- a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java +++ b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java @@ -4,23 +4,24 @@ import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.List; +import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.visitor.SchemaStatVisitor; import com.alibaba.druid.stat.DruidStatManagerFacade; -import com.alibaba.druid.stat.JdbcSqlStat; import com.alibaba.druid.support.JSONDruidStatService; import com.alibaba.druid.util.IOUtils; import com.alibaba.druid.util.StringUtils; /** + * 注意:避免直接调用Druid相关对象例如DruidDataSource等,相关调用要到DruidStatManagerFacade里用反射实现 + * * @author sandzhang */ public class StatViewServlet extends HttpServlet { @@ -37,7 +38,7 @@ public class StatViewServlet extends HttpServlet { private static JSONDruidStatService jsonDruidStatService = JSONDruidStatService.getInstance(); public String templatePage; - private static DateFormat format = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS"); + private static DateFormat format = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS"); public void init() throws ServletException { try { @@ -76,22 +77,19 @@ public class StatViewServlet extends HttpServlet { if (path.startsWith("/connectionInfo-") && path.endsWith(".html")) { Integer id = StringUtils.subStringToInteger(path, "connectionInfo-", "."); - DruidDataSource datasource = druidStatManager.getDruidDataSourceById(id); - returnViewConnectionInfo(datasource, request, response); + returnViewConnectionInfo(id, request, response); return; } if (path.startsWith("/activeConnectionStackTrace-") && path.endsWith(".html")) { Integer id = StringUtils.subStringToInteger(path, "activeConnectionStackTrace-", "."); - DruidDataSource datasource = druidStatManager.getDruidDataSourceById(id); - returnViewActiveConnectionStackTrace(datasource, request, response); + returnViewActiveConnectionStackTrace(id, request, response); return; } if (path.startsWith("/sql-") && path.endsWith(".html")) { Integer id = StringUtils.subStringToInteger(path, "sql-", "."); - JdbcSqlStat sqlStat = druidStatManager.getSqlStatById(id); - returnViewSqlStat(sqlStat, response); + returnViewSqlStat(druidStatManager.getSqlStatData(id), response); return; } @@ -99,63 +97,58 @@ public class StatViewServlet extends HttpServlet { returnResourceFile(path, response); } - private void returnViewActiveConnectionStackTrace(DruidDataSource datasource, HttpServletRequest request, + private void returnViewActiveConnectionStackTrace(Integer id, 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))); + text = text.replaceAll("\\{datasourceId\\}", id.toString()); response.getWriter().print(text); } - private void returnViewConnectionInfo(DruidDataSource datasource, HttpServletRequest request, - HttpServletResponse response) throws IOException { - if (datasource == null) return; - + private void returnViewConnectionInfo(Integer id, HttpServletRequest request, HttpServletResponse response) + throws IOException { String text = IOUtils.readFromResource(RESOURCE_PATH + "/connectionInfo.html"); - text = text.replaceAll("\\{datasourceId\\}", String.valueOf(System.identityHashCode(datasource))); + text = text.replaceAll("\\{datasourceId\\}", id.toString()); response.getWriter().print(text); } - private void returnViewSqlStat(JdbcSqlStat sqlStat, HttpServletResponse response) throws IOException { + private void returnViewSqlStat(Map sqlStat, HttpServletResponse response) throws IOException { if (sqlStat == null) return; StringBuilder content = new StringBuilder(); - content.append("

FULL SQL

" + sqlStat.getSql() + "

"); + content.append("

FULL SQL

" + sqlStat.get("SQL") + "

"); content.append("

Format View:

"); content.append("
"); content.append("

API:com.alibaba.druid.sql.SQLUtils.format(sql,DBType);

"); content.append("
"); - - if (sqlStat.getLastSlowParameters() != null && sqlStat.getLastSlowParameters().trim().length() > 0) { - content.append("

LastSlow SQL View:

"); - content.append(""); - content.append(""); - content.append(""); - content.append(""); - content.append(""); - content.append(""); - content.append(""); - content.append(""); - content.append(""); - content.append("
MaxTimespanOccurTime" + format.format(sqlStat.getExecuteNanoSpanMaxOccurTime()) + "
LastSlowParameters" + sqlStat.getLastSlowParameters() + "
"); - content.append("
"); - } - - List statementList = SQLUtils.parseStatements(sqlStat.getSql(), sqlStat.getDbType()); + + if (sqlStat.get("LastSlowParameters") != null + && sqlStat.get("LastSlowParameters").toString().trim().length() > 0) { + content.append("

LastSlow SQL View:

"); + content.append(""); + content.append(""); + content.append(""); + content.append(""); + content.append(""); + content.append(""); + content.append(""); + content.append(""); + content.append(""); + content.append("
SlowestSqlOccurTime" + format.format(sqlStat.get("MaxTimespanOccurTime")) + "
LastSlowParameters" + sqlStat.get("LastSlowParameters") + "
"); + content.append("
"); + } + + List statementList = SQLUtils.parseStatements((String) sqlStat.get("SQL"), + (String) sqlStat.get("DbType")); + if (!statementList.isEmpty()) { content.append("

Parse View:

"); SQLStatement statemen = statementList.get(0); - SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(statementList, sqlStat.getDbType()); + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(statementList, (String) sqlStat.get("DbType")); statemen.accept(visitor); content.append(""); content.append(""); diff --git a/test.html b/test.html deleted file mode 100644 index e69de29bb2..0000000000