failedFuture(t));
}
return this;
diff --git a/core/src/main/java/com/taobao/arthas/core/util/ArthasBanner.java b/core/src/main/java/com/taobao/arthas/core/util/ArthasBanner.java
index a906c9116..01de9e121 100644
--- a/core/src/main/java/com/taobao/arthas/core/util/ArthasBanner.java
+++ b/core/src/main/java/com/taobao/arthas/core/util/ArthasBanner.java
@@ -1,8 +1,9 @@
package com.taobao.arthas.core.util;
+import com.alibaba.arthas.deps.org.slf4j.Logger;
+import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.taobao.arthas.common.PidUtils;
import com.taobao.arthas.core.shell.ShellServerOptions;
-import com.taobao.middleware.logger.Logger;
import com.taobao.text.Color;
import com.taobao.text.Decoration;
import com.taobao.text.ui.TableElement;
@@ -29,7 +30,7 @@ public class ArthasBanner {
private static String VERSION = "unknown";
private static String THANKS = "";
- private static final Logger logger = LogUtil.getArthasLogger();
+ private static final Logger logger = LoggerFactory.getLogger(ArthasBanner.class);
static {
try {
diff --git a/core/src/main/java/com/taobao/arthas/core/util/Constants.java b/core/src/main/java/com/taobao/arthas/core/util/Constants.java
index bd80e310b..5beb6b75e 100644
--- a/core/src/main/java/com/taobao/arthas/core/util/Constants.java
+++ b/core/src/main/java/com/taobao/arthas/core/util/Constants.java
@@ -5,8 +5,6 @@ import java.io.File;
import com.taobao.arthas.common.PidUtils;
import com.taobao.arthas.core.view.Ansi;
-import static com.taobao.arthas.core.util.LogUtil.LOGS_DIR;
-
/**
* @author ralf0131 2016-12-28 16:20.
*/
@@ -53,9 +51,4 @@ public class Constants {
*/
public static final String PID = PidUtils.currentPid();
- /**
- * 缓存目录
- */
- public static final String CACHE_ROOT = LOGS_DIR + File.separator + "arthas-cache";
-
}
diff --git a/core/src/main/java/com/taobao/arthas/core/util/LogUtil.java b/core/src/main/java/com/taobao/arthas/core/util/LogUtil.java
index ae2f8a363..c9fd27ee9 100644
--- a/core/src/main/java/com/taobao/arthas/core/util/LogUtil.java
+++ b/core/src/main/java/com/taobao/arthas/core/util/LogUtil.java
@@ -1,141 +1,137 @@
package com.taobao.arthas.core.util;
-import com.taobao.middleware.logger.Level;
-import com.taobao.middleware.logger.Logger;
-import com.taobao.middleware.logger.LoggerFactory;
-import com.taobao.middleware.logger.support.LogLog;
-import com.taobao.middleware.logger.support.LoggerHelper;
-
import java.io.File;
+import java.util.Iterator;
+
+import com.alibaba.arthas.deps.ch.qos.logback.classic.LoggerContext;
+import com.alibaba.arthas.deps.ch.qos.logback.classic.joran.JoranConfigurator;
+import com.alibaba.arthas.deps.ch.qos.logback.classic.spi.ILoggingEvent;
+import com.alibaba.arthas.deps.ch.qos.logback.core.Appender;
+import com.alibaba.arthas.deps.ch.qos.logback.core.rolling.RollingFileAppender;
+import com.alibaba.arthas.deps.org.slf4j.Logger;
+import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
+import com.taobao.arthas.common.AnsiLog;
+import com.taobao.arthas.core.env.ArthasEnvironment;
/**
- * Arthas日志
- * Created by vlinux on 15/3/8.
+ *
+ * @author hengyunabc
+ *
*/
public class LogUtil {
- /**
- * Arthas 内部日志Logger
- */
- private static final Logger arthasLogger;
-
- private static final org.slf4j.Logger resultLogger;
+ public static final String LOGGING_CONFIG_PROPERTY = "arthas.logging.config";
+ public static final String LOGGING_CONFIG = "${arthas.logging.config:${arthas.home}/logback.xml}";
/**
- * 接管Netty的Logger
+ * The name of the property that contains the name of the log file. Names can be
+ * an exact location or relative to the current directory.
*/
- private static final Logger nettyLogger;
+ public static final String FILE_NAME_PROPERTY = "arthas.logging.file.name";
+ public static final String ARTHAS_LOG_FILE = "ARTHAS_LOG_FILE";
/**
- * 接管termd的Logger
+ * The name of the property that contains the directory where log files are
+ * written.
*/
- private static final Logger termdLogger;
+ public static final String FILE_PATH_PROPERTY = "arthas.logging.file.path";
+ public static final String ARTHAS_LOG_PATH = "ARTHAS_LOG_PATH";
+
+ private static String logFile = "";
/**
- * 接管tunnel client的Logger
+ *
+ * 1. 尝试从 arthas.logging.config 这个配置里加载 logback.xml
+ * 2. 尝试从 arthas.home 下面找 logback.xml
+ *
+ * 可以用 arthas.logging.file.name 指定具体arthas.log的名字
+ * 可以用 arthas.logging.file.path 指定具体arthas.log的目录
+ *
+ *
+ *
+ * @param env
*/
- private static final Logger tunnelClientLogger;
+ public static LoggerContext initLooger(ArthasEnvironment env) {
+ String loggingConfig = env.resolvePlaceholders(LOGGING_CONFIG);
+ if (loggingConfig == null || loggingConfig.trim().isEmpty()) {
+ return null;
+ }
+ AnsiLog.debug("arthas logging file: " + loggingConfig);
+ File configFile = new File(loggingConfig);
+ if (!configFile.isFile()) {
+ AnsiLog.error("can not find arthas logging config: " + loggingConfig);
+ return null;
+ }
- public static final String LOGGER_FILE;
+ try {
+ LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
+ loggerContext.reset();
- /**
- * default value is ~/logs
- */
- public static String LOGS_DIR;
-
- /**
- * default value is ~/logs/arthas
- */
- public static String LOGS_ARTHAS_DIR;
-
- static {
- detectArthasLogDirectory();
- LOGGER_FILE = LoggerHelper.getLogFile("arthas", "arthas.log");
-
- LogLog.setQuietMode(true);
-
- LoggerHelper.setPattern("arthas-cache", "%d{yyyy-MM-dd HH:mm:ss.SSS}%n%m%n");
-
- arthasLogger = LoggerFactory.getLogger("arthas");
- arthasLogger.activateAppenderWithTimeAndSizeRolling("arthas", "arthas.log", "UTF-8", "100MB");
- arthasLogger.setLevel(Level.INFO);
- arthasLogger.setAdditivity(false);
-
- com.taobao.middleware.logger.Logger log = LoggerFactory.getLogger("result");
- log.activateAppenderWithSizeRolling("arthas-cache", "result.log", "UTF-8", "100MB", 3);
- log.setAdditivity(false);
- log.activateAsync(64, -1);
- resultLogger = (org.slf4j.Logger) log.getDelegate();
-
- nettyLogger = LoggerFactory.getLogger("io.netty");
- nettyLogger.activateAppender(arthasLogger);
- nettyLogger.setLevel(Level.INFO);
- nettyLogger.setAdditivity(false);
-
- termdLogger = LoggerFactory.getLogger("io.termd");
- termdLogger.activateAppender(arthasLogger);
- termdLogger.setLevel(Level.INFO);
- termdLogger.setAdditivity(false);
-
- tunnelClientLogger = LoggerFactory.getLogger("com.alibaba.arthas.tunnel.client");
- tunnelClientLogger.activateAppender(arthasLogger);
- tunnelClientLogger.setLevel(Level.INFO);
- tunnelClientLogger.setAdditivity(false);
- }
-
- private static void detectArthasLogDirectory() {
- String dpath = System.getProperty("JM.LOG.PATH");
- if (StringUtils.isEmpty(dpath)) {
- File logDirectory = new File(System.getProperty("user.home") + File.separator + "logs" + File.separator);
- try {
- // when user is nobody mkdir will fail. #572
- logDirectory.mkdirs();
- } catch (Throwable e) {
- // ignore
+ String fileName = env.getProperty(FILE_NAME_PROPERTY);
+ ;
+ if (fileName != null) {
+ loggerContext.putProperty(ARTHAS_LOG_FILE, fileName);
}
- if (!logDirectory.exists()) {
- // try to set a temp directory
- logDirectory = new File(System.getProperty("java.io.tmpdir") + File.separator + "logs" + File.separator);
- try {
- logDirectory.mkdirs();
- } catch (Throwable e) {
- // ignore
+ String filePath = env.getProperty(FILE_PATH_PROPERTY);
+ if (filePath != null) {
+ loggerContext.putProperty(ARTHAS_LOG_PATH, filePath);
+ }
+
+ JoranConfigurator configurator = new JoranConfigurator();
+ configurator.setContext(loggerContext);
+ configurator.doConfigure(configFile.toURI().toURL()); // load logback xml file
+
+ // 查找 arthas.log appender
+ Iterator> appenders = loggerContext.getLogger("root").iteratorForAppenders();
+
+ while (appenders.hasNext()) {
+ Appender appender = appenders.next();
+ if (appender instanceof RollingFileAppender) {
+ RollingFileAppender fileAppender = (RollingFileAppender) appender;
+ if ("ARTHAS".equalsIgnoreCase(fileAppender.getName())) {
+ logFile = fileAppender.getFile();
+ }
}
}
- if (logDirectory.exists()) {
- LOGS_DIR = logDirectory.getAbsolutePath();
- System.setProperty("JM.LOG.PATH", logDirectory.getAbsolutePath());
+
+ return loggerContext;
+ } catch (Throwable e) {
+ AnsiLog.error("try to load arthas logging config file error: " + configFile, e);
+ }
+ return null;
+ }
+
+ public static String loggingFile() {
+ if (logFile == null || logFile.trim().isEmpty()) {
+ return "arthas.log";
+ }
+ return logFile;
+ }
+
+ public static String loggingDir() {
+ if (logFile != null && !logFile.isEmpty()) {
+ String parent = new File(logFile).getParent();
+ if (parent != null) {
+ return parent;
}
+ }
+ return new File("").getAbsolutePath();
+ }
+
+ public static String cacheDir() {
+ File logsDir = new File(loggingDir()).getParentFile();
+ if (logsDir.exists()) {
+ File arthasCacheDir = new File(logsDir, "arthas-cache");
+ arthasCacheDir.mkdirs();
+ return arthasCacheDir.getAbsolutePath();
} else {
- LOGS_DIR = dpath;
+ File arthasCacheDir = new File("arthas-cache");
+ arthasCacheDir.mkdirs();
+ return arthasCacheDir.getAbsolutePath();
}
- if (StringUtils.isEmpty(LOGS_DIR)) {
- LOGS_DIR = "logs";
- }
- LOGS_ARTHAS_DIR = LOGS_DIR + File.separator + "arthas";
}
- public static Logger getArthasLogger() {
- return arthasLogger;
- }
-
- public static org.slf4j.Logger getResultLogger() {
- return resultLogger;
- }
-
- public static void closeResultLogger() {
- closeSlf4jLogger(resultLogger);
- }
-
- public static void closeSlf4jLogger(org.slf4j.Logger logger) {
- if (logger != null) {
- if (logger instanceof ch.qos.logback.classic.Logger) {
- ((ch.qos.logback.classic.Logger) logger).detachAndStopAllAppenders();
- } else {
- // arthas strongly depends on logback.
- // So do nothing here
- // https://github.com/alibaba/arthas/issues/319
- }
- }
+ public static Logger getResultLogger() {
+ return LoggerFactory.getLogger("result");
}
}
diff --git a/core/src/main/java/com/taobao/arthas/core/util/collection/ThreadUnsafeGaStack.java b/core/src/main/java/com/taobao/arthas/core/util/collection/ThreadUnsafeGaStack.java
index c35b64fe1..d879f418d 100644
--- a/core/src/main/java/com/taobao/arthas/core/util/collection/ThreadUnsafeGaStack.java
+++ b/core/src/main/java/com/taobao/arthas/core/util/collection/ThreadUnsafeGaStack.java
@@ -1,6 +1,7 @@
package com.taobao.arthas.core.util.collection;
-import com.taobao.arthas.core.util.LogUtil;
+import com.alibaba.arthas.deps.org.slf4j.Logger;
+import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import java.util.NoSuchElementException;
@@ -14,7 +15,7 @@ import static java.lang.System.arraycopy;
* @param
*/
public class ThreadUnsafeGaStack implements GaStack {
-
+ private static final Logger logger = LoggerFactory.getLogger(ThreadUnsafeGaStack.class);
private final static int EMPTY_INDEX = -1;
private final static int DEFAULT_STACK_DEEP = 12;
@@ -38,8 +39,10 @@ public class ThreadUnsafeGaStack implements GaStack {
private void ensureCapacityInternal(int expectDeep) {
final int currentStackSize = elementArray.length;
if (elementArray.length <= expectDeep) {
- LogUtil.getArthasLogger().debug("resize GaStack to double length: " + currentStackSize * 2 + " for thread: "
- + Thread.currentThread().getName());
+ if (logger.isDebugEnabled()) {
+ logger.debug("resize GaStack to double length: " + currentStackSize * 2 + " for thread: "
+ + Thread.currentThread().getName());
+ }
final Object[] newElementArray = new Object[currentStackSize * 2];
arraycopy(elementArray, 0, newElementArray, 0, currentStackSize);
this.elementArray = newElementArray;
@@ -64,8 +67,9 @@ public class ThreadUnsafeGaStack implements GaStack {
} finally {
if (current == EMPTY_INDEX && elementArray.length > DEFAULT_STACK_DEEP) {
elementArray = new Object[DEFAULT_STACK_DEEP];
- LogUtil.getArthasLogger().debug(
- "resize GaStack to default length for thread: " + Thread.currentThread().getName());
+ if (logger.isDebugEnabled()) {
+ logger.debug("resize GaStack to default length for thread: " + Thread.currentThread().getName());
+ }
}
}
}
diff --git a/core/src/main/java/logback.xml b/core/src/main/java/logback.xml
new file mode 100644
index 000000000..42f32d670
--- /dev/null
+++ b/core/src/main/java/logback.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+ ${ARTHAS_LOG_FILE}
+
+ %date %level [%thread] %logger{10} [%file:%line] %msg%n
+
+
+
+ ${ARTHAS_LOG_FILE}.%d{yyyy-MM-dd}.%i.log
+
+ 7
+ 1MB
+ 10MB
+
+
+
+
+
+ ${RESULT_LOG_FILE}
+
+ %date %level [%thread] %logger{10} [%file:%line] %msg%n
+
+
+
+ ${RESULT_LOG_FILE}.%d{yyyy-MM-dd}.%i.log
+
+ 7
+ 1MB
+ 10MB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/test/java/com/taobao/arthas/core/util/LogUtilTest.java b/core/src/test/java/com/taobao/arthas/core/util/LogUtilTest.java
new file mode 100644
index 000000000..483497395
--- /dev/null
+++ b/core/src/test/java/com/taobao/arthas/core/util/LogUtilTest.java
@@ -0,0 +1,168 @@
+package com.taobao.arthas.core.util;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.assertj.core.api.Assertions;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import com.alibaba.arthas.deps.ch.qos.logback.classic.Level;
+import com.alibaba.arthas.deps.ch.qos.logback.classic.Logger;
+import com.alibaba.arthas.deps.ch.qos.logback.classic.LoggerContext;
+import com.alibaba.arthas.deps.ch.qos.logback.classic.spi.ILoggingEvent;
+import com.alibaba.arthas.deps.ch.qos.logback.core.Appender;
+import com.alibaba.arthas.deps.ch.qos.logback.core.rolling.RollingFileAppender;
+import com.taobao.arthas.core.env.ArthasEnvironment;
+import com.taobao.arthas.core.env.PropertiesPropertySource;
+
+/**
+ *
+ * @author hengyunabc
+ *
+ */
+public class LogUtilTest {
+ @Rule
+ public TemporaryFolder tempFolder = new TemporaryFolder();
+
+ ArthasEnvironment arthasEnvironment;
+ String testResourcesDir;
+
+ @Before
+ public void before() throws URISyntaxException {
+ ClassLoader classLoader = LogUtilTest.class.getClassLoader();
+ String logbakXmlPath = classLoader.getResource("logback-test.xml").toURI().getPath();
+
+ testResourcesDir = new File(logbakXmlPath).getParent();
+
+ arthasEnvironment = new ArthasEnvironment();
+ }
+
+ @Test
+ public void testArthasHome() throws URISyntaxException {
+ Properties properties1 = new Properties();
+ properties1.put("arthas.home", testResourcesDir);
+ arthasEnvironment.addLast(new PropertiesPropertySource("test1", properties1));
+
+ LoggerContext loggerContext = LogUtil.initLooger(arthasEnvironment);
+
+ Logger logger = loggerContext.getLogger("root");
+ Level level = logger.getLevel();
+
+ Assertions.assertThat(level).isEqualTo(Level.ERROR);
+ }
+
+ @Test
+ public void testLogConfig() throws URISyntaxException {
+ Properties properties1 = new Properties();
+ properties1.put("arthas.home", testResourcesDir);
+ properties1.put(LogUtil.LOGGING_CONFIG_PROPERTY, testResourcesDir + "/logback-test.xml");
+ arthasEnvironment.addLast(new PropertiesPropertySource("test1", properties1));
+
+ LoggerContext loggerContext = LogUtil.initLooger(arthasEnvironment);
+
+ Logger logger = loggerContext.getLogger("root");
+ Level level = logger.getLevel();
+
+ Assertions.assertThat(level).isEqualTo(Level.WARN);
+ }
+
+ @Test
+ public void test_DefaultLogFile() throws URISyntaxException {
+ Properties properties1 = new Properties();
+ properties1.put("arthas.home", testResourcesDir);
+
+ String logFile = new File(System.getProperty("user.home"), "logs/arthas/arthas.log").getAbsolutePath();
+
+ arthasEnvironment.addLast(new PropertiesPropertySource("test1", properties1));
+
+ LoggerContext loggerContext = LogUtil.initLooger(arthasEnvironment);
+
+ Logger logger = loggerContext.getLogger("root");
+ Level level = logger.getLevel();
+
+ Assertions.assertThat(level).isEqualTo(Level.ERROR);
+
+ Iterator> appenders = logger.iteratorForAppenders();
+
+ boolean foundFileAppender = false;
+ while (appenders.hasNext()) {
+ Appender appender = appenders.next();
+ if (appender instanceof RollingFileAppender) {
+ RollingFileAppender fileAppender = (RollingFileAppender) appender;
+ String file = fileAppender.getFile();
+ Assertions.assertThat(file).isEqualTo(logFile);
+ foundFileAppender = true;
+ }
+ }
+ Assertions.assertThat(foundFileAppender).isEqualTo(true);
+ }
+
+ @Test
+ public void test_ARTHAS_LOG_FILE() throws URISyntaxException {
+ Properties properties1 = new Properties();
+ properties1.put("arthas.home", testResourcesDir);
+
+ String logFile = new File(tempFolder.getRoot().getAbsoluteFile(), "test.log").getAbsolutePath();
+
+ properties1.put(LogUtil.FILE_NAME_PROPERTY, logFile);
+ arthasEnvironment.addLast(new PropertiesPropertySource("test1", properties1));
+
+ LoggerContext loggerContext = LogUtil.initLooger(arthasEnvironment);
+
+ Logger logger = loggerContext.getLogger("root");
+ Level level = logger.getLevel();
+
+ Assertions.assertThat(level).isEqualTo(Level.ERROR);
+
+ Iterator> appenders = logger.iteratorForAppenders();
+
+ boolean foundFileAppender = false;
+ while (appenders.hasNext()) {
+ Appender appender = appenders.next();
+ if (appender instanceof RollingFileAppender) {
+ RollingFileAppender fileAppender = (RollingFileAppender) appender;
+ String file = fileAppender.getFile();
+ Assertions.assertThat(file).isEqualTo(logFile);
+ foundFileAppender = true;
+ }
+ }
+ Assertions.assertThat(foundFileAppender).isEqualTo(true);
+ }
+
+ @Test
+ public void test_ARTHAS_LOG_PATH() throws URISyntaxException {
+ Properties properties1 = new Properties();
+ properties1.put("arthas.home", testResourcesDir);
+
+ String logFile = new File(tempFolder.getRoot().getAbsoluteFile(), "arthas.log").getAbsolutePath();
+
+ properties1.put(LogUtil.FILE_PATH_PROPERTY, tempFolder.getRoot().getAbsolutePath());
+ arthasEnvironment.addLast(new PropertiesPropertySource("test1", properties1));
+
+ LoggerContext loggerContext = LogUtil.initLooger(arthasEnvironment);
+
+ Logger logger = loggerContext.getLogger("root");
+ Level level = logger.getLevel();
+
+ Assertions.assertThat(level).isEqualTo(Level.ERROR);
+
+ Iterator> appenders = logger.iteratorForAppenders();
+
+ boolean foundFileAppender = false;
+ while (appenders.hasNext()) {
+ Appender appender = appenders.next();
+ if (appender instanceof RollingFileAppender) {
+ RollingFileAppender fileAppender = (RollingFileAppender) appender;
+ String file = fileAppender.getFile();
+ Assertions.assertThat(file).isEqualTo(logFile);
+ foundFileAppender = true;
+ }
+ }
+ Assertions.assertThat(foundFileAppender).isEqualTo(true);
+ }
+}
diff --git a/core/src/test/resources/logback-test.xml b/core/src/test/resources/logback-test.xml
new file mode 100644
index 000000000..a36f03764
--- /dev/null
+++ b/core/src/test/resources/logback-test.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ ${CONSOLE_LOG_PATTERN}
+ utf8
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/test/resources/logback.xml b/core/src/test/resources/logback.xml
new file mode 100644
index 000000000..682355e8c
--- /dev/null
+++ b/core/src/test/resources/logback.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+ ${ARTHAS_LOG_FILE}
+
+ %date %level [%thread] %logger{10} [%file:%line] %msg%n
+
+
+
+ ${ARTHAS_LOG_FILE}.%d{yyyy-MM-dd}.%i.log
+
+ 7
+ 1MB
+ 10MB
+
+
+
+
+
+ ${CONSOLE_LOG_PATTERN}
+ utf8
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packaging/src/main/assembly/assembly.xml b/packaging/src/main/assembly/assembly.xml
index 7e4372b22..1f2810a83 100644
--- a/packaging/src/main/assembly/assembly.xml
+++ b/packaging/src/main/assembly/assembly.xml
@@ -17,6 +17,14 @@
../core/target/arthas-core-shade.jar
arthas-core.jar
+
+ ../core/src/main/java/logback.xml
+ logback.xml
+
+
+ ../core/src/main/java/arthas.properties
+ arthas.properties
+
../agent/target/arthas-agent-jar-with-dependencies.jar
arthas-agent.jar