implemention of console monitor tool

This commit is contained in:
shrek wang
2012-08-26 09:32:25 +08:00
parent cfeac1dc98
commit 239818d459
9 changed files with 536 additions and 62 deletions
@@ -15,6 +15,7 @@
*/
package com.alibaba.druid.stat;
import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.ArrayList;
@@ -172,6 +173,15 @@ public class DruidStatManagerFacade {
return datasourceList;
}
public List<List<String>> getActiveConnStackTraceList() {
List<List<String>> traceList = new ArrayList<List<String>>();
for (Object dataSource : getDruidDataSourceInstances()) {
List<String> stacks = ((DruidDataSource) dataSource).getActiveConnectionStackTrace();
traceList.add(stacks);
}
return traceList;
}
public Map<String, Object> returnJSONBasicStat() {
Map<String, Object> dataMap = new LinkedHashMap<String, Object>();
dataMap.put("Version", VERSION.getVersionNumber());
@@ -95,6 +95,10 @@ public class DruidStatService implements DruidStatServiceMBean {
return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.getDataSourceStatDataList());
}
if (url.equals("/activeConnectionStackTrace.json")) {
return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.getActiveConnStackTraceList());
}
if (url.startsWith("/datasource-")) {
Integer id = StringUtils.subStringToInteger(url, "datasource-", ".");
Object result = statManagerFacade.getDataSourceStatData(id);
@@ -39,83 +39,57 @@ public class DruidStat {
private static final String LOCAL_CONNECTOR_ADDRESS_PROP = "com.sun.management.jmxremote.localConnectorAddress";
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
if (args.length == 0) {
printHelp();
Option opt = null;
if (Option.isPrintHelp(args)) {
Option.printHelp();
return;
}
String option = args[0];
String url;
if (option.equals("-sql")) {
url = "/sql.json";
} else {
printHelp();
try {
opt = Option.parseOptions(args);
} catch (OptionParseException e) {
System.out.println(e.getMessage());
Option.printHelp();
return;
}
String arg = args[1];
int vmid = Integer.parseInt(arg);
String address = loadManagementAgentAndGetAddress(vmid);
printDruidStat(opt);
}
@SuppressWarnings("all")
public static void printDruidStat(Option option) throws Exception {
String address = loadManagementAgentAndGetAddress(option.getVmid());
JMXServiceURL jmxUrl = new JMXServiceURL(address);
JMXConnector jmxc = JMXConnectorFactory.connect(jmxUrl);
MBeanServerConnection jmxConn = jmxc.getMBeanServerConnection();
ObjectName name = new ObjectName(DruidStatService.MBEAN_NAME);
String result = (String) jmxConn.invoke(name, "service", new String[] { url },
new String[] { String.class.getName() });
Map<String, Object> o = (Map<String, Object>) JSONUtils.parse(result);
if (option.equals("-sql")) {
List<Map<String, Object>> content = (List<Map<String, Object>>) o.get("Content");
for (Map<String, Object> sqlStat : content) {
Number id = (Number) sqlStat.get("ID");
String sql = (String) sqlStat.get("SQL");
System.out.print(id);
System.out.print(" : ");
System.out.println();
System.out.println(sql);
System.out.println();
}
String[] fields = new String[] {"ID", "RunningCount", "ExecuteCount" };
for (int i = 0; i < fields.length; ++i) {
if (i != 0) {
System.out.print('\t');
}
System.out.print(fields[i]);
}
System.out.println();
for (Map<String, Object> sqlStat : content) {
for (int i = 0; i < fields.length; ++i) {
if (i != 0) {
System.out.print('\t');
}
Object value = sqlStat.get(fields[i]);
System.out.print(value);
}
System.out.println();
}
if (option.printSqlData()) {
List<Map<String, Object>> content = (List<Map<String, Object>>) invokeService(jmxConn, Option.SQL);
TabledDataPrinter.printSqlData(content, option);
}
//System.out.println(o);
// ... ...
if (option.printDataSourceData()) {
List<Map<String, Object>> content = (List<Map<String, Object>>) invokeService(jmxConn, Option.DATA_SOURCE);
TabledDataPrinter.printDataSourceData(content, option);
}
if (option.printActiveConn()) {
List<List<String>> content = (List<List<String>>) invokeService(jmxConn, Option.ACTIVE_CONN);
TabledDataPrinter.printActiveConnStack(content, option);
}
}
private static void printHelp() {
System.out.println("Usage: druidStat -help|-options");
System.out.println(" druidStat -<option> <vmid>");
System.out.println();
System.out.println("Definitions: druidStat -help|-options");
System.out.println(" <option> An option reported by the -options option");
@SuppressWarnings("all")
private static Object invokeService(MBeanServerConnection jmxConn, int dataType) throws Exception {
String url = Option.getUrl(dataType);
ObjectName name = new ObjectName(DruidStatService.MBEAN_NAME);
String result = (String) jmxConn.invoke(name, "service", new String[] { url }, new String[] { String.class.getName() });
Map<String, Object> o = (Map<String, Object>) JSONUtils.parse(result);
List<Map<String, Object>> content = (List<Map<String, Object>>) o.get("Content");
return content;
}
private static String loadManagementAgentAndGetAddress(int vmid) throws IOException {
@@ -0,0 +1,123 @@
package com.alibaba.druid.support.console;
public class Option {
public static enum PrintStyle {HORIZONTAL , VERTICAL };
public static final int DATA_SOURCE = 1 ;
public static final int SQL = 2 ;
public static final int ACTIVE_CONN = 4 ;
private PrintStyle style = PrintStyle.HORIZONTAL;
private int printDataType = 0;
private int vmid = -1;
public void addPrintDataType(int newValue) {
this.printDataType= this.printDataType | newValue;
}
public static boolean isPrintHelp(String[] args) {
if (args == null ) return true;
for (String arg: args) {
if (arg.equals("-h") || arg.equals("--help")) {
return true;
}
}
return false;
}
public boolean printSqlData() {
return ((printDataType & SQL) == SQL);
}
public boolean printDataSourceData() {
return ( (printDataType & DATA_SOURCE) == DATA_SOURCE);
}
public boolean printActiveConn() {
return ( (printDataType & ACTIVE_CONN) == ACTIVE_CONN);
}
public int getPrintDataType() {
return this.printDataType;
}
public void setStyle(PrintStyle style) {
this.style=style;
}
public PrintStyle getStyle() {
return this.style;
}
public void setVmid(int vmid) {
this.vmid=vmid;
}
public int getVmid() {
return this.vmid;
}
public static String getUrl(int dataType) {
switch (dataType) {
case SQL:
return "/sql.json";
case DATA_SOURCE:
return "/datasource.json";
case ACTIVE_CONN:
return "/activeConnectionStackTrace.json";
default:
return null;
}
}
public static Option parseOptions(String[] args) throws OptionParseException{
Option option = new Option();
int i = 0;
if (args.length < 1 ) {
throw new OptionParseException("not enough arguments!");
}
while (i < args.length) {
if ( i == args.length -1 ) {
if (args[i].startsWith("-")) throw new OptionParseException("please specify vmid in last arguments!");
try {
int vmid = Integer.parseInt(args[i]);
option.setVmid(vmid);
} catch (NumberFormatException e) {
throw new OptionParseException("vmid argument is not a integer!");
}
}
if (!args[i].startsWith("-")) {
i++;
continue;
}
if (args[i].equals("-sql")) {
option.addPrintDataType(SQL);
} else if (args[i].equals("-ds")) {
option.addPrintDataType(DATA_SOURCE);
} else if (args[i].equals("-act")) {
option.addPrintDataType(ACTIVE_CONN);
} else if (args[i].equals("-s1")) {
option.setStyle(PrintStyle.HORIZONTAL);
} else if (args[i].equals("-s2")) {
option.setStyle(PrintStyle.VERTICAL);
}
i++;
}
if (option.getPrintDataType() == 0) {
throw new OptionParseException("please specify one or more arguments in {'-sql','-ds','-act'}.");
}
return option;
}
public static void printHelp() {
System.out.println("Usage: druidStat -help | -sql -ds -act -s1 -s2 vmid");
System.out.println();
System.out.println("arguments: ");
System.out.println(" vmid the process id of jvm that running druid");
System.out.println(" -sql print sql stat data");
System.out.println(" -ds print datasource stat data");
System.out.println(" -act print active connection stacktrace data");
System.out.println(" -s1 print field name in first row");
System.out.println(" -s2 print field name in first column");
}
}
@@ -0,0 +1,17 @@
package com.alibaba.druid.support.console;
public class OptionParseException extends Exception {
public OptionParseException(String msg) {
super(msg);
}
public OptionParseException(String msg, Throwable cause) {
super(msg,cause);
}
public OptionParseException(Throwable cause) {
super(cause);
}
}
@@ -0,0 +1,76 @@
package com.alibaba.druid.support.console;
import java.util.ArrayList;
import java.util.List;
public class TableFormatter {
public static String format(List<String[]> rows) {
String[] titlerow = rows.get(0);
int[] maxLens = new int[titlerow.length];
for (int i=0; i<rows.size(); i++) {
String[] row = rows.get(i);
for (int j=0; j<row.length; j++) {
int len = displayLen(row[j]);
if ( len > maxLens[j]) {
maxLens[j] = len;
}
}
}
StringBuilder sb = new StringBuilder();
sb.append(makeSplitLine(maxLens));
for (int i=0; i<rows.size(); i++) {
String[] row = rows.get(i);
sb.append("|");
for (int j=0; j<row.length; j++) {
sb.append( padStr( row[j], maxLens[j]));
sb.append(" |");
}
sb.append("\n");
//title row
if (i==0) {
sb.append(makeSplitLine(maxLens));
}
}
sb.append(makeSplitLine(maxLens));
return sb.toString();
}
public static String makeSplitLine(int[] maxLens) {
StringBuilder sb = new StringBuilder("+");
for (int len : maxLens) {
for (int i=0; i<len; i++) {
sb.append("-");
}
sb.append("-+");
}
sb.append("\n");
return sb.toString();
}
public static int displayLen(String value) {
return value.length();
}
public static String padStr(String old, int length) {
if (old == null ) return "";
int vlen = displayLen(old);
if (vlen > length) return old;
StringBuffer sb = new StringBuffer(old);
for (int i=0; i< length -vlen ; i++) {
sb.append(" ");
}
return sb.toString();
}
public static void main(String[] args) {
List<String[]> v = new ArrayList<String[]>();
v.add(new String[]{"name","age","addr"});
v.add(new String[]{"shrek", "200", "hangzhou zhejiang "});
v.add(new String[]{"what as", "11", "asdfa"});
String formattedStr = format(v);
System.out.println(formattedStr);
}
}
@@ -0,0 +1,108 @@
package com.alibaba.druid.support.console;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class TabledDataPrinter {
private static final int SQL_MAX_LEN = 32;
private static final String[] sqlFields = new String[] {
"ID", "DataSource", "SQL", "ExecuteCount", "ErrorCount",
"TotalTime", "LastTime", "MaxTimespan", "LastError", "EffectedRowCount",
"FetchRowCount", "MaxTimespanOccurTime", "BatchSizeMax", "BatchSizeTotal", "ConcurrentMax",
"RunningCount", "Name", "File",
"LastErrorMessage", "LastErrorClass", "LastErrorStackTrace", "LastErrorTime",
"DbType", "URL", "InTransactionCount",
"Histogram", "LastSlowParameters", "ResultSetHoldTime", "ExecuteAndResultSetHoldTime", "FetchRowCountHistogram",
"EffectedRowCountHistogram", "ExecuteAndResultHoldTimeHistogram", "EffectedRowCountMax", "FetchRowCountMax", "ClobOpenCount" };
private static final String[] dsFields = new String[] {
"Identity", "Name", "DbType", "DriverClassName", "URL", "UserName", "FilterClassNames",
"WaitThreadCount", "NotEmptyWaitCount", "NotEmptyWaitMillis",
"PoolingCount", "PoolingPeak", "PoolingPeakTime",
"ActiveCount", "ActivePeak", "ActivePeakTime",
"InitialSize", "MinIdle", "MaxActive",
"QueryTimeout", "TransactionQueryTimeout", "LoginTimeout", "ValidConnectionCheckerClassName", "ExceptionSorterClassName",
"TestOnBorrow", "TestOnReturn", "TestWhileIdle",
"DefaultAutoCommit", "DefaultReadOnly", "DefaultTransactionIsolation",
"LogicConnectCount", "LogicCloseCount", "LogicConnectErrorCount",
"PhysicalConnectCount", "PhysicalCloseCount", "PhysicalConnectErrorCount",
"ExecuteCount", "ErrorCount", "CommitCount", "RollbackCount",
"PSCacheAccessCount", "PSCacheHitCount", "PSCacheMissCount",
"StartTransactionCount", "TransactionHistogram",
"ConnectionHoldTimeHistogram", "RemoveAbandoned", "ClobOpenCount" };
public static void printActiveConnStack(List<List<String >> content,Option opt) {
for (List<String> stack : content) {
for (String line : stack) {
System.out.println(line);
}
System.out.println("===============================\n");
}
}
public static void printDataSourceData(List<Map<String, Object>> content,Option opt) {
if (opt.getStyle() == Option.PrintStyle.HORIZONTAL) {
System.out.println(getFormattedOutput(content, dsFields));
} else {
System.out.println(getVerticalFormattedOutput(content, dsFields));
}
}
public static void printSqlData(List<Map<String, Object>> content, Option opt) {
if (opt.getStyle() == Option.PrintStyle.HORIZONTAL) {
System.out.println(getFormattedOutput(content, sqlFields));
} else {
System.out.println(getVerticalFormattedOutput(content, sqlFields));
}
}
public static String getFormattedOutput(List<Map<String, Object>> content, String[] titleFields) {
List<String[]> printContents = new ArrayList<String[]>();
printContents.add(titleFields);
for (Map<String, Object> sqlStat : content) {
String[] row = new String[titleFields.length];
for (int i = 0; i < titleFields.length; ++i) {
Object value = sqlStat.get(titleFields[i]);
row[i] = handleAndConvert(value,titleFields[i]);
}
printContents.add(row);
}
String formattedStr = TableFormatter.format(printContents);
return formattedStr;
}
public static String getVerticalFormattedOutput(List<Map<String, Object>> content, String[] titleFields) {
List<String[]> printContents = new ArrayList<String[]>();
for (int i = 0; i < titleFields.length; ++i) {
String[] row = new String[content.size()+1];
row[0] = titleFields[i];
for (int j=0; j<content.size(); j++) {
Map<String,Object> sqlStat = content.get(j);
Object value = sqlStat.get(titleFields[i]);
row[j+1] = handleAndConvert(value, titleFields[i]);
}
printContents.add(row);
}
String formattedStr = TableFormatter.format(printContents);
return formattedStr;
}
public static String handleAndConvert(Object value, String fieldName) {
if (value == null) value = "";
if (fieldName.equals("SQL")) {
String sql = (String)value;
if (sql.length() > SQL_MAX_LEN) {
sql = sql.substring(0,SQL_MAX_LEN-3) + "...";
}
value = sql;
}
return value.toString();
}
}
@@ -0,0 +1,99 @@
package com.alibaba.druid.console;
import java.sql.Connection;
import java.sql.Statement;
import com.alibaba.druid.support.console.Option;
import org.junit.runner.notification.Failure;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import com.alibaba.druid.support.console.DruidStat;
import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.druid.pool.DruidDataSource;
import java.lang.management.ManagementFactory;
import junit.framework.TestCase;
public class DruidStatTest extends TestCase {
private DruidDataSource dataSource;
private DruidDataSource dataSource2;
private static String getSelfPid() {
String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
return pid;
}
protected void setUp() throws Exception {
dataSource = new DruidDataSource();
dataSource.setMinIdle(1);
dataSource.setUrl("jdbc:h2:mem:test;");
dataSource.setTestOnBorrow(false);
dataSource.setFilters("stat");
dataSource.setRemoveAbandoned(true);
dataSource.setRemoveAbandonedTimeout(600);
JdbcUtils.execute(dataSource, "CREATE TABLE user (id INT, name VARCHAR(40))");
JdbcUtils.execute(dataSource, "insert into user values(20,'name1')");
JdbcUtils.execute(dataSource, "insert into user values(30,'name2')");
dataSource2 = new DruidDataSource();
dataSource2.setMinIdle(1);
dataSource2.setUrl("jdbc:h2:mem:test2;");
dataSource2.setTestOnBorrow(false);
dataSource2.setFilters("stat");
dataSource2.setRemoveAbandoned(true);
dataSource2.setRemoveAbandonedTimeout(600);
JdbcUtils.execute(dataSource2, "CREATE TABLE user (id INT, name VARCHAR(40))");
JdbcUtils.execute(dataSource2, "insert into user values(20,'name1')");
}
protected void tearDown() throws Exception {
JdbcUtils.execute(dataSource, "DROP TABLE user");
JdbcUtils.close(dataSource);
JdbcUtils.execute(dataSource2, "DROP TABLE user");
JdbcUtils.close(dataSource2);
}
public void test_printDruidStat() throws Exception {
String pid = getSelfPid();
String[] cmdArray = {"-sql", pid};
Option opt = Option.parseOptions(cmdArray);
DruidStat.printDruidStat(opt);
}
public void test_printDruidStat2() throws Exception {
String pid = getSelfPid();
String[] cmdArray = {"-ds","-s2", pid};
Option opt = Option.parseOptions(cmdArray);
DruidStat.printDruidStat(opt);
}
public void test_printDruidStat3() throws Exception {
String pid = getSelfPid();
String[] cmdArray = {"-act", pid};
Option opt = Option.parseOptions(cmdArray);
Connection conn = null;
Statement stmt = null;
try {
conn = dataSource.getConnection();
stmt = conn.createStatement();
stmt.execute("insert into user values(30,'name2')");
DruidStat.printDruidStat(opt);
} finally {
if (stmt != null ) try { stmt.close(); } catch (Exception e) {}
if (conn != null ) try { conn.close(); } catch (Exception e) {}
}
}
public static void main(String[] args) {
Result result = JUnitCore.runClasses(DruidStatTest.class);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
}
}
@@ -0,0 +1,63 @@
package com.alibaba.druid.console;
import com.alibaba.druid.support.console.OptionParseException;
import com.alibaba.druid.support.console.Option;
import junit.framework.TestCase;
import junit.framework.Assert;
public class OptionTest extends TestCase {
public void test_parseOptions() throws Exception {
String[] cmdArray = {"-sql","-ds", "200"};
Option opt = Option.parseOptions(cmdArray);
Assert.assertNotNull(opt);
Assert.assertTrue(opt.printSqlData());
Assert.assertTrue(opt.printDataSourceData());
Assert.assertFalse(opt.printActiveConn());
Assert.assertEquals(opt.getVmid(), 200);
cmdArray = new String[] {"-act", "738"};
opt = Option.parseOptions(cmdArray);
Assert.assertNotNull(opt);
Assert.assertFalse(opt.printSqlData());
Assert.assertFalse(opt.printDataSourceData());
Assert.assertTrue(opt.printActiveConn());
Assert.assertEquals(opt.getStyle(), Option.PrintStyle.HORIZONTAL);
Assert.assertEquals(opt.getVmid(), 738);
cmdArray = new String[] {"-ds", "-s2", "1319"};
opt = Option.parseOptions(cmdArray);
Assert.assertNotNull(opt);
Assert.assertFalse(opt.printSqlData());
Assert.assertTrue(opt.printDataSourceData());
Assert.assertFalse(opt.printActiveConn());
Assert.assertEquals(opt.getStyle(), Option.PrintStyle.VERTICAL);
Assert.assertEquals(opt.getVmid(), 1319);
//not enough arguments
cmdArray = new String[] {};
try {
opt = Option.parseOptions(cmdArray);
} catch (OptionParseException e) {
System.out.println(e.getMessage());
Assert.assertNotNull(e);
}
//need vmid
cmdArray = new String[] {"-ds"};
try {
opt = Option.parseOptions(cmdArray);
} catch (Exception e) {
System.out.println(e.getMessage());
Assert.assertNotNull(e);
}
}
public void test_printHelp() throws Exception {
Option.printHelp();
}
}