Skip to content

Commit

Permalink
Merge pull request #12 from sunwu51/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
sunwu51 authored Feb 18, 2024
2 parents a45d13b + 717ddba commit e54b02c
Show file tree
Hide file tree
Showing 15 changed files with 127 additions and 43 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ $ java -cp "%JAVA_HOME%\lib\tools.jar";swapper.jar w.Attach
# usage
根据上面log中去请求页面,`http://localhost:8000` 默认是8000端口,如果出现冲突会替换,以上面log中为准。

建议测试环境,jvm启动参数添加`-Xverify:none`,否则部分信息不会打印。

注意!! 工具中所有的类名,只能是类,不能是接口。
## 1 watch
watch作用是对函数环绕增强,打印出入参和函数耗时
Expand Down
2 changes: 1 addition & 1 deletion dependency-reduced-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>c:/Program Files/Java/jdk1.8.0_77/lib/tools.jar</systemPath>
<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>
</dependencies>
<properties>
Expand Down
Empty file modified mvnw
100755 → 100644
Empty file.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>c:/Program Files/Java/jdk1.8.0_77/lib/tools.jar</systemPath>
<systemPath>${JAVA8_HOME}/lib/tools.jar</systemPath>
</dependency>
<dependency>
<groupId>org.nanohttpd</groupId> <!-- <groupId>com.nanohttpd</groupId> for 2.1.0 and earlier -->
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/w/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

