Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# TProfiler

TProfiler是一款代码性能分析工具。

作者:shutong.dy@taobao.com

**重要提示:TProfiler 需要 Java 6™ 虚拟机环境运行。**

TProfiler 旨在用于生产环境,可持续监控方法执行的时间和次数、生成方法热点、对象创建热点以及线程状态分析等数据,为排查系统性能瓶颈提供数据支持。

更多详细信息和使用文档,请参阅 [TProfiler Wiki](https://github.com/alibaba/TProfiler/wiki)。该Wiki包含更全面的中文文档,包括:

* TProfiler介绍
* TProfiler实现原理
* TProfiler日志分析
* TProfiler配置部署

## 贡献

TProfiler 的源代码使用 GPL version 2 许可证。我们欢迎各种贡献,如果您有任何想法、Bug报告或补丁,请随时提交。
4 changes: 4 additions & 0 deletions src/main/java/com/taobao/profile/Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ public static void setRecordTime(int recordTime) {
Manager.recordTime = recordTime;
}

public ProfConfig getProfConfig() {
return profConfig;
}

/**
* 设置包名过滤器
*
Expand Down
20 changes: 10 additions & 10 deletions src/main/java/com/taobao/profile/Profiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,10 @@ public static void start4Mysql(String host,int port,String db,String sql){
Object[] frameData = new Object[6];
frameData[0] = thrData.stackNum;
frameData[1] = startTime;
frameData[2] = host;
frameData[2] = host != null ? host : "";
frameData[3] = port;
frameData[4] = db;
frameData[5] = sql;
frameData[4] = db != null ? db : "";
frameData[5] = sql != null ? sql : "";
thrData.stackFrame.push(frameData);
thrData.stackNum++;
} catch (Exception e) {
Expand Down Expand Up @@ -296,19 +296,19 @@ public static void end4Mysql(){
RecordSlowQuery record = new RecordSlowQuery();
Map<String, String> map = new HashMap<String, String>();

map.put("host", (String) frameData[2]);
map.put("port", frameData[3].toString());
map.put("db", (String) frameData[4]);
map.put("sql", (String) frameData[5]);
map.put("host", String.valueOf(frameData[2]));
map.put("port", String.valueOf(frameData[3]));
map.put("db", String.valueOf(frameData[4]));
map.put("sql", String.valueOf(frameData[5]));
record.setRequestDesc(map);
record.setUseTime(endTime - (Long) frameData[1]);
record.setType("MYSQL");

StringBuilder sb = new StringBuilder();
sb.append("MYSQL");
sb.append((String) frameData[2]);
sb.append(frameData[3].toString());
sb.append((String) frameData[4]);
sb.append(String.valueOf(frameData[2]));
sb.append(String.valueOf(frameData[3]));
sb.append(String.valueOf(frameData[4]));

if(!isNeedRecord(record.getUseTime())){
return;
Expand Down
44 changes: 34 additions & 10 deletions src/main/java/com/taobao/profile/client/TProfilerClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,43 @@ private static String read(InputStream in) throws IOException {
* @param args
*/
public static void main(String[] args) {
if (args.length != 3) {
System.err.println("Usage: <server ip> <server port> <command[start/stop/status/flushmethod]>");
if (args.length < 3 || args.length > 4) {
System.err.println("Usage: <server ip> <server port> <command[start/stop/status/flushmethod]> [auth_token]");
return;
}
int port = Integer.valueOf(args[1]);
if (args[2].toLowerCase().equals(Manager.START)) {
start(args[0], port);
} else if (args[2].toLowerCase().equals(Manager.STOP)) {
stop(args[0], port);
} else if (args[2].toLowerCase().equals(Manager.FLUSHMETHOD)) {
flushMethod(args[0], port);

String serverIp = args[0];
int port = Integer.valueOf(args[1]);
String commandName = args[2].toLowerCase();
String authToken = null;

if (args.length == 4) {
authToken = args[3];
}

String commandToSend = "";
if (commandName.equals(Manager.START.toLowerCase())) {
commandToSend = Manager.START;
} else if (commandName.equals(Manager.STOP.toLowerCase())) {
commandToSend = Manager.STOP;
} else if (commandName.equals(Manager.FLUSHMETHOD.toLowerCase())) {
commandToSend = Manager.FLUSHMETHOD;
} else if (commandName.equals(Manager.STATUS.toLowerCase())) {
commandToSend = Manager.STATUS;
} else {
System.err.println("Unknown command: " + commandName);
return;
}

String finalCommand = commandToSend;
if (authToken != null && !authToken.trim().isEmpty()) {
finalCommand = authToken + "@" + commandToSend;
}

if (commandToSend.equals(Manager.STATUS)) {
System.out.println(getStatus(finalCommand, serverIp, port));
} else {
System.out.println(status(args[0], port));
doSend(finalCommand, serverIp, port);
}
}
}
60 changes: 49 additions & 11 deletions src/main/java/com/taobao/profile/config/ProfConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ public class ProfConfig {
*/
private int recordTime;

private String socketBindAddress;
private String socketAuthToken;

/**
* 构造方法
*/
Expand Down Expand Up @@ -184,9 +187,21 @@ private void extractDefaultProfile() throws IOException {
for (int len = -1; (len = in.read(buffer)) != -1;){
out.write(buffer, 0, len);
}
}finally{
in.close();
out.close();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace(); // Or a proper logger
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace(); // Or a proper logger
}
}
}
}

