transform command: logger

This commit is contained in:
gongdewei 2020-07-14 20:12:57 +08:00
parent 4a48a7b073
commit 40c2c5e039
3 changed files with 174 additions and 106 deletions

View File

@ -1,7 +1,5 @@
package com.taobao.arthas.core.command.logger;
import static com.taobao.text.ui.Element.label;
import java.io.IOException;
import java.io.InputStream;
import java.lang.instrument.Instrumentation;
@ -21,6 +19,7 @@ import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.common.IOUtils;
import com.taobao.arthas.common.ReflectUtils;
import com.taobao.arthas.core.command.Constants;
import com.taobao.arthas.core.command.model.LoggerModel;
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.ClassLoaderUtils;
@ -29,15 +28,11 @@ import com.taobao.middleware.cli.annotations.Description;
import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Option;
import com.taobao.middleware.cli.annotations.Summary;
import com.taobao.text.Decoration;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
/**
* logger command
*
* @author hengyunabc 2019-09-04
*
* @author hengyunabc 2019-09-04
*/
//@formatter:off
@Name("logger")
@ -60,7 +55,7 @@ public class LoggerCommand extends AnnotatedCommand {
private static Map<Class<?>, byte[]> classToBytesMap = new HashMap<Class<?>, byte[]>();
private static String arthasClassLoaderHash = ClassLoaderUtils
.classLoaderHash(LoggerCommand.class.getClassLoader());
.classLoaderHash(LoggerCommand.class.getClassLoader());
static {
LoggerHelperBytes = loadClassBytes(LoggerHelper.class);
@ -111,15 +106,11 @@ public class LoggerCommand extends AnnotatedCommand {
@Override
public void process(CommandProcess process) {
int status = 0;
try {
if (this.name != null && this.level != null) {
level(process);
} else {
loggers(process, name);
}
} finally {
process.end(status);
// 每个分支中调用process.end()结束执行
if (this.name != null && this.level != null) {
level(process);
} else {
loggers(process, name);
}
}
@ -154,9 +145,9 @@ public class LoggerCommand extends AnnotatedCommand {
}
if (result) {
process.write("Update logger level success.\n");
process.end(0, "Update logger level success.");
} else {
process.write("Update logger level fail. Try to specify the classloader with the -c option. Use `sc -d CLASSNAME` to find out the classloader hashcode.\n");
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.");
}
}
@ -194,97 +185,21 @@ public class LoggerCommand extends AnnotatedCommand {
if (loggerTypes.contains(LoggerType.LOG4J)) {
Map<String, Map<String, Object>> loggerInfoMap = loggerInfo(classLoader, Log4jHelper.class);
String renderResult = renderLoggerInfo(loggerInfoMap, process.width());
process.write(renderResult);
process.appendResult(new LoggerModel(loggerInfoMap));
}
if (loggerTypes.contains(LoggerType.LOGBACK)) {
Map<String, Map<String, Object>> loggerInfoMap = loggerInfo(classLoader, LogbackHelper.class);
String renderResult = renderLoggerInfo(loggerInfoMap, process.width());
process.write(renderResult);
process.appendResult(new LoggerModel(loggerInfoMap));
}
if (loggerTypes.contains(LoggerType.LOG4J2)) {
Map<String, Map<String, Object>> loggerInfoMap = loggerInfo(classLoader, Log4j2Helper.class);
String renderResult = renderLoggerInfo(loggerInfoMap, process.width());
process.write(renderResult);
process.appendResult(new LoggerModel(loggerInfoMap));
}
}
}
private String renderLoggerInfo(Map<String, Map<String, Object>> loggerInfos, int width) {
StringBuilder sb = new StringBuilder(8192);
for (Entry<String, Map<String, Object>> entry : loggerInfos.entrySet()) {
Map<String, Object> info = entry.getValue();
TableElement table = new TableElement(2, 10).leftCellPadding(1).rightCellPadding(1);
TableElement appendersTable = new TableElement().rightCellPadding(1);
Class<?> clazz = (Class<?>) info.get(LoggerHelper.clazz);
table.row(label(LoggerHelper.name).style(Decoration.bold.bold()), label("" + info.get(LoggerHelper.name)))
.row(label(LoggerHelper.clazz).style(Decoration.bold.bold()), label("" + clazz.getName()))
.row(label(LoggerHelper.classLoader).style(Decoration.bold.bold()),
label("" + clazz.getClassLoader()))
.row(label(LoggerHelper.classLoaderHash).style(Decoration.bold.bold()),
label("" + StringUtils.classLoaderHash(clazz)))
.row(label(LoggerHelper.level).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.level)));
if (info.get(LoggerHelper.effectiveLevel) != null) {
table.row(label(LoggerHelper.effectiveLevel).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.effectiveLevel)));
}
if (info.get(LoggerHelper.config) != null) {
table.row(label(LoggerHelper.config).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.config)));
}
table.row(label(LoggerHelper.additivity).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.additivity)))
.row(label(LoggerHelper.codeSource).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.codeSource)));
@SuppressWarnings("unchecked")
List<Map<String, Object>> appenders = (List<Map<String, Object>>) info.get(LoggerHelper.appenders);
if (appenders != null && !appenders.isEmpty()) {
for (Map<String, Object> appenderInfo : appenders) {
Class<?> appenderClass = (Class<?>) appenderInfo.get(LoggerHelper.clazz);
appendersTable.row(label(LoggerHelper.name).style(Decoration.bold.bold()),
label("" + appenderInfo.get(LoggerHelper.name)));
appendersTable.row(label(LoggerHelper.clazz), label("" + appenderClass.getName()));
appendersTable.row(label(LoggerHelper.classLoader), label("" + appenderClass.getClassLoader()));
appendersTable.row(label(LoggerHelper.classLoaderHash),
label("" + StringUtils.classLoaderHash(appenderClass)));
if (appenderInfo.get(LoggerHelper.file) != null) {
appendersTable.row(label(LoggerHelper.file), label("" + appenderInfo.get(LoggerHelper.file)));
}
if (appenderInfo.get(LoggerHelper.target) != null) {
appendersTable.row(label(LoggerHelper.target),
label("" + appenderInfo.get(LoggerHelper.target)));
}
if (appenderInfo.get(LoggerHelper.blocking) != null) {
appendersTable.row(label(LoggerHelper.blocking),
label("" + appenderInfo.get(LoggerHelper.blocking)));
}
if (appenderInfo.get(LoggerHelper.appenderRef) != null) {
appendersTable.row(label(LoggerHelper.appenderRef),
label("" + appenderInfo.get(LoggerHelper.appenderRef)));
}
}
table.row(label("appenders").style(Decoration.bold.bold()), appendersTable);
}
sb.append(RenderUtil.render(table, width)).append('\n');
}
return sb.toString();
process.end();
}
private static String helperClassNameWithClassLoader(ClassLoader classLoader, Class<?> helperClass) {
@ -304,25 +219,46 @@ public class LoggerCommand extends AnnotatedCommand {
} catch (ClassNotFoundException e) {
try {
byte[] helperClassBytes = AsmRenameUtil.renameClass(classToBytesMap.get(helperClass),
helperClass.getName(), helperClassName);
helperClass.getName(), helperClassName);
ReflectUtils.defineClass(helperClassName, helperClassBytes, classLoader);
} catch (Throwable e1) {
logger.error("arthas loggger command try to define helper class error: " + helperClassName,
e1);
e1);
}
}
try {
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,
new Object[] { name, includeNoAppender });
new Object[]{name, includeNoAppender});
} catch (Throwable e) {
// ignore
}
//expose attributes to json: classloader, classloaderHash
for (Map<String, Object> loggerInfo : loggers.values()) {
Class clazz = (Class) loggerInfo.get(LoggerHelper.clazz);
loggerInfo.put(LoggerHelper.classLoader, getClassLoaderName(clazz.getClassLoader()));
loggerInfo.put(LoggerHelper.classLoaderHash, StringUtils.classLoaderHash(clazz));
List<Map<String, Object>> appenders = (List<Map<String, Object>>) loggerInfo.get(LoggerHelper.appenders);
for (Map<String, Object> appenderInfo : appenders) {
Class appenderClass = (Class) appenderInfo.get(LoggerHelper.clazz);
if (appenderClass != null) {
appenderInfo.put(LoggerHelper.classLoader, getClassLoaderName(appenderClass.getClassLoader()));
appenderInfo.put(LoggerHelper.classLoaderHash, StringUtils.classLoaderHash(appenderClass));
}
}
}
return loggers;
}
private String getClassLoaderName(ClassLoader classLoader) {
return classLoader == null ? null : classLoader.toString();
}
private Boolean updateLevel(Instrumentation inst, Class<?> helperClass) throws Exception {
ClassLoader classLoader = null;
if (hashCode == null) {
@ -332,8 +268,8 @@ public class LoggerCommand extends AnnotatedCommand {
}
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 });
Method updateLevelMethod = clazz.getMethod("updateLevel", new Class<?>[]{String.class, String.class});
return (Boolean) updateLevelMethod.invoke(null, new Object[]{this.name, this.level});
}
@ -360,7 +296,7 @@ public class LoggerCommand extends AnnotatedCommand {
private static byte[] loadClassBytes(Class<?> clazz) {
try {
InputStream stream = LoggerCommand.class.getClassLoader()
.getResourceAsStream(clazz.getName().replace('.', '/') + ".class");
.getResourceAsStream(clazz.getName().replace('.', '/') + ".class");
return IOUtils.getBytes(stream);
} catch (IOException e) {

View File

@ -0,0 +1,34 @@
package com.taobao.arthas.core.command.model;
import java.util.Map;
/**
* Model of logger command
*
* @author gongdewei 2020/4/22
*/
public class LoggerModel extends ResultModel {
private Map<String, Map<String, Object>> loggerInfoMap;
public LoggerModel() {
}
public LoggerModel(Map<String, Map<String, Object>> loggerInfoMap) {
this.loggerInfoMap = loggerInfoMap;
}
public Map<String, Map<String, Object>> getLoggerInfoMap() {
return loggerInfoMap;
}
public void setLoggerInfoMap(Map<String, Map<String, Object>> loggerInfoMap) {
this.loggerInfoMap = loggerInfoMap;
}
@Override
public String getType() {
return "logger";
}
}

View File

@ -0,0 +1,98 @@
package com.taobao.arthas.core.command.view;
import com.taobao.arthas.core.command.logger.LoggerHelper;
import com.taobao.arthas.core.command.model.LoggerModel;
import com.taobao.arthas.core.shell.command.CommandProcess;
import com.taobao.arthas.core.util.StringUtils;
import com.taobao.text.Decoration;
import com.taobao.text.ui.TableElement;
import com.taobao.text.util.RenderUtil;
import java.util.List;
import java.util.Map;
import static com.taobao.text.ui.Element.label;
/**
* View of 'logger' command
*
* @author gongdewei 2020/4/22
*/
public class LoggerView extends ResultView<LoggerModel> {
@Override
public void draw(CommandProcess process, LoggerModel result) {
process.write(renderLoggerInfo(result.getLoggerInfoMap(), process.width()));
}
private String renderLoggerInfo(Map<String, Map<String, Object>> loggerInfos, int width) {
StringBuilder sb = new StringBuilder(8192);
for (Map.Entry<String, Map<String, Object>> entry : loggerInfos.entrySet()) {
Map<String, Object> info = entry.getValue();
TableElement table = new TableElement(2, 10).leftCellPadding(1).rightCellPadding(1);
TableElement appendersTable = new TableElement().rightCellPadding(1);
Class<?> clazz = (Class<?>) info.get(LoggerHelper.clazz);
table.row(label(LoggerHelper.name).style(Decoration.bold.bold()), label("" + info.get(LoggerHelper.name)))
.row(label(LoggerHelper.clazz).style(Decoration.bold.bold()), label("" + clazz.getName()))
.row(label(LoggerHelper.classLoader).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.classLoader)))
.row(label(LoggerHelper.classLoaderHash).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.classLoaderHash)))
.row(label(LoggerHelper.level).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.level)));
if (info.get(LoggerHelper.effectiveLevel) != null) {
table.row(label(LoggerHelper.effectiveLevel).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.effectiveLevel)));
}
if (info.get(LoggerHelper.config) != null) {
table.row(label(LoggerHelper.config).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.config)));
}
table.row(label(LoggerHelper.additivity).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.additivity)))
.row(label(LoggerHelper.codeSource).style(Decoration.bold.bold()),
label("" + info.get(LoggerHelper.codeSource)));
@SuppressWarnings("unchecked")
List<Map<String, Object>> appenders = (List<Map<String, Object>>) info.get(LoggerHelper.appenders);
if (appenders != null && !appenders.isEmpty()) {
for (Map<String, Object> appenderInfo : appenders) {
Class<?> appenderClass = (Class<?>) appenderInfo.get(LoggerHelper.clazz);
appendersTable.row(label(LoggerHelper.name).style(Decoration.bold.bold()),
label("" + appenderInfo.get(LoggerHelper.name)));
appendersTable.row(label(LoggerHelper.clazz), label("" + appenderClass.getName()));
appendersTable.row(label(LoggerHelper.classLoader), label("" + info.get(LoggerHelper.classLoader)));
appendersTable.row(label(LoggerHelper.classLoaderHash),
label("" + info.get(LoggerHelper.classLoaderHash)));
if (appenderInfo.get(LoggerHelper.file) != null) {
appendersTable.row(label(LoggerHelper.file), label("" + appenderInfo.get(LoggerHelper.file)));
}
if (appenderInfo.get(LoggerHelper.target) != null) {
appendersTable.row(label(LoggerHelper.target),
label("" + appenderInfo.get(LoggerHelper.target)));
}
if (appenderInfo.get(LoggerHelper.blocking) != null) {
appendersTable.row(label(LoggerHelper.blocking),
label("" + appenderInfo.get(LoggerHelper.blocking)));
}
if (appenderInfo.get(LoggerHelper.appenderRef) != null) {
appendersTable.row(label(LoggerHelper.appenderRef),
label("" + appenderInfo.get(LoggerHelper.appenderRef)));
}
}
table.row(label("appenders").style(Decoration.bold.bold()), appendersTable);
}
sb.append(RenderUtil.render(table, width)).append('\n');
}
return sb.toString();
}
}