Expand Down
55 changes: 45 additions & 10 deletions src/main/java/w/Global.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import fi.iki.elonen.NanoWSD;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.util.*;
Expand All @@ -35,6 +37,8 @@ public class Global {
*/
public static int wsPort = 0;

public static boolean nonVerifying;

/**
* The Javassist ClassPool used in this project.
*/
Expand Down Expand Up @@ -145,6 +149,19 @@ public static void error(Object content) {
log(2, "" + content);
}

/**
* Print error log, and broadcast to all websocket client
* @param content
* @param e
*/
public static void error(Object content, Throwable e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String stackTraceString = sw.toString();
log(2, content + "\n" + stackTraceString);
}

/**
* To pretty string, by m3.prettyobjct.*
* @param obj
Expand All @@ -167,7 +184,12 @@ public static String toString(Object obj) {
* @throws JsonProcessingException
*/
public static String toJson(Object obj) throws JsonProcessingException {
return PrintUtils.getObjectMapper().writeValueAsString(obj);
try {
return PrintUtils.getObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
Global.error("re transform error:", e);
return "toJson error";
}
}

/**
Expand Down Expand Up @@ -201,6 +223,7 @@ public static synchronized void addActiveTransformer(Class<?> c, BaseClassTransf
activeTransformers.computeIfAbsent(className, k->new HashMap<>()).computeIfAbsent(classLoader, k->new ArrayList<>()).add(transformer);
}


/**
* Remove transformer By uuid
* @param uuid
Expand All @@ -211,6 +234,13 @@ public static synchronized void deleteTransformer(UUID uuid) {
if (it.getUuid().equals(uuid)) {
it.setStatus(-1);
instrumentation.removeTransformer(it);
for (Class<?> aClass : allLoadedClasses.getOrDefault(it.getClassName(), new HashSet<>())) {
try {
instrumentation.retransformClasses(aClass);
} catch (Exception e) {
Global.error("delete re transform error:", e);
}
}
return true;
}
return false;
Expand Down Expand Up @@ -247,12 +277,10 @@ public static synchronized void reset() {
}
for (String cl : cls) {
for (Class<?> aClass : Global.allLoadedClasses.getOrDefault(cl, new HashSet<>())) {
if (aClass.getClassLoader() != null) {
try {
instrumentation.retransformClasses(aClass);
} catch (UnmodifiableClassException e) {
log(2, "re transform error " + e.getMessage());
}
try {
instrumentation.retransformClasses(aClass);
} catch (Exception e) {
Global.error("reset re transform error: ", e);
}
}

Expand Down Expand Up @@ -322,10 +350,17 @@ private static synchronized void send(String content) {
}

public synchronized static void fillLoadedClasses() {
int count = 0;
long start = System.currentTimeMillis();
for (Class cls : instrumentation.getAllLoadedClasses()) {
String name = cls.getName();
allLoadedClasses.computeIfAbsent(name, k -> new HashSet<>())
.add(cls);
if (cls.getClassLoader() != null) {
String name = cls.getName();
allLoadedClasses.computeIfAbsent(name, k -> new HashSet<>())
.add(cls);
count ++;

}
}
info("fill loaded classes cost: " + (System.currentTimeMillis() - start) + "ms, class num:" + count);
}
}
5 changes: 3 additions & 2 deletions src/main/java/w/core/ExecBundle.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public synchronized static void changeBodyAndInvoke(String body) throws Exceptio
});
Global.activeTransformers
.getOrDefault("w.Exec", new HashMap<>()).clear();
Swapper.getInstance().swap(message);
invoke();
if (Swapper.getInstance().swap(message)) {
invoke();
}
}
}
23 changes: 14 additions & 9 deletions src/main/java/w/core/Swapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import w.core.model.*;
import w.web.message.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;


Expand All @@ -16,7 +20,7 @@ public static Swapper getInstance() {
return INSTANCE;
}

public void swap(Message message) {
public boolean swap(Message message) {
BaseClassTransformer transformer = null;
try {
switch (message.getType()) {
Expand All @@ -40,23 +44,24 @@ public void swap(Message message) {
throw new RuntimeException("message type not support");
}
} catch (Throwable e) {
e.printStackTrace();
Global.error("build transform error");
Global.error("build transform error:", e);
return false;
}

Global.addTransformer(transformer);
Global.info("add transform finish, will retrans class");


for (Class<?> aClass : Global.allLoadedClasses.getOrDefault(transformer.getClassName(), new HashSet<>())) {
if (aClass.getClassLoader() != null) {
try {
Global.addActiveTransformer(aClass, transformer);
} catch (Throwable e) {
Global.error("re transform error " + e.getMessage());
}
try {
Global.addActiveTransformer(aClass, transformer);
} catch (Throwable e) {
Global.error("re transform error:", e);
return false;
}
}

return true;
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/main/java/w/core/model/BaseClassTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import lombok.Setter;
import w.Global;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
Expand Down Expand Up @@ -42,8 +44,7 @@ public byte[] transform(ClassLoader loader, String className, Class<?> classBein
Global.info(className + " re transform by " + uuid + " success <(^-^)>");
return r;
} catch (Exception e) {
e.printStackTrace();
Global.error(className + " re transform fail by " + uuid + " -(′д`)-: " + e.getMessage());
Global.error(className + " re transform fail by " + uuid + " -(′д`)-: ", e);
}
}
return null;
Expand Down
35 changes: 28 additions & 7 deletions src/main/java/w/core/model/OuterWatchTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private void addOuterWatchCodeToMethod(CtMethod ctMethod) throws CannotCompileEx
public void edit(MethodCall m) throws CannotCompileException {
if (m.getMethodName().equals(innerMethod)) {
if (innerClassName.equals("*") || m.getClassName().equals(innerClassName)) {
m.replace("{" +
String code = "{" +
"long start = System.currentTimeMillis();" +
"String req = null;" +
"String res = null;" +
Expand All @@ -78,19 +78,40 @@ public void edit(MethodCall m) throws CannotCompileException {
" req = Arrays.toString($args);" +
" res = \"\" + $_;" +
"} else if (printFormat == 2) {" +
" try{" +
"req = w.Global.toJson($args);" +
"res = w.Global.toJson(($w)$_);" +
"} " +
" catch (Exception e) {req = \"convert json error\"; res=req;}" +
"req = w.Global.toJson($args);" +
"res = w.Global.toJson(($w)$_);" +
"} else {" +
" req = w.Global.toString($args);" +
" res = w.Global.toString(($w)$_);" +
"}" +
"w.util.RequestUtils.fillCurThread(\"" + message.getId() + "\");" +
"w.Global.info(\"line" + m.getLineNumber() + ",cost:\"+duration+\"ms,req:\"+req+\",res:\"+res+\",exception:\"+t);" +
"w.util.RequestUtils.clearRequestCtx();" +
"}}");
"}}";
if (!Global.nonVerifying) {
code = "{" +
"long start = System.currentTimeMillis();" +
"$_ = $proceed($$);" +
"long duration = System.currentTimeMillis() - start;" +
"String req = null;" +
"String res = null;" +
"int printFormat = " + printFormat +";" +
"if (printFormat == 1) {" +
" req = Arrays.toString($args);" +
" res = \"\" + $_;" +
"} else if (printFormat == 2) {" +
"req = w.Global.toJson($args);" +
"res = w.Global.toJson(($w)$_);" +
"} else {" +
" req = w.Global.toString($args);" +
" res = w.Global.toString(($w)$_);" +
"}" +
"w.util.RequestUtils.fillCurThread(\"" + message.getId() + "\");" +
"w.Global.info(\"line" + m.getLineNumber() + ",cost:\"+duration+\"ms,req:\"+req+\",res:\"+res);" +
"w.util.RequestUtils.clearRequestCtx();" +
"}";
}
m.replace(code);
}
}
}
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/w/core/model/WatchTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ private void addWatchCodeToMethod(CtMethod ctMethod) throws CannotCompileExcepti
afterCode.append("res = \"\" + $_;");
catchCode.append("String req = Arrays.toString($args);");
} else if (printFormat == 2) {
afterCode.append("try {req = w.Global.toJson($args);} catch (Exception e) {req = \"convert json error\";}");
afterCode.append("try {res = w.Global.toJson(($w)$_);} catch (Exception e) {res = \"convert json error\";}");
catchCode.append("String req = \"convert json error\";try {req = w.Global.toJson($args);} catch (Exception e) {}");
afterCode.append("req = w.Global.toJson($args);");
afterCode.append("res = w.Global.toJson(($w)$_);");
catchCode.append("String req = w.Global.toJson($args);");
} else {
afterCode.append("req = w.Global.toString($args);");
afterCode.append("res = w.Global.toString(($w)$_);");
Expand All @@ -81,8 +81,9 @@ private void addWatchCodeToMethod(CtMethod ctMethod) throws CannotCompileExcepti
.append("w.util.RequestUtils.clearRequestCtx();")
.append("}");
ctMethod.insertAfter(afterCode.toString());
System.out.println(catchCode);
ctMethod.addCatch(catchCode.toString(), Global.classPool.get("java.lang.Throwable"));
if (Global.nonVerifying) {
ctMethod.addCatch(catchCode.toString(), Global.classPool.get("java.lang.Throwable"));
}
}

public boolean equals(Object other) {
Expand Down
20 changes: 16 additions & 4 deletions src/main/java/w/util/SpringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@
import ognl.*;
import w.Global;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;

/**
* @author Frank
Expand Down Expand Up @@ -60,6 +59,19 @@ public static void initFromLoadedClasses() throws NoSuchMethodException, Invocat
break;
}
}

RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
List<String> inputArguments = runtimeMXBean.getInputArguments();
String xverifyValue = null;
for (String a : inputArguments) {
if (a.startsWith("-Xverify:")) {
xverifyValue = a.substring("-Xverify:".length());
break;
}
}
if (Objects.equals("none", xverifyValue)) {
Global.nonVerifying = true;
}
}

public static String generateSpringCtxCode() {
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/w/web/Websocketd.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import fi.iki.elonen.NanoWSD;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.UUID;

/**
Expand Down Expand Up @@ -77,7 +79,7 @@ private void dispatch(String msg) {
try {
Global.deleteTransformer(UUID.fromString(deleteMessage.getUuid()));
} catch (Exception e) {
Global.error(e.getMessage());
Global.error("delete error:", e);
}
}
break;
Expand All @@ -89,7 +91,7 @@ private void dispatch(String msg) {
e.printStackTrace();
Global.error("not a valid message");
} catch (Throwable e) {
e.printStackTrace();
Global.error("error:", e);
} finally {
RequestUtils.clearRequestCtx();
}
Expand Down
Empty file modified src/main/resources/w_amd64.so
100755 → 100644
Empty file.

0 comments on commit e54b02c

Please sign in to comment.