mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
add logger command. #736
This commit is contained in:
@@ -26,6 +26,7 @@ import com.taobao.arthas.core.command.klass100.OgnlCommand;
|
||||
import com.taobao.arthas.core.command.klass100.RedefineCommand;
|
||||
import com.taobao.arthas.core.command.klass100.SearchClassCommand;
|
||||
import com.taobao.arthas.core.command.klass100.SearchMethodCommand;
|
||||
import com.taobao.arthas.core.command.logger.LoggerCommand;
|
||||
import com.taobao.arthas.core.command.monitor200.DashboardCommand;
|
||||
import com.taobao.arthas.core.command.monitor200.HeapDumpCommand;
|
||||
import com.taobao.arthas.core.command.monitor200.JvmCommand;
|
||||
@@ -93,6 +94,7 @@ public class BuiltinCommandPack implements CommandResolver {
|
||||
commands.add(Command.create(SystemPropertyCommand.class));
|
||||
commands.add(Command.create(SystemEnvCommand.class));
|
||||
commands.add(Command.create(VMOptionCommand.class));
|
||||
commands.add(Command.create(LoggerCommand.class));
|
||||
commands.add(Command.create(HistoryCommand.class));
|
||||
commands.add(Command.create(CatCommand.class));
|
||||
commands.add(Command.create(PwdCommand.class));
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
package com.taobao.arthas.core.command.logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.Appender;
|
||||
import org.apache.log4j.AsyncAppender;
|
||||
import org.apache.log4j.ConsoleAppender;
|
||||
import org.apache.log4j.FileAppender;
|
||||
import org.apache.log4j.Level;
|
||||
import org.apache.log4j.LogManager;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2019-09-06
|
||||
*
|
||||
*/
|
||||
public class Log4jHelper {
|
||||
|
||||
private static boolean Log4j = false;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> loggerClass = Class.forName("org.apache.log4j.Logger");
|
||||
// 这里可能会加载到应用中依赖的log4j,因此需要判断classloader
|
||||
if (loggerClass.getClassLoader().equals(Log4jHelper.class.getClassLoader())) {
|
||||
LogManager.getLoggerRepository();
|
||||
Log4j = true;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
public static Boolean updateLevel(String name, String level) {
|
||||
if (Log4j) {
|
||||
Level l = Level.toLevel(level, Level.ERROR);
|
||||
Logger logger = LogManager.getLoggerRepository().exists(name);
|
||||
if (logger != null) {
|
||||
logger.setLevel(l);
|
||||
return true;
|
||||
} else {
|
||||
Logger root = LogManager.getLoggerRepository().getRootLogger();
|
||||
if (root.getName().equals(name)) {
|
||||
root.setLevel(l);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Map<String, Map<String, Object>> getLoggers(String name, boolean includeNoAppender) {
|
||||
Map<String, Map<String, Object>> loggerInfoMap = new HashMap<String, Map<String, Object>>();
|
||||
if (!Log4j) {
|
||||
return loggerInfoMap;
|
||||
}
|
||||
|
||||
if (name != null && !name.trim().isEmpty()) {
|
||||
Logger logger = LogManager.getLoggerRepository().exists(name);
|
||||
if (logger != null) {
|
||||
loggerInfoMap.put(name, doGetLoggerInfo(logger));
|
||||
}
|
||||
} else {
|
||||
// 获取所有logger时,如果没有appender则忽略
|
||||
@SuppressWarnings("unchecked")
|
||||
Enumeration<Logger> loggers = LogManager.getLoggerRepository().getCurrentLoggers();
|
||||
|
||||
if (loggers != null) {
|
||||
while (loggers.hasMoreElements()) {
|
||||
Logger logger = loggers.nextElement();
|
||||
Map<String, Object> info = doGetLoggerInfo(logger);
|
||||
if (!includeNoAppender) {
|
||||
List<?> appenders = (List<?>) info.get(LoggerHelper.appenders);
|
||||
if (appenders != null && !appenders.isEmpty()) {
|
||||
loggerInfoMap.put(logger.getName(), info);
|
||||
}
|
||||
} else {
|
||||
loggerInfoMap.put(logger.getName(), info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger root = LogManager.getLoggerRepository().getRootLogger();
|
||||
if (root != null) {
|
||||
Map<String, Object> info = doGetLoggerInfo(root);
|
||||
if (!includeNoAppender) {
|
||||
List<?> appenders = (List<?>) info.get(LoggerHelper.appenders);
|
||||
if (appenders != null && !appenders.isEmpty()) {
|
||||
loggerInfoMap.put(root.getName(), info);
|
||||
}
|
||||
} else {
|
||||
loggerInfoMap.put(root.getName(), info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loggerInfoMap;
|
||||
}
|
||||
|
||||
private static Map<String, Object> doGetLoggerInfo(Logger logger) {
|
||||
Map<String, Object> info = new HashMap<String, Object>();
|
||||
info.put(LoggerHelper.name, logger.getName());
|
||||
info.put(LoggerHelper.clazz, logger.getClass());
|
||||
info.put(LoggerHelper.additivity, logger.getAdditivity());
|
||||
|
||||
Level level = logger.getLevel(), effectiveLevel = logger.getEffectiveLevel();
|
||||
if (level != null) {
|
||||
info.put(LoggerHelper.level, level.toString());
|
||||
}
|
||||
if (effectiveLevel != null) {
|
||||
info.put(LoggerHelper.effectiveLevel, effectiveLevel.toString());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> result = doGetLoggerAppenders(logger.getAllAppenders());
|
||||
info.put(LoggerHelper.appenders, result);
|
||||
return info;
|
||||
}
|
||||
|
||||
private static List<Map<String, Object>> doGetLoggerAppenders(Enumeration<Appender> appenders) {
|
||||
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
||||
|
||||
while (appenders.hasMoreElements()) {
|
||||
Map<String, Object> info = new HashMap<String, Object>();
|
||||
Appender appender = appenders.nextElement();
|
||||
|
||||
info.put(LoggerHelper.name, appender.getName());
|
||||
info.put(LoggerHelper.clazz, appender.getClass());
|
||||
|
||||
result.add(info);
|
||||
if (appender instanceof FileAppender) {
|
||||
info.put(LoggerHelper.file, ((FileAppender) appender).getFile());
|
||||
} else if (appender instanceof ConsoleAppender) {
|
||||
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);
|
||||
}
|
||||
info.put(LoggerHelper.appenderRef, appenderRef);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.taobao.arthas.core.command.logger;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.security.CodeSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.ILoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.AsyncAppender;
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
import ch.qos.logback.core.ConsoleAppender;
|
||||
import ch.qos.logback.core.FileAppender;
|
||||
import ch.qos.logback.core.pattern.PatternLayoutBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2019-09-06
|
||||
*
|
||||
*/
|
||||
public class LogbackHelper {
|
||||
|
||||
private static boolean Logback = false;
|
||||
private static Field headField, lengthOptionField;
|
||||
private static ILoggerFactory loggerFactoryInstance;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> loggerClass = Class.forName("ch.qos.logback.classic.Logger");
|
||||
// 这里可能会加载到应用中依赖的logback,因此需要判断classloader
|
||||
if (loggerClass.getClassLoader().equals(LogbackHelper.class.getClassLoader())) {
|
||||
ILoggerFactory loggerFactory = org.slf4j.LoggerFactory.getILoggerFactory();
|
||||
|
||||
if (loggerFactory instanceof LoggerContext) {
|
||||
loggerFactoryInstance = loggerFactory;
|
||||
|
||||
headField = PatternLayoutBase.class.getDeclaredField("head");
|
||||
headField.setAccessible(true);
|
||||
|
||||
lengthOptionField = ThrowableProxyConverter.class.getDeclaredField("lengthOption");
|
||||
lengthOptionField.setAccessible(true);
|
||||
|
||||
Logback = true;
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
public static Boolean updateLevel(String name, String level) {
|
||||
if (Logback) {
|
||||
try {
|
||||
Level l = Level.toLevel(level, Level.ERROR);
|
||||
LoggerContext loggerContext = (LoggerContext) loggerFactoryInstance;
|
||||
|
||||
Logger logger = loggerContext.exists(name);
|
||||
if (logger != null) {
|
||||
logger.setLevel(l);
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Map<String, Map<String, Object>> getLoggers(String name, boolean includeNoAppender) {
|
||||
Map<String, Map<String, Object>> loggerInfoMap = new LinkedHashMap<String, Map<String, Object>>();
|
||||
|
||||
if (Logback) {
|
||||
LoggerContext loggerContext = (LoggerContext) loggerFactoryInstance;
|
||||
if (name != null && !name.trim().isEmpty()) {
|
||||
Logger logger = loggerContext.exists(name);
|
||||
if (logger != null) {
|
||||
loggerInfoMap.put(name, doGetLoggerInfo(logger));
|
||||
}
|
||||
} else {
|
||||
// 获取所有logger时,如果没有appender则忽略
|
||||
List<Logger> loggers = loggerContext.getLoggerList();
|
||||
for (Logger logger : loggers) {
|
||||
Map<String, Object> info = doGetLoggerInfo(logger);
|
||||
|
||||
if (!includeNoAppender) {
|
||||
List<?> appenders = (List<?>) info.get(LoggerHelper.appenders);
|
||||
if (appenders != null && !appenders.isEmpty()) {
|
||||
loggerInfoMap.put(logger.getName(), info);
|
||||
}
|
||||
} else {
|
||||
loggerInfoMap.put(logger.getName(), info);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loggerInfoMap;
|
||||
}
|
||||
|
||||
private static Map<String, Object> doGetLoggerInfo(Logger logger) {
|
||||
Map<String, Object> info = new LinkedHashMap<String, Object>();
|
||||
info.put(LoggerHelper.name, logger.getName());
|
||||
info.put(LoggerHelper.clazz, logger.getClass());
|
||||
CodeSource codeSource = logger.getClass().getProtectionDomain().getCodeSource();
|
||||
if (codeSource != null) {
|
||||
info.put(LoggerHelper.codeSource, codeSource.getLocation());
|
||||
}
|
||||
info.put(LoggerHelper.additivity, logger.isAdditive());
|
||||
|
||||
Level level = logger.getLevel(), effectiveLevel = logger.getEffectiveLevel();
|
||||
if (level != null) {
|
||||
info.put(LoggerHelper.level, level.toString());
|
||||
}
|
||||
if (effectiveLevel != null) {
|
||||
info.put(LoggerHelper.effectiveLevel, effectiveLevel.toString());
|
||||
}
|
||||
|
||||
List<Map<String, Object>> result = doGetLoggerAppenders(logger.iteratorForAppenders());
|
||||
info.put(LoggerHelper.appenders, result);
|
||||
return info;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static List<Map<String, Object>> doGetLoggerAppenders(Iterator<Appender<ILoggingEvent>> appenders) {
|
||||
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
||||
|
||||
while (appenders.hasNext()) {
|
||||
Map<String, Object> info = new LinkedHashMap<String, Object>();
|
||||
Appender<ILoggingEvent> appender = appenders.next();
|
||||
info.put(LoggerHelper.name, appender.getName());
|
||||
info.put(LoggerHelper.clazz, appender.getClass());
|
||||
if (appender instanceof FileAppender) {
|
||||
info.put(LoggerHelper.file, ((FileAppender) appender).getFile());
|
||||
} else if (appender instanceof AsyncAppender) {
|
||||
AsyncAppender aa = (AsyncAppender) appender;
|
||||
Iterator<Appender<ILoggingEvent>> iter = aa.iteratorForAppenders();
|
||||
List<Map<String, Object>> asyncs = doGetLoggerAppenders(iter);
|
||||
|
||||
// 异步appender所 ref的 appender,参考: https://logback.qos.ch/manual/appenders.html
|
||||
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.appenderRef, appenderRef);
|
||||
} else if (appender instanceof ConsoleAppender) {
|
||||
info.put(LoggerHelper.target, ((ConsoleAppender) appender).getTarget());
|
||||
}
|
||||
result.add(info);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
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;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.taobao.arthas.common.IOUtils;
|
||||
import com.taobao.arthas.common.ReflectUtils;
|
||||
import com.taobao.arthas.core.command.Constants;
|
||||
import com.taobao.arthas.core.shell.command.AnnotatedCommand;
|
||||
import com.taobao.arthas.core.shell.command.CommandProcess;
|
||||
import com.taobao.arthas.core.util.ClassLoaderUtils;
|
||||
import com.taobao.arthas.core.util.LogUtil;
|
||||
import com.taobao.arthas.core.util.StringUtils;
|
||||
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.middleware.logger.Logger;
|
||||
import com.taobao.text.Decoration;
|
||||
import com.taobao.text.ui.TableElement;
|
||||
import com.taobao.text.util.RenderUtil;
|
||||
|
||||
/**
|
||||
* logger command
|
||||
*
|
||||
* TODO support log4j2
|
||||
*
|
||||
* @author hengyunabc 2019-09-04
|
||||
*
|
||||
*/
|
||||
@Name("logger")
|
||||
@Summary("Print logger info, and update the logger level")
|
||||
@Description("\nExamples:\n" + " logger\n" + " logger -c 327a647b\n" + " logger --name ROOT --level debug\n"
|
||||
+ Constants.WIKI + Constants.WIKI_HOME + "logger")
|
||||
public class LoggerCommand extends AnnotatedCommand {
|
||||
private static final Logger logger = LogUtil.getArthasLogger();
|
||||
|
||||
private static byte[] LoggerHelperBytes;
|
||||
private static byte[] Log4jHelperBytes;
|
||||
private static byte[] LogbackHelperBytes;
|
||||
|
||||
private static Map<Class<?>, byte[]> classToBytesMap = new HashMap<Class<?>, byte[]>();
|
||||
|
||||
static {
|
||||
LoggerHelperBytes = loadClassBytes(LoggerHelper.class);
|
||||
Log4jHelperBytes = loadClassBytes(Log4jHelper.class);
|
||||
LogbackHelperBytes = loadClassBytes(LogbackHelper.class);
|
||||
|
||||
classToBytesMap.put(LoggerHelper.class, LoggerHelperBytes);
|
||||
classToBytesMap.put(Log4jHelper.class, Log4jHelperBytes);
|
||||
classToBytesMap.put(LogbackHelper.class, LogbackHelperBytes);
|
||||
}
|
||||
|
||||
private String name;
|
||||
|
||||
private String hashCode;
|
||||
|
||||
private String level;
|
||||
|
||||
/**
|
||||
* include the logger don't have appender, default false.
|
||||
*/
|
||||
private boolean includeNoAppender;
|
||||
|
||||
/**
|
||||
* include the arthas logger, default false.
|
||||
*/
|
||||
private boolean includeArthasLogger;
|
||||
|
||||
@Option(shortName = "n", longName = "name")
|
||||
@Description("logger name")
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Option(shortName = "c", longName = "classloader")
|
||||
@Description("classLoader hashcode")
|
||||
public void setHashCode(String hashCode) {
|
||||
this.hashCode = hashCode;
|
||||
}
|
||||
|
||||
@Option(shortName = "l", longName = "level")
|
||||
@Description("set logger level")
|
||||
public void setLevel(String level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Option(longName = "include-no-appender", flag = true)
|
||||
@Description("include the loggers don't have appender, default value false")
|
||||
public void setHaveAppender(boolean includeNoAppender) {
|
||||
this.includeNoAppender = includeNoAppender;
|
||||
}
|
||||
|
||||
@Option(longName = "include-arthas-logger", flag = true)
|
||||
@Description("include the arthas loggers, default value false")
|
||||
public void setIncludeArthasLogger(boolean includeArthasLogger) {
|
||||
this.includeArthasLogger = includeArthasLogger;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
public void level(CommandProcess process) {
|
||||
Instrumentation inst = process.session().getInstrumentation();
|
||||
boolean result = false;
|
||||
try {
|
||||
Boolean updateResult = this.updateLevel(inst, Log4jHelper.class);
|
||||
if (Boolean.TRUE.equals(updateResult)) {
|
||||
result = true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("arthas", "logger command update log4j level error", e);
|
||||
}
|
||||
|
||||
try {
|
||||
Boolean updateResult = this.updateLevel(inst, LogbackHelper.class);
|
||||
if (Boolean.TRUE.equals(updateResult)) {
|
||||
result = true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.error("arthas", "logger command update logback level error", e);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
process.write("update logger level success.\n");
|
||||
} else {
|
||||
process.write("update logger level fail.\n");
|
||||
}
|
||||
}
|
||||
|
||||
public void loggers(CommandProcess process, String name) {
|
||||
Map<ClassLoader, LoggerTypes> classLoaderLoggerMap = new LinkedHashMap<ClassLoader, LoggerTypes>();
|
||||
|
||||
for (Class<?> clazz : process.session().getInstrumentation().getAllLoadedClasses()) {
|
||||
String className = clazz.getName();
|
||||
ClassLoader classLoader = clazz.getClassLoader();
|
||||
|
||||
// skip the arthas classloader
|
||||
if (this.includeArthasLogger == false && classLoader != null && this.getClass().getClassLoader().getClass()
|
||||
.getName().equals(classLoader.getClass().getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if special classloader
|
||||
if (this.hashCode != null && !this.hashCode.equals(StringUtils.classLoaderHash(clazz))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (classLoader != null) {
|
||||
LoggerTypes loggerTypes = classLoaderLoggerMap.get(classLoader);
|
||||
if (loggerTypes == null) {
|
||||
loggerTypes = new LoggerTypes();
|
||||
classLoaderLoggerMap.put(classLoader, loggerTypes);
|
||||
}
|
||||
if ("org.apache.log4j.Logger".equals(className)) {
|
||||
loggerTypes.addType(LoggerType.LOG4J);
|
||||
} else if ("ch.qos.logback.classic.Logger".equals(className)) {
|
||||
loggerTypes.addType(LoggerType.LOGBACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Entry<ClassLoader, LoggerTypes> entry : classLoaderLoggerMap.entrySet()) {
|
||||
ClassLoader classLoader = entry.getKey();
|
||||
LoggerTypes loggerTypes = entry.getValue();
|
||||
|
||||
if (loggerTypes.contains(LoggerType.LOG4J)) {
|
||||
Map<String, Map<String, Object>> loggerInfoMap = loggerInfo(classLoader, Log4jHelper.class);
|
||||
String renderResult = renderLoggerInfo(loggerInfoMap, process.width());
|
||||
|
||||
process.write(renderResult);
|
||||
}
|
||||
|
||||
if (loggerTypes.contains(LoggerType.LOGBACK)) {
|
||||
Map<String, Map<String, Object>> loggerInfoMap = loggerInfo(classLoader, LogbackHelper.class);
|
||||
String renderResult = renderLoggerInfo(loggerInfoMap, process.width());
|
||||
|
||||
process.write(renderResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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)))
|
||||
.row(label(LoggerHelper.effectiveLevel).style(Decoration.bold.bold()),
|
||||
label("" + info.get(LoggerHelper.effectiveLevel)))
|
||||
.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.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();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Map<String, Object>> loggerInfo(ClassLoader classLoader, Class<?> helperClass) {
|
||||
Map<String, Map<String, Object>> loggers = Collections.emptyMap();
|
||||
try {
|
||||
classLoader.loadClass(helperClass.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
ReflectUtils.defineClass(helperClass.getName(), classToBytesMap.get(helperClass), classLoader);
|
||||
} catch (Exception e1) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Class<?> clazz = classLoader.loadClass(helperClass.getName());
|
||||
Method getLoggersMethod = clazz.getMethod("getLoggers", new Class<?>[] { String.class, boolean.class });
|
||||
loggers = (Map<String, Map<String, Object>>) getLoggersMethod.invoke(null,
|
||||
new Object[] { name, includeNoAppender });
|
||||
} catch (Throwable e) {
|
||||
// ignore
|
||||
}
|
||||
return loggers;
|
||||
}
|
||||
|
||||
private Boolean updateLevel(Instrumentation inst, Class<?> helperClass) throws Exception {
|
||||
ClassLoader classLoader = null;
|
||||
if (hashCode == null) {
|
||||
classLoader = ClassLoader.getSystemClassLoader();
|
||||
} else {
|
||||
classLoader = ClassLoaderUtils.getClassLoader(inst, hashCode);
|
||||
}
|
||||
|
||||
Class<?> clazz = classLoader.loadClass(helperClass.getName());
|
||||
Method updateLevelMethod = clazz.getMethod("updateLevel", new Class<?>[] { String.class, String.class });
|
||||
return (Boolean) updateLevelMethod.invoke(null, new Object[] { this.name, this.level });
|
||||
|
||||
}
|
||||
|
||||
static enum LoggerType {
|
||||
LOG4J, LOGBACK
|
||||
}
|
||||
|
||||
static class LoggerTypes {
|
||||
Set<LoggerType> types = new HashSet<LoggerType>();
|
||||
|
||||
public Collection<LoggerType> types() {
|
||||
return types;
|
||||
}
|
||||
|
||||
public void addType(LoggerType type) {
|
||||
types.add(type);
|
||||
}
|
||||
|
||||
public boolean contains(LoggerType type) {
|
||||
return types.contains(type);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] loadClassBytes(Class<?> clazz) {
|
||||
try {
|
||||
InputStream stream = LoggerCommand.class.getClassLoader()
|
||||
.getResourceAsStream(clazz.getName().replace('.', '/') + ".class");
|
||||
|
||||
return IOUtils.getBytes(stream);
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.taobao.arthas.core.command.logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2019-09-06
|
||||
*
|
||||
*/
|
||||
public interface LoggerHelper {
|
||||
public static final String clazz = "class";
|
||||
public static final String classLoader = "classLoader";
|
||||
public static final String classLoaderHash = "classLoaderHash";
|
||||
public static final String codeSource = "codeSource";
|
||||
|
||||
// logger info
|
||||
public static final String level = "level";
|
||||
public static final String effectiveLevel = "effectiveLevel";
|
||||
// type boolean
|
||||
public static final String additivity = "additivity";
|
||||
public static final String appenders = "appenders";
|
||||
|
||||
// appender info
|
||||
public static final String name = "name";
|
||||
public static final String file = "file";
|
||||
// type List<String>
|
||||
public static final String appenderRef = "appenderRef";
|
||||
public static final String target = "target";
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user