You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@rocketmq.apache.org by GitBox <gi...@apache.org> on 2018/03/02 08:07:43 UTC

[GitHub] zhouxinyu closed pull request #224: [ROCKETMQ-367] Add logging component.

zhouxinyu closed pull request #224: [ROCKETMQ-367] Add logging component.
URL: https://github.com/apache/rocketmq/pull/224
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/logging/pom.xml b/logging/pom.xml
new file mode 100644
index 000000000..baad6ad0c
--- /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 000000000..7714640ff
--- /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 000000000..fae69dda6
--- /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 000000000..ec176ce6b
--- /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 000000000..1a2468473
--- /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 000000000..c06156310
--- /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 000000000..7ea3561df
--- /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 000000000..487682cd4
--- /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 000000000..470ed41da
--- /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 000000000..469cb52b2
--- /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 000000000..1b3e95539
--- /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 000000000..b6d104977
--- /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 000000000..7cb0645de
--- /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 000000000..28496dd56
--- /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 000000000..c47dba684
--- /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 000000000..04b9f06e8
--- /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 000000000..ba6ec3ba6
--- /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 000000000..37ff8bd47
--- /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 000000000..66ef18eae
--- /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 000000000..21667e148
--- /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 000000000..6a56c20ff
--- /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 000000000..4e738e230
--- /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 000000000..977e553b7
--- /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 000000000..5fa80ad56
--- /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 000000000..c1ab20044
--- /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 4326b4669..4be64a6f6 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>
@@ -528,6 +529,11 @@
                 <artifactId>rocketmq-example</artifactId>
                 <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>


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services