mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
fix logger command print parent ClassLoader result problem. #870
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package com.taobao.arthas.core.command.logger;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.commons.ClassRemapper;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
import org.objectweb.asm.commons.SimpleRemapper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2019-09-23
|
||||
*
|
||||
*/
|
||||
public class AsmRenameUtil {
|
||||
|
||||
public static byte[] renameClass(byte[] bytes, final String oldName, final String newName) {
|
||||
ClassReader reader = new ClassReader(bytes);
|
||||
ClassWriter writer = new ClassWriter(reader, 0);
|
||||
|
||||
final String internalOldName = oldName.replace('.', '/');
|
||||
final String internalNewName = newName.replace('.', '/');
|
||||
// ClassVisitor visitor = new ClassRemapper(writer, new Remapper() {
|
||||
//
|
||||
// @Override
|
||||
// public String mapType(String internalName) {
|
||||
// if (internalName.equals(internalOldName)) {
|
||||
// return internalNewName;
|
||||
// } else {
|
||||
// return super.mapType(internalName);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// });
|
||||
|
||||
ClassVisitor visitor = new ClassRemapper(writer, new SimpleRemapper(internalOldName, internalNewName));
|
||||
|
||||
|
||||
reader.accept(visitor, 0);
|
||||
return writer.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import org.apache.logging.log4j.core.appender.FileAppender;
|
||||
import org.apache.logging.log4j.core.config.Configuration;
|
||||
import org.apache.logging.log4j.core.config.LoggerConfig;
|
||||
|
||||
import com.taobao.arthas.core.util.StringUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2019-09-20
|
||||
@@ -30,12 +32,12 @@ public class Log4j2Helper {
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> loggerClass = Class.forName("org.apache.logging.log4j.Logger");
|
||||
Class<?> loggerClass = Log4j2Helper.class.getClassLoader().loadClass("org.apache.logging.log4j.Logger");
|
||||
// 这里可能会加载到其它上游ClassLoader的log4j2,因此需要判断是否当前classloader
|
||||
if (loggerClass.getClassLoader().equals(Log4j2Helper.class.getClassLoader())) {
|
||||
Log4j2 = true;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
configField = LoggerConfig.class.getDeclaredField("config");
|
||||
configField.setAccessible(true);
|
||||
@@ -93,6 +95,10 @@ public class Log4j2Helper {
|
||||
if (loggerConfig == null) {
|
||||
return loggerInfoMap;
|
||||
}
|
||||
// 排掉非root时,获取到root的logger config
|
||||
if (!name.equalsIgnoreCase(LoggerConfig.ROOT) && StringUtils.isEmpty(loggerConfig.getName())) {
|
||||
return loggerInfoMap;
|
||||
}
|
||||
loggerInfoMap.put(name, doGetLoggerInfo(loggerConfig));
|
||||
} else {
|
||||
// 获取所有logger时,如果没有appender则忽略
|
||||
@@ -116,7 +122,7 @@ public class Log4j2Helper {
|
||||
|
||||
private static Object getConfigField(LoggerConfig loggerConfig) {
|
||||
try {
|
||||
if(configField != null) {
|
||||
if (configField != null) {
|
||||
return configField.get(loggerConfig);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
@@ -143,7 +149,7 @@ public class Log4j2Helper {
|
||||
if (config != null) {
|
||||
info.put(LoggerHelper.config, config);
|
||||
}
|
||||
|
||||
|
||||
info.put(LoggerHelper.additivity, loggerConfig.isAdditive());
|
||||
|
||||
Level level = loggerConfig.getLevel();
|
||||
|
||||
@@ -26,7 +26,7 @@ public class Log4jHelper {
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> loggerClass = Class.forName("org.apache.log4j.Logger");
|
||||
Class<?> loggerClass = Log4jHelper.class.getClassLoader().loadClass("org.apache.log4j.Logger");
|
||||
// 这里可能会加载到其它上游ClassLoader的log4j,因此需要判断是否当前classloader
|
||||
if (loggerClass.getClassLoader().equals(Log4jHelper.class.getClassLoader())) {
|
||||
Log4j = true;
|
||||
@@ -129,6 +129,10 @@ public class Log4jHelper {
|
||||
private static List<Map<String, Object>> doGetLoggerAppenders(Enumeration<Appender> appenders) {
|
||||
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
||||
|
||||
if (appenders == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
while (appenders.hasMoreElements()) {
|
||||
Map<String, Object> info = new HashMap<String, Object>();
|
||||
Appender appender = appenders.nextElement();
|
||||
@@ -143,15 +147,18 @@ public class Log4jHelper {
|
||||
info.put(LoggerHelper.target, ((ConsoleAppender) appender).getTarget());
|
||||
} else if (appender instanceof AsyncAppender) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> asyncs = doGetLoggerAppenders(((AsyncAppender) appender).getAllAppenders());
|
||||
// 标明异步appender
|
||||
List<String> appenderRef = new ArrayList<String>();
|
||||
for (Map<String, Object> a : asyncs) {
|
||||
appenderRef.add((String) a.get(LoggerHelper.name));
|
||||
result.add(a);
|
||||
Enumeration<Appender> appendersOfAsync = ((AsyncAppender) appender).getAllAppenders();
|
||||
if (appendersOfAsync != null) {
|
||||
List<Map<String, Object>> asyncs = doGetLoggerAppenders(appendersOfAsync);
|
||||
// 标明异步appender
|
||||
List<String> appenderRef = new ArrayList<String>();
|
||||
for (Map<String, Object> a : asyncs) {
|
||||
appenderRef.add((String) a.get(LoggerHelper.name));
|
||||
result.add(a);
|
||||
}
|
||||
info.put(LoggerHelper.blocking, ((AsyncAppender) appender).getBlocking());
|
||||
info.put(LoggerHelper.appenderRef, appenderRef);
|
||||
}
|
||||
info.put(LoggerHelper.blocking, ((AsyncAppender) appender).getBlocking());
|
||||
info.put(LoggerHelper.appenderRef, appenderRef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ public class LogbackHelper {
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> loggerClass = Class.forName("ch.qos.logback.classic.Logger");
|
||||
Class<?> loggerClass = LogbackHelper.class.getClassLoader().loadClass("ch.qos.logback.classic.Logger");
|
||||
// 这里可能会加载到应用中依赖的logback,因此需要判断classloader
|
||||
if (loggerClass.getClassLoader().equals(LogbackHelper.class.getClassLoader())) {
|
||||
ILoggerFactory loggerFactory = org.slf4j.LoggerFactory.getILoggerFactory();
|
||||
|
||||
@@ -41,8 +41,8 @@ import com.taobao.text.util.RenderUtil;
|
||||
*/
|
||||
@Name("logger")
|
||||
@Summary("Print logger info, and update the logger level")
|
||||
@Description("\nExamples:\n" + " logger\n" + " logger -c 327a647b\n" + " logger -c 327a647b --name ROOT --level debug\n"
|
||||
+ Constants.WIKI + Constants.WIKI_HOME + "logger")
|
||||
@Description("\nExamples:\n" + " logger\n" + " logger -c 327a647b\n"
|
||||
+ " logger -c 327a647b --name ROOT --level debug\n" + Constants.WIKI + Constants.WIKI_HOME + "logger")
|
||||
public class LoggerCommand extends AnnotatedCommand {
|
||||
private static final Logger logger = LogUtil.getArthasLogger();
|
||||
|
||||
@@ -53,6 +53,9 @@ public class LoggerCommand extends AnnotatedCommand {
|
||||
|
||||
private static Map<Class<?>, byte[]> classToBytesMap = new HashMap<Class<?>, byte[]>();
|
||||
|
||||
private static String arthasClassLoaderHash = ClassLoaderUtils
|
||||
.classLoaderHash(LoggerCommand.class.getClassLoader());
|
||||
|
||||
static {
|
||||
LoggerHelperBytes = loadClassBytes(LoggerHelper.class);
|
||||
Log4jHelperBytes = loadClassBytes(Log4jHelper.class);
|
||||
@@ -278,7 +281,8 @@ public class LoggerCommand extends AnnotatedCommand {
|
||||
label("" + appenderInfo.get(LoggerHelper.target)));
|
||||
}
|
||||
if (appenderInfo.get(LoggerHelper.blocking) != null) {
|
||||
appendersTable.row(label(LoggerHelper.blocking), label("" + appenderInfo.get(LoggerHelper.blocking)));
|
||||
appendersTable.row(label(LoggerHelper.blocking),
|
||||
label("" + appenderInfo.get(LoggerHelper.blocking)));
|
||||
}
|
||||
if (appenderInfo.get(LoggerHelper.appenderRef) != null) {
|
||||
appendersTable.row(label(LoggerHelper.appenderRef),
|
||||
@@ -294,21 +298,33 @@ public class LoggerCommand extends AnnotatedCommand {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String helperClassNameWithClassLoader(ClassLoader classLoader, Class<?> helperClass) {
|
||||
String classLoaderHash = ClassLoaderUtils.classLoaderHash(classLoader);
|
||||
String className = helperClass.getName();
|
||||
// if want to debug, change to return className
|
||||
return className + arthasClassLoaderHash + classLoaderHash;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Map<String, Object>> loggerInfo(ClassLoader classLoader, Class<?> helperClass) {
|
||||
Map<String, Map<String, Object>> loggers = Collections.emptyMap();
|
||||
|
||||
String helperClassName = helperClassNameWithClassLoader(classLoader, helperClass);
|
||||
try {
|
||||
classLoader.loadClass(helperClass.getName());
|
||||
classLoader.loadClass(helperClassName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
ReflectUtils.defineClass(helperClass.getName(), classToBytesMap.get(helperClass), classLoader);
|
||||
} catch (Exception e1) {
|
||||
// ignore
|
||||
byte[] helperClassBytes = AsmRenameUtil.renameClass(classToBytesMap.get(helperClass),
|
||||
helperClass.getName(), helperClassName);
|
||||
ReflectUtils.defineClass(helperClassName, helperClassBytes, classLoader);
|
||||
} catch (Throwable e1) {
|
||||
logger.error("arthas", "arthas loggger command try to define helper class error: " + helperClassName,
|
||||
e1);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Class<?> clazz = classLoader.loadClass(helperClass.getName());
|
||||
Class<?> clazz = classLoader.loadClass(helperClassName);
|
||||
Method getLoggersMethod = clazz.getMethod("getLoggers", new Class<?>[] { String.class, boolean.class });
|
||||
loggers = (Map<String, Map<String, Object>>) getLoggersMethod.invoke(null,
|
||||
new Object[] { name, includeNoAppender });
|
||||
@@ -326,7 +342,7 @@ public class LoggerCommand extends AnnotatedCommand {
|
||||
classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode);
|
||||
}
|
||||
|
||||
Class<?> clazz = classLoader.loadClass(helperClass.getName());
|
||||
Class<?> clazz = classLoader.loadClass(helperClassNameWithClassLoader(classLoader, helperClass));
|
||||
Method updateLevelMethod = clazz.getMethod("updateLevel", new Class<?>[] { String.class, String.class });
|
||||
return (Boolean) updateLevelMethod.invoke(null, new Object[] { this.name, this.level });
|
||||
|
||||
|
||||
@@ -38,4 +38,20 @@ public class ClassLoaderUtils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String classLoaderHash(ClassLoader classLoader) {
|
||||
int hashCode = 0;
|
||||
if (classLoader == null) {
|
||||
hashCode = System.identityHashCode(classLoader);
|
||||
} else {
|
||||
hashCode = classLoader.hashCode();
|
||||
}
|
||||
if (hashCode <= 0) {
|
||||
hashCode = System.identityHashCode(classLoader);
|
||||
if (hashCode < 0) {
|
||||
hashCode = -hashCode;
|
||||
}
|
||||
}
|
||||
return Integer.toHexString(hashCode);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user