diff --git a/src/main/java/com/alibaba/druid/support/console/DruidStat.java b/src/main/java/com/alibaba/druid/support/console/DruidStat.java index 73f207764d..293409f7c9 100644 --- a/src/main/java/com/alibaba/druid/support/console/DruidStat.java +++ b/src/main/java/com/alibaba/druid/support/console/DruidStat.java @@ -15,6 +15,7 @@ */ package com.alibaba.druid.support.console; +import java.util.ArrayList; import java.io.File; import java.io.IOException; import java.util.List; @@ -61,20 +62,21 @@ public class DruidStat { @SuppressWarnings("all") public static void printDruidStat(Option option) throws Exception { - String address = loadManagementAgentAndGetAddress(option.getVmid()); + String address = loadManagementAgentAndGetAddress(option.getPid()); JMXServiceURL jmxUrl = new JMXServiceURL(address); JMXConnector jmxc = JMXConnectorFactory.connect(jmxUrl); MBeanServerConnection jmxConn = jmxc.getMBeanServerConnection(); - - if (option.printSqlData()) { - List> content = (List>) invokeService(jmxConn, Option.SQL); - TabledDataPrinter.printSqlData(content, option); - } if (option.printDataSourceData()) { List> content = (List>) invokeService(jmxConn, Option.DATA_SOURCE); TabledDataPrinter.printDataSourceData(content, option); } + + if (option.printSqlData()) { + List> content = (List>) invokeService(jmxConn, Option.SQL); + TabledDataPrinter.printSqlData(content, option); + } + if (option.printActiveConn()) { List> content = (List>) invokeService(jmxConn, Option.ACTIVE_CONN); TabledDataPrinter.printActiveConnStack(content, option); @@ -83,7 +85,24 @@ public class DruidStat { } @SuppressWarnings("all") - private static Object invokeService(MBeanServerConnection jmxConn, int dataType) throws Exception { + public static List getDataSourceIds(Option option) throws Exception{ + String address = loadManagementAgentAndGetAddress(option.getPid()); + JMXServiceURL jmxUrl = new JMXServiceURL(address); + JMXConnector jmxc = JMXConnectorFactory.connect(jmxUrl); + MBeanServerConnection jmxConn = jmxc.getMBeanServerConnection(); + List> content = (List>) invokeService(jmxConn, Option.DATA_SOURCE); + TabledDataPrinter.printDataSourceData(content, option); + + List result = new ArrayList(); + for (Map dsStat : content) { + Integer id = (Integer)dsStat.get("Identity"); + result.add(id); + } + return result; + } + + @SuppressWarnings("all") + public 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() }); diff --git a/src/main/java/com/alibaba/druid/support/console/Option.java b/src/main/java/com/alibaba/druid/support/console/Option.java index bf59ef4e54..ab7a9600b6 100644 --- a/src/main/java/com/alibaba/druid/support/console/Option.java +++ b/src/main/java/com/alibaba/druid/support/console/Option.java @@ -17,15 +17,15 @@ 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; + private int pid = -1; private int id = -1; + private int interval = -1; + private boolean detailPrint; public void addPrintDataType(int newValue) { this.printDataType= this.printDataType | newValue; @@ -55,18 +55,12 @@ public class Option { 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 void setPid(int pid) { + this.pid=pid; } - public int getVmid() { - return this.vmid; + public int getPid() { + return this.pid; } public static String getUrl(int dataType) { @@ -82,6 +76,15 @@ public class Option { } } + private static int parsePositiveInt(String v) { + try { + int pid = Integer.parseInt(v); + return pid; + } catch (NumberFormatException e) { + return -1; + } + } + public static Option parseOptions(String[] args) throws OptionParseException{ Option option = new Option(); int i = 0; @@ -90,57 +93,71 @@ public class Option { } 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; - } + int v1 = parsePositiveInt(args[i]); + + //check last two arguments + if ( (i == args.length - 2) && v1 > 0) { + int v2 = parsePositiveInt(args[i+1]); + if ( v2 > 0) { + option.setPid(v1); + option.setInterval(v2); + } else { + throw new OptionParseException("请在参数的最后位置上 指定 pid 和 refresh-interval"); + } + break; + } else if ( i == args.length -1 ) { + option.setPid(v1); + } + 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); + } else if (args[i].equals("-detail")) { + option.setDetailPrint(true); } else if (args[i].equals("-id")) { try { int id = Integer.parseInt(args[i+1]); option.setId(id); + i++; } catch (NumberFormatException e) { - throw new OptionParseException("vmid argument is not a integer!"); + throw new OptionParseException("id参数必须是整数"); } } i++; } + if (option.getPrintDataType() == 0) { - throw new OptionParseException("please specify one or more arguments in {'-sql','-ds','-act'}."); + throw new OptionParseException("请在{'-sql','-ds','-act'}参数中选择一个或多个"); + } + if (option.getPid() == -1 ) { + throw new OptionParseException("请在参数中指定 pid"); } return option; } public static void printHelp() { - System.out.println("Usage: druidStat -help | -sql -ds -act -s1 -s2 -id vmid"); + System.out.println("Usage: druidStat -help | -sql -ds -act [-detail] [-id id] [refresh-interval]"); 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"); - System.out.println(" -id only print the sql data matched with id, use this with -sql argument" ); - } + System.out.println("参数: "); + System.out.println(" -help 打印此帮助信息"); + System.out.println(" -sql 打印SQL统计数据"); + System.out.println(" -ds 打印DataSource统计数据"); + System.out.println(" -act 打印活动连接的堆栈信息"); + System.out.println(" -detail 打印统计数据的全部字段信息"); + System.out.println(" -id id 要打印的数据的具体id值" ); + System.out.println(" pid 使用druid连接池的jvm进程id"); + System.out.println(" refresh-interval 自动刷新时间间隔, 以秒为单位" ); + + System.out.println(); + System.out.println("说明: "); + System.out.println(" -sql,-ds,-act参数中要至少指定一种数据进行打印, 可以组合使用, 比如 -sql -ds 一起的话就打印两种统计数据"); + System.out.println(" -id id可以跟 -sql 或-ds组合, 比如 -sql -id 5 或 -ds -id 1086752"); + System.out.println(" pid必需指定, refresh-interval可选, 如不指定,则打印数据后退出"); + System.out.println(" pid和refresh-interval参数必需放在命令行的最后, 否则解析会出错"); + } public int getId() { return id; @@ -150,6 +167,18 @@ public class Option { this.id = id; } - + public void setDetailPrint(boolean detailPrint) { + this.detailPrint=detailPrint; + } + public boolean isDetailPrint() { + return this.detailPrint; + } + + public void setInterval(int interval) { + this.interval=interval; + } + public int getInterval() { + return this.interval; + } } diff --git a/src/main/java/com/alibaba/druid/support/console/TabledDataPrinter.java b/src/main/java/com/alibaba/druid/support/console/TabledDataPrinter.java index 8645e71a51..7d13add569 100644 --- a/src/main/java/com/alibaba/druid/support/console/TabledDataPrinter.java +++ b/src/main/java/com/alibaba/druid/support/console/TabledDataPrinter.java @@ -28,15 +28,13 @@ public class TabledDataPrinter { private static final String[] sqlRowTitle = new String[] { "ID", "SQL", "ExecCount", "ExecTime", - "ExecMax","Txn", "Error","Update","FetchRow","Running","Concurrent", - "ExecHisto", "ExecRsHisto","FetchRowHisto","UpdateHisto" }; + "ExecMax","Txn", "Error","Update","FetchRow","Running","Concurrent", "ExecRsHisto" }; private static final String[] sqlRowField = new String[] { "ID", "SQL", "ExecuteCount", "TotalTime", "MaxTimespan", "InTransactionCount", "ErrorCount", "EffectedRowCount", "FetchRowCount", - "RunningCount","ConcurrentMax","Histogram","ExecuteAndResultHoldTimeHistogram", - "FetchRowCountHistogram","EffectedRowCountHistogram" }; + "RunningCount","ConcurrentMax","ExecuteAndResultHoldTimeHistogram" }; private static final String[] sqlColField = new String[] { "ID", "DataSource", "SQL", "ExecuteCount", "ErrorCount", @@ -50,16 +48,16 @@ public class TabledDataPrinter { private static final String[] dsRowTitle = new String[] { - "Name", "DbType", + "Identity", "DbType", "PoolingCount", "PoolingPeak", "PoolingPeakTime", "ActiveCount", "ActivePeak", "ActivePeakTime", - "ExecuteCount", "ErrorCount", "CommitCount", "RollbackCount" }; + "ExecuteCount", "ErrorCount" }; private static final String[] dsRowField = new String[] { - "Name", "DbType", + "Identity", "DbType", "PoolingCount", "PoolingPeak", "PoolingPeakTime", "ActiveCount", "ActivePeak", "ActivePeakTime", - "ExecuteCount", "ErrorCount", "CommitCount", "RollbackCount" }; + "ExecuteCount", "ErrorCount"}; private static final String[] dsColField = new String[] { @@ -88,35 +86,73 @@ public class TabledDataPrinter { } public static void printDataSourceData(List> content,Option opt) { - if (opt.getStyle() == Option.PrintStyle.HORIZONTAL) { - System.out.println(getFormattedOutput(content, dsRowTitle, dsRowField)); - } else { + while (true ) { + _printDataSourceData(content, opt); + if (opt.getInterval() == -1) break; + try { + Thread.sleep( opt.getInterval() * 1000 ); + } catch (Exception e) { + e.printStackTrace(); + break; + } + } + } + + public static void _printDataSourceData(List> content,Option opt) { + if (opt.getId() != -1 ) { + List> matchedContent = new ArrayList>(); + for (Map dsStat : content) { + Integer idStr = (Integer)dsStat.get("Identity"); + if (idStr.intValue() == opt.getId()) { + matchedContent.add(dsStat); + break; + } + } + content = matchedContent; + } + if (opt.isDetailPrint()) { System.out.println(getVerticalFormattedOutput(content, dsColField)); + } else { + System.out.println(getFormattedOutput(content, dsRowTitle, dsRowField)); } } public static void printSqlData(List> content, Option opt) { - if (opt.getId() != -1) { + while (true ) { + _printSqlData(content, opt); + if (opt.getInterval() == -1) break; + try { + Thread.sleep( opt.getInterval() * 1000 ); + } catch (Exception e) { + e.printStackTrace(); + break; + } + } + } + + public static void _printSqlData(List> content, Option opt) { + if (opt.getId() != -1 ) { List> matchedContent = new ArrayList>(); for (Map sqlStat : content) { Integer idStr = (Integer)sqlStat.get("ID"); if (idStr.intValue() == opt.getId()) { matchedContent.add(sqlStat); - String dbType = (String) sqlStat.get("DbType"); - String sql = (String) sqlStat.get("SQL"); - System.out.println(SQLUtils.format(sql, dbType)); - System.out.println("===============================\n"); + if (opt.isDetailPrint()) { + String dbType = (String) sqlStat.get("DbType"); + String sql = (String) sqlStat.get("SQL"); + System.out.println("Formatted SQL:"); + System.out.println(SQLUtils.format(sql, dbType)); + System.out.println(); + } break; } } content = matchedContent; - - } - if (opt.getStyle() == Option.PrintStyle.HORIZONTAL) { - System.out.println(getFormattedOutput(content, sqlRowTitle, sqlRowField)); - } else { + if (opt.isDetailPrint()) { System.out.println(getVerticalFormattedOutput(content, sqlColField)); + } else { + System.out.println(getFormattedOutput(content, sqlRowTitle, sqlRowField)); } } diff --git a/src/test/java/com/alibaba/druid/bvt/console/DruidStatTest.java b/src/test/java/com/alibaba/druid/bvt/console/DruidStatTest.java index e1be753a5b..3d9e932407 100644 --- a/src/test/java/com/alibaba/druid/bvt/console/DruidStatTest.java +++ b/src/test/java/com/alibaba/druid/bvt/console/DruidStatTest.java @@ -1,6 +1,7 @@ package com.alibaba.druid.bvt.console; +import java.util.List; import java.sql.Connection; import java.sql.Statement; import com.alibaba.druid.support.console.Option; @@ -62,16 +63,27 @@ public class DruidStatTest extends TestCase { 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); + cmdArray = new String[] {"-sql","-id","1", pid}; + opt = Option.parseOptions(cmdArray); DruidStat.printDruidStat(opt); + + cmdArray = new String[] {"-sql","-detail", "-id","1", pid}; + opt = Option.parseOptions(cmdArray); + DruidStat.printDruidStat(opt); + + cmdArray = new String[] {"-ds",pid}; + opt = Option.parseOptions(cmdArray); + List ids = DruidStat.getDataSourceIds(opt); + opt.setDetailPrint(true); + opt.setId( ids.get(0).intValue()); + DruidStat.printDruidStat(opt); + + } - public void test_printDruidStat3() throws Exception { + + public void test_printDruidStat2() throws Exception { String pid = getSelfPid(); String[] cmdArray = {"-act", pid}; Option opt = Option.parseOptions(cmdArray); diff --git a/src/test/java/com/alibaba/druid/bvt/console/OptionTest.java b/src/test/java/com/alibaba/druid/bvt/console/OptionTest.java index f6f97420b6..1c738be72a 100644 --- a/src/test/java/com/alibaba/druid/bvt/console/OptionTest.java +++ b/src/test/java/com/alibaba/druid/bvt/console/OptionTest.java @@ -1,5 +1,8 @@ package com.alibaba.druid.bvt.console; +import org.junit.runner.notification.Failure; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; import com.alibaba.druid.support.console.OptionParseException; import com.alibaba.druid.support.console.Option; @@ -16,7 +19,7 @@ public class OptionTest extends TestCase { Assert.assertTrue(opt.printSqlData()); Assert.assertTrue(opt.printDataSourceData()); Assert.assertFalse(opt.printActiveConn()); - Assert.assertEquals(opt.getVmid(), 200); + Assert.assertEquals(opt.getPid(), 200); cmdArray = new String[] {"-act", "738"}; opt = Option.parseOptions(cmdArray); @@ -24,25 +27,38 @@ public class OptionTest extends TestCase { Assert.assertFalse(opt.printSqlData()); Assert.assertFalse(opt.printDataSourceData()); Assert.assertTrue(opt.printActiveConn()); - Assert.assertEquals(opt.getStyle(), Option.PrintStyle.HORIZONTAL); - Assert.assertEquals(opt.getVmid(), 738); + Assert.assertEquals(opt.getPid(), 738); - cmdArray = new String[] {"-ds", "-s2", "1319"}; + cmdArray = new String[] {"-ds", "-detail", "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); + Assert.assertTrue(opt.isDetailPrint()); + Assert.assertEquals(opt.getPid(), 1319); cmdArray = new String[] {"-sql","-id","5","200"}; opt = Option.parseOptions(cmdArray); Assert.assertNotNull(opt); Assert.assertEquals(opt.getId(), 5); - Assert.assertEquals(opt.getVmid(), 200); + Assert.assertEquals(opt.getPid(), 200); + + cmdArray = new String[] {"-sql","-id","5","200", "3"}; + opt = Option.parseOptions(cmdArray); + Assert.assertNotNull(opt); + Assert.assertEquals(opt.getId(), 5); + Assert.assertEquals(opt.getPid(), 200); + Assert.assertEquals(opt.getInterval(), 3); + cmdArray = new String[] {"-ds","-id","5", "-detail", "200", "3"}; + opt = Option.parseOptions(cmdArray); + Assert.assertNotNull(opt); + Assert.assertEquals(opt.getId(), 5); + Assert.assertEquals(opt.getPid(), 200); + Assert.assertEquals(opt.getInterval(), 3); + Assert.assertEquals(opt.isDetailPrint(), true); //not enough arguments cmdArray = new String[] {}; @@ -53,7 +69,7 @@ public class OptionTest extends TestCase { Assert.assertNotNull(e); } - //need vmid + //need pid cmdArray = new String[] {"-ds"}; try { opt = Option.parseOptions(cmdArray); @@ -67,4 +83,11 @@ public class OptionTest extends TestCase { public void test_printHelp() throws Exception { Option.printHelp(); } + + public static void main(String[] args) { + Result result = JUnitCore.runClasses(OptionTest.class); + for (Failure failure : result.getFailures()) { + System.out.println(failure.toString()); + } + } }