You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by yu...@apache.org on 2018/03/02 08:07:43 UTC
[rocketmq] branch develop updated: [ROCKETMQ-367] Add logging
component. (#224)
This is an automated email from the ASF dual-hosted git repository.
yukon pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/rocketmq.git
The following commit(s) were added to refs/heads/develop by this push:
new 305f571 [ROCKETMQ-367] Add logging component. (#224)
305f571 is described below
commit 305f5717c6fe4ad6596433673d27c4831b382d1e
Author: lindzh <li...@163.com>
AuthorDate: Fri Mar 2 16:07:41 2018 +0800
[ROCKETMQ-367] Add logging component. (#224)
---
logging/pom.xml | 50 +
.../rocketmq/logging/InnerLoggerFactory.java | 478 ++++++++
.../apache/rocketmq/logging/InternalLogger.java | 63 +
.../rocketmq/logging/InternalLoggerFactory.java | 93 ++
.../rocketmq/logging/Slf4jLoggerFactory.java | 153 +++
.../apache/rocketmq/logging/inner/Appender.java | 228 ++++
.../org/apache/rocketmq/logging/inner/Layout.java | 39 +
.../org/apache/rocketmq/logging/inner/Level.java | 156 +++
.../org/apache/rocketmq/logging/inner/Logger.java | 467 ++++++++
.../rocketmq/logging/inner/LoggingBuilder.java | 1230 ++++++++++++++++++++
.../rocketmq/logging/inner/LoggingEvent.java | 121 ++
.../apache/rocketmq/logging/inner/SysLogger.java | 89 ++
.../org/apache/rocketmq/logging/package-info.java | 35 +
.../apache/rocketmq/logging/BasicloggerTest.java | 70 ++
.../rocketmq/logging/InnerLoggerFactoryTest.java | 92 ++
.../rocketmq/logging/InternalLoggerTest.java | 72 ++
.../rocketmq/logging/Slf4jLoggerFactoryTest.java | 80 ++
.../rocketmq/logging/inner/AppenderTest.java | 160 +++
.../apache/rocketmq/logging/inner/LayoutTest.java | 54 +
.../apache/rocketmq/logging/inner/LevelTest.java | 37 +
.../logging/inner/LoggerRepositoryTest.java | 49 +
.../apache/rocketmq/logging/inner/LoggerTest.java | 115 ++
.../rocketmq/logging/inner/LoggingBuilderTest.java | 113 ++
.../logging/inner/MessageFormatterTest.java | 40 +
logging/src/test/resources/logback_test.xml | 46 +
pom.xml | 6 +
26 files changed, 4136 insertions(+)
diff --git a/logging/pom.xml b/logging/pom.xml
new file mode 100644
index 0000000..baad6ad
--- /dev/null
+++ b/logging/pom.xml
@@ -0,0 +1,50 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.rocketmq</groupId>
+ <artifactId>rocketmq-all</artifactId>
+ <version>4.3.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>jar</packaging>
+ <artifactId>rocketmq-logging</artifactId>
+ <name>rocketmq-logging ${project.version}</name>
+
+ <properties>
+ <maven.compiler.source>1.6</maven.compiler.source>
+ <maven.compiler.target>1.6</maven.compiler.target>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/InnerLoggerFactory.java b/logging/src/main/java/org/apache/rocketmq/logging/InnerLoggerFactory.java
new file mode 100644
index 0000000..7714640
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/InnerLoggerFactory.java
@@ -0,0 +1,478 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging;
+
+import org.apache.rocketmq.logging.inner.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class InnerLoggerFactory extends InternalLoggerFactory {
+
+ @Override
+ protected InternalLogger getLoggerInstance(String name) {
+ return new InnerLogger(name);
+ }
+
+ @Override
+ protected String getLoggerType() {
+ return LOGGER_INNER;
+ }
+
+ @Override
+ protected void shutdown() {
+ Logger.getRepository().shutdown();
+ }
+
+ public static class InnerLogger implements InternalLogger {
+
+ private Logger logger;
+
+ public InnerLogger(String name) {
+ logger = Logger.getLogger(name);
+ }
+
+ @Override
+ public String getName() {
+ return logger.getName();
+ }
+
+ @Override
+ public void debug(String var1) {
+ logger.debug(var1);
+ }
+
+ @Override
+ public void debug(String var1, Throwable var2) {
+ logger.debug(var1, var2);
+ }
+
+ @Override
+ public void info(String var1) {
+ logger.info(var1);
+ }
+
+ @Override
+ public void info(String var1, Throwable var2) {
+ logger.info(var1, var2);
+ }
+
+ @Override
+ public void warn(String var1) {
+ logger.warn(var1);
+ }
+
+ @Override
+ public void warn(String var1, Throwable var2) {
+ logger.warn(var1, var2);
+ }
+
+ @Override
+ public void error(String var1) {
+ logger.error(var1);
+ }
+
+ @Override
+ public void error(String var1, Throwable var2) {
+ logger.error(var1, var2);
+ }
+
+ @Override
+ public void debug(String var1, Object var2) {
+ FormattingTuple format = MessageFormatter.format(var1, var2);
+ logger.debug(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void debug(String var1, Object var2, Object var3) {
+ FormattingTuple format = MessageFormatter.format(var1, var2, var3);
+ logger.debug(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void debug(String var1, Object... var2) {
+ FormattingTuple format = MessageFormatter.arrayFormat(var1, var2);
+ logger.debug(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void info(String var1, Object var2) {
+ FormattingTuple format = MessageFormatter.format(var1, var2);
+ logger.info(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void info(String var1, Object var2, Object var3) {
+ FormattingTuple format = MessageFormatter.format(var1, var2, var3);
+ logger.info(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void info(String var1, Object... var2) {
+ FormattingTuple format = MessageFormatter.arrayFormat(var1, var2);
+ logger.info(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void warn(String var1, Object var2) {
+ FormattingTuple format = MessageFormatter.format(var1, var2);
+ logger.warn(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void warn(String var1, Object... var2) {
+ FormattingTuple format = MessageFormatter.arrayFormat(var1, var2);
+ logger.warn(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void warn(String var1, Object var2, Object var3) {
+ FormattingTuple format = MessageFormatter.format(var1, var2, var3);
+ logger.warn(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void error(String var1, Object var2) {
+ FormattingTuple format = MessageFormatter.format(var1, var2);
+ logger.warn(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void error(String var1, Object var2, Object var3) {
+ FormattingTuple format = MessageFormatter.format(var1, var2, var3);
+ logger.warn(format.getMessage(), format.getThrowable());
+ }
+
+ @Override
+ public void error(String var1, Object... var2) {
+ FormattingTuple format = MessageFormatter.arrayFormat(var1, var2);
+ logger.warn(format.getMessage(), format.getThrowable());
+ }
+
+ public Logger getLogger() {
+ return logger;
+ }
+ }
+
+
+ public static class FormattingTuple {
+ private String message;
+ private Throwable throwable;
+ private Object[] argArray;
+
+ public FormattingTuple(String message) {
+ this(message, null, null);
+ }
+
+ public FormattingTuple(String message, Object[] argArray, Throwable throwable) {
+ this.message = message;
+ this.throwable = throwable;
+ if (throwable == null) {
+ this.argArray = argArray;
+ } else {
+ this.argArray = trimmedCopy(argArray);
+ }
+
+ }
+
+ static Object[] trimmedCopy(Object[] argArray) {
+ if (argArray != null && argArray.length != 0) {
+ int trimemdLen = argArray.length - 1;
+ Object[] trimmed = new Object[trimemdLen];
+ System.arraycopy(argArray, 0, trimmed, 0, trimemdLen);
+ return trimmed;
+ } else {
+ throw new IllegalStateException("non-sensical empty or null argument array");
+ }
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+
+ public Object[] getArgArray() {
+ return this.argArray;
+ }
+
+ public Throwable getThrowable() {
+ return this.throwable;
+ }
+ }
+
+ public static class MessageFormatter {
+
+ public MessageFormatter() {
+ }
+
+ public static FormattingTuple format(String messagePattern, Object arg) {
+ return arrayFormat(messagePattern, new Object[]{arg});
+ }
+
+ public static FormattingTuple format(String messagePattern, Object arg1, Object arg2) {
+ return arrayFormat(messagePattern, new Object[]{arg1, arg2});
+ }
+
+ static Throwable getThrowableCandidate(Object[] argArray) {
+ if (argArray != null && argArray.length != 0) {
+ Object lastEntry = argArray[argArray.length - 1];
+ return lastEntry instanceof Throwable ? (Throwable) lastEntry : null;
+ } else {
+ return null;
+ }
+ }
+
+ public static FormattingTuple arrayFormat(String messagePattern, Object[] argArray) {
+ Throwable throwableCandidate = getThrowableCandidate(argArray);
+ if (messagePattern == null) {
+ return new FormattingTuple(null, argArray, throwableCandidate);
+ } else if (argArray == null) {
+ return new FormattingTuple(messagePattern);
+ } else {
+ int i = 0;
+ StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
+
+ int len;
+ for (len = 0; len < argArray.length; ++len) {
+ int j = messagePattern.indexOf("{}", i);
+ if (j == -1) {
+ if (i == 0) {
+ return new FormattingTuple(messagePattern, argArray, throwableCandidate);
+ }
+
+ sbuf.append(messagePattern.substring(i, messagePattern.length()));
+ return new FormattingTuple(sbuf.toString(), argArray, throwableCandidate);
+ }
+
+ if (isEscapeDelimeter(messagePattern, j)) {
+ if (!isDoubleEscaped(messagePattern, j)) {
+ --len;
+ sbuf.append(messagePattern.substring(i, j - 1));
+ sbuf.append('{');
+ i = j + 1;
+ } else {
+ sbuf.append(messagePattern.substring(i, j - 1));
+ deeplyAppendParameter(sbuf, argArray[len], null);
+ i = j + 2;
+ }
+ } else {
+ sbuf.append(messagePattern.substring(i, j));
+ deeplyAppendParameter(sbuf, argArray[len], null);
+ i = j + 2;
+ }
+ }
+
+ sbuf.append(messagePattern.substring(i, messagePattern.length()));
+ if (len < argArray.length - 1) {
+ return new FormattingTuple(sbuf.toString(), argArray, throwableCandidate);
+ } else {
+ return new FormattingTuple(sbuf.toString(), argArray, null);
+ }
+ }
+ }
+
+ static boolean isEscapeDelimeter(String messagePattern, int delimeterStartIndex) {
+ if (delimeterStartIndex == 0) {
+ return false;
+ } else {
+ char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
+ return potentialEscape == 92;
+ }
+ }
+
+ static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {
+ return delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == 92;
+ }
+
+ private static void deeplyAppendParameter(StringBuilder sbuf, Object o, Map<Object[], Object> seenMap) {
+ if (o == null) {
+ sbuf.append("null");
+ } else {
+ if (!o.getClass().isArray()) {
+ safeObjectAppend(sbuf, o);
+ } else if (o instanceof boolean[]) {
+ booleanArrayAppend(sbuf, (boolean[]) o);
+ } else if (o instanceof byte[]) {
+ byteArrayAppend(sbuf, (byte[]) o);
+ } else if (o instanceof char[]) {
+ charArrayAppend(sbuf, (char[]) o);
+ } else if (o instanceof short[]) {
+ shortArrayAppend(sbuf, (short[]) o);
+ } else if (o instanceof int[]) {
+ intArrayAppend(sbuf, (int[]) o);
+ } else if (o instanceof long[]) {
+ longArrayAppend(sbuf, (long[]) o);
+ } else if (o instanceof float[]) {
+ floatArrayAppend(sbuf, (float[]) o);
+ } else if (o instanceof double[]) {
+ doubleArrayAppend(sbuf, (double[]) o);
+ } else {
+ objectArrayAppend(sbuf, (Object[]) o, seenMap);
+ }
+
+ }
+ }
+
+ private static void safeObjectAppend(StringBuilder sbuf, Object o) {
+ try {
+ String t = o.toString();
+ sbuf.append(t);
+ } catch (Throwable var3) {
+ System.err.println("RocketMQ InnerLogger: Failed toString() invocation on an object of type [" + o.getClass().getName() + "]");
+ var3.printStackTrace();
+ sbuf.append("[FAILED toString()]");
+ }
+
+ }
+
+ private static void objectArrayAppend(StringBuilder sbuf, Object[] a, Map<Object[], Object> seenMap) {
+ if (seenMap == null) {
+ seenMap = new HashMap<Object[], Object>();
+ }
+ sbuf.append('[');
+ if (!seenMap.containsKey(a)) {
+ seenMap.put(a, null);
+ int len = a.length;
+
+ for (int i = 0; i < len; ++i) {
+ deeplyAppendParameter(sbuf, a[i], seenMap);
+ if (i != len - 1) {
+ sbuf.append(", ");
+ }
+ }
+
+ seenMap.remove(a);
+ } else {
+ sbuf.append("...");
+ }
+
+ sbuf.append(']');
+ }
+
+ private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) {
+ sbuf.append('[');
+ int len = a.length;
+
+ for (int i = 0; i < len; ++i) {
+ sbuf.append(a[i]);
+ if (i != len - 1) {
+ sbuf.append(", ");
+ }
+ }
+
+ sbuf.append(']');
+ }
+
+ private static void byteArrayAppend(StringBuilder sbuf, byte[] a) {
+ sbuf.append('[');
+ int len = a.length;
+
+ for (int i = 0; i < len; ++i) {
+ sbuf.append(a[i]);
+ if (i != len - 1) {
+ sbuf.append(", ");
+ }
+ }
+
+ sbuf.append(']');
+ }
+
+ private static void charArrayAppend(StringBuilder sbuf, char[] a) {
+ sbuf.append('[');
+ int len = a.length;
+
+ for (int i = 0; i < len; ++i) {
+ sbuf.append(a[i]);
+ if (i != len - 1) {
+ sbuf.append(", ");
+ }
+ }
+
+ sbuf.append(']');
+ }
+
+ private static void shortArrayAppend(StringBuilder sbuf, short[] a) {
+ sbuf.append('[');
+ int len = a.length;
+
+ for (int i = 0; i < len; ++i) {
+ sbuf.append(a[i]);
+ if (i != len - 1) {
+ sbuf.append(", ");
+ }
+ }
+
+ sbuf.append(']');
+ }
+
+ private static void intArrayAppend(StringBuilder sbuf, int[] a) {
+ sbuf.append('[');
+ int len = a.length;
+
+ for (int i = 0; i < len; ++i) {
+ sbuf.append(a[i]);
+ if (i != len - 1) {
+ sbuf.append(", ");
+ }
+ }
+
+ sbuf.append(']');
+ }
+
+ private static void longArrayAppend(StringBuilder sbuf, long[] a) {
+ sbuf.append('[');
+ int len = a.length;
+
+ for (int i = 0; i < len; ++i) {
+ sbuf.append(a[i]);
+ if (i != len - 1) {
+ sbuf.append(", ");
+ }
+ }
+
+ sbuf.append(']');
+ }
+
+ private static void floatArrayAppend(StringBuilder sbuf, float[] a) {
+ sbuf.append('[');
+ int len = a.length;
+
+ for (int i = 0; i < len; ++i) {
+ sbuf.append(a[i]);
+ if (i != len - 1) {
+ sbuf.append(", ");
+ }
+ }
+
+ sbuf.append(']');
+ }
+
+ private static void doubleArrayAppend(StringBuilder sbuf, double[] a) {
+ sbuf.append('[');
+ int len = a.length;
+
+ for (int i = 0; i < len; ++i) {
+ sbuf.append(a[i]);
+ if (i != len - 1) {
+ sbuf.append(", ");
+ }
+ }
+
+ sbuf.append(']');
+ }
+ }
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/InternalLogger.java b/logging/src/main/java/org/apache/rocketmq/logging/InternalLogger.java
new file mode 100644
index 0000000..fae69dd
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/InternalLogger.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging;
+
+public interface InternalLogger {
+
+ String getName();
+
+ void debug(String var1);
+
+ void debug(String var1, Object var2);
+
+ void debug(String var1, Object var2, Object var3);
+
+ void debug(String var1, Object... var2);
+
+ void debug(String var1, Throwable var2);
+
+ void info(String var1);
+
+ void info(String var1, Object var2);
+
+ void info(String var1, Object var2, Object var3);
+
+ void info(String var1, Object... var2);
+
+ void info(String var1, Throwable var2);
+
+ void warn(String var1);
+
+ void warn(String var1, Object var2);
+
+ void warn(String var1, Object... var2);
+
+ void warn(String var1, Object var2, Object var3);
+
+ void warn(String var1, Throwable var2);
+
+ void error(String var1);
+
+ void error(String var1, Object var2);
+
+ void error(String var1, Object var2, Object var3);
+
+ void error(String var1, Object... var2);
+
+ void error(String var1, Throwable var2);
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/InternalLoggerFactory.java b/logging/src/main/java/org/apache/rocketmq/logging/InternalLoggerFactory.java
new file mode 100644
index 0000000..ec176ce
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/InternalLoggerFactory.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class InternalLoggerFactory {
+
+ public static final String LOGGER_SLF4J = "slf4j";
+
+ public static final String LOGGER_INNER = "inner";
+
+ public static final String DEFAULT_LOGGER = LOGGER_SLF4J;
+
+ private static String loggerType = null;
+
+ private static ConcurrentHashMap<String, InternalLoggerFactory> loggerFactoryCache = new ConcurrentHashMap<String, InternalLoggerFactory>();
+
+ public static InternalLogger getLogger(Class clazz) {
+ return getLogger(clazz.getName());
+ }
+
+ public static InternalLogger getLogger(String name) {
+ return getLoggerFactory().getLoggerInstance(name);
+ }
+
+ private static InternalLoggerFactory getLoggerFactory() {
+ InternalLoggerFactory internalLoggerFactory = null;
+ if (loggerType != null) {
+ internalLoggerFactory = loggerFactoryCache.get(loggerType);
+ }
+ if (internalLoggerFactory == null) {
+ internalLoggerFactory = loggerFactoryCache.get(DEFAULT_LOGGER);
+ }
+ if (internalLoggerFactory == null) {
+ internalLoggerFactory = loggerFactoryCache.get(LOGGER_INNER);
+ }
+ if (internalLoggerFactory == null) {
+ throw new RuntimeException("[RocketMQ] Logger init failed, please check logger");
+ }
+ return internalLoggerFactory;
+ }
+
+ public static void setCurrentLoggerType(String type) {
+ loggerType = type;
+ }
+
+ static {
+ try {
+ new Slf4jLoggerFactory();
+ } catch (Throwable e) {
+ //ignore
+ }
+ try {
+ new InnerLoggerFactory();
+ } catch (Throwable e) {
+ //ignore
+ }
+ }
+
+ public InternalLoggerFactory() {
+ doRegister();
+ }
+
+ protected void doRegister() {
+ String loggerType = getLoggerType();
+ if (loggerFactoryCache.get(loggerType) != null) {
+ return;
+ }
+ loggerFactoryCache.put(loggerType, this);
+ }
+
+ protected abstract void shutdown();
+
+ protected abstract InternalLogger getLoggerInstance(String name);
+
+ protected abstract String getLoggerType();
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/Slf4jLoggerFactory.java b/logging/src/main/java/org/apache/rocketmq/logging/Slf4jLoggerFactory.java
new file mode 100644
index 0000000..1a24684
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/Slf4jLoggerFactory.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Slf4jLoggerFactory extends InternalLoggerFactory {
+
+ @Override
+ protected String getLoggerType() {
+ return InternalLoggerFactory.LOGGER_SLF4J;
+ }
+
+ @Override
+ protected InternalLogger getLoggerInstance(String name) {
+ return new Slf4jLogger(name);
+ }
+
+ @Override
+ protected void shutdown() {
+
+ }
+
+ public static class Slf4jLogger implements InternalLogger {
+
+ private Logger logger = null;
+
+ public Slf4jLogger(String name) {
+ logger = LoggerFactory.getLogger(name);
+ }
+
+ @Override
+ public String getName() {
+ return logger.getName();
+ }
+
+ @Override
+ public void debug(String s) {
+ logger.debug(s);
+ }
+
+ @Override
+ public void debug(String s, Object o) {
+ logger.debug(s, o);
+ }
+
+ @Override
+ public void debug(String s, Object o, Object o1) {
+ logger.debug(s, o, o1);
+ }
+
+ @Override
+ public void debug(String s, Object... objects) {
+ logger.debug(s, objects);
+ }
+
+ @Override
+ public void debug(String s, Throwable throwable) {
+ logger.debug(s, throwable);
+ }
+
+ @Override
+ public void info(String s) {
+ logger.info(s);
+ }
+
+ @Override
+ public void info(String s, Object o) {
+ logger.info(s, o);
+ }
+
+ @Override
+ public void info(String s, Object o, Object o1) {
+ logger.info(s, o, o1);
+ }
+
+ @Override
+ public void info(String s, Object... objects) {
+ logger.info(s, objects);
+ }
+
+ @Override
+ public void info(String s, Throwable throwable) {
+ logger.info(s, throwable);
+ }
+
+ @Override
+ public void warn(String s) {
+ logger.warn(s);
+ }
+
+ @Override
+ public void warn(String s, Object o) {
+ logger.warn(s, o);
+ }
+
+ @Override
+ public void warn(String s, Object... objects) {
+ logger.warn(s, objects);
+ }
+
+ @Override
+ public void warn(String s, Object o, Object o1) {
+ logger.warn(s, o, o1);
+ }
+
+ @Override
+ public void warn(String s, Throwable throwable) {
+ logger.warn(s, throwable);
+ }
+
+ @Override
+ public void error(String s) {
+ logger.error(s);
+ }
+
+ @Override
+ public void error(String s, Object o) {
+ logger.error(s, o);
+ }
+
+ @Override
+ public void error(String s, Object o, Object o1) {
+ logger.error(s, o, o1);
+ }
+
+ @Override
+ public void error(String s, Object... objects) {
+ logger.error(s, objects);
+ }
+
+ @Override
+ public void error(String s, Throwable throwable) {
+ logger.error(s, throwable);
+ }
+ }
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/inner/Appender.java b/logging/src/main/java/org/apache/rocketmq/logging/inner/Appender.java
new file mode 100755
index 0000000..c061563
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/inner/Appender.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+
+import java.io.InterruptedIOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public abstract class Appender {
+
+ public static final int CODE_WRITE_FAILURE = 1;
+ public static final int CODE_FLUSH_FAILURE = 2;
+ public static final int CODE_CLOSE_FAILURE = 3;
+ public static final int CODE_FILE_OPEN_FAILURE = 4;
+
+ public final static String LINE_SEP = System.getProperty("line.separator");
+
+ boolean firstTime = true;
+
+ protected Layout layout;
+
+ protected String name;
+
+ protected boolean closed = false;
+
+ public void activateOptions() {
+ }
+
+ abstract protected void append(LoggingEvent event);
+
+ public void finalize() {
+ try {
+ super.finalize();
+ } catch (Throwable throwable) {
+ SysLogger.error("Finalizing appender named [" + name + "]. error", throwable);
+ }
+ if (this.closed) {
+ return;
+ }
+
+ SysLogger.debug("Finalizing appender named [" + name + "].");
+ close();
+ }
+
+ public Layout getLayout() {
+ return layout;
+ }
+
+ public final String getName() {
+ return this.name;
+ }
+
+ public synchronized void doAppend(LoggingEvent event) {
+ if (closed) {
+ SysLogger.error("Attempted to append to closed appender named [" + name + "].");
+ return;
+ }
+ this.append(event);
+ }
+
+ public void setLayout(Layout layout) {
+ this.layout = layout;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public abstract void close();
+
+ public void handleError(String message, Exception e, int errorCode) {
+ if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
+ Thread.currentThread().interrupt();
+ }
+ if (firstTime) {
+ SysLogger.error(message + " code:" + errorCode, e);
+ firstTime = false;
+ }
+ }
+
+ public void handleError(String message) {
+ if (firstTime) {
+ SysLogger.error(message);
+ firstTime = false;
+ }
+ }
+
+
+ public interface AppenderPipeline {
+
+ void addAppender(Appender newAppender);
+
+ Enumeration getAllAppenders();
+
+ Appender getAppender(String name);
+
+ boolean isAttached(Appender appender);
+
+ void removeAllAppenders();
+
+ void removeAppender(Appender appender);
+
+ void removeAppender(String name);
+ }
+
+
+ public static class AppenderPipelineImpl implements AppenderPipeline {
+
+
+ protected Vector<Appender> appenderList;
+
+ public void addAppender(Appender newAppender) {
+ if (newAppender == null) {
+ return;
+ }
+
+ if (appenderList == null) {
+ appenderList = new Vector<Appender>(1);
+ }
+ if (!appenderList.contains(newAppender)) {
+ appenderList.addElement(newAppender);
+ }
+ }
+
+ public int appendLoopOnAppenders(LoggingEvent event) {
+ int size = 0;
+ Appender appender;
+
+ if (appenderList != null) {
+ size = appenderList.size();
+ for (int i = 0; i < size; i++) {
+ appender = appenderList.elementAt(i);
+ appender.doAppend(event);
+ }
+ }
+ return size;
+ }
+
+ public Enumeration getAllAppenders() {
+ if (appenderList == null) {
+ return null;
+ } else {
+ return appenderList.elements();
+ }
+ }
+
+ public Appender getAppender(String name) {
+ if (appenderList == null || name == null) {
+ return null;
+ }
+
+ int size = appenderList.size();
+ Appender appender;
+ for (int i = 0; i < size; i++) {
+ appender = appenderList.elementAt(i);
+ if (name.equals(appender.getName())) {
+ return appender;
+ }
+ }
+ return null;
+ }
+
+ public boolean isAttached(Appender appender) {
+ if (appenderList == null || appender == null) {
+ return false;
+ }
+
+ int size = appenderList.size();
+ Appender a;
+ for (int i = 0; i < size; i++) {
+ a = appenderList.elementAt(i);
+ if (a == appender) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void removeAllAppenders() {
+ if (appenderList != null) {
+ int len = appenderList.size();
+ for (int i = 0; i < len; i++) {
+ Appender a = appenderList.elementAt(i);
+ a.close();
+ }
+ appenderList.removeAllElements();
+ appenderList = null;
+ }
+ }
+
+ public void removeAppender(Appender appender) {
+ if (appender == null || appenderList == null) {
+ return;
+ }
+ appenderList.removeElement(appender);
+ }
+
+ public void removeAppender(String name) {
+ if (name == null || appenderList == null) {
+ return;
+ }
+ int size = appenderList.size();
+ for (int i = 0; i < size; i++) {
+ if (name.equals((appenderList.elementAt(i)).getName())) {
+ appenderList.removeElementAt(i);
+ break;
+ }
+ }
+ }
+
+ }
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/inner/Layout.java b/logging/src/main/java/org/apache/rocketmq/logging/inner/Layout.java
new file mode 100644
index 0000000..7ea3561
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/inner/Layout.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+public abstract class Layout {
+
+ public abstract String format(LoggingEvent event);
+
+ public String getContentType() {
+ return "text/plain";
+ }
+
+ public String getHeader() {
+ return null;
+ }
+
+ public String getFooter() {
+ return null;
+ }
+
+
+ abstract public boolean ignoresThrowable();
+
+}
\ No newline at end of file
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/inner/Level.java b/logging/src/main/java/org/apache/rocketmq/logging/inner/Level.java
new file mode 100755
index 0000000..487682c
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/inner/Level.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import java.io.Serializable;
+
+public class Level implements Serializable {
+
+ transient int level;
+ transient String levelStr;
+ transient int syslogEquivalent;
+
+ public final static int OFF_INT = Integer.MAX_VALUE;
+ public final static int ERROR_INT = 40000;
+ public final static int WARN_INT = 30000;
+ public final static int INFO_INT = 20000;
+ public final static int DEBUG_INT = 10000;
+ public final static int ALL_INT = Integer.MIN_VALUE;
+
+
+ private static final String ALL_NAME = "ALL";
+
+ private static final String DEBUG_NAME = "DEBUG";
+
+ private static final String INFO_NAME = "INFO";
+
+ private static final String WARN_NAME = "WARN";
+
+ private static final String ERROR_NAME = "ERROR";
+
+ private static final String OFF_NAME = "OFF";
+
+ final static public Level OFF = new Level(OFF_INT, OFF_NAME, 0);
+
+ final static public Level ERROR = new Level(ERROR_INT, ERROR_NAME, 3);
+
+ final static public Level WARN = new Level(WARN_INT, WARN_NAME, 4);
+
+ final static public Level INFO = new Level(INFO_INT, INFO_NAME, 6);
+
+ final static public Level DEBUG = new Level(DEBUG_INT, DEBUG_NAME, 7);
+
+ final static public Level ALL = new Level(ALL_INT, ALL_NAME, 7);
+
+ static final long serialVersionUID = 3491141966387921974L;
+
+ protected Level(int level, String levelStr, int syslogEquivalent) {
+ this.level = level;
+ this.levelStr = levelStr;
+ this.syslogEquivalent = syslogEquivalent;
+ }
+
+ public static Level toLevel(String sArg) {
+ return toLevel(sArg, Level.DEBUG);
+ }
+
+ public static Level toLevel(int val) {
+ return toLevel(val, Level.DEBUG);
+ }
+
+ public static Level toLevel(int val, Level defaultLevel) {
+ switch (val) {
+ case ALL_INT:
+ return ALL;
+ case DEBUG_INT:
+ return Level.DEBUG;
+ case INFO_INT:
+ return Level.INFO;
+ case WARN_INT:
+ return Level.WARN;
+ case ERROR_INT:
+ return Level.ERROR;
+ case OFF_INT:
+ return OFF;
+ default:
+ return defaultLevel;
+ }
+ }
+
+ public static Level toLevel(String sArg, Level defaultLevel) {
+ if (sArg == null) {
+ return defaultLevel;
+ }
+ String s = sArg.toUpperCase();
+
+ if (s.equals(ALL_NAME)) {
+ return Level.ALL;
+ }
+ if (s.equals(DEBUG_NAME)) {
+ return Level.DEBUG;
+ }
+ if (s.equals(INFO_NAME)) {
+ return Level.INFO;
+ }
+ if (s.equals(WARN_NAME)) {
+ return Level.WARN;
+ }
+ if (s.equals(ERROR_NAME)) {
+ return Level.ERROR;
+ }
+ if (s.equals(OFF_NAME)) {
+ return Level.OFF;
+ }
+
+ if (s.equals(INFO_NAME)) {
+ return Level.INFO;
+ }
+ return defaultLevel;
+ }
+
+
+ public boolean equals(Object o) {
+ if (o instanceof Level) {
+ Level r = (Level) o;
+ return this.level == r.level;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int result = level;
+ result = 31 * result + (levelStr != null ? levelStr.hashCode() : 0);
+ result = 31 * result + syslogEquivalent;
+ return result;
+ }
+
+ public boolean isGreaterOrEqual(Level r) {
+ return level >= r.level;
+ }
+
+ final public String toString() {
+ return levelStr;
+ }
+
+ public final int toInt() {
+ return level;
+ }
+
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/inner/Logger.java b/logging/src/main/java/org/apache/rocketmq/logging/inner/Logger.java
new file mode 100755
index 0000000..470ed41
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/inner/Logger.java
@@ -0,0 +1,467 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+
+public class Logger implements Appender.AppenderPipeline {
+
+ private static final String FQCN = Logger.class.getName();
+
+ private static final DefaultLoggerRepository REPOSITORY = new DefaultLoggerRepository(new RootLogger(Level.DEBUG));
+
+ public static LoggerRepository getRepository() {
+ return REPOSITORY;
+ }
+
+ private String name;
+
+ volatile private Level level;
+
+ volatile private Logger parent;
+
+ Appender.AppenderPipelineImpl appenderPipeline;
+
+ private boolean additive = true;
+
+ private Logger(String name) {
+ this.name = name;
+ }
+
+ static public Logger getLogger(String name) {
+ return getRepository().getLogger(name);
+ }
+
+ static public Logger getLogger(Class clazz) {
+ return getRepository().getLogger(clazz.getName());
+ }
+
+ public static Logger getRootLogger() {
+ return getRepository().getRootLogger();
+ }
+
+ synchronized public void addAppender(Appender newAppender) {
+ if (appenderPipeline == null) {
+ appenderPipeline = new Appender.AppenderPipelineImpl();
+ }
+ appenderPipeline.addAppender(newAppender);
+ }
+
+ public void callAppenders(LoggingEvent event) {
+ int writes = 0;
+
+ for (Logger logger = this; logger != null; logger = logger.parent) {
+ synchronized (logger) {
+ if (logger.appenderPipeline != null) {
+ writes += logger.appenderPipeline.appendLoopOnAppenders(event);
+ }
+ if (!logger.additive) {
+ break;
+ }
+ }
+ }
+
+ if (writes == 0) {
+ getRepository().emitNoAppenderWarning(this);
+ }
+ }
+
+ synchronized void closeNestedAppenders() {
+ Enumeration enumeration = this.getAllAppenders();
+ if (enumeration != null) {
+ while (enumeration.hasMoreElements()) {
+ Appender a = (Appender) enumeration.nextElement();
+ if (a instanceof Appender.AppenderPipeline) {
+ a.close();
+ }
+ }
+ }
+ }
+
+ public void debug(Object message) {
+ if (getRepository().isDisabled(Level.DEBUG_INT)) {
+ return;
+ }
+ if (Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {
+ forcedLog(FQCN, Level.DEBUG, message, null);
+ }
+ }
+
+
+ public void debug(Object message, Throwable t) {
+ if (getRepository().isDisabled(Level.DEBUG_INT)) {
+ return;
+ }
+ if (Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel())) {
+ forcedLog(FQCN, Level.DEBUG, message, t);
+ }
+ }
+
+
+ public void error(Object message) {
+ if (getRepository().isDisabled(Level.ERROR_INT)) {
+ return;
+ }
+ if (Level.ERROR.isGreaterOrEqual(this.getEffectiveLevel())) {
+ forcedLog(FQCN, Level.ERROR, message, null);
+ }
+ }
+
+ public void error(Object message, Throwable t) {
+ if (getRepository().isDisabled(Level.ERROR_INT)) {
+ return;
+ }
+ if (Level.ERROR.isGreaterOrEqual(this.getEffectiveLevel())) {
+ forcedLog(FQCN, Level.ERROR, message, t);
+ }
+
+ }
+
+
+ protected void forcedLog(String fqcn, Level level, Object message, Throwable t) {
+ callAppenders(new LoggingEvent(fqcn, this, level, message, t));
+ }
+
+
+ synchronized public Enumeration getAllAppenders() {
+ if (appenderPipeline == null) {
+ return null;
+ } else {
+ return appenderPipeline.getAllAppenders();
+ }
+ }
+
+ synchronized public Appender getAppender(String name) {
+ if (appenderPipeline == null || name == null) {
+ return null;
+ }
+
+ return appenderPipeline.getAppender(name);
+ }
+
+ public Level getEffectiveLevel() {
+ for (Logger c = this; c != null; c = c.parent) {
+ if (c.level != null) {
+ return c.level;
+ }
+ }
+ return null;
+ }
+
+ public final String getName() {
+ return name;
+ }
+
+ final public Level getLevel() {
+ return this.level;
+ }
+
+
+ public void info(Object message) {
+ if (getRepository().isDisabled(Level.INFO_INT)) {
+ return;
+ }
+ if (Level.INFO.isGreaterOrEqual(this.getEffectiveLevel())) {
+ forcedLog(FQCN, Level.INFO, message, null);
+ }
+ }
+
+ public void info(Object message, Throwable t) {
+ if (getRepository().isDisabled(Level.INFO_INT)) {
+ return;
+ }
+ if (Level.INFO.isGreaterOrEqual(this.getEffectiveLevel())) {
+ forcedLog(FQCN, Level.INFO, message, t);
+ }
+ }
+
+ public boolean isAttached(Appender appender) {
+ return appender != null && appenderPipeline != null && appenderPipeline.isAttached(appender);
+ }
+
+ synchronized public void removeAllAppenders() {
+ if (appenderPipeline != null) {
+ appenderPipeline.removeAllAppenders();
+ appenderPipeline = null;
+ }
+ }
+
+ synchronized public void removeAppender(Appender appender) {
+ if (appender == null || appenderPipeline == null) {
+ return;
+ }
+ appenderPipeline.removeAppender(appender);
+ }
+
+ synchronized public void removeAppender(String name) {
+ if (name == null || appenderPipeline == null) {
+ return;
+ }
+ appenderPipeline.removeAppender(name);
+ }
+
+ public void setAdditivity(boolean additive) {
+ this.additive = additive;
+ }
+
+ public void setLevel(Level level) {
+ this.level = level;
+ }
+
+ public void warn(Object message) {
+ if (getRepository().isDisabled(Level.WARN_INT)) {
+ return;
+ }
+
+ if (Level.WARN.isGreaterOrEqual(this.getEffectiveLevel())) {
+ forcedLog(FQCN, Level.WARN, message, null);
+ }
+ }
+
+ public void warn(Object message, Throwable t) {
+ if (getRepository().isDisabled(Level.WARN_INT)) {
+ return;
+ }
+ if (Level.WARN.isGreaterOrEqual(this.getEffectiveLevel())) {
+ forcedLog(FQCN, Level.WARN, message, t);
+ }
+ }
+
+ public interface LoggerRepository {
+
+ boolean isDisabled(int level);
+
+ void setLogLevel(Level level);
+
+ void emitNoAppenderWarning(Logger cat);
+
+ Level getLogLevel();
+
+ Logger getLogger(String name);
+
+ Logger getRootLogger();
+
+ Logger exists(String name);
+
+ void shutdown();
+
+ Enumeration getCurrentLoggers();
+ }
+
+ public static class ProvisionNode extends Vector<Logger> {
+
+ ProvisionNode(Logger logger) {
+ super();
+ addElement(logger);
+ }
+ }
+
+ public static class DefaultLoggerRepository implements LoggerRepository {
+
+ final Hashtable<CategoryKey,Object> ht = new Hashtable<CategoryKey,Object>();
+ Logger root;
+
+ int logLevelInt;
+ Level logLevel;
+
+ boolean emittedNoAppenderWarning = false;
+
+ public DefaultLoggerRepository(Logger root) {
+ this.root = root;
+ setLogLevel(Level.ALL);
+ }
+
+ public void emitNoAppenderWarning(Logger cat) {
+ if (!this.emittedNoAppenderWarning) {
+ SysLogger.warn("No appenders could be found for logger (" + cat.getName() + ").");
+ SysLogger.warn("Please initialize the logger system properly.");
+ this.emittedNoAppenderWarning = true;
+ }
+ }
+
+ public Logger exists(String name) {
+ Object o = ht.get(new CategoryKey(name));
+ if (o instanceof Logger) {
+ return (Logger) o;
+ } else {
+ return null;
+ }
+ }
+
+ public void setLogLevel(Level l) {
+ if (l != null) {
+ logLevelInt = l.level;
+ logLevel = l;
+ }
+ }
+
+ public Level getLogLevel() {
+ return logLevel;
+ }
+
+
+ public Logger getLogger(String name) {
+ CategoryKey key = new CategoryKey(name);
+ Logger logger;
+
+ synchronized (ht) {
+ Object o = ht.get(key);
+ if (o == null) {
+ logger = makeNewLoggerInstance(name);
+ ht.put(key, logger);
+ updateParents(logger);
+ return logger;
+ } else if (o instanceof Logger) {
+ return (Logger) o;
+ } else if (o instanceof ProvisionNode) {
+ logger = makeNewLoggerInstance(name);
+ ht.put(key, logger);
+ updateChildren((ProvisionNode) o, logger);
+ updateParents(logger);
+ return logger;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public Logger makeNewLoggerInstance(String name) {
+ return new Logger(name);
+ }
+
+ public Enumeration getCurrentLoggers() {
+ Vector<Logger> loggers = new Vector<Logger>(ht.size());
+
+ Enumeration elems = ht.elements();
+ while (elems.hasMoreElements()) {
+ Object o = elems.nextElement();
+ if (o instanceof Logger) {
+ Logger logger = (Logger)o;
+ loggers.addElement(logger);
+ }
+ }
+ return loggers.elements();
+ }
+
+
+ public Logger getRootLogger() {
+ return root;
+ }
+
+ public boolean isDisabled(int level) {
+ return logLevelInt > level;
+ }
+
+
+ public void shutdown() {
+ Logger root = getRootLogger();
+ root.closeNestedAppenders();
+
+ synchronized (ht) {
+ Enumeration cats = this.getCurrentLoggers();
+ while (cats.hasMoreElements()) {
+ Logger c = (Logger) cats.nextElement();
+ c.closeNestedAppenders();
+ }
+ root.removeAllAppenders();
+ }
+ }
+
+
+ private void updateParents(Logger cat) {
+ String name = cat.name;
+ int length = name.length();
+ boolean parentFound = false;
+
+ for (int i = name.lastIndexOf('.', length - 1); i >= 0;
+ i = name.lastIndexOf('.', i - 1)) {
+ String substr = name.substring(0, i);
+
+ CategoryKey key = new CategoryKey(substr);
+ Object o = ht.get(key);
+ if (o == null) {
+ ht.put(key, new ProvisionNode(cat));
+ } else if (o instanceof Logger) {
+ parentFound = true;
+ cat.parent = (Logger) o;
+ break;
+ } else if (o instanceof ProvisionNode) {
+ ((ProvisionNode) o).addElement(cat);
+ } else {
+ Exception e = new IllegalStateException("unexpected object type " + o.getClass() + " in ht.");
+ e.printStackTrace();
+ }
+ }
+ if (!parentFound) {
+ cat.parent = root;
+ }
+ }
+
+ private void updateChildren(ProvisionNode pn, Logger logger) {
+ final int last = pn.size();
+
+ for (int i = 0; i < last; i++) {
+ Logger l = pn.elementAt(i);
+ if (!l.parent.name.startsWith(logger.name)) {
+ logger.parent = l.parent;
+ l.parent = logger;
+ }
+ }
+ }
+
+ private class CategoryKey {
+
+ String name;
+ int hashCache;
+
+ CategoryKey(String name) {
+ this.name = name;
+ hashCache = name.hashCode();
+ }
+
+ final public int hashCode() {
+ return hashCache;
+ }
+
+ final public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (o != null && o instanceof CategoryKey) {
+ CategoryKey cc = (CategoryKey) o;
+ return name.equals(cc.name);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ }
+
+ public static class RootLogger extends Logger {
+
+ public RootLogger(Level level) {
+ super("root");
+ setLevel(level);
+ }
+ }
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/inner/LoggingBuilder.java b/logging/src/main/java/org/apache/rocketmq/logging/inner/LoggingBuilder.java
new file mode 100644
index 0000000..469cb52
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/inner/LoggingBuilder.java
@@ -0,0 +1,1230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FilterWriter;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+public class LoggingBuilder {
+
+ public static final String SYSTEM_OUT = "System.out";
+ public static final String SYSTEM_ERR = "System.err";
+
+ public static final String LOGGING_ENCODING = "rocketmq.logging.inner.encoding";
+ public static final String ENCODING = System.getProperty(LOGGING_ENCODING, "UTF-8");
+
+ public static AppenderBuilder newAppenderBuilder() {
+ return new AppenderBuilder();
+ }
+
+ public static class AppenderBuilder {
+ private AsyncAppender asyncAppender;
+
+ private Appender appender = null;
+
+ private AppenderBuilder() {
+
+ }
+
+ public AppenderBuilder withLayout(Layout layout) {
+ appender.setLayout(layout);
+ return this;
+ }
+
+ public AppenderBuilder withName(String name) {
+ appender.setName(name);
+ return this;
+ }
+
+ public AppenderBuilder withConsoleAppender(String target) {
+ ConsoleAppender consoleAppender = new ConsoleAppender();
+ consoleAppender.setTarget(target);
+ consoleAppender.activateOptions();
+ this.appender = consoleAppender;
+ return this;
+ }
+
+ public AppenderBuilder withFileAppender(String file) {
+ FileAppender appender = new FileAppender();
+ appender.setFile(file);
+ appender.setAppend(true);
+ appender.setBufferedIO(false);
+ appender.setEncoding(ENCODING);
+ appender.setImmediateFlush(true);
+ appender.activateOptions();
+ this.appender = appender;
+ return this;
+ }
+
+ public AppenderBuilder withRollingFileAppender(String file, String maxFileSize, int maxFileIndex) {
+ RollingFileAppender appender = new RollingFileAppender();
+ appender.setFile(file);
+ appender.setAppend(true);
+ appender.setBufferedIO(false);
+ appender.setEncoding(ENCODING);
+ appender.setImmediateFlush(true);
+ appender.setMaximumFileSize(Integer.parseInt(maxFileSize));
+ appender.setMaxBackupIndex(maxFileIndex);
+ appender.activateOptions();
+ this.appender = appender;
+ return this;
+ }
+
+ public AppenderBuilder withDailyFileRollingAppender(String file, String datePattern) {
+ DailyRollingFileAppender appender = new DailyRollingFileAppender();
+ appender.setFile(file);
+ appender.setAppend(true);
+ appender.setBufferedIO(false);
+ appender.setEncoding(ENCODING);
+ appender.setImmediateFlush(true);
+ appender.setDatePattern(datePattern);
+ appender.activateOptions();
+ this.appender = appender;
+ return this;
+ }
+
+ public AppenderBuilder withAsync(boolean blocking, int buffSize) {
+ AsyncAppender asyncAppender = new AsyncAppender();
+ asyncAppender.setBlocking(blocking);
+ asyncAppender.setBufferSize(buffSize);
+ this.asyncAppender = asyncAppender;
+ return this;
+ }
+
+ public Appender build() {
+ if (appender == null) {
+ throw new RuntimeException("please specify appender first");
+ }
+ if (asyncAppender != null) {
+ asyncAppender.addAppender(appender);
+ return asyncAppender;
+ } else {
+ return appender;
+ }
+ }
+ }
+
+ public static class AsyncAppender extends Appender implements Appender.AppenderPipeline {
+
+ public static final int DEFAULT_BUFFER_SIZE = 128;
+
+ private final List<LoggingEvent> buffer = new ArrayList<LoggingEvent>();
+
+ private final Map<String, DiscardSummary> discardMap = new HashMap<String, DiscardSummary>();
+
+ private int bufferSize = DEFAULT_BUFFER_SIZE;
+
+ private final AppenderPipelineImpl appenderPipeline;
+
+ private final Thread dispatcher;
+
+ private boolean blocking = true;
+
+ public AsyncAppender() {
+ appenderPipeline = new AppenderPipelineImpl();
+
+ dispatcher = new Thread(new Dispatcher(this, buffer, discardMap, appenderPipeline));
+
+ dispatcher.setDaemon(true);
+
+ dispatcher.setName("AsyncAppender-Dispatcher-" + dispatcher.getName());
+ dispatcher.start();
+ }
+
+ public void addAppender(final Appender newAppender) {
+ synchronized (appenderPipeline) {
+ appenderPipeline.addAppender(newAppender);
+ }
+ }
+
+ public void append(final LoggingEvent event) {
+ if ((dispatcher == null) || !dispatcher.isAlive() || (bufferSize <= 0)) {
+ synchronized (appenderPipeline) {
+ appenderPipeline.appendLoopOnAppenders(event);
+ }
+
+ return;
+ }
+
+ event.getThreadName();
+ event.getRenderedMessage();
+
+ synchronized (buffer) {
+ while (true) {
+ int previousSize = buffer.size();
+
+ if (previousSize < bufferSize) {
+ buffer.add(event);
+
+ if (previousSize == 0) {
+ buffer.notifyAll();
+ }
+
+ break;
+ }
+
+ boolean discard = true;
+ if (blocking
+ && !Thread.interrupted()
+ && Thread.currentThread() != dispatcher) {
+ try {
+ buffer.wait();
+ discard = false;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ if (discard) {
+ String loggerName = event.getLoggerName();
+ DiscardSummary summary = discardMap.get(loggerName);
+
+ if (summary == null) {
+ summary = new DiscardSummary(event);
+ discardMap.put(loggerName, summary);
+ } else {
+ summary.add(event);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ public void close() {
+
+ synchronized (buffer) {
+ closed = true;
+ buffer.notifyAll();
+ }
+
+ try {
+ dispatcher.join();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ SysLogger.error(
+ "Got an InterruptedException while waiting for the "
+ + "dispatcher to finish.", e);
+ }
+
+ synchronized (appenderPipeline) {
+ Enumeration iter = appenderPipeline.getAllAppenders();
+ if (iter != null) {
+ while (iter.hasMoreElements()) {
+ Object next = iter.nextElement();
+ if (next instanceof Appender) {
+ ((Appender) next).close();
+ }
+ }
+ }
+ }
+ }
+
+ public Enumeration getAllAppenders() {
+ synchronized (appenderPipeline) {
+ return appenderPipeline.getAllAppenders();
+ }
+ }
+
+ public Appender getAppender(final String name) {
+ synchronized (appenderPipeline) {
+ return appenderPipeline.getAppender(name);
+ }
+ }
+
+ public boolean isAttached(final Appender appender) {
+ synchronized (appenderPipeline) {
+ return appenderPipeline.isAttached(appender);
+ }
+ }
+
+ public void removeAllAppenders() {
+ synchronized (appenderPipeline) {
+ appenderPipeline.removeAllAppenders();
+ }
+ }
+
+ public void removeAppender(final Appender appender) {
+ synchronized (appenderPipeline) {
+ appenderPipeline.removeAppender(appender);
+ }
+ }
+
+ public void removeAppender(final String name) {
+ synchronized (appenderPipeline) {
+ appenderPipeline.removeAppender(name);
+ }
+ }
+
+ public void setBufferSize(final int size) {
+ if (size < 0) {
+ throw new NegativeArraySizeException("size");
+ }
+
+ synchronized (buffer) {
+ bufferSize = (size < 1) ? 1 : size;
+ buffer.notifyAll();
+ }
+ }
+
+ public int getBufferSize() {
+ return bufferSize;
+ }
+
+ public void setBlocking(final boolean value) {
+ synchronized (buffer) {
+ blocking = value;
+ buffer.notifyAll();
+ }
+ }
+
+ public boolean getBlocking() {
+ return blocking;
+ }
+
+ private final class DiscardSummary {
+
+ private LoggingEvent maxEvent;
+
+ private int count;
+
+ public DiscardSummary(final LoggingEvent event) {
+ maxEvent = event;
+ count = 1;
+ }
+
+ public void add(final LoggingEvent event) {
+ if (event.getLevel().toInt() > maxEvent.getLevel().toInt()) {
+ maxEvent = event;
+ }
+ count++;
+ }
+
+ public LoggingEvent createEvent() {
+ String msg =
+ MessageFormat.format(
+ "Discarded {0} messages due to full event buffer including: {1}",
+ count, maxEvent.getMessage());
+
+ return new LoggingEvent(
+ "AsyncAppender.DONT_REPORT_LOCATION",
+ Logger.getLogger(maxEvent.getLoggerName()),
+ maxEvent.getLevel(),
+ msg,
+ null);
+ }
+ }
+
+ private class Dispatcher implements Runnable {
+
+ private final AsyncAppender parent;
+
+ private final List<LoggingEvent> buffer;
+
+ private final Map<String, DiscardSummary> discardMap;
+
+ private final AppenderPipelineImpl appenderPipeline;
+
+ public Dispatcher(
+ final AsyncAppender parent, final List<LoggingEvent> buffer, final Map<String, DiscardSummary> discardMap,
+ final AppenderPipelineImpl appenderPipeline) {
+
+ this.parent = parent;
+ this.buffer = buffer;
+ this.appenderPipeline = appenderPipeline;
+ this.discardMap = discardMap;
+ }
+
+ public void run() {
+ boolean isActive = true;
+
+ try {
+ while (isActive) {
+ LoggingEvent[] events = null;
+
+ synchronized (buffer) {
+ int bufferSize = buffer.size();
+ isActive = !parent.closed;
+
+ while ((bufferSize == 0) && isActive) {
+ buffer.wait();
+ bufferSize = buffer.size();
+ isActive = !parent.closed;
+ }
+
+ if (bufferSize > 0) {
+ events = new LoggingEvent[bufferSize + discardMap.size()];
+ buffer.toArray(events);
+
+ int index = bufferSize;
+ Collection<DiscardSummary> values = discardMap.values();
+ for (DiscardSummary value : values) {
+ events[index++] = value.createEvent();
+ }
+
+ buffer.clear();
+ discardMap.clear();
+
+ buffer.notifyAll();
+ }
+ }
+ if (events != null) {
+ for (LoggingEvent event : events) {
+ synchronized (appenderPipeline) {
+ appenderPipeline.appendLoopOnAppenders(event);
+ }
+ }
+ }
+ }
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ private static class QuietWriter extends FilterWriter {
+
+ protected Appender appender;
+
+ public QuietWriter(Writer writer, Appender appender) {
+ super(writer);
+ this.appender = appender;
+ }
+
+ public void write(String string) {
+ if (string != null) {
+ try {
+ out.write(string);
+ } catch (Exception e) {
+ appender.handleError("Failed to write [" + string + "].", e,
+ Appender.CODE_WRITE_FAILURE);
+ }
+ }
+ }
+
+ public void flush() {
+ try {
+ out.flush();
+ } catch (Exception e) {
+ appender.handleError("Failed to flush writer,", e,
+ Appender.CODE_FLUSH_FAILURE);
+ }
+ }
+ }
+
+ public static class WriterAppender extends Appender {
+
+
+ protected boolean immediateFlush = true;
+
+ protected String encoding;
+
+
+ protected QuietWriter qw;
+
+ public WriterAppender() {
+
+ }
+
+ public void setImmediateFlush(boolean value) {
+ immediateFlush = value;
+ }
+
+
+ public boolean getImmediateFlush() {
+ return immediateFlush;
+ }
+
+ public void activateOptions() {
+ }
+
+
+ public void append(LoggingEvent event) {
+ if (!checkEntryConditions()) {
+ return;
+ }
+ subAppend(event);
+ }
+
+ protected boolean checkEntryConditions() {
+ if (this.closed) {
+ SysLogger.warn("Not allowed to write to a closed appender.");
+ return false;
+ }
+
+ if (this.qw == null) {
+ handleError("No output stream or file set for the appender named [" +
+ name + "].");
+ return false;
+ }
+
+ if (this.layout == null) {
+ handleError("No layout set for the appender named [" + name + "].");
+ return false;
+ }
+ return true;
+ }
+
+ public synchronized void close() {
+ if (this.closed) {
+ return;
+ }
+ this.closed = true;
+ writeFooter();
+ reset();
+ }
+
+ protected void closeWriter() {
+ if (qw != null) {
+ try {
+ qw.close();
+ } catch (IOException e) {
+ handleError("Could not close " + qw, e, CODE_CLOSE_FAILURE);
+ }
+ }
+ }
+
+ protected OutputStreamWriter createWriter(OutputStream os) {
+ OutputStreamWriter retval = null;
+
+ String enc = getEncoding();
+ if (enc != null) {
+ try {
+ retval = new OutputStreamWriter(os, enc);
+ } catch (IOException e) {
+ SysLogger.warn("Error initializing output writer.");
+ SysLogger.warn("Unsupported encoding?");
+ }
+ }
+ if (retval == null) {
+ retval = new OutputStreamWriter(os);
+ }
+ return retval;
+ }
+
+ public String getEncoding() {
+ return encoding;
+ }
+
+ public void setEncoding(String value) {
+ encoding = value;
+ }
+
+
+ public synchronized void setWriter(Writer writer) {
+ reset();
+ this.qw = new QuietWriter(writer, this);
+ writeHeader();
+ }
+
+ protected void subAppend(LoggingEvent event) {
+ this.qw.write(this.layout.format(event));
+
+ if (layout.ignoresThrowable()) {
+ String[] s = event.getThrowableStr();
+ if (s != null) {
+ for (String s1 : s) {
+ this.qw.write(s1);
+ this.qw.write(LINE_SEP);
+ }
+ }
+ }
+
+ if (shouldFlush(event)) {
+ this.qw.flush();
+ }
+ }
+
+ protected void reset() {
+ closeWriter();
+ this.qw = null;
+ }
+
+ protected void writeFooter() {
+ if (layout != null) {
+ String f = layout.getFooter();
+ if (f != null && this.qw != null) {
+ this.qw.write(f);
+ this.qw.flush();
+ }
+ }
+ }
+
+ protected void writeHeader() {
+ if (layout != null) {
+ String h = layout.getHeader();
+ if (h != null && this.qw != null) {
+ this.qw.write(h);
+ }
+ }
+ }
+
+ protected boolean shouldFlush(final LoggingEvent event) {
+ return event != null && immediateFlush;
+ }
+ }
+
+
+ public static class FileAppender extends WriterAppender {
+
+ protected boolean fileAppend = true;
+
+ protected String fileName = null;
+
+ protected boolean bufferedIO = false;
+
+ protected int bufferSize = 8 * 1024;
+
+ public FileAppender() {
+ }
+
+ public FileAppender(Layout layout, String filename, boolean append)
+ throws IOException {
+ this.layout = layout;
+ this.setFile(filename, append, false, bufferSize);
+ }
+
+ public void setFile(String file) {
+ fileName = file.trim();
+ }
+
+ public boolean getAppend() {
+ return fileAppend;
+ }
+
+ public String getFile() {
+ return fileName;
+ }
+
+ public void activateOptions() {
+ if (fileName != null) {
+ try {
+ setFile(fileName, fileAppend, bufferedIO, bufferSize);
+ } catch (IOException e) {
+ handleError("setFile(" + fileName + "," + fileAppend + ") call failed.",
+ e, CODE_FILE_OPEN_FAILURE);
+ }
+ } else {
+ SysLogger.warn("File option not set for appender [" + name + "].");
+ SysLogger.warn("Are you using FileAppender instead of ConsoleAppender?");
+ }
+ }
+
+ protected void closeFile() {
+ if (this.qw != null) {
+ try {
+ this.qw.close();
+ } catch (IOException e) {
+ if (e instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ SysLogger.error("Could not close " + qw, e);
+ }
+ }
+ }
+
+ public boolean getBufferedIO() {
+ return this.bufferedIO;
+ }
+
+ public int getBufferSize() {
+ return this.bufferSize;
+ }
+
+ public void setAppend(boolean flag) {
+ fileAppend = flag;
+ }
+
+ public void setBufferedIO(boolean bufferedIO) {
+ this.bufferedIO = bufferedIO;
+ if (bufferedIO) {
+ immediateFlush = false;
+ }
+ }
+
+ public void setBufferSize(int bufferSize) {
+ this.bufferSize = bufferSize;
+ }
+
+ public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
+ throws IOException {
+ SysLogger.debug("setFile called: " + fileName + ", " + append);
+
+ if (bufferedIO) {
+ setImmediateFlush(false);
+ }
+
+ reset();
+ FileOutputStream ostream;
+ try {
+ ostream = new FileOutputStream(fileName, append);
+ } catch (FileNotFoundException ex) {
+ String parentName = new File(fileName).getParent();
+ if (parentName != null) {
+ File parentDir = new File(parentName);
+ if (!parentDir.exists() && parentDir.mkdirs()) {
+ ostream = new FileOutputStream(fileName, append);
+ } else {
+ throw ex;
+ }
+ } else {
+ throw ex;
+ }
+ }
+ Writer fw = createWriter(ostream);
+ if (bufferedIO) {
+ fw = new BufferedWriter(fw, bufferSize);
+ }
+ this.setQWForFiles(fw);
+ this.fileName = fileName;
+ this.fileAppend = append;
+ this.bufferedIO = bufferedIO;
+ this.bufferSize = bufferSize;
+ writeHeader();
+ SysLogger.debug("setFile ended");
+ }
+
+ protected void setQWForFiles(Writer writer) {
+ this.qw = new QuietWriter(writer, this);
+ }
+
+ protected void reset() {
+ closeFile();
+ this.fileName = null;
+ super.reset();
+ }
+ }
+
+
+ public static class RollingFileAppender extends FileAppender {
+
+ protected long maxFileSize = 10 * 1024 * 1024;
+
+ protected int maxBackupIndex = 1;
+
+ private long nextRollover = 0;
+
+ public RollingFileAppender() {
+ super();
+ }
+
+ public int getMaxBackupIndex() {
+ return maxBackupIndex;
+ }
+
+ public long getMaximumFileSize() {
+ return maxFileSize;
+ }
+
+ public void rollOver() {
+ File target;
+ File file;
+
+ if (qw != null) {
+ long size = ((CountingQuietWriter) qw).getCount();
+ SysLogger.debug("rolling over count=" + size);
+ nextRollover = size + maxFileSize;
+ }
+ SysLogger.debug("maxBackupIndex=" + maxBackupIndex);
+
+ boolean renameSucceeded = true;
+ if (maxBackupIndex > 0) {
+ file = new File(fileName + '.' + maxBackupIndex);
+ if (file.exists()) {
+ renameSucceeded = file.delete();
+ }
+
+ for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
+ file = new File(fileName + "." + i);
+ if (file.exists()) {
+ target = new File(fileName + '.' + (i + 1));
+ SysLogger.debug("Renaming file " + file + " to " + target);
+ renameSucceeded = file.renameTo(target);
+ }
+ }
+
+ if (renameSucceeded) {
+ target = new File(fileName + "." + 1);
+
+ this.closeFile(); // keep windows happy.
+
+ file = new File(fileName);
+ SysLogger.debug("Renaming file " + file + " to " + target);
+ renameSucceeded = file.renameTo(target);
+
+ if (!renameSucceeded) {
+ try {
+ this.setFile(fileName, true, bufferedIO, bufferSize);
+ } catch (IOException e) {
+ if (e instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ SysLogger.error("setFile(" + fileName + ", true) call failed.", e);
+ }
+ }
+ }
+ }
+
+ if (renameSucceeded) {
+ try {
+ this.setFile(fileName, false, bufferedIO, bufferSize);
+ nextRollover = 0;
+ } catch (IOException e) {
+ if (e instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ SysLogger.error("setFile(" + fileName + ", false) call failed.", e);
+ }
+ }
+ }
+
+ public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize)
+ throws IOException {
+ super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
+ if (append) {
+ File f = new File(fileName);
+ ((CountingQuietWriter) qw).setCount(f.length());
+ }
+ }
+
+ public void setMaxBackupIndex(int maxBackups) {
+ this.maxBackupIndex = maxBackups;
+ }
+
+ public void setMaximumFileSize(long maxFileSize) {
+ this.maxFileSize = maxFileSize;
+ }
+
+ protected void setQWForFiles(Writer writer) {
+ this.qw = new CountingQuietWriter(writer, this);
+ }
+
+ protected void subAppend(LoggingEvent event) {
+ super.subAppend(event);
+ if (fileName != null && qw != null) {
+ long size = ((CountingQuietWriter) qw).getCount();
+ if (size >= maxFileSize && size >= nextRollover) {
+ rollOver();
+ }
+ }
+ }
+
+ protected class CountingQuietWriter extends QuietWriter {
+
+ protected long count;
+
+ public CountingQuietWriter(Writer writer, Appender appender) {
+ super(writer, appender);
+ }
+
+ public void write(String string) {
+ try {
+ out.write(string);
+ count += string.length();
+ } catch (IOException e) {
+ appender.handleError("Write failure.", e, Appender.CODE_WRITE_FAILURE);
+ }
+ }
+
+ public long getCount() {
+ return count;
+ }
+
+ public void setCount(long count) {
+ this.count = count;
+ }
+
+ }
+ }
+
+
+ public static class DailyRollingFileAppender extends FileAppender {
+
+ static final int TOP_OF_TROUBLE = -1;
+ static final int TOP_OF_MINUTE = 0;
+ static final int TOP_OF_HOUR = 1;
+ static final int HALF_DAY = 2;
+ static final int TOP_OF_DAY = 3;
+ static final int TOP_OF_WEEK = 4;
+ static final int TOP_OF_MONTH = 5;
+
+
+ /**
+ * The date pattern. By default, the pattern is set to
+ * "'.'yyyy-MM-dd" meaning daily rollover.
+ */
+ private String datePattern = "'.'yyyy-MM-dd";
+
+ private String scheduledFilename;
+
+ private long nextCheck = System.currentTimeMillis() - 1;
+
+ Date now = new Date();
+
+ SimpleDateFormat sdf;
+
+ RollingCalendar rc = new RollingCalendar();
+
+ final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
+
+
+ public void setDatePattern(String pattern) {
+ datePattern = pattern;
+ }
+
+ public String getDatePattern() {
+ return datePattern;
+ }
+
+ public void activateOptions() {
+ super.activateOptions();
+ if (datePattern != null && fileName != null) {
+ now.setTime(System.currentTimeMillis());
+ sdf = new SimpleDateFormat(datePattern);
+ int type = computeCheckPeriod();
+ printPeriodicity(type);
+ rc.setType(type);
+ File file = new File(fileName);
+ scheduledFilename = fileName + sdf.format(new Date(file.lastModified()));
+
+ } else {
+ SysLogger.error("Either File or DatePattern options are not set for appender [" + name + "].");
+ }
+ }
+
+ void printPeriodicity(int type) {
+ switch (type) {
+ case TOP_OF_MINUTE:
+ SysLogger.debug("Appender [" + name + "] to be rolled every minute.");
+ break;
+ case TOP_OF_HOUR:
+ SysLogger.debug("Appender [" + name + "] to be rolled on top of every hour.");
+ break;
+ case HALF_DAY:
+ SysLogger.debug("Appender [" + name + "] to be rolled at midday and midnight.");
+ break;
+ case TOP_OF_DAY:
+ SysLogger.debug("Appender [" + name + "] to be rolled at midnight.");
+ break;
+ case TOP_OF_WEEK:
+ SysLogger.debug("Appender [" + name + "] to be rolled at start of week.");
+ break;
+ case TOP_OF_MONTH:
+ SysLogger.debug("Appender [" + name + "] to be rolled at start of every month.");
+ break;
+ default:
+ SysLogger.warn("Unknown periodicity for appender [" + name + "].");
+ }
+ }
+
+ int computeCheckPeriod() {
+ RollingCalendar rollingCalendar = new RollingCalendar(gmtTimeZone, Locale.getDefault());
+ // set sate to 1970-01-01 00:00:00 GMT
+ Date epoch = new Date(0);
+ if (datePattern != null) {
+ for (int i = TOP_OF_MINUTE; i <= TOP_OF_MONTH; i++) {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(datePattern);
+ simpleDateFormat.setTimeZone(gmtTimeZone);
+ String r0 = simpleDateFormat.format(epoch);
+ rollingCalendar.setType(i);
+ Date next = new Date(rollingCalendar.getNextCheckMillis(epoch));
+ String r1 = simpleDateFormat.format(next);
+ if (r0.equals(r1)) {
+ return i;
+ }
+ }
+ }
+ return TOP_OF_TROUBLE;
+ }
+
+ void rollOver() throws IOException {
+
+ if (datePattern == null) {
+ handleError("Missing DatePattern option in rollOver().");
+ return;
+ }
+
+ String datedFilename = fileName + sdf.format(now);
+
+ if (scheduledFilename.equals(datedFilename)) {
+ return;
+ }
+ this.closeFile();
+
+ File target = new File(scheduledFilename);
+ if (target.exists() && !target.delete()) {
+ SysLogger.error("Failed to delete [" + scheduledFilename + "].");
+ }
+
+ File file = new File(fileName);
+ boolean result = file.renameTo(target);
+ if (result) {
+ SysLogger.debug(fileName + " -> " + scheduledFilename);
+ } else {
+ SysLogger.error("Failed to rename [" + fileName + "] to [" + scheduledFilename + "].");
+ }
+
+ try {
+ this.setFile(fileName, true, this.bufferedIO, this.bufferSize);
+ } catch (IOException e) {
+ handleError("setFile(" + fileName + ", true) call failed.");
+ }
+ scheduledFilename = datedFilename;
+ }
+
+ protected void subAppend(LoggingEvent event) {
+ long n = System.currentTimeMillis();
+ if (n >= nextCheck) {
+ now.setTime(n);
+ nextCheck = rc.getNextCheckMillis(now);
+ try {
+ rollOver();
+ } catch (IOException ioe) {
+ if (ioe instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ SysLogger.error("rollOver() failed.", ioe);
+ }
+ }
+ super.subAppend(event);
+ }
+ }
+
+ private static class RollingCalendar extends GregorianCalendar {
+ private static final long serialVersionUID = -3560331770601814177L;
+
+ int type = DailyRollingFileAppender.TOP_OF_TROUBLE;
+
+ RollingCalendar() {
+ super();
+ }
+
+ RollingCalendar(TimeZone tz, Locale locale) {
+ super(tz, locale);
+ }
+
+ void setType(int type) {
+ this.type = type;
+ }
+
+ public long getNextCheckMillis(Date now) {
+ return getNextCheckDate(now).getTime();
+ }
+
+ public Date getNextCheckDate(Date now) {
+ this.setTime(now);
+
+ switch (type) {
+ case DailyRollingFileAppender.TOP_OF_MINUTE:
+ this.set(Calendar.SECOND, 0);
+ this.set(Calendar.MILLISECOND, 0);
+ this.add(Calendar.MINUTE, 1);
+ break;
+ case DailyRollingFileAppender.TOP_OF_HOUR:
+ this.set(Calendar.MINUTE, 0);
+ this.set(Calendar.SECOND, 0);
+ this.set(Calendar.MILLISECOND, 0);
+ this.add(Calendar.HOUR_OF_DAY, 1);
+ break;
+ case DailyRollingFileAppender.HALF_DAY:
+ this.set(Calendar.MINUTE, 0);
+ this.set(Calendar.SECOND, 0);
+ this.set(Calendar.MILLISECOND, 0);
+ int hour = get(Calendar.HOUR_OF_DAY);
+ if (hour < 12) {
+ this.set(Calendar.HOUR_OF_DAY, 12);
+ } else {
+ this.set(Calendar.HOUR_OF_DAY, 0);
+ this.add(Calendar.DAY_OF_MONTH, 1);
+ }
+ break;
+ case DailyRollingFileAppender.TOP_OF_DAY:
+ this.set(Calendar.HOUR_OF_DAY, 0);
+ this.set(Calendar.MINUTE, 0);
+ this.set(Calendar.SECOND, 0);
+ this.set(Calendar.MILLISECOND, 0);
+ this.add(Calendar.DATE, 1);
+ break;
+ case DailyRollingFileAppender.TOP_OF_WEEK:
+ this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek());
+ this.set(Calendar.HOUR_OF_DAY, 0);
+ this.set(Calendar.MINUTE, 0);
+ this.set(Calendar.SECOND, 0);
+ this.set(Calendar.MILLISECOND, 0);
+ this.add(Calendar.WEEK_OF_YEAR, 1);
+ break;
+ case DailyRollingFileAppender.TOP_OF_MONTH:
+ this.set(Calendar.DATE, 1);
+ this.set(Calendar.HOUR_OF_DAY, 0);
+ this.set(Calendar.MINUTE, 0);
+ this.set(Calendar.SECOND, 0);
+ this.set(Calendar.MILLISECOND, 0);
+ this.add(Calendar.MONTH, 1);
+ break;
+ default:
+ throw new IllegalStateException("Unknown periodicity type.");
+ }
+ return getTime();
+ }
+ }
+
+ public static class ConsoleAppender extends WriterAppender {
+
+ protected String target = SYSTEM_OUT;
+
+ public ConsoleAppender() {
+ }
+
+ public void setTarget(String value) {
+ String v = value.trim();
+
+ if (SYSTEM_OUT.equalsIgnoreCase(v)) {
+ target = SYSTEM_OUT;
+ } else if (SYSTEM_ERR.equalsIgnoreCase(v)) {
+ target = SYSTEM_ERR;
+ } else {
+ targetWarn(value);
+ }
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ void targetWarn(String val) {
+ SysLogger.warn("[" + val + "] should be System.out or System.err.");
+ SysLogger.warn("Using previously set target, System.out by default.");
+ }
+
+ public void activateOptions() {
+ if (target.equals(SYSTEM_ERR)) {
+ setWriter(createWriter(System.err));
+ } else {
+ setWriter(createWriter(System.out));
+ }
+ super.activateOptions();
+ }
+
+ protected final void closeWriter() {
+
+ }
+ }
+
+ public static LayoutBuilder newLayoutBuilder() {
+ return new LayoutBuilder();
+ }
+
+ public static class LayoutBuilder {
+
+ private Layout layout;
+
+ public LayoutBuilder withSimpleLayout() {
+ layout = new SimpleLayout();
+ return this;
+ }
+
+ public LayoutBuilder withDefaultLayout() {
+ layout = new DefaultLayout();
+ return this;
+ }
+
+ public Layout build() {
+ if (layout == null) {
+ layout = new SimpleLayout();
+ }
+ return layout;
+ }
+ }
+
+ public static class SimpleLayout extends Layout {
+
+ @Override
+ public String format(LoggingEvent event) {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(event.getLevel().toString());
+ sb.append(" - ");
+ sb.append(event.getRenderedMessage());
+ sb.append("\r\n");
+ return sb.toString();
+ }
+
+ @Override
+ public boolean ignoresThrowable() {
+ return false;
+ }
+ }
+
+
+ /**
+ * %d{yyy-MM-dd HH:mm:ss,SSS} %p %c{1}%L - %m%n
+ */
+ public static class DefaultLayout extends Layout {
+ @Override
+ public String format(LoggingEvent event) {
+
+ StringBuilder sb = new StringBuilder();
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,sss");
+ String format = simpleDateFormat.format(new Date(event.timeStamp));
+ sb.append(format);
+ sb.append(" ");
+ sb.append(event.getLevel());
+ sb.append(" ");
+ sb.append(event.getLoggerName());
+ sb.append(" - ");
+ sb.append(event.getMessage());
+ String[] throwableStr = event.getThrowableStr();
+ if (throwableStr != null) {
+ sb.append("\r\n");
+ for (String s : throwableStr) {
+ sb.append(s);
+ sb.append("\r\n");
+ }
+ }
+ sb.append("\r\n");
+ return sb.toString();
+ }
+
+ @Override
+ public boolean ignoresThrowable() {
+ return false;
+ }
+ }
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/inner/LoggingEvent.java b/logging/src/main/java/org/apache/rocketmq/logging/inner/LoggingEvent.java
new file mode 100644
index 0000000..1b3e955
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/inner/LoggingEvent.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.LineNumberReader;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+public class LoggingEvent implements java.io.Serializable {
+
+ transient public final String fqnOfCategoryClass;
+
+ transient private Object message;
+
+ transient private Level level;
+
+ transient private Logger logger;
+
+ private String renderedMessage;
+
+ private String threadName;
+
+ public final long timeStamp;
+
+ private Throwable throwable;
+
+ public LoggingEvent(String fqnOfCategoryClass, Logger logger,
+ Level level, Object message, Throwable throwable) {
+ this.fqnOfCategoryClass = fqnOfCategoryClass;
+ this.message = message;
+ this.logger = logger;
+ this.throwable = throwable;
+ this.level = level;
+ timeStamp = System.currentTimeMillis();
+ }
+
+ public Object getMessage() {
+ if (message != null) {
+ return message;
+ } else {
+ return getRenderedMessage();
+ }
+ }
+
+ public String getRenderedMessage() {
+ if (renderedMessage == null && message != null) {
+ if (message instanceof String) {
+ renderedMessage = (String) message;
+ } else {
+ renderedMessage = message.toString();
+ }
+ }
+ return renderedMessage;
+ }
+
+ public String getThreadName() {
+ if (threadName == null) {
+ threadName = (Thread.currentThread()).getName();
+ }
+ return threadName;
+ }
+
+ public Level getLevel() {
+ return level;
+ }
+
+ public String getLoggerName() {
+ return logger.getName();
+ }
+
+ public String[] getThrowableStr() {
+ if (throwable == null) {
+ return null;
+ }
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ try {
+ throwable.printStackTrace(pw);
+ } catch (RuntimeException ex) {
+ SysLogger.warn("InnerLogger print stack trace error", ex);
+ }
+ pw.flush();
+ LineNumberReader reader = new LineNumberReader(
+ new StringReader(sw.toString()));
+ ArrayList<String> lines = new ArrayList<String>();
+ try {
+ String line = reader.readLine();
+ while (line != null) {
+ lines.add(line);
+ line = reader.readLine();
+ }
+ } catch (IOException ex) {
+ if (ex instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ lines.add(ex.toString());
+ }
+ String[] tempRep = new String[lines.size()];
+ lines.toArray(tempRep);
+ return tempRep;
+ }
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/inner/SysLogger.java b/logging/src/main/java/org/apache/rocketmq/logging/inner/SysLogger.java
new file mode 100755
index 0000000..b6d1049
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/inner/SysLogger.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+public class SysLogger {
+
+ protected static boolean debugEnabled = false;
+
+ private static boolean quietMode = false;
+
+ private static final String PREFIX = "RocketMQLog: ";
+ private static final String ERR_PREFIX = "RocketMQLog:ERROR ";
+ private static final String WARN_PREFIX = "RocketMQLog:WARN ";
+
+ public static void setInternalDebugging(boolean enabled) {
+ debugEnabled = enabled;
+ }
+
+ public static void debug(String msg) {
+ if (debugEnabled && !quietMode) {
+ System.out.printf("%s", PREFIX + msg);
+ }
+ }
+
+ public static void debug(String msg, Throwable t) {
+ if (debugEnabled && !quietMode) {
+ System.out.printf("%s", PREFIX + msg);
+ if (t != null) {
+ t.printStackTrace(System.out);
+ }
+ }
+ }
+
+ public static void error(String msg) {
+ if (quietMode) {
+ return;
+ }
+ System.err.println(ERR_PREFIX + msg);
+ }
+
+ public static void error(String msg, Throwable t) {
+ if (quietMode) {
+ return;
+ }
+
+ System.err.println(ERR_PREFIX + msg);
+ if (t != null) {
+ t.printStackTrace();
+ }
+ }
+
+ public static void setQuietMode(boolean quietMode) {
+ SysLogger.quietMode = quietMode;
+ }
+
+ public static void warn(String msg) {
+ if (quietMode) {
+ return;
+ }
+
+ System.err.println(WARN_PREFIX + msg);
+ }
+
+ public static void warn(String msg, Throwable t) {
+ if (quietMode) {
+ return;
+ }
+
+ System.err.println(WARN_PREFIX + msg);
+ if (t != null) {
+ t.printStackTrace();
+ }
+ }
+}
diff --git a/logging/src/main/java/org/apache/rocketmq/logging/package-info.java b/logging/src/main/java/org/apache/rocketmq/logging/package-info.java
new file mode 100644
index 0000000..7cb0645
--- /dev/null
+++ b/logging/src/main/java/org/apache/rocketmq/logging/package-info.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging;
+
+/*
+ This package is a minimal logger on the basis of Apache Log4j without
+ file configuration and pattern layout configuration. Main forked files are
+ followed as below:
+ 1. LoggingEvent
+ 2. Logger
+ 3. Layout
+ 4. Level
+ 5. AsyncAppender
+ 6. FileAppender
+ 7. RollingFileAppender
+ 8. DailyRollingFileAppender
+ 9. ConsoleAppender
+
+ For more information about Apache Log4j, please go to https://github.com/apache/log4j.
+ */
\ No newline at end of file
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/BasicloggerTest.java b/logging/src/test/java/org/apache/rocketmq/logging/BasicloggerTest.java
new file mode 100644
index 0000000..28496dd
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/BasicloggerTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging;
+
+import org.apache.rocketmq.logging.inner.Level;
+import org.apache.rocketmq.logging.inner.Logger;
+import org.apache.rocketmq.logging.inner.LoggingEvent;
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+public class BasicLoggerTest {
+
+ protected Logger logger = Logger.getLogger("test");
+
+ protected LoggingEvent loggingEvent;
+
+ protected String loggingDir = System.getProperty("user.home") + "/logs/rocketmq-test";
+
+ @Before
+ public void createLoggingEvent() {
+ loggingEvent = new LoggingEvent(Logger.class.getName(), logger, Level.INFO,
+ "junit test error", new RuntimeException("createLogging error"));
+ }
+
+ public String readFile(String file) throws IOException {
+ StringBuilder stringBuilder = new StringBuilder();
+ FileInputStream fileInputStream = new FileInputStream(file);
+ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
+ String line = bufferedReader.readLine();
+ while (line != null) {
+ stringBuilder.append(line);
+ stringBuilder.append("\r\n");
+ line = bufferedReader.readLine();
+ }
+ bufferedReader.close();
+ return stringBuilder.toString();
+ }
+
+ @After
+ public void clean() {
+ File file = new File(loggingDir);
+ if (file.exists()) {
+ File[] files = file.listFiles();
+ for (File file1 : files) {
+ file1.delete();
+ }
+ }
+ }
+}
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/InnerLoggerFactoryTest.java b/logging/src/test/java/org/apache/rocketmq/logging/InnerLoggerFactoryTest.java
new file mode 100644
index 0000000..c47dba6
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/InnerLoggerFactoryTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging;
+
+import org.apache.rocketmq.logging.inner.Appender;
+import org.apache.rocketmq.logging.inner.Level;
+import org.apache.rocketmq.logging.inner.Logger;
+import org.apache.rocketmq.logging.inner.LoggingBuilder;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+public class InnerLoggerFactoryTest extends BasicLoggerTest {
+
+ private ByteArrayOutputStream byteArrayOutputStream;
+
+ public static final String LOGGER = "ConsoleLogger";
+
+ private PrintStream out;
+
+ @Before
+ public void initLogger() {
+ out = System.out;
+ byteArrayOutputStream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(byteArrayOutputStream));
+
+ Appender consoleAppender = LoggingBuilder.newAppenderBuilder()
+ .withConsoleAppender(LoggingBuilder.SYSTEM_OUT)
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+ Logger consoleLogger = Logger.getLogger("ConsoleLogger");
+ consoleLogger.setAdditivity(false);
+ consoleLogger.addAppender(consoleAppender);
+ consoleLogger.setLevel(Level.INFO);
+ }
+
+ @After
+ public void fixConsole() {
+ System.setOut(out);
+ }
+
+ @Test
+ public void testInnerLoggerFactory() {
+ InternalLoggerFactory.setCurrentLoggerType(InternalLoggerFactory.LOGGER_INNER);
+
+ InternalLogger logger1 = InnerLoggerFactory.getLogger(LOGGER);
+ InternalLogger logger = InternalLoggerFactory.getLogger(LOGGER);
+
+ Assert.assertTrue(logger.getName().equals(logger1.getName()));
+
+ InternalLogger logger2 = InnerLoggerFactory.getLogger(InnerLoggerFactoryTest.class);
+ InnerLoggerFactory.InnerLogger logger3 = (InnerLoggerFactory.InnerLogger) logger2;
+
+ logger.info("innerLogger inner info Message");
+ logger.error("innerLogger inner error Message", new RuntimeException());
+ logger.debug("innerLogger inner debug message");
+ logger3.info("innerLogger info message");
+ logger3.error("logback error message");
+ logger3.info("info {}", "hahahah");
+ logger3.warn("warn {}", "hahahah");
+ logger3.warn("logger3 warn");
+ logger3.error("error {}", "hahahah");
+ logger3.debug("debug {}", "hahahah");
+
+ String content = new String(byteArrayOutputStream.toByteArray());
+ System.out.println(content);
+
+ Assert.assertTrue(content.contains("InnerLoggerFactoryTest"));
+ Assert.assertTrue(content.contains("info"));
+ Assert.assertTrue(content.contains("RuntimeException"));
+ Assert.assertTrue(!content.contains("debug"));
+ }
+}
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/InternalLoggerTest.java b/logging/src/test/java/org/apache/rocketmq/logging/InternalLoggerTest.java
new file mode 100644
index 0000000..04b9f06
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/InternalLoggerTest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging;
+
+import org.apache.rocketmq.logging.inner.Appender;
+import org.apache.rocketmq.logging.inner.Level;
+import org.apache.rocketmq.logging.inner.Logger;
+import org.apache.rocketmq.logging.inner.LoggingBuilder;
+import org.apache.rocketmq.logging.inner.SysLogger;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+
+public class InternalLoggerTest {
+
+
+ @Test
+ public void testInternalLogger() {
+ SysLogger.setQuietMode(false);
+ SysLogger.setInternalDebugging(true);
+ PrintStream out = System.out;
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(byteArrayOutputStream));
+
+ Appender consoleAppender = LoggingBuilder.newAppenderBuilder()
+ .withConsoleAppender(LoggingBuilder.SYSTEM_OUT)
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+
+ Logger consoleLogger = Logger.getLogger("ConsoleLogger");
+ consoleLogger.setAdditivity(false);
+ consoleLogger.addAppender(consoleAppender);
+ consoleLogger.setLevel(Level.INFO);
+
+ Logger.getRootLogger().addAppender(consoleAppender);
+
+ InternalLoggerFactory.setCurrentLoggerType(InternalLoggerFactory.LOGGER_INNER);
+ InternalLogger logger = InternalLoggerFactory.getLogger(InternalLoggerTest.class);
+ InternalLogger consoleLogger1 = InternalLoggerFactory.getLogger("ConsoleLogger");
+
+ consoleLogger1.warn("simple warn {}", 14555);
+
+ logger.info("testInternalLogger");
+ consoleLogger1.info("consoleLogger1");
+
+ System.setOut(out);
+ consoleAppender.close();
+
+ String result = new String(byteArrayOutputStream.toByteArray());
+ Assert.assertTrue(result.contains("consoleLogger1"));
+ Assert.assertTrue(result.contains("testInternalLogger"));
+ }
+
+}
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/Slf4jLoggerFactoryTest.java b/logging/src/test/java/org/apache/rocketmq/logging/Slf4jLoggerFactoryTest.java
new file mode 100644
index 0000000..ba6ec3b
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/Slf4jLoggerFactoryTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging;
+
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.joran.spi.JoranException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.ILoggerFactory;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.URL;
+
+public class Slf4jLoggerFactoryTest extends BasicLoggerTest {
+
+ public static final String LOGGER = "Slf4jTestLogger";
+
+ @Before
+ public void initLogback() throws JoranException {
+ InternalLoggerFactory.setCurrentLoggerType(InternalLoggerFactory.LOGGER_SLF4J);
+ System.setProperty("loggingDir", loggingDir);
+ ILoggerFactory iLoggerFactory = LoggerFactory.getILoggerFactory();
+ JoranConfigurator joranConfigurator = new JoranConfigurator();
+ joranConfigurator.setContext((Context) iLoggerFactory);
+ URL logbackConfigFile = Slf4jLoggerFactoryTest.class.getClassLoader().getResource("logback_test.xml");
+ if (logbackConfigFile == null) {
+ throw new RuntimeException("can't find logback_test.xml");
+ } else {
+ joranConfigurator.doConfigure(logbackConfigFile);
+ }
+ }
+
+ @Test
+ public void testSlf4j() throws IOException {
+ InternalLogger logger1 = Slf4jLoggerFactory.getLogger(LOGGER);
+ InternalLogger logger = InternalLoggerFactory.getLogger(LOGGER);
+ Assert.assertTrue(logger.getName().equals(logger1.getName()));
+ InternalLogger logger2 = Slf4jLoggerFactory.getLogger(Slf4jLoggerFactoryTest.class);
+ Slf4jLoggerFactory.Slf4jLogger logger3 = (Slf4jLoggerFactory.Slf4jLogger) logger2;
+
+ String file = loggingDir + "/logback_test.log";
+
+ logger.info("logback slf4j info Message");
+ logger.error("logback slf4j error Message", new RuntimeException());
+ logger.debug("logback slf4j debug message");
+ logger3.info("logback info message");
+ logger3.error("logback error message");
+ logger3.info("info {}", "hahahah");
+ logger3.warn("warn {}", "hahahah");
+ logger3.warn("logger3 warn");
+ logger3.error("error {}", "hahahah");
+ logger3.debug("debug {}", "hahahah");
+ String content = readFile(file);
+ System.out.println(content);
+
+ Assert.assertTrue(content.contains("Slf4jLoggerFactoryTest"));
+ Assert.assertTrue(content.contains("info"));
+ Assert.assertTrue(content.contains("RuntimeException"));
+ Assert.assertTrue(!content.contains("debug"));
+ }
+
+}
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/inner/AppenderTest.java b/logging/src/test/java/org/apache/rocketmq/logging/inner/AppenderTest.java
new file mode 100644
index 0000000..37ff8bd
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/inner/AppenderTest.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import org.apache.rocketmq.logging.BasicLoggerTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+public class AppenderTest extends BasicLoggerTest {
+
+ @Test
+ public void testConsole() {
+ SysLogger.setQuietMode(false);
+ SysLogger.setInternalDebugging(true);
+ PrintStream out = System.out;
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(byteArrayOutputStream));
+
+ Appender consoleAppender = LoggingBuilder.newAppenderBuilder()
+ .withConsoleAppender(LoggingBuilder.SYSTEM_OUT)
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+ LoggingBuilder.ConsoleAppender consoleAppender1 = (LoggingBuilder.ConsoleAppender) consoleAppender;
+ String target = consoleAppender1.getTarget();
+ Assert.assertTrue(target.equals(LoggingBuilder.SYSTEM_OUT));
+
+ Layout layout = consoleAppender.getLayout();
+ Assert.assertTrue(layout instanceof LoggingBuilder.DefaultLayout);
+
+ Logger consoleLogger = Logger.getLogger("ConsoleLogger");
+ consoleLogger.setAdditivity(false);
+ consoleLogger.addAppender(consoleAppender);
+ consoleLogger.setLevel(Level.INFO);
+
+ Logger.getRootLogger().addAppender(consoleAppender);
+ Logger.getLogger(AppenderTest.class).info("this is a AppenderTest log");
+
+ Logger.getLogger("ConsoleLogger").info("console info Message");
+ Logger.getLogger("ConsoleLogger").error("console error Message", new RuntimeException());
+ Logger.getLogger("ConsoleLogger").debug("console debug message");
+ System.setOut(out);
+ consoleAppender.close();
+
+ String result = new String(byteArrayOutputStream.toByteArray());
+
+ Assert.assertTrue(result.contains("info"));
+ Assert.assertTrue(result.contains("RuntimeException"));
+ Assert.assertTrue(!result.contains("debug"));
+ Assert.assertTrue(result.contains("AppenderTest"));
+ }
+
+ @Test
+ public void testInnerFile() throws IOException {
+ String file = loggingDir + "/logger.log";
+
+ Logger fileLogger = Logger.getLogger("fileLogger");
+
+ Appender myappender = LoggingBuilder.newAppenderBuilder()
+ .withDailyFileRollingAppender(file, "'.'yyyy-MM-dd")
+ .withName("myappender")
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+ fileLogger.addAppender(myappender);
+
+ Logger.getLogger("fileLogger").setLevel(Level.INFO);
+
+ Logger.getLogger("fileLogger").info("fileLogger info Message");
+ Logger.getLogger("fileLogger").error("fileLogger error Message", new RuntimeException());
+ Logger.getLogger("fileLogger").debug("fileLogger debug message");
+
+ myappender.close();
+
+ String content = readFile(file);
+
+ System.out.println(content);
+
+ Assert.assertTrue(content.contains("info"));
+ Assert.assertTrue(content.contains("RuntimeException"));
+ Assert.assertTrue(!content.contains("debug"));
+ }
+
+
+
+ @Test
+ public void asyncAppenderTest() {
+ Appender appender = LoggingBuilder.newAppenderBuilder().withAsync(false, 1024)
+ .withConsoleAppender(LoggingBuilder.SYSTEM_OUT)
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+ Assert.assertTrue(appender instanceof LoggingBuilder.AsyncAppender);
+ LoggingBuilder.AsyncAppender asyncAppender = (LoggingBuilder.AsyncAppender) appender;
+ Assert.assertTrue(!asyncAppender.getBlocking());
+ Assert.assertTrue(asyncAppender.getBufferSize() > 0);
+ }
+
+ @Test
+ public void testWriteAppender() {
+ LoggingBuilder.WriterAppender writerAppender = new LoggingBuilder.WriterAppender();
+ writerAppender.setImmediateFlush(true);
+ Assert.assertTrue(writerAppender.getImmediateFlush());
+ }
+
+ @Test
+ public void testFileAppender() throws IOException {
+ LoggingBuilder.FileAppender fileAppender = new LoggingBuilder.FileAppender(
+ new LoggingBuilder.SimpleLayout(), loggingDir + "/simple.log", true);
+ fileAppender.setBufferSize(1024);
+ int bufferSize = fileAppender.getBufferSize();
+ boolean bufferedIO = fileAppender.getBufferedIO();
+ Assert.assertTrue(!bufferedIO);
+ Assert.assertTrue(bufferSize > 0);
+ Assert.assertTrue(fileAppender.getAppend());
+
+ LoggingBuilder.RollingFileAppender rollingFileAppender = new LoggingBuilder.RollingFileAppender();
+ rollingFileAppender.setImmediateFlush(true);
+ rollingFileAppender.setMaximumFileSize(1024 * 1024);
+ rollingFileAppender.setMaxBackupIndex(10);
+ rollingFileAppender.setAppend(true);
+ rollingFileAppender.setFile(loggingDir + "/rolling_file.log");
+ rollingFileAppender.setName("myRollingFileAppender");
+
+ rollingFileAppender.activateOptions();
+
+ Assert.assertTrue(rollingFileAppender.getMaximumFileSize() > 0);
+ Assert.assertTrue(rollingFileAppender.getMaxBackupIndex() == 10);
+ }
+
+ @Test
+ public void testDailyRollingAppender() {
+ LoggingBuilder.DailyRollingFileAppender dailyRollingFileAppender = new LoggingBuilder.DailyRollingFileAppender();
+ dailyRollingFileAppender.setFile(loggingDir + "/daily.log");
+ dailyRollingFileAppender.setName("dailyAppender");
+ dailyRollingFileAppender.setAppend(true);
+ dailyRollingFileAppender.setDatePattern("'.'yyyy-mm-dd");
+ String datePattern = dailyRollingFileAppender.getDatePattern();
+ Assert.assertTrue(datePattern != null);
+ dailyRollingFileAppender.activateOptions();
+ }
+
+}
+
+
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/inner/LayoutTest.java b/logging/src/test/java/org/apache/rocketmq/logging/inner/LayoutTest.java
new file mode 100644
index 0000000..66ef18e
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/inner/LayoutTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import org.apache.rocketmq.logging.BasicLoggerTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class LayoutTest extends BasicLoggerTest {
+
+ @Test
+ public void testSimpleLayout() {
+ Layout layout = LoggingBuilder.newLayoutBuilder().withSimpleLayout().build();
+ String format = layout.format(loggingEvent);
+ Assert.assertTrue(format.contains("junit"));
+ }
+
+ @Test
+ public void testDefaultLayout() {
+ Layout layout = LoggingBuilder.newLayoutBuilder().withDefaultLayout().build();
+ String format = layout.format(loggingEvent);
+ String contentType = layout.getContentType();
+ Assert.assertTrue(contentType.contains("text"));
+ Assert.assertTrue(format.contains("createLoggingEvent"));
+ Assert.assertTrue(format.contains("createLogging error"));
+ Assert.assertTrue(format.contains(Thread.currentThread().getName()));
+ }
+
+ @Test
+ public void testLogFormat() {
+ Layout innerLayout = LoggingBuilder.newLayoutBuilder().withDefaultLayout().build();
+
+ LoggingEvent loggingEvent = new LoggingEvent(Logger.class.getName(), logger, org.apache.rocketmq.logging.inner.Level.INFO,
+ "junit test error", null);
+ String format = innerLayout.format(loggingEvent);
+
+ System.out.println(format);
+ }
+}
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/inner/LevelTest.java b/logging/src/test/java/org/apache/rocketmq/logging/inner/LevelTest.java
new file mode 100644
index 0000000..21667e1
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/inner/LevelTest.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class LevelTest {
+
+ @Test
+ public void levelTest() {
+ Level info = Level.toLevel("info");
+ Level error = Level.toLevel(3);
+ Assert.assertTrue(error != null && info != null);
+ }
+
+ @Test
+ public void loggerLevel(){
+ Level level = Logger.getRootLogger().getLevel();
+ Assert.assertTrue(level!=null);
+ }
+}
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/inner/LoggerRepositoryTest.java b/logging/src/test/java/org/apache/rocketmq/logging/inner/LoggerRepositoryTest.java
new file mode 100644
index 0000000..6a56c20
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/inner/LoggerRepositoryTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import org.apache.rocketmq.logging.BasicLoggerTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Enumeration;
+
+public class LoggerRepositoryTest extends BasicLoggerTest {
+
+ @Test
+ public void testLoggerRepository() {
+ Logger.getRepository().setLogLevel(Level.INFO);
+
+ String file = loggingDir + "/repo.log";
+ Logger fileLogger = Logger.getLogger("repoLogger");
+
+ Appender myappender = LoggingBuilder.newAppenderBuilder()
+ .withDailyFileRollingAppender(file, "'.'yyyy-MM-dd")
+ .withName("repoAppender")
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+ fileLogger.addAppender(myappender);
+ Logger.getLogger("repoLogger").setLevel(Level.INFO);
+ Logger repoLogger = Logger.getRepository().exists("repoLogger");
+ Assert.assertTrue(repoLogger != null);
+ Enumeration currentLoggers = Logger.getRepository().getCurrentLoggers();
+ Level logLevel = Logger.getRepository().getLogLevel();
+ Assert.assertTrue(logLevel.equals(Level.INFO));
+// Logger.getRepository().shutdown();
+ }
+}
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/inner/LoggerTest.java b/logging/src/test/java/org/apache/rocketmq/logging/inner/LoggerTest.java
new file mode 100644
index 0000000..4e738e2
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/inner/LoggerTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import org.apache.rocketmq.logging.BasicLoggerTest;
+import org.apache.rocketmq.logging.InnerLoggerFactory;
+import org.apache.rocketmq.logging.InternalLogger;
+import org.apache.rocketmq.logging.InternalLoggerFactory;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+public class LoggerTest extends BasicLoggerTest {
+
+
+ @Before
+ public void init() {
+ InternalLoggerFactory.setCurrentLoggerType(InnerLoggerFactory.LOGGER_INNER);
+ }
+
+ @Test
+ public void testInnerConsoleLogger() throws IOException {
+ PrintStream out = System.out;
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(byteArrayOutputStream));
+
+ Appender consoleAppender = LoggingBuilder.newAppenderBuilder()
+ .withConsoleAppender(LoggingBuilder.SYSTEM_OUT)
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+ Logger.getLogger("ConsoleLogger").addAppender(consoleAppender);
+ Logger.getLogger("ConsoleLogger").setLevel(Level.INFO);
+
+ InternalLogger consoleLogger1 = InternalLoggerFactory.getLogger("ConsoleLogger");
+ consoleLogger1.info("console info Message");
+ consoleLogger1.error("console error Message", new RuntimeException());
+ consoleLogger1.debug("console debug message");
+
+ consoleLogger1.info("console {} test", "simple");
+ consoleLogger1.info("[WATERMARK] Send Queue Size: {} SlowTimeMills: {}", 1, 300);
+ consoleLogger1.info("new consumer connected, group: {} {} {} channel: {}", "mygroup", "orderly",
+ "broudcast", new RuntimeException("simple object"));
+
+ System.setOut(out);
+ consoleAppender.close();
+
+ String result = new String(byteArrayOutputStream.toByteArray());
+
+ System.out.println(result);
+
+ Assert.assertTrue(result.contains("info"));
+ Assert.assertTrue(result.contains("RuntimeException"));
+ Assert.assertTrue(result.contains("WATERMARK"));
+ Assert.assertTrue(result.contains("consumer"));
+ Assert.assertTrue(result.contains("broudcast"));
+ Assert.assertTrue(result.contains("simple test"));
+ Assert.assertTrue(!result.contains("debug"));
+ }
+
+ @Test
+ public void testInnerFileLogger() throws IOException {
+ String file = loggingDir + "/inner.log";
+
+ Logger fileLogger = Logger.getLogger("innerLogger");
+
+ Appender myappender = LoggingBuilder.newAppenderBuilder()
+ .withDailyFileRollingAppender(file, "'.'yyyy-MM-dd")
+ .withName("innerAppender")
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+ fileLogger.addAppender(myappender);
+ fileLogger.setLevel(Level.INFO);
+
+ InternalLogger innerLogger = InternalLoggerFactory.getLogger("innerLogger");
+
+ innerLogger.info("fileLogger info Message");
+ innerLogger.error("fileLogger error Message", new RuntimeException());
+ innerLogger.debug("fileLogger debug message");
+
+ myappender.close();
+
+ String content = readFile(file);
+
+ System.out.println(content);
+
+ Assert.assertTrue(content.contains("info"));
+ Assert.assertTrue(content.contains("RuntimeException"));
+ Assert.assertTrue(!content.contains("debug"));
+ }
+
+ @After
+ public void close() {
+ InternalLoggerFactory.setCurrentLoggerType(null);
+ }
+}
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/inner/LoggingBuilderTest.java b/logging/src/test/java/org/apache/rocketmq/logging/inner/LoggingBuilderTest.java
new file mode 100644
index 0000000..977e553
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/inner/LoggingBuilderTest.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+import org.apache.rocketmq.logging.BasicLoggerTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.PrintStream;
+
+public class LoggingBuilderTest extends BasicLoggerTest {
+
+ @Test
+ public void testConsole() {
+ PrintStream out = System.out;
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(byteArrayOutputStream));
+
+ Appender consoleAppender = LoggingBuilder.newAppenderBuilder()
+ .withConsoleAppender(LoggingBuilder.SYSTEM_OUT)
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+ consoleAppender.doAppend(loggingEvent);
+ String result = new String(byteArrayOutputStream.toByteArray());
+ System.setOut(out);
+
+ Assert.assertTrue(result.contains(loggingEvent.getMessage().toString()));
+
+ }
+
+ @Test
+ public void testFileAppender() throws InterruptedException {
+ String logFile = loggingDir + "/file.log";
+ Appender rollingFileAppender = LoggingBuilder.newAppenderBuilder().withAsync(false, 102400)
+ .withFileAppender(logFile).withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+ for (int i = 0; i < 10; i++) {
+ rollingFileAppender.doAppend(loggingEvent);
+ }
+ rollingFileAppender.close();
+
+ File file = new File(logFile);
+ Assert.assertTrue(file.length() > 0);
+ }
+
+ @Test
+ public void testRollingFileAppender() throws InterruptedException {
+
+ String rollingFile = loggingDir + "/rolling.log";
+ Appender rollingFileAppender = LoggingBuilder.newAppenderBuilder().withAsync(false, 1024)
+ .withRollingFileAppender(rollingFile, "1024", 5)
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+ for (int i = 0; i < 100; i++) {
+ rollingFileAppender.doAppend(loggingEvent);
+ }
+ rollingFileAppender.close();
+
+ int cc = 0;
+ for (int i = 0; i < 5; i++) {
+ File file;
+ if (i == 0) {
+ file = new File(rollingFile);
+ } else {
+ file = new File(rollingFile + "." + i);
+ }
+ if (file.exists() && file.length() > 0) {
+ cc += 1;
+ }
+ }
+ Assert.assertTrue(cc >= 2);
+ }
+
+ @Test
+ public void testDailyRollingFileAppender() throws InterruptedException {
+ String rollingFile = loggingDir + "/daily-rolling--222.log";
+ Appender rollingFileAppender = LoggingBuilder.newAppenderBuilder().withAsync(false, 1024)
+ .withDailyFileRollingAppender(rollingFile, "'.'yyyy-MM-dd_HH-mm-ss-SSS")
+ .withLayout(LoggingBuilder.newLayoutBuilder().withDefaultLayout().build()).build();
+
+ for (int i = 0; i < 100; i++) {
+ rollingFileAppender.doAppend(loggingEvent);
+ }
+
+ rollingFileAppender.close();
+
+ File file = new File(loggingDir);
+ String[] list = file.list(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.startsWith("daily-rolling--222.log");
+ }
+ });
+ Assert.assertTrue(list.length > 0);
+ }
+}
diff --git a/logging/src/test/java/org/apache/rocketmq/logging/inner/MessageFormatterTest.java b/logging/src/test/java/org/apache/rocketmq/logging/inner/MessageFormatterTest.java
new file mode 100644
index 0000000..5fa80ad
--- /dev/null
+++ b/logging/src/test/java/org/apache/rocketmq/logging/inner/MessageFormatterTest.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.rocketmq.logging.inner;
+
+
+import org.apache.rocketmq.logging.InnerLoggerFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MessageFormatterTest {
+
+ @Test
+ public void formatTest(){
+ InnerLoggerFactory.FormattingTuple logging = InnerLoggerFactory.MessageFormatter.format("this is {},and {}", "logging", 6546);
+ String message = logging.getMessage();
+ Assert.assertTrue(message.contains("logging"));
+
+ InnerLoggerFactory.FormattingTuple format = InnerLoggerFactory.MessageFormatter.format("cause exception {}", 143545, new RuntimeException());
+ String message1 = format.getMessage();
+ Throwable throwable = format.getThrowable();
+ System.out.println(message1);
+ Assert.assertTrue(throwable != null);
+ }
+
+}
diff --git a/logging/src/test/resources/logback_test.xml b/logging/src/test/resources/logback_test.xml
new file mode 100644
index 0000000..c1ab200
--- /dev/null
+++ b/logging/src/test/resources/logback_test.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<configuration>
+ <appender name="RocketmqClientAppender"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${loggingDir}/logback_test.log</file>
+ <append>true</append>
+ <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${loggingDir}/logback_test.%i.log
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>5</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>10MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>%d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n</pattern>
+ <charset class="java.nio.charset.Charset">UTF-8</charset>
+ </encoder>
+ </appender>
+
+ <logger name="Slf4jTestLogger" additivity="false">
+ <level value="INFO"/>
+ <appender-ref ref="RocketmqClientAppender"/>
+ </logger>
+
+
+</configuration>
diff --git a/pom.xml b/pom.xml
index 4326b46..4be64a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -125,6 +125,7 @@
<module>test</module>
<module>distribution</module>
<module>openmessaging</module>
+ <module>logging</module>
</modules>
<build>
@@ -529,6 +530,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rocketmq-logging</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
--
To stop receiving notification emails like this one, please contact
yukon@apache.org.