Expand Down Expand Up @@ -232,6 +247,8 @@ private void loadConfig(Properties properties) throws VariableNotFoundException
String debugMode = properties.getProperty("debugMode");
String port = properties.getProperty("port");
String recordTime = properties.getProperty("recordTime","-1");
String socketBindAddressProp = properties.getProperty("profiler.socket.bindaddress");
String socketAuthTokenProp = properties.getProperty("profiler.socket.authtoken");

setPort(port == null ? 50000 : Integer.valueOf(port));
setDebugMode("true".equalsIgnoreCase(debugMode == null ? null : debugMode.trim()));
Expand All @@ -245,6 +262,8 @@ private void loadConfig(Properties properties) throws VariableNotFoundException
setStartProfTime(startProfTime);
setNeedNanoTime("true".equals(needNanoTime));
setIgnoreGetSetMethod("true".equals(ignoreGetSetMethod));
setSocketBindAddress(socketBindAddressProp);
setSocketAuthToken(socketAuthTokenProp);
if (eachProfUseTime == null) {
setEachProfUseTime(5);
} else {
Expand Down Expand Up @@ -274,7 +293,7 @@ private void loadConfig(Properties properties) throws VariableNotFoundException
* @return
*/
public String getStartProfTime() {
return startProfTime;
return startProfTime != null ? startProfTime : "";
}

/**
Expand All @@ -288,7 +307,7 @@ public void setStartProfTime(String startProfTime) {
* @return
*/
public String getEndProfTime() {
return endProfTime;
return endProfTime != null ? endProfTime : "";
}

/**
Expand All @@ -302,7 +321,7 @@ public void setEndProfTime(String endProfTime) {
* @return
*/
public String getLogFilePath() {
return logFilePath;
return logFilePath != null ? logFilePath : "";
}

/**
Expand All @@ -316,7 +335,7 @@ public void setLogFilePath(String logFilePath) {
* @return the methodFilePath
*/
public String getMethodFilePath() {
return methodFilePath;
return methodFilePath != null ? methodFilePath : "";
}

/**
Expand All @@ -331,7 +350,7 @@ public void setMethodFilePath(String methodFilePath) {
* @return
*/
public String getIncludePackageStartsWith() {
return includePackageStartsWith;
return includePackageStartsWith != null ? includePackageStartsWith : "";
}

/**
Expand Down Expand Up @@ -373,7 +392,7 @@ public void setEachProfIntervalTime(int eachProfIntervalTime) {
* @return
*/
public String getExcludePackageStartsWith() {
return excludePackageStartsWith;
return excludePackageStartsWith != null ? excludePackageStartsWith : "";
}

/**
Expand Down Expand Up @@ -431,7 +450,7 @@ public void setSamplerIntervalTime(int samplerIntervalTime) {
* @return the samplerFilePath
*/
public String getSamplerFilePath() {
return samplerFilePath;
return samplerFilePath != null ? samplerFilePath : "";
}

/**
Expand All @@ -445,7 +464,7 @@ public int getSamplerIntervalTime() {
* @return the excludeClassLoader
*/
public String getExcludeClassLoader() {
return excludeClassLoader;
return excludeClassLoader != null ? excludeClassLoader : "";
}

/**
Expand Down Expand Up @@ -484,4 +503,23 @@ public int getRecordTime() {
public void setRecordTime(int recordTime) {
this.recordTime = recordTime;
}

public String getSocketBindAddress() {
if (socketBindAddress == null || socketBindAddress.trim().isEmpty()) {
return "127.0.0.1"; // Default to localhost
}
return socketBindAddress;
}

public void setSocketBindAddress(String socketBindAddress) {
this.socketBindAddress = socketBindAddress;
}

public String getSocketAuthToken() {
return socketAuthToken; // Can be null or empty if not set
}

public void setSocketAuthToken(String socketAuthToken) {
this.socketAuthToken = socketAuthToken;
}
}
42 changes: 39 additions & 3 deletions src/main/java/com/taobao/profile/thread/DataDumpThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,40 @@ public class DataDumpThread extends Thread {
*/
public DataDumpThread(ProfConfig config) {
// 读取用户配置
fileWriter = new DailyRollingFileWriter(config.getLogFilePath());
File temp = new File(config.getLogFilePath());
mysqlFileWriter = new DailyRollingFileWriter(temp.getParent()+"/mysqlProfiler.log");
String logFilePath = config.getLogFilePath(); // Already non-null due to ProfConfig changes (returns "")
// Initialize fileWriter (assuming DailyRollingFileWriter can handle empty string path or throw error)
try {
fileWriter = new DailyRollingFileWriter(logFilePath);
} catch (Exception e) {
System.err.println("TProfiler: Failed to initialize fileWriter for path: " + logFilePath);
e.printStackTrace();
fileWriter = null; // Set to null if init fails
}

String mysqlLogPath;
if (logFilePath.isEmpty()) {
// If main log path is empty (not configured), mysql log also goes to a default name in current dir
mysqlLogPath = "mysqlProfiler.log";
System.err.println("TProfiler: logFilePath is empty. MySQL logs will be in current dir: " + new File(mysqlLogPath).getAbsolutePath());
} else {
File temp = new File(logFilePath);
String parentDir = temp.getParent();
if (parentDir == null) {
// logFilePath is a relative filename like "profiler.log"
mysqlLogPath = "mysqlProfiler.log";
System.err.println("TProfiler: logFilePath has no parent directory. MySQL logs will be in current dir: " + new File(mysqlLogPath).getAbsolutePath());
} else {
mysqlLogPath = new File(parentDir, "mysqlProfiler.log").getPath();
}
}

try {
mysqlFileWriter = new DailyRollingFileWriter(mysqlLogPath);
} catch (Exception e) {
System.err.println("TProfiler: Failed to initialize mysqlFileWriter for path: " + mysqlLogPath);
e.printStackTrace();
mysqlFileWriter = null; // Ensure it's null if initialization fails
}
eachProfUseTime = config.getEachProfUseTime();
eachProfIntervalTime = config.getEachProfIntervalTime();
}
Expand Down Expand Up @@ -86,6 +117,9 @@ public void run() {
if (fileWriter != null) {
fileWriter.closeFile();
}
if (mysqlFileWriter != null) {
mysqlFileWriter.closeFile();
}
// 等待已开始的End方法执行完成
try {
TimeUnit.MILLISECONDS.sleep(500L);
Expand All @@ -102,6 +136,7 @@ public void run() {
* @return
*/
private void dumpProfileData() {
if (fileWriter == null) return;
ThreadData[] threadData = Profiler.threadProfile;
for (int index = 0; index < threadData.length; index++) {
ThreadData profilerData = threadData[index];
Expand Down Expand Up @@ -137,6 +172,7 @@ private void dumpProfileData() {
* 记录Mysql方法的日志
*/
private void dumpMysqlData(){
if (mysqlFileWriter == null) return;

SlowQueryData[] threadData = Profiler.slowQueryProfile;
for (int index = 0; index < threadData.length; index++) {
Expand Down
Loading