fix logger command print parent ClassLoader result problem. #870

pull/882/head
hengyunabc 5 years ago
parent 7950027113
commit f9e698d09c

@ -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.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.config.LoggerConfig;
import com.taobao.arthas.core.util.StringUtils;
/** /**
* *
* @author hengyunabc 2019-09-20 * @author hengyunabc 2019-09-20
@ -30,7 +32,7 @@ public class Log4j2Helper {
static { static {
try { try {
Class<?> loggerClass = Class.forName("org.apache.logging.log4j.Logger"); Class<?> loggerClass = Log4j2Helper.class.getClassLoader().loadClass("org.apache.logging.log4j.Logger");
// 这里可能会加载到其它上游ClassLoader的log4j2因此需要判断是否当前classloader // 这里可能会加载到其它上游ClassLoader的log4j2因此需要判断是否当前classloader
if (loggerClass.getClassLoader().equals(Log4j2Helper.class.getClassLoader())) { if (loggerClass.getClassLoader().equals(Log4j2Helper.class.getClassLoader())) {
Log4j2 = true; Log4j2 = true;
@ -93,6 +95,10 @@ public class Log4j2Helper {
if (loggerConfig == null) { if (loggerConfig == null) {
return loggerInfoMap; return loggerInfoMap;
} }
// 排掉非root时获取到root的logger config
if (!name.equalsIgnoreCase(LoggerConfig.ROOT) && StringUtils.isEmpty(loggerConfig.getName())) {
return loggerInfoMap;
}
loggerInfoMap.put(name, doGetLoggerInfo(loggerConfig)); loggerInfoMap.put(name, doGetLoggerInfo(loggerConfig));
} else { } else {
// 获取所有logger时如果没有appender则忽略 // 获取所有logger时如果没有appender则忽略

@ -26,7 +26,7 @@ public class Log4jHelper {
static { static {
try { try {
Class<?> loggerClass = Class.forName("org.apache.log4j.Logger"); Class<?> loggerClass = Log4jHelper.class.getClassLoader().loadClass("org.apache.log4j.Logger");
// 这里可能会加载到其它上游ClassLoader的log4j因此需要判断是否当前classloader // 这里可能会加载到其它上游ClassLoader的log4j因此需要判断是否当前classloader
if (loggerClass.getClassLoader().equals(Log4jHelper.class.getClassLoader())) { if (loggerClass.getClassLoader().equals(Log4jHelper.class.getClassLoader())) {
Log4j = true; Log4j = true;
@ -129,6 +129,10 @@ public class Log4jHelper {
private static List<Map<String, Object>> doGetLoggerAppenders(Enumeration<Appender> appenders) { private static List<Map<String, Object>> doGetLoggerAppenders(Enumeration<Appender> appenders) {
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>(); List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
if (appenders == null) {
return result;
}
while (appenders.hasMoreElements()) { while (appenders.hasMoreElements()) {
Map<String, Object> info = new HashMap<String, Object>(); Map<String, Object> info = new HashMap<String, Object>();
Appender appender = appenders.nextElement(); Appender appender = appenders.nextElement();
@ -143,7 +147,9 @@ public class Log4jHelper {
info.put(LoggerHelper.target, ((ConsoleAppender) appender).getTarget()); info.put(LoggerHelper.target, ((ConsoleAppender) appender).getTarget());
} else if (appender instanceof AsyncAppender) { } else if (appender instanceof AsyncAppender) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<Map<String, Object>> asyncs = doGetLoggerAppenders(((AsyncAppender) appender).getAllAppenders()); Enumeration<Appender> appendersOfAsync = ((AsyncAppender) appender).getAllAppenders();
if (appendersOfAsync != null) {
List<Map<String, Object>> asyncs = doGetLoggerAppenders(appendersOfAsync);
// 标明异步appender // 标明异步appender
List<String> appenderRef = new ArrayList<String>(); List<String> appenderRef = new ArrayList<String>();
for (Map<String, Object> a : asyncs) { for (Map<String, Object> a : asyncs) {
@ -154,6 +160,7 @@ public class Log4jHelper {
info.put(LoggerHelper.appenderRef, appenderRef); info.put(LoggerHelper.appenderRef, appenderRef);
} }
} }
}
return result; return result;
} }

@ -34,7 +34,7 @@ public class LogbackHelper {
static { static {
try { try {
Class<?> loggerClass = Class.forName("ch.qos.logback.classic.Logger"); Class<?> loggerClass = LogbackHelper.class.getClassLoader().loadClass("ch.qos.logback.classic.Logger");
// 这里可能会加载到应用中依赖的logback因此需要判断classloader // 这里可能会加载到应用中依赖的logback因此需要判断classloader
if (loggerClass.getClassLoader().equals(LogbackHelper.class.getClassLoader())) { if (loggerClass.getClassLoader().equals(LogbackHelper.class.getClassLoader())) {
ILoggerFactory loggerFactory = org.slf4j.LoggerFactory.getILoggerFactory(); ILoggerFactory loggerFactory = org.slf4j.LoggerFactory.getILoggerFactory();

@ -41,8 +41,8 @@ import com.taobao.text.util.RenderUtil;
*/ */
@Name("logger") @Name("logger")
@Summary("Print logger info, and update the logger level") @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" @Description("\nExamples:\n" + " logger\n" + " logger -c 327a647b\n"
+ Constants.WIKI + Constants.WIKI_HOME + "logger") + " logger -c 327a647b --name ROOT --level debug\n" + Constants.WIKI + Constants.WIKI_HOME + "logger")
public class LoggerCommand extends AnnotatedCommand { public class LoggerCommand extends AnnotatedCommand {
private static final Logger logger = LogUtil.getArthasLogger(); 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 Map<Class<?>, byte[]> classToBytesMap = new HashMap<Class<?>, byte[]>();
private static String arthasClassLoaderHash = ClassLoaderUtils
.classLoaderHash(LoggerCommand.class.getClassLoader());
static { static {
LoggerHelperBytes = loadClassBytes(LoggerHelper.class); LoggerHelperBytes = loadClassBytes(LoggerHelper.class);
Log4jHelperBytes = loadClassBytes(Log4jHelper.class); Log4jHelperBytes = loadClassBytes(Log4jHelper.class);
@ -278,7 +281,8 @@ public class LoggerCommand extends AnnotatedCommand {
label("" + appenderInfo.get(LoggerHelper.target))); label("" + appenderInfo.get(LoggerHelper.target)));
} }
if (appenderInfo.get(LoggerHelper.blocking) != null) { 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) { if (appenderInfo.get(LoggerHelper.appenderRef) != null) {
appendersTable.row(label(LoggerHelper.appenderRef), appendersTable.row(label(LoggerHelper.appenderRef),
@ -294,21 +298,33 @@ public class LoggerCommand extends AnnotatedCommand {
return sb.toString(); 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") @SuppressWarnings("unchecked")
private Map<String, Map<String, Object>> loggerInfo(ClassLoader classLoader, Class<?> helperClass) { private Map<String, Map<String, Object>> loggerInfo(ClassLoader classLoader, Class<?> helperClass) {
Map<String, Map<String, Object>> loggers = Collections.emptyMap(); Map<String, Map<String, Object>> loggers = Collections.emptyMap();
String helperClassName = helperClassNameWithClassLoader(classLoader, helperClass);
try { try {
classLoader.loadClass(helperClass.getName()); classLoader.loadClass(helperClassName);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
try { try {
ReflectUtils.defineClass(helperClass.getName(), classToBytesMap.get(helperClass), classLoader); byte[] helperClassBytes = AsmRenameUtil.renameClass(classToBytesMap.get(helperClass),
} catch (Exception e1) { helperClass.getName(), helperClassName);
// ignore ReflectUtils.defineClass(helperClassName, helperClassBytes, classLoader);
} catch (Throwable e1) {
logger.error("arthas", "arthas loggger command try to define helper class error: " + helperClassName,
e1);
} }
} }
try { try {
Class<?> clazz = classLoader.loadClass(helperClass.getName()); Class<?> clazz = classLoader.loadClass(helperClassName);
Method getLoggersMethod = clazz.getMethod("getLoggers", new Class<?>[] { String.class, boolean.class }); Method getLoggersMethod = clazz.getMethod("getLoggers", new Class<?>[] { String.class, boolean.class });
loggers = (Map<String, Map<String, Object>>) getLoggersMethod.invoke(null, loggers = (Map<String, Map<String, Object>>) getLoggersMethod.invoke(null,
new Object[] { name, includeNoAppender }); new Object[] { name, includeNoAppender });
@ -326,7 +342,7 @@ public class LoggerCommand extends AnnotatedCommand {
classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode); 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 }); Method updateLevelMethod = clazz.getMethod("updateLevel", new Class<?>[] { String.class, String.class });
return (Boolean) updateLevelMethod.invoke(null, new Object[] { this.name, this.level }); return (Boolean) updateLevelMethod.invoke(null, new Object[] { this.name, this.level });

@ -38,4 +38,20 @@ public class ClassLoaderUtils {
} }
return null; 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);
}
} }

Loading…
Cancel
Save