improve logger command detect log type. #2269

pull/2286/head
hengyunabc 2 years ago
parent b18fb08866
commit 6762a22f84

@ -115,6 +115,28 @@ public class LoggerCommand extends AnnotatedCommand {
@Override @Override
public void process(CommandProcess process) { public void process(CommandProcess process) {
// 所有代码都用 hashCode 来定位classloader如果有指定 classLoaderClass则尝试用 classLoaderClass 找到对应 classloader 的 hashCode
if (hashCode == null && classLoaderClass != null) {
Instrumentation inst = process.session().getInstrumentation();
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst,
classLoaderClass);
if (matchedClassLoaders.size() == 1) {
hashCode = Integer.toHexString(matchedClassLoaders.get(0).hashCode());
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils
.createClassLoaderVOList(matchedClassLoaders);
LoggerModel loggerModel = new LoggerModel().setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(loggerModel);
process.end(-1,
"Found more than one classloader by class name, please specify classloader with '-c <classloader hash>'");
return;
} else {
process.end(-1, "Can not find classloader by class name: " + classLoaderClass + ".");
return;
}
}
// 每个分支中调用process.end()结束执行 // 每个分支中调用process.end()结束执行
if (this.name != null && this.level != null) { if (this.name != null && this.level != null) {
level(process); level(process);
@ -126,66 +148,67 @@ public class LoggerCommand extends AnnotatedCommand {
public void level(CommandProcess process) { public void level(CommandProcess process) {
Instrumentation inst = process.session().getInstrumentation(); Instrumentation inst = process.session().getInstrumentation();
boolean result = false; boolean result = false;
// 如果不指定 classloader则默认用 SystemClassLoader
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
if (hashCode != null) {
classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode);
if (classLoader == null) {
process.end(-1, "Can not find classloader by hashCode: " + hashCode + ".");
return;
}
}
LoggerTypes loggerTypes = findLoggerTypes(process.session().getInstrumentation(), classLoader);
if (loggerTypes.contains(LoggerType.LOG4J)) {
try { try {
Boolean updateResult = this.updateLevel(inst, Log4jHelper.class); Boolean updateResult = this.updateLevel(inst, classLoader, Log4jHelper.class);
if (Boolean.TRUE.equals(updateResult)) { if (Boolean.TRUE.equals(updateResult)) {
result = true; result = true;
} }
} catch (Throwable e) { } catch (Throwable e) {
logger.error("logger command update log4j level error", e); logger.error("logger command update log4j level error", e);
} }
}
if (loggerTypes.contains(LoggerType.LOGBACK)) {
try { try {
Boolean updateResult = this.updateLevel(inst, LogbackHelper.class); Boolean updateResult = this.updateLevel(inst, classLoader, LogbackHelper.class);
if (Boolean.TRUE.equals(updateResult)) { if (Boolean.TRUE.equals(updateResult)) {
result = true; result = true;
} }
} catch (Throwable e) { } catch (Throwable e) {
logger.error("logger command update logback level error", e); logger.error("logger command update logback level error", e);
} }
}
if (loggerTypes.contains(LoggerType.LOG4J2)) {
try { try {
Boolean updateResult = this.updateLevel(inst, Log4j2Helper.class); Boolean updateResult = this.updateLevel(inst, classLoader, Log4j2Helper.class);
if (Boolean.TRUE.equals(updateResult)) { if (Boolean.TRUE.equals(updateResult)) {
result = true; result = true;
} }
} catch (Throwable e) { } catch (Throwable e) {
logger.error("logger command update log4j2 level error", e); logger.error("logger command update log4j2 level error", e);
} }
}
if (result) { if (result) {
process.end(0, "Update logger level success."); process.end(0, "Update logger level success.");
} else { } else {
process.end(-1, "Update logger level fail. Try to specify the classloader with the -c option. Use `sc -d CLASSNAME` to find out the classloader hashcode."); process.end(-1,
"Update logger level fail. Try to specify the classloader with the -c option. Use `sc -d CLASSNAME` to find out the classloader hashcode.");
} }
} }
public void loggers(CommandProcess process) { public void loggers(CommandProcess process) {
Map<ClassLoader, LoggerTypes> classLoaderLoggerMap = new LinkedHashMap<ClassLoader, LoggerTypes>(); Map<ClassLoader, LoggerTypes> classLoaderLoggerMap = new LinkedHashMap<ClassLoader, LoggerTypes>();
// 如果不指定 classloader则打印所有 classloader 里的 logger 信息
for (Class<?> clazz : process.session().getInstrumentation().getAllLoadedClasses()) { for (Class<?> clazz : process.session().getInstrumentation().getAllLoadedClasses()) {
String className = clazz.getName(); String className = clazz.getName();
ClassLoader classLoader = clazz.getClassLoader(); ClassLoader classLoader = clazz.getClassLoader();
if (hashCode == null && classLoaderClass != null) {
Instrumentation inst = process.session().getInstrumentation();
List<ClassLoader> matchedClassLoaders = ClassLoaderUtils.getClassLoaderByClassName(inst, classLoaderClass);
if (matchedClassLoaders.size() == 1) {
hashCode = Integer.toHexString(matchedClassLoaders.get(0).hashCode());
} else if (matchedClassLoaders.size() > 1) {
Collection<ClassLoaderVO> classLoaderVOList = ClassUtils.createClassLoaderVOList(matchedClassLoaders);
LoggerModel loggerModel = new LoggerModel()
.setClassLoaderClass(classLoaderClass)
.setMatchedClassLoaders(classLoaderVOList);
process.appendResult(loggerModel);
process.end(-1, "Found more than one classloader by class name, please specify classloader with '-c <classloader hash>'");
return;
} else {
process.end(-1, "Can not find classloader by class name: " + classLoaderClass + ".");
return;
}
}
// if special classloader // if special classloader
if (this.hashCode != null && !this.hashCode.equals(StringUtils.classLoaderHash(clazz))) { if (this.hashCode != null && !this.hashCode.equals(StringUtils.classLoaderHash(clazz))) {
continue; continue;
@ -197,13 +220,7 @@ public class LoggerCommand extends AnnotatedCommand {
loggerTypes = new LoggerTypes(); loggerTypes = new LoggerTypes();
classLoaderLoggerMap.put(classLoader, loggerTypes); classLoaderLoggerMap.put(classLoader, loggerTypes);
} }
if ("org.apache.log4j.Logger".equals(className)) { updateLoggerType(loggerTypes, classLoader, className);
loggerTypes.addType(LoggerType.LOG4J);
} else if ("ch.qos.logback.classic.Logger".equals(className)) {
loggerTypes.addType(LoggerType.LOGBACK);
} else if ("org.apache.logging.log4j.Logger".equals(className)) {
loggerTypes.addType(LoggerType.LOG4J2);
}
} }
} }
@ -230,33 +247,72 @@ public class LoggerCommand extends AnnotatedCommand {
process.end(); process.end();
} }
private static String helperClassNameWithClassLoader(ClassLoader classLoader, Class<?> helperClass) { private LoggerTypes findLoggerTypes(Instrumentation inst, ClassLoader classLoader) {
LoggerTypes loggerTypes = new LoggerTypes();
for (Class<?> clazz : inst.getAllLoadedClasses()) {
if(classLoader == clazz.getClassLoader()) {
updateLoggerType(loggerTypes, classLoader, clazz.getName());
}
}
return loggerTypes;
}
private void updateLoggerType(LoggerTypes loggerTypes, ClassLoader classLoader, String className) {
if ("org.apache.log4j.Logger".equals(className)) {
// 判断 org.apache.log4j.AsyncAppender 是否存在,如果存在则是 log4j不是slf4j-over-log4j
try {
if (classLoader.getResource("org/apache/log4j/AsyncAppender.class") != null) {
loggerTypes.addType(LoggerType.LOG4J);
}
} catch (Throwable e) {
// ignore
}
} else if ("ch.qos.logback.classic.Logger".equals(className)) {
try {
if (classLoader.getResource("ch/qos/logback/core/Appender.class") != null) {
loggerTypes.addType(LoggerType.LOGBACK);
}
} catch (Throwable e) {
// ignore
}
} else if ("org.apache.logging.log4j.Logger".equals(className)) {
try {
if (classLoader.getResource("org/apache/logging/log4j/core/LoggerContext.class") != null) {
loggerTypes.addType(LoggerType.LOG4J2);
}
} catch (Throwable e) {
// ignore
}
}
}
private static Class<?> helperClassNameWithClassLoader(ClassLoader classLoader, Class<?> helperClass) {
String classLoaderHash = ClassLoaderUtils.classLoaderHash(classLoader); String classLoaderHash = ClassLoaderUtils.classLoaderHash(classLoader);
String className = helperClass.getName(); String className = helperClass.getName();
// if want to debug, change to return className // if want to debug, change to return className
return className + arthasClassLoaderHash + classLoaderHash; String helperClassName = 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 { try {
classLoader.loadClass(helperClassName); return classLoader.loadClass(helperClassName);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
try { try {
byte[] helperClassBytes = AsmRenameUtil.renameClass(classToBytesMap.get(helperClass), byte[] helperClassBytes = AsmRenameUtil.renameClass(classToBytesMap.get(helperClass),
helperClass.getName(), helperClassName); helperClass.getName(), helperClassName);
ReflectUtils.defineClass(helperClassName, helperClassBytes, classLoader); return ReflectUtils.defineClass(helperClassName, helperClassBytes, classLoader);
} catch (Throwable e1) { } catch (Throwable e1) {
logger.error("arthas loggger command try to define helper class error: " + helperClassName, logger.error("arthas loggger command try to define helper class error: " + helperClassName,
e1); e1);
} }
} }
return null;
}
@SuppressWarnings("unchecked")
private Map<String, Map<String, Object>> loggerInfo(ClassLoader classLoader, Class<?> helperClass) {
Map<String, Map<String, Object>> loggers = Collections.emptyMap();
try { try {
Class<?> clazz = classLoader.loadClass(helperClassName); Class<?> clazz = helperClassNameWithClassLoader(classLoader, helperClass);
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});
@ -287,18 +343,10 @@ public class LoggerCommand extends AnnotatedCommand {
return classLoader == null ? null : classLoader.toString(); return classLoader == null ? null : classLoader.toString();
} }
private Boolean updateLevel(Instrumentation inst, Class<?> helperClass) throws Exception { private Boolean updateLevel(Instrumentation inst, ClassLoader classLoader, Class<?> helperClass) throws Exception {
ClassLoader classLoader = null; Class<?> clazz = helperClassNameWithClassLoader(classLoader, helperClass);
if (hashCode == null) {
classLoader = ClassLoader.getSystemClassLoader();
} else {
classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode);
}
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});
} }
static enum LoggerType { static enum LoggerType {

Loading…
Cancel
Save