Merge pull request #105 from shrekwang/master

命令行工具继续改进
This commit is contained in:
温高铁
2012-08-28 02:30:25 -07:00
5 changed files with 204 additions and 85 deletions
@@ -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<Map<String, Object>> content = (List<Map<String, Object>>) invokeService(jmxConn, Option.SQL);
TabledDataPrinter.printSqlData(content, option);
}
if (option.printDataSourceData()) {
List<Map<String, Object>> content = (List<Map<String, Object>>) invokeService(jmxConn, Option.DATA_SOURCE);
TabledDataPrinter.printDataSourceData(content, option);
}
if (option.printSqlData()) {
List<Map<String, Object>> content = (List<Map<String, Object>>) invokeService(jmxConn, Option.SQL);
TabledDataPrinter.printSqlData(content, option);
}
if (option.printActiveConn()) {
List<List<String>> content = (List<List<String>>) 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<Integer> 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<Map<String, Object>> content = (List<Map<String, Object>>) invokeService(jmxConn, Option.DATA_SOURCE);
TabledDataPrinter.printDataSourceData(content, option);
List<Integer> result = new ArrayList<Integer>();
for (Map<String, Object> 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() });
@@ -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] <pid> [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;
}
}
@@ -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<Map<String, Object>> 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<Map<String, Object>> content,Option opt) {
if (opt.getId() != -1 ) {
List<Map<String,Object>> matchedContent = new ArrayList<Map<String,Object>>();
for (Map<String, Object> 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<Map<String, Object>> 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<Map<String, Object>> content, Option opt) {
if (opt.getId() != -1 ) {
List<Map<String,Object>> matchedContent = new ArrayList<Map<String,Object>>();
for (Map<String, Object> 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));
}
}
@@ -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<Integer> 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);
@@ -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());
}
}
}