diff --git a/pom.xml b/pom.xml index d3d4eec..7a93d28 100644 --- a/pom.xml +++ b/pom.xml @@ -1,76 +1,90 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + 4.0.0 - com.wenshuo - javaagent - 2.1.2 - jar + com.wenshuo + javaagent + 2.1.2 + jar - javaagent - 基于javaagent技术来记录方法执行次数和时间 - https://github.com/dingjs/javaagent + javaagent + 基于javaagent技术来记录方法执行次数和时间 + https://github.com/dingjs/javaagent - - UTF-8 - 1.6 - UTF-8 - - - - dingjsh - 丁建水 - 47954233@qq.com - - - - - Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0.txt - repo - - + + UTF-8 + 1.6 + UTF-8 + + + + dingjsh + 丁建水 + 47954233@qq.com + + + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + repo + + - - - - org.apache.maven.plugins - maven-jar-plugin - 3.3.0 - - - - com.wenshuo.agent.Agent - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - ${project.build.target} - ${project.build.target} - - - - + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + com.wenshuo.agent.Agent + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${project.build.target} + ${project.build.target} + + + + - + + + com.sun + tools + ${java.version} + system + true + ${java.home}/../lib/tools.jar + + + junit + junit + 4.13.2 + test + + + org.slf4j + slf4j-api + 1.7.36 + compile + true + - com.sun - tools - ${java.version} - system + commons-logging + commons-logging + 1.2 + compile true - ${java.home}/../lib/tools.jar - - junit - junit - 4.13.2 - test - - + diff --git a/src/main/java/com/wenshuo/agent/Agent.java b/src/main/java/com/wenshuo/agent/Agent.java index c32f651..4397784 100644 --- a/src/main/java/com/wenshuo/agent/Agent.java +++ b/src/main/java/com/wenshuo/agent/Agent.java @@ -4,8 +4,13 @@ * Copyright 2015 wenshuo, Inc. All rights reserved. * wenshuo PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ + package com.wenshuo.agent; + import java.lang.instrument.Instrumentation; + +import com.wenshuo.agent.applog.AppLogFactory; +import com.wenshuo.agent.applog.IAppLog; import com.wenshuo.agent.log.ExecuteLogUtils; import com.wenshuo.agent.transformer.AgentLogClassFileTransformer; @@ -16,10 +21,12 @@ */ public class Agent { + private static IAppLog log = AppLogFactory.getAppLog(Agent.class); + public static void premain(String agentArs, Instrumentation inst) { - System.out.println("javaagent启动成功,将自动记录方法的执行次数和时间"); // 初始化配置 ConfigUtils.initProperties(agentArs); + log.info("javaagent启动成功,将自动记录方法的执行次数和时间,日志文件路径:" + ConfigUtils.getLogFileName()); ExecuteLogUtils.init(); inst.addTransformer(new AgentLogClassFileTransformer()); } diff --git a/src/main/java/com/wenshuo/agent/ConfigUtils.java b/src/main/java/com/wenshuo/agent/ConfigUtils.java index 400a9be..e086fc2 100644 --- a/src/main/java/com/wenshuo/agent/ConfigUtils.java +++ b/src/main/java/com/wenshuo/agent/ConfigUtils.java @@ -7,6 +7,9 @@ import java.util.Properties; import java.util.Set; +import com.wenshuo.agent.applog.AppLogFactory; +import com.wenshuo.agent.applog.IAppLog; + /** * 获取配置信息
* ConfigUtils @@ -24,6 +27,8 @@ public class ConfigUtils { private static Set excludeClassRegexs; + private static IAppLog log = AppLogFactory.getAppLog(ConfigUtils.class); + private ConfigUtils() { super(); } @@ -49,7 +54,7 @@ private static Properties getProperties(String propertiesFileName) { input = ConfigUtils.class.getClassLoader().getResourceAsStream("agent.properties"); properties.load(input); } catch (Exception e) { - System.err.println("未找到默认配置"); + log.warn("未找到默认配置"); } finally { AgentUtils.closeQuietly(input); } @@ -58,7 +63,7 @@ private static Properties getProperties(String propertiesFileName) { input = new FileInputStream(propertiesFileName); properties.load(input); } catch (Exception e) { - System.err.println(e); + log.error("解析配置文件出错:" + propertiesFileName, e); } finally { AgentUtils.closeQuietly(input); } @@ -158,4 +163,5 @@ public static boolean isUsingNanoTime() { String value = getProperty(ConfigConsts.LOG_TIME_NANO); return "true".equalsIgnoreCase(value); } + } diff --git a/src/main/java/com/wenshuo/agent/applog/AppLogFactory.java b/src/main/java/com/wenshuo/agent/applog/AppLogFactory.java new file mode 100644 index 0000000..4283064 --- /dev/null +++ b/src/main/java/com/wenshuo/agent/applog/AppLogFactory.java @@ -0,0 +1,52 @@ +/** + * @projectName javaagent + * @package com.wenshuo.agent.applog + * @className com.wenshuo.agent.applog.IAppLogFactory + * @copyright Copyright 2023 Thunisoft, Inc All rights reserved. + */ + +package com.wenshuo.agent.applog; + +/** + * AppLogFactory + * + * @author dingjsh + * @description javaagent日志工厂类 + * @date 2023-10-16 11:49 + * @since 2.1.3 + */ +public class AppLogFactory { + + private static final String SLF4J_FACTORY_CLASS_NAME = "org.slf4j.LoggerFactory"; + + private static final String COMMONS_LOGGING_FACTORY_CLASS_NAME = "org.apache.commons.logging.LogFactory"; + + /** + * 如果工程中有slf4j,则采用slf4j输出日志,如果有commons-logging,则采用commons-logging,否则用console + * @param clazz + * @return javaagent日志对象 + */ + public static IAppLog getAppLog(Class clazz) { + if (isClassPresent(SLF4J_FACTORY_CLASS_NAME, Thread.currentThread().getContextClassLoader())) { + return new Slf4jAppLog(clazz); + } else if (isClassPresent(COMMONS_LOGGING_FACTORY_CLASS_NAME, Thread.currentThread().getContextClassLoader())) { + return new CommonsLoggingAppLog(clazz); + } else { + return new ConsoleAppLog(); + } + } + + protected static boolean isClassPresent(String className, ClassLoader classLoader) { + try { + resolve(className, classLoader); + return true; + } catch (Throwable throwable) { + return false; + } + } + + protected static Class resolve(String className, ClassLoader classLoader) throws ClassNotFoundException { + return classLoader != null ? Class.forName(className, false, classLoader) : Class.forName(className); + } + +} \ No newline at end of file diff --git a/src/main/java/com/wenshuo/agent/applog/CommonsLoggingAppLog.java b/src/main/java/com/wenshuo/agent/applog/CommonsLoggingAppLog.java new file mode 100644 index 0000000..f832c0d --- /dev/null +++ b/src/main/java/com/wenshuo/agent/applog/CommonsLoggingAppLog.java @@ -0,0 +1,50 @@ +/** + * @projectName javaagent + * @package com.wenshuo.agent.applog + * @className com.wenshuo.agent.applog.CommonsLoggingAppLog + * @copyright Copyright 2023 Thunisoft, Inc All rights reserved. + */ + +package com.wenshuo.agent.applog; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * CommonsLoggingAppLog + * + * @author dingjsh + * @description + * @date 2023-10-16 17:35 + * @since 2.1.3 + */ +class CommonsLoggingAppLog implements IAppLog { + + private Log log; + + public CommonsLoggingAppLog(Class clazz) { + log = LogFactory.getLog(clazz); + } + + @Override + public void info(String message) { + log.info(message); + + } + + @Override + public void warn(String message) { + log.warn(message); + } + + @Override + public void error(String message) { + log.error(message); + } + + @Override + public void error(String message, Throwable t) { + log.error(message, t); + } + +} \ No newline at end of file diff --git a/src/main/java/com/wenshuo/agent/applog/ConsoleAppLog.java b/src/main/java/com/wenshuo/agent/applog/ConsoleAppLog.java new file mode 100644 index 0000000..d9011c8 --- /dev/null +++ b/src/main/java/com/wenshuo/agent/applog/ConsoleAppLog.java @@ -0,0 +1,40 @@ +/** + * @projectName javaagent + * @package com.wenshuo.agent.applog + * @className com.wenshuo.agent.applog.ConsoleAppLog + * @copyright Copyright 2023 Thunisoft, Inc All rights reserved. + */ + +package com.wenshuo.agent.applog; + +/** + * ConsoleAppLog + * + * @author dingjsh + * @description + * @date 2023-10-16 17:37 + * @since 2.1.3 + */ +class ConsoleAppLog implements IAppLog { + + @Override + public void info(String message) { + System.out.println("[info ] " + message); + } + + @Override + public void warn(String message) { + System.out.println("[warn ] " + message); + } + + @Override + public void error(String message) { + System.err.println("[error ] " + message); + } + + @Override + public void error(String message, Throwable t) { + System.err.println("[error ] " + message); + } + +} \ No newline at end of file diff --git a/src/main/java/com/wenshuo/agent/applog/IAppLog.java b/src/main/java/com/wenshuo/agent/applog/IAppLog.java new file mode 100644 index 0000000..2aa9821 --- /dev/null +++ b/src/main/java/com/wenshuo/agent/applog/IAppLog.java @@ -0,0 +1,28 @@ +/** + * @projectName javaagent + * @package com.wenshuo.agent.applog + * @className com.wenshuo.agent.applog.IAppLog + * @copyright Copyright 2023 Thunisoft, Inc All rights reserved. + */ + +package com.wenshuo.agent.applog; + +/** + * IAppLog + * + * @author dingjsh + * @description javaagent日志接口 + * @date 2023-10-16 11:46 + * @since 2.1.3 + */ +public interface IAppLog { + + void info(String message); + + void warn(String message); + + void error(String message); + + void error(String message, Throwable t); + +} \ No newline at end of file diff --git a/src/main/java/com/wenshuo/agent/applog/Slf4jAppLog.java b/src/main/java/com/wenshuo/agent/applog/Slf4jAppLog.java new file mode 100644 index 0000000..ed60c66 --- /dev/null +++ b/src/main/java/com/wenshuo/agent/applog/Slf4jAppLog.java @@ -0,0 +1,50 @@ +/** + * @projectName javaagent + * @package com.wenshuo.agent.applog + * @className com.wenshuo.agent.applog.Slf4jAppLog + * @copyright Copyright 2023 Thunisoft, Inc All rights reserved. + */ + +package com.wenshuo.agent.applog; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Slf4jAppLog + * + * @author dingjsh + * @description + * @date 2023-10-16 16:58 + * @since 2.1.3 + */ +class Slf4jAppLog implements IAppLog { + + private Logger log; + + public Slf4jAppLog(Class clazz) { + log = LoggerFactory.getLogger(clazz); + } + + @Override + public void info(String message) { + log.info(message); + + } + + @Override + public void warn(String message) { + log.warn(message); + } + + @Override + public void error(String message) { + log.error(message); + } + + @Override + public void error(String message, Throwable t) { + log.error(message, t); + } + +} \ No newline at end of file diff --git a/src/main/java/com/wenshuo/agent/log/ExecuteLogUtils.java b/src/main/java/com/wenshuo/agent/log/ExecuteLogUtils.java index c1f9678..624d8c1 100644 --- a/src/main/java/com/wenshuo/agent/log/ExecuteLogUtils.java +++ b/src/main/java/com/wenshuo/agent/log/ExecuteLogUtils.java @@ -2,6 +2,7 @@ * @(#)ExecuteLogUtils.java 2015-7-27 下午05:57:01 javaagent Copyright 2015 wenshuo, Inc. All rights reserved. wenshuo * PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ + package com.wenshuo.agent.log; import java.io.BufferedWriter; @@ -24,6 +25,8 @@ import com.wenshuo.agent.AgentUtils; import com.wenshuo.agent.ConfigUtils; import com.wenshuo.agent.NamedThreadFactory; +import com.wenshuo.agent.applog.AppLogFactory; +import com.wenshuo.agent.applog.IAppLog; /** * ExecuteLogUtils @@ -57,6 +60,8 @@ public class ExecuteLogUtils { private static volatile boolean isInitialized = false; + private static final IAppLog log = AppLogFactory.getAppLog(ExecuteLogUtils.class); + private ExecuteLogUtils() { super(); } @@ -76,7 +81,7 @@ public static synchronized void init() { logAvgExecuteTime = ConfigUtils.isLogAvgExecuteTime(); isUsingNanoTime = ConfigUtils.isUsingNanoTime(); if (AgentUtils.isBlank(logFileName)) { - System.err.println("日志文件名为空"); + log.error("日志文件名为空"); throw new RuntimeException("日志文件名为空"); } setNextDateStartTimeMillis(); @@ -136,7 +141,7 @@ private static void logExecuteCounter(String className, String methodName, long ConcurrentHashMap methodCounterMap = getOrCreateClassExecutesMapping(className); long[] counter = methodCounterMap.get(methodName); if (null == counter) { - methodCounterMap.put(methodName, new long[]{1, executeTime}); + methodCounterMap.put(methodName, new long[] {1, executeTime}); } else { counter[0]++; counter[1] = executeTime + counter[1]; @@ -179,7 +184,7 @@ private static void writeLog(String logValue, boolean newLine, long currTimeMill counterLogWriter.newLine(); } } catch (IOException e) { - System.err.println(e); + log.error(e.getMessage(), e); } } @@ -188,7 +193,7 @@ private static void flushLogAndClose() { try { counterLogWriter.flush(); } catch (IOException e) { - System.err.println(e); + log.error(e.getMessage(), e); } finally { AgentUtils.closeQuietly(counterLogWriter); counterLogWriter = null; @@ -224,7 +229,7 @@ private static void initWriter() { counterLogWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logFile, true), ENCODING), BUFFER_SIZE); } catch (IOException e) { - System.err.println(e); + log.error(e.getMessage(), e); throw new RuntimeException("无法初始化【" + logFileName + "】,建议您检查磁盘空间,或者手动删除该日志文件"); } } @@ -254,7 +259,7 @@ private static File getLogFile(String logFileName) throws IOException { AgentUtils.forceMkdir(dirFile); boolean created = logFile.createNewFile(); if (!created) { - System.err.println("【" + logFileName + "】创建失败"); + log.error("【" + logFileName + "】创建失败"); throw new RuntimeException("【" + logFileName + "】创建失败"); } } @@ -276,7 +281,7 @@ private static Date date2StartTime(Date date) { try { startTime = sdf.parse(dateStr + " 00:00:00"); } catch (ParseException e) { - System.err.println(e); + log.error(e.getMessage(), e); } return startTime; } @@ -313,4 +318,5 @@ private static long removeJSONArrayEndBracket() throws IOException { f.close(); return length; } + } \ No newline at end of file diff --git a/src/main/java/com/wenshuo/agent/log/OutputLogRunnable.java b/src/main/java/com/wenshuo/agent/log/OutputLogRunnable.java index 3a08620..09e4f47 100644 --- a/src/main/java/com/wenshuo/agent/log/OutputLogRunnable.java +++ b/src/main/java/com/wenshuo/agent/log/OutputLogRunnable.java @@ -4,27 +4,28 @@ * Copyright 2015 wenshuo, Inc. All rights reserved. * wenshuo PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ + package com.wenshuo.agent.log; +import com.wenshuo.agent.applog.AppLogFactory; +import com.wenshuo.agent.applog.IAppLog; + /** * OutputLogRunnable - * + * * @author dingjsh * @time 2015-7-28下午03:27:20 */ public class OutputLogRunnable implements Runnable { - /* - * (non-Javadoc) - * - * @see java.lang.Runnable#run() - */ + private static IAppLog log = AppLogFactory.getAppLog(OutputLogRunnable.class); + @Override public void run() { - try{ + try { ExecuteLogUtils.outputCounterLog(); - }catch(Exception e){ - System.err.println(e); + } catch (Exception e) { + log.error(e.getMessage(), e); } } diff --git a/src/main/java/com/wenshuo/agent/transformer/AgentLogClassFileTransformer.java b/src/main/java/com/wenshuo/agent/transformer/AgentLogClassFileTransformer.java index 545b231..6602f06 100644 --- a/src/main/java/com/wenshuo/agent/transformer/AgentLogClassFileTransformer.java +++ b/src/main/java/com/wenshuo/agent/transformer/AgentLogClassFileTransformer.java @@ -1,7 +1,16 @@ package com.wenshuo.agent.transformer; +import java.io.IOException; +import java.lang.instrument.ClassFileTransformer; +import java.security.ProtectionDomain; +import java.util.Collections; +import java.util.Set; +import java.util.regex.Pattern; + import com.wenshuo.agent.ConfigUtils; import com.wenshuo.agent.PojoDetector; +import com.wenshuo.agent.applog.AppLogFactory; +import com.wenshuo.agent.applog.IAppLog; import com.wenshuo.agent.javassist.CannotCompileException; import com.wenshuo.agent.javassist.ClassPool; import com.wenshuo.agent.javassist.CtClass; @@ -9,16 +18,10 @@ import com.wenshuo.agent.javassist.LoaderClassPath; import com.wenshuo.agent.javassist.Modifier; import com.wenshuo.agent.javassist.NotFoundException; -import java.io.IOException; -import java.lang.instrument.ClassFileTransformer; -import java.security.ProtectionDomain; -import java.util.Collections; -import java.util.Set; -import java.util.regex.Pattern; /** * AgentLogClassFileTransformer 类增强,增加agent日志 - * + * * @author dingjsh * @time 2015-7-24上午09:53:44 */ @@ -28,9 +31,10 @@ public class AgentLogClassFileTransformer implements ClassFileTransformer { private static final String AGENT_PACKAGE_NAME = "com.wenshuo.agent"; + private static IAppLog log = AppLogFactory.getAppLog(AgentLogClassFileTransformer.class); public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, - ProtectionDomain protectionDomain, byte[] classfileBuffer) { + ProtectionDomain protectionDomain, byte[] classfileBuffer) { byte[] byteCode = classfileBuffer; className = className.replace('/', '.'); if (!isNeedLogExecuteInfo(className)) { @@ -55,7 +59,7 @@ private byte[] aopLog(ClassLoader loader, String className, byte[] byteCode) { } byteCode = aopLog(cc, className, byteCode); } catch (Exception ex) { - System.err.println(ex); + log.error(ex.getMessage(), ex); } return byteCode; } @@ -91,19 +95,20 @@ private void aopLog(String className, CtMethod m) throws CannotCompileException boolean isMethodStatic = Modifier.isStatic(m.getModifiers()); String aopClassName = isMethodStatic ? "\"" + className + "\"" : "this.getClass().getName()"; final String timeMethodStr - = ConfigUtils.isUsingNanoTime() ? "java.lang.System.nanoTime()" : "java.lang.System.currentTimeMillis()"; + = ConfigUtils.isUsingNanoTime() ? "java.lang.System.nanoTime()" : "java.lang.System.currentTimeMillis" + + "()"; // 避免变量名重复 m.addLocalVariable("dingjsh_javaagent_elapsedTime", CtClass.longType); m.insertBefore("dingjsh_javaagent_elapsedTime = " + timeMethodStr + ";"); m.insertAfter("dingjsh_javaagent_elapsedTime = " + timeMethodStr + " - dingjsh_javaagent_elapsedTime;"); m.insertAfter(LOG_UTILS + ".log(" + aopClassName + ",\"" + m.getName() - + "\",(long)dingjsh_javaagent_elapsedTime" + ");"); + + "\",(long)dingjsh_javaagent_elapsedTime" + ");"); } /** * 是否需要记录执行信息 - * + * * @param className 类名 * @return 是否需要记录执行信息 * @author dingjsh @@ -152,4 +157,5 @@ private boolean isNeedLogExecuteInfo(String className) { } return isNeeded; } + }