From 3f1d63e02e77481bec0afca7bc2b9ddcb49ef781 Mon Sep 17 00:00:00 2001 From: pengzhile Date: Fri, 21 Jan 2022 18:10:26 +0800 Subject: [PATCH] update the lifecycle of the transformer Signed-off-by: pengzhile --- README.md | 4 +- pom.xml | 2 +- .../java/com/janetfilter/core/Dispatcher.java | 14 +++- .../com/janetfilter/core/Environment.java | 24 +++++-- .../java/com/janetfilter/core/Launcher.java | 2 +- .../janetfilter/core/commons/DebugInfo.java | 69 +++++++++++++------ .../core/plugin/MyTransformer.java | 34 +++++++++ .../com/janetfilter/core/utils/DateUtils.java | 11 ++- 8 files changed, 128 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 0e1999a..bead308 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ja-netfilter v2.2.0 +# ja-netfilter v2.2.1 ### A javaagent framework @@ -49,7 +49,7 @@ EQUAL,somedomain * the `ja-netfilter` will **NOT** output debugging information by default * add environment variable `JANF_DEBUG=1` (log level) and start to enable it * or add system property `-Djanf.debug=1` (log level) to enable it -* log level: `NONE=0`, `DEBUG=1`, `INFO=2`, `WARN=3`, `ERROR=4`; +* log level: `NONE=0`, `DEBUG=1`, `INFO=2`, `WARN=3`, `ERROR=4` ## Plugin system diff --git a/pom.xml b/pom.xml index 74973f9..d34c09f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.ja-netfilter ja-netfilter - 2.2.0 + 2.2.1 ja-netfilter A javaagent framework diff --git a/src/main/java/com/janetfilter/core/Dispatcher.java b/src/main/java/com/janetfilter/core/Dispatcher.java index cd36e29..d89cd01 100644 --- a/src/main/java/com/janetfilter/core/Dispatcher.java +++ b/src/main/java/com/janetfilter/core/Dispatcher.java @@ -63,12 +63,24 @@ public final class Dispatcher implements ClassFileTransformer { try { for (MyTransformer transformer : globalTransformers) { - classFileBuffer = transformer.transform(className, classFileBuffer, order++); + transformer.before(className, classFileBuffer); + } + + for (MyTransformer transformer : globalTransformers) { + classFileBuffer = transformer.preTransform(className, classFileBuffer, order++); } for (MyTransformer transformer : transformers) { classFileBuffer = transformer.transform(className, classFileBuffer, order++); } + + for (MyTransformer transformer : globalTransformers) { + classFileBuffer = transformer.postTransform(className, classFileBuffer, order++); + } + + for (MyTransformer transformer : globalTransformers) { + transformer.after(className, classFileBuffer); + } } catch (Throwable e) { DebugInfo.error("Transform class failed: " + className, e); } diff --git a/src/main/java/com/janetfilter/core/Environment.java b/src/main/java/com/janetfilter/core/Environment.java index 5983972..1afaa24 100644 --- a/src/main/java/com/janetfilter/core/Environment.java +++ b/src/main/java/com/janetfilter/core/Environment.java @@ -7,6 +7,8 @@ import java.io.File; public final class Environment { private final String pid; + private final String version; + private final String appName; private final File baseDir; private final File agentFile; private final File configDir; @@ -23,24 +25,34 @@ public final class Environment { baseDir = agentFile.getParentFile(); if (StringUtils.isEmpty(app)) { + appName = ""; configDir = new File(baseDir, "config"); pluginsDir = new File(baseDir, "plugins"); logsDir = new File(baseDir, "logs"); } else { - app = app.toLowerCase(); - configDir = new File(baseDir, "config-" + app); - pluginsDir = new File(baseDir, "plugins-" + app); - logsDir = new File(baseDir, "logs-" + app); + appName = app.toLowerCase(); + configDir = new File(baseDir, "config-" + appName); + pluginsDir = new File(baseDir, "plugins-" + appName); + logsDir = new File(baseDir, "logs-" + appName); } - nativePrefix = StringUtils.randomMethodName(15) + "_"; pid = ProcessUtils.currentId(); + version = Launcher.VERSION; + nativePrefix = StringUtils.randomMethodName(15) + "_"; } public String getPid() { return pid; } + public String getVersion() { + return version; + } + + public String getAppName() { + return appName; + } + public File getBaseDir() { return baseDir; } @@ -69,6 +81,8 @@ public final class Environment { public String toString() { return "Environment: {" + "\n\tpid = " + pid + + ", \n\tversion = " + version + + ", \n\tappName = " + appName + ", \n\tbaseDir = " + baseDir + ", \n\tagentFile = " + agentFile + ", \n\tconfigDir = " + configDir + diff --git a/src/main/java/com/janetfilter/core/Launcher.java b/src/main/java/com/janetfilter/core/Launcher.java index 9893400..0251f68 100644 --- a/src/main/java/com/janetfilter/core/Launcher.java +++ b/src/main/java/com/janetfilter/core/Launcher.java @@ -12,7 +12,7 @@ import java.util.jar.JarFile; public class Launcher { public static final String ATTACH_ARG = "--attach"; - public static final String VERSION = "v2.2.0"; + public static final String VERSION = "v2.2.1"; private static boolean loaded = false; diff --git a/src/main/java/com/janetfilter/core/commons/DebugInfo.java b/src/main/java/com/janetfilter/core/commons/DebugInfo.java index 1d1e990..00cbaac 100644 --- a/src/main/java/com/janetfilter/core/commons/DebugInfo.java +++ b/src/main/java/com/janetfilter/core/commons/DebugInfo.java @@ -7,10 +7,13 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class DebugInfo { + private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(); private static final String CLASS_NAME = DebugInfo.class.getName(); - private static final String LOG_TEMPLATE = "[%s] %s %s : %s%n"; + private static final String LOG_TEMPLATE = "%s %-5s [%s] %s-%d : %s%n"; private static final Level LOG_LEVEL; private static File logFile; @@ -93,26 +96,7 @@ public class DebugInfo { return; } - String caller = "UNKNOWN"; - StackTraceElement[] traces = new Throwable().getStackTrace(); - for (int i = 1, l = traces.length; i < l; i++) { // thank RayGicEFL - StackTraceElement element = traces[i]; - if (!CLASS_NAME.equals(element.getClassName())) { - caller = element.toString(); - break; - } - } - - String outContent = String.format(LOG_TEMPLATE, DateUtils.formatDateTime(), caller, level, content); - if (null == e) { - writeContent(outContent); - return; - } - - synchronized (DebugInfo.class) { - writeContent(outContent, System.err); - writeException(e); - } + EXECUTOR.execute(new WriteTask(level, content, e)); } private static void writeContent(String content) { @@ -173,4 +157,47 @@ public class DebugInfo { return NONE; } } + + private static class WriteTask implements Runnable { + private final Level level; + private final String content; + private final Throwable exception; + private final Throwable stackException; + + private final String threadName; + + WriteTask(Level level, String content, Throwable exception) { + this.level = level; + this.content = content; + this.exception = exception; + this.stackException = new Throwable(); + this.threadName = Thread.currentThread().getName(); + } + + @Override + public void run() { + int line = 0; + String caller = "UNKNOWN"; + StackTraceElement[] traces = stackException.getStackTrace(); + for (int i = 1, l = traces.length; i < l; i++) { // thank RayGicEFL + StackTraceElement element = traces[i]; + if (!CLASS_NAME.equals(element.getClassName())) { + line = element.getLineNumber(); + caller = element.getClassName(); + break; + } + } + + String outContent = String.format(LOG_TEMPLATE, DateUtils.formatDateTimeMicro(), level, threadName, caller, line, content); + if (null == exception) { + writeContent(outContent); + return; + } + + synchronized (DebugInfo.class) { + writeContent(outContent, System.err); + writeException(exception); + } + } + } } diff --git a/src/main/java/com/janetfilter/core/plugin/MyTransformer.java b/src/main/java/com/janetfilter/core/plugin/MyTransformer.java index 758744b..2d3570e 100644 --- a/src/main/java/com/janetfilter/core/plugin/MyTransformer.java +++ b/src/main/java/com/janetfilter/core/plugin/MyTransformer.java @@ -1,9 +1,43 @@ package com.janetfilter.core.plugin; public interface MyTransformer { + /** + * @return class name like this: package/to/className, null means it's a global transformer + */ String getHookClassName(); + /** + * for global transformers only + */ + default void before(String className, byte[] classBytes) throws Exception { + + } + + /** + * for global transformers only + */ + default byte[] preTransform(String className, byte[] classBytes, int order) throws Exception { + return transform(className, classBytes, order); // for old version + } + + /** + * for normal transformers only + */ default byte[] transform(String className, byte[] classBytes, int order) throws Exception { return classBytes; } + + /** + * for global transformers only + */ + default byte[] postTransform(String className, byte[] classBytes, int order) throws Exception { + return classBytes; + } + + /** + * for global transformers only + */ + default void after(String className, byte[] classBytes) throws Exception { + + } } diff --git a/src/main/java/com/janetfilter/core/utils/DateUtils.java b/src/main/java/com/janetfilter/core/utils/DateUtils.java index c798b98..070a488 100644 --- a/src/main/java/com/janetfilter/core/utils/DateUtils.java +++ b/src/main/java/com/janetfilter/core/utils/DateUtils.java @@ -7,6 +7,7 @@ import java.util.Date; public class DateUtils { public static final DateFormat FULL_DF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + public static final DateFormat FULL_MICRO_DF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); public static final DateFormat DATE_DF = new SimpleDateFormat("yyyy-MM-dd"); public static final DateFormat TIME_DF = new SimpleDateFormat("HH:mm:ss"); @@ -15,7 +16,15 @@ public class DateUtils { } public static String formatDateTime() { - return FULL_DF.format(new Date()); + return formatDateTime(new Date()); + } + + public static String formatDateTimeMicro(Date date) { + return FULL_MICRO_DF.format(date); + } + + public static String formatDateTimeMicro() { + return formatDateTimeMicro(new Date()); } public static String formatDate(Date date) {