* There are two types of logger for command center and common modules specified by annotation of `LogTarget` * Add implementing examples in `sentinel-demo/sentinel-demo-log-logback` * All implementations should support placeholder '{}'master
@@ -15,36 +15,77 @@ | |||
*/ | |||
package com.alibaba.csp.sentinel.log; | |||
import java.util.logging.Handler; | |||
import java.util.logging.Level; | |||
import java.util.logging.Logger; | |||
import java.util.Iterator; | |||
import java.util.ServiceLoader; | |||
/** | |||
* Logger for command center. | |||
*/ | |||
public class CommandCenterLog extends LogBase { | |||
private static final Logger heliumRecordLog = Logger.getLogger("cspCommandCenterLog"); | |||
private static final String FILE_NAME = "command-center.log"; | |||
private static Handler logHandler = null; | |||
public class CommandCenterLog { | |||
private static com.alibaba.csp.sentinel.log.Logger log = null; | |||
static { | |||
logHandler = makeLogger(FILE_NAME, heliumRecordLog); | |||
ServiceLoader<Logger> load = ServiceLoader.load(Logger.class); | |||
Logger logger = null; | |||
Iterator<Logger> iterator = load.iterator(); | |||
while (iterator.hasNext()) { | |||
Logger next = iterator.next(); | |||
LogTarget annotation = next.getClass().getAnnotation(LogTarget.class); | |||
if (annotation == null) { | |||
continue; | |||
} | |||
String value = annotation.value().name(); | |||
if (value.equals(LogType.COMMAND_CENTER_LOG.name())) { | |||
logger = next; | |||
break; | |||
} | |||
} | |||
// Use user implementations. | |||
if (logger != null) { | |||
log = logger; | |||
} else { | |||
// Use default implementations. | |||
log = new CommandCenterLogLogging(); | |||
} | |||
} | |||
public static void info(String format, Object... arguments) { | |||
log.info(format, arguments); | |||
} | |||
public static void info(String msg, Throwable e) { | |||
log.info(msg, e); | |||
} | |||
public static void warn(String format, Object... arguments) { | |||
log.warn(format, arguments); | |||
} | |||
public static void warn(String msg, Throwable e) { | |||
log.warn(msg, e); | |||
} | |||
public static void trace(String format, Object... arguments) { | |||
log.trace(format, arguments); | |||
} | |||
public static void trace(String msg, Throwable e) { | |||
log.trace(msg, e); | |||
} | |||
public static void info(String detail, Object... params) { | |||
log(heliumRecordLog, logHandler, Level.INFO, detail, params); | |||
public static void debug(String format, Object... arguments) { | |||
log.debug(format, arguments); | |||
} | |||
public static void info(String detail, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.INFO, detail, e); | |||
public static void debug(String msg, Throwable e) { | |||
log.debug(msg, e); | |||
} | |||
public static void warn(String detail, Object... params) { | |||
log(heliumRecordLog, logHandler, Level.WARNING, detail, params); | |||
public static void error(String format, Object... arguments) { | |||
log.error(format, arguments); | |||
} | |||
public static void warn(String detail, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.WARNING, detail, e); | |||
public static void error(String msg, Throwable e) { | |||
log.error(msg, e); | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
/* | |||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 | |||
* | |||
* https://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 com.alibaba.csp.sentinel.log; | |||
import java.util.logging.Handler; | |||
import java.util.logging.Logger; | |||
/** | |||
* Default logger implementation. | |||
* @author xue8 | |||
*/ | |||
public class CommandCenterLogLogging extends LogBase implements com.alibaba.csp.sentinel.log.Logger { | |||
private final Logger heliumRecordLog = Logger.getLogger("cspCommandCenterLog"); | |||
private final String FILE_NAME = "command-center.log"; | |||
private final Handler logHandler = makeLogger(FILE_NAME, heliumRecordLog); | |||
@Override | |||
public void info(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.INFO, format, arguments); | |||
} | |||
@Override | |||
public void info(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.INFO, msg, e); | |||
} | |||
@Override | |||
public void warn(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.WARNING, format, arguments); | |||
} | |||
@Override | |||
public void warn(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.WARNING, msg, e); | |||
} | |||
@Override | |||
public void trace(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.TRACE, format, arguments); | |||
} | |||
@Override | |||
public void trace(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.TRACE, msg, e); | |||
} | |||
@Override | |||
public void debug(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.DEBUG, format, arguments); | |||
} | |||
@Override | |||
public void debug(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.DEBUG, msg, e); | |||
} | |||
@Override | |||
public void error(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.ERROR, format, arguments); | |||
} | |||
@Override | |||
public void error(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.ERROR, msg, e); | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
/* | |||
* Copyright 1999-2018 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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. | |||
*/ | |||
/** | |||
* Copyright notice | |||
* This code copy from SLF4J which licensed under the MIT License. | |||
* | |||
*/ | |||
package com.alibaba.csp.sentinel.log; | |||
/** | |||
* Holds the results of formatting done by {@link MessageFormatter}. | |||
* | |||
* @author Joern Huxhorn | |||
*/ | |||
public class FormattingTuple { | |||
static public FormattingTuple NULL = new FormattingTuple(null); | |||
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; | |||
this.argArray = argArray; | |||
} | |||
public String getMessage() { | |||
return message; | |||
} | |||
public Object[] getArgArray() { | |||
return argArray; | |||
} | |||
public Throwable getThrowable() { | |||
return throwable; | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
/* | |||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 | |||
* | |||
* https://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 com.alibaba.csp.sentinel.log; | |||
/** | |||
* Logging levels | |||
* @author xue8 | |||
*/ | |||
public class Level extends java.util.logging.Level { | |||
private static final String defaultBundle = "sun.util.logging.resources.logging"; | |||
public static final Level ERROR = new Level("ERROR", 1000); | |||
public static final Level WARNING = new Level("WARNING", 900); | |||
public static final Level INFO = new Level("INFO", 800); | |||
public static final Level DEBUG = new Level("DEBUG", 700); | |||
public static final Level TRACE = new Level("TRACE", 600); | |||
protected Level(String name, int value) { | |||
super(name, value, defaultBundle); | |||
} | |||
} |
@@ -152,11 +152,10 @@ public class LogBase { | |||
return; | |||
} | |||
LoggerUtils.disableOtherHandlers(logger, handler); | |||
if (params.length == 0) { | |||
logger.log(level, detail); | |||
} else { | |||
logger.log(level, detail, params); | |||
} | |||
FormattingTuple formattingTuple = MessageFormatter.arrayFormat(detail, params); | |||
String message = formattingTuple.getMessage(); | |||
logger.log(level, message); | |||
} | |||
protected static void log(Logger logger, Handler handler, Level level, String detail, Throwable throwable) { | |||
@@ -0,0 +1,32 @@ | |||
/* | |||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 | |||
* | |||
* https://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 com.alibaba.csp.sentinel.log; | |||
import java.lang.annotation.*; | |||
/** | |||
* @author xue8 | |||
*/ | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.TYPE) | |||
@Documented | |||
public @interface LogTarget { | |||
/** | |||
* Returns the kinds of log type. | |||
* @return Returns the kinds of log type | |||
*/ | |||
LogType value() default LogType.RECORD_LOG; | |||
} |
@@ -0,0 +1,25 @@ | |||
/* | |||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 | |||
* | |||
* https://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 com.alibaba.csp.sentinel.log; | |||
/** | |||
* An enum marks log type. | |||
* @author xue8 | |||
*/ | |||
public enum LogType { | |||
COMMAND_CENTER_LOG, | |||
RECORD_LOG, | |||
} |
@@ -0,0 +1,113 @@ | |||
/* | |||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 | |||
* | |||
* https://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 com.alibaba.csp.sentinel.log; | |||
/** | |||
* Provide logger SPI interface. | |||
* The default implementation is {@link java.util.logging}. | |||
* | |||
* Notice, the placeholder only supports the most popular placeholder convention (slf4j). | |||
* So, if you're not using slf4j, you should create adapters compatible with placeholders "{}". | |||
* | |||
* @author xue8 | |||
*/ | |||
public interface Logger { | |||
/** | |||
* Log a message at the INFO level according to the specified format | |||
* and arguments. | |||
* @param format the format string | |||
* @param arguments a list of arguments | |||
*/ | |||
void info(String format, Object... arguments); | |||
/** | |||
* Log an exception (throwable) at the INFO level with an | |||
* accompanying message. | |||
* | |||
* @param msg the message accompanying the exception | |||
* @param e the exception (throwable) to log | |||
*/ | |||
void info(String msg, Throwable e); | |||
/** | |||
* Log a message at the WARN level according to the specified format | |||
* and arguments. | |||
* @param format the format string | |||
* @param arguments a list of arguments | |||
*/ | |||
void warn(String format, Object... arguments); | |||
/** | |||
* Log an exception (throwable) at the WARN level with an | |||
* accompanying message. | |||
* | |||
* @param msg the message accompanying the exception | |||
* @param e the exception (throwable) to log | |||
*/ | |||
void warn(String msg, Throwable e); | |||
/** | |||
* Log a message at the TRACE level according to the specified format | |||
* and arguments. | |||
* @param format the format string | |||
* @param arguments a list of arguments | |||
*/ | |||
void trace(String format, Object... arguments); | |||
/** | |||
* Log an exception (throwable) at the TRACE level with an | |||
* accompanying message. | |||
* | |||
* @param msg the message accompanying the exception | |||
* @param e the exception (throwable) to log | |||
*/ | |||
void trace(String msg, Throwable e); | |||
/** | |||
* Log a message at the DEBUG level according to the specified format | |||
* and arguments. | |||
* @param format the format string | |||
* @param arguments a list of arguments | |||
*/ | |||
void debug(String format, Object... arguments); | |||
/** | |||
* Log an exception (throwable) at the DEBUG level with an | |||
* accompanying message. | |||
* | |||
* @param msg the message accompanying the exception | |||
* @param e the exception (throwable) to log | |||
*/ | |||
void debug(String msg, Throwable e); | |||
/** | |||
* Log a message at the ERROR level according to the specified format | |||
* and arguments. | |||
* @param format the format string | |||
* @param arguments a list of arguments | |||
*/ | |||
void error(String format, Object... arguments); | |||
/** | |||
* Log an exception (throwable) at the ERROR level with an | |||
* accompanying message. | |||
* | |||
* @param msg the message accompanying the exception | |||
* @param e the exception (throwable) to log | |||
*/ | |||
void error(String msg, Throwable e); | |||
} |
@@ -0,0 +1,427 @@ | |||
/* | |||
* Copyright 1999-2018 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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. | |||
*/ | |||
/** | |||
* Copyright notice | |||
* This code copy from SLF4J which licensed under the MIT License. | |||
* | |||
*/ | |||
/** | |||
* Copyright notice | |||
* This code copy from SLF4J which licensed under the MIT License. | |||
* | |||
*/ | |||
package com.alibaba.csp.sentinel.log; | |||
// contributors: lizongbo: proposed special treatment of array parameter values | |||
// Joern Huxhorn: pointed out double[] omission, suggested deep array copy | |||
import java.text.MessageFormat; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
/** | |||
* Formats messages according to very simple substitution rules. Substitutions | |||
* can be made 1, 2 or more arguments. | |||
* | |||
* <p> | |||
* For example, | |||
* | |||
* <pre> | |||
* MessageFormatter.format("Hi {}.", "there") | |||
* </pre> | |||
* | |||
* will return the string "Hi there.". | |||
* <p> | |||
* The {} pair is called the <em>formatting anchor</em>. It serves to designate | |||
* the location where arguments need to be substituted within the message | |||
* pattern. | |||
* <p> | |||
* In case your message contains the '{' or the '}' character, you do not have | |||
* to do anything special unless the '}' character immediately follows '{'. For | |||
* example, | |||
* | |||
* <pre> | |||
* MessageFormatter.format("Set {1,2,3} is not equal to {}.", "1,2"); | |||
* </pre> | |||
* | |||
* will return the string "Set {1,2,3} is not equal to 1,2.". | |||
* | |||
* <p> | |||
* If for whatever reason you need to place the string "{}" in the message | |||
* without its <em>formatting anchor</em> meaning, then you need to escape the | |||
* '{' character with '\', that is the backslash character. Only the '{' | |||
* character should be escaped. There is no need to escape the '}' character. | |||
* For example, | |||
* | |||
* <pre> | |||
* MessageFormatter.format("Set \\{} is not equal to {}.", "1,2"); | |||
* </pre> | |||
* | |||
* will return the string "Set {} is not equal to 1,2.". | |||
* | |||
* <p> | |||
* The escaping behavior just described can be overridden by escaping the escape | |||
* character '\'. Calling | |||
* | |||
* <pre> | |||
* MessageFormatter.format("File name is C:\\\\{}.", "file.zip"); | |||
* </pre> | |||
* | |||
* will return the string "File name is C:\file.zip". | |||
* | |||
* <p> | |||
* The formatting conventions are different than those of {@link MessageFormat} | |||
* which ships with the Java platform. This is justified by the fact that | |||
* SLF4J's implementation is 10 times faster than that of {@link MessageFormat}. | |||
* This local performance difference is both measurable and significant in the | |||
* larger context of the complete logging processing chain. | |||
* | |||
* <p> | |||
* See also {@link #format(String, Object)}, | |||
* {@link #format(String, Object, Object)} and | |||
* {@link #arrayFormat(String, Object[])} methods for more details. | |||
* | |||
* @author Ceki Gülcü | |||
* @author Joern Huxhorn | |||
*/ | |||
final public class MessageFormatter { | |||
static final char DELIM_START = '{'; | |||
static final char DELIM_STOP = '}'; | |||
static final String DELIM_STR = "{}"; | |||
private static final char ESCAPE_CHAR = '\\'; | |||
/** | |||
* Performs single argument substitution for the 'messagePattern' passed as | |||
* parameter. | |||
* <p> | |||
* For example, | |||
* | |||
* <pre> | |||
* MessageFormatter.format("Hi {}.", "there"); | |||
* </pre> | |||
* | |||
* will return the string "Hi there.". | |||
* <p> | |||
* | |||
* @param messagePattern | |||
* The message pattern which will be parsed and formatted | |||
* @param arg | |||
* The argument to be substituted in place of the formatting anchor | |||
* @return The formatted message | |||
*/ | |||
final public static FormattingTuple format(String messagePattern, Object arg) { | |||
return arrayFormat(messagePattern, new Object[] { arg }); | |||
} | |||
/** | |||
* | |||
* Performs a two argument substitution for the 'messagePattern' passed as | |||
* parameter. | |||
* <p> | |||
* For example, | |||
* | |||
* <pre> | |||
* MessageFormatter.format("Hi {}. My name is {}.", "Alice", "Bob"); | |||
* </pre> | |||
* | |||
* will return the string "Hi Alice. My name is Bob.". | |||
* | |||
* @param messagePattern | |||
* The message pattern which will be parsed and formatted | |||
* @param arg1 | |||
* The argument to be substituted in place of the first formatting | |||
* anchor | |||
* @param arg2 | |||
* The argument to be substituted in place of the second formatting | |||
* anchor | |||
* @return The formatted message | |||
*/ | |||
final public static FormattingTuple format(final String messagePattern, Object arg1, Object arg2) { | |||
return arrayFormat(messagePattern, new Object[] { arg1, arg2 }); | |||
} | |||
static final Throwable getThrowableCandidate(Object[] argArray) { | |||
if (argArray == null || argArray.length == 0) { | |||
return null; | |||
} | |||
final Object lastEntry = argArray[argArray.length - 1]; | |||
if (lastEntry instanceof Throwable) { | |||
return (Throwable) lastEntry; | |||
} | |||
return null; | |||
} | |||
final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray) { | |||
Throwable throwableCandidate = getThrowableCandidate(argArray); | |||
Object[] args = argArray; | |||
if (throwableCandidate != null) { | |||
args = trimmedCopy(argArray); | |||
} | |||
return arrayFormat(messagePattern, args, throwableCandidate); | |||
} | |||
private static Object[] trimmedCopy(Object[] argArray) { | |||
if (argArray == null || argArray.length == 0) { | |||
throw new IllegalStateException("non-sensical empty or null argument array"); | |||
} | |||
final int trimemdLen = argArray.length - 1; | |||
Object[] trimmed = new Object[trimemdLen]; | |||
System.arraycopy(argArray, 0, trimmed, 0, trimemdLen); | |||
return trimmed; | |||
} | |||
final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray, Throwable throwable) { | |||
if (messagePattern == null) { | |||
return new FormattingTuple(null, argArray, throwable); | |||
} | |||
if (argArray == null) { | |||
return new FormattingTuple(messagePattern); | |||
} | |||
int i = 0; | |||
int j; | |||
// use string builder for better multicore performance | |||
StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50); | |||
int L; | |||
for (L = 0; L < argArray.length; L++) { | |||
j = messagePattern.indexOf(DELIM_STR, i); | |||
if (j == -1) { | |||
// no more variables | |||
if (i == 0) { // this is a simple string | |||
return new FormattingTuple(messagePattern, argArray, throwable); | |||
} else { // add the tail string which contains no variables and return | |||
// the result. | |||
sbuf.append(messagePattern, i, messagePattern.length()); | |||
return new FormattingTuple(sbuf.toString(), argArray, throwable); | |||
} | |||
} else { | |||
if (isEscapedDelimeter(messagePattern, j)) { | |||
if (!isDoubleEscaped(messagePattern, j)) { | |||
L--; // DELIM_START was escaped, thus should not be incremented | |||
sbuf.append(messagePattern, i, j - 1); | |||
sbuf.append(DELIM_START); | |||
i = j + 1; | |||
} else { | |||
// The escape character preceding the delimiter start is | |||
// itself escaped: "abc x:\\{}" | |||
// we have to consume one backward slash | |||
sbuf.append(messagePattern, i, j - 1); | |||
deeplyAppendParameter(sbuf, argArray[L], new HashMap<Object[], Object>()); | |||
i = j + 2; | |||
} | |||
} else { | |||
// normal case | |||
sbuf.append(messagePattern, i, j); | |||
deeplyAppendParameter(sbuf, argArray[L], new HashMap<Object[], Object>()); | |||
i = j + 2; | |||
} | |||
} | |||
} | |||
// append the characters following the last {} pair. | |||
sbuf.append(messagePattern, i, messagePattern.length()); | |||
return new FormattingTuple(sbuf.toString(), argArray, throwable); | |||
} | |||
final static boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) { | |||
if (delimeterStartIndex == 0) { | |||
return false; | |||
} | |||
char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1); | |||
if (potentialEscape == ESCAPE_CHAR) { | |||
return true; | |||
} else { | |||
return false; | |||
} | |||
} | |||
final static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) { | |||
if (delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR) { | |||
return true; | |||
} else { | |||
return false; | |||
} | |||
} | |||
// special treatment of array values was suggested by 'lizongbo' | |||
private static void deeplyAppendParameter(StringBuilder sbuf, Object o, Map<Object[], Object> seenMap) { | |||
if (o == null) { | |||
sbuf.append("null"); | |||
return; | |||
} | |||
if (!o.getClass().isArray()) { | |||
safeObjectAppend(sbuf, o); | |||
} else { | |||
// check for primitive array types because they | |||
// unfortunately cannot be cast to Object[] | |||
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 oAsString = o.toString(); | |||
sbuf.append(oAsString); | |||
} catch (Throwable t) { | |||
sbuf.append("[FAILED toString()]"); | |||
} | |||
} | |||
private static void objectArrayAppend(StringBuilder sbuf, Object[] a, Map<Object[], Object> seenMap) { | |||
sbuf.append('['); | |||
if (!seenMap.containsKey(a)) { | |||
seenMap.put(a, null); | |||
final int len = a.length; | |||
for (int i = 0; i < len; i++) { | |||
deeplyAppendParameter(sbuf, a[i], seenMap); | |||
if (i != len - 1) { | |||
sbuf.append(", "); | |||
} | |||
} | |||
// allow repeats in siblings | |||
seenMap.remove(a); | |||
} else { | |||
sbuf.append("..."); | |||
} | |||
sbuf.append(']'); | |||
} | |||
private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) { | |||
sbuf.append('['); | |||
final 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('['); | |||
final 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('['); | |||
final 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('['); | |||
final 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('['); | |||
final 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('['); | |||
final 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('['); | |||
final 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('['); | |||
final int len = a.length; | |||
for (int i = 0; i < len; i++) { | |||
sbuf.append(a[i]); | |||
if (i != len - 1) { | |||
sbuf.append(", "); | |||
} | |||
} | |||
sbuf.append(']'); | |||
} | |||
} |
@@ -15,9 +15,8 @@ | |||
*/ | |||
package com.alibaba.csp.sentinel.log; | |||
import java.util.logging.Handler; | |||
import java.util.logging.Level; | |||
import java.util.logging.Logger; | |||
import java.util.Iterator; | |||
import java.util.ServiceLoader; | |||
/*** | |||
* The basic logger for vital events. | |||
@@ -25,27 +24,71 @@ import java.util.logging.Logger; | |||
* @author youji.zj | |||
*/ | |||
public class RecordLog extends LogBase { | |||
private static final Logger heliumRecordLog = Logger.getLogger("cspSentinelRecordLog"); | |||
private static final String FILE_NAME = "sentinel-record.log"; | |||
private static Handler logHandler = null; | |||
private static com.alibaba.csp.sentinel.log.Logger log = null; | |||
static { | |||
logHandler = makeLogger(FILE_NAME, heliumRecordLog); | |||
ServiceLoader<Logger> load = ServiceLoader.load(Logger.class); | |||
Logger logger = null; | |||
Iterator<Logger> iterator = load.iterator(); | |||
while (iterator.hasNext()) { | |||
Logger next = iterator.next(); | |||
LogTarget annotation = next.getClass().getAnnotation(LogTarget.class); | |||
if (annotation == null) { | |||
continue; | |||
} | |||
String value = annotation.value().name(); | |||
if (value.equals(LogType.RECORD_LOG.name())) { | |||
logger = next; | |||
break; | |||
} | |||
} | |||
// Use user implementations. | |||
if (logger != null) { | |||
log = logger; | |||
} else { | |||
// Use default implementations. | |||
log = new RecordLogLogging(); | |||
} | |||
} | |||
public static void info(String detail, Object... params) { | |||
log(heliumRecordLog, logHandler, Level.INFO, detail, params); | |||
public static void info(String format, Object... arguments) { | |||
log.info(format, arguments); | |||
} | |||
public static void info(String detail, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.INFO, detail, e); | |||
public static void info(String msg, Throwable e) { | |||
log.info(msg, e); | |||
} | |||
public static void warn(String detail, Object... params) { | |||
log(heliumRecordLog, logHandler, Level.WARNING, detail, params); | |||
public static void warn(String format, Object... arguments) { | |||
log.warn(format, arguments); | |||
} | |||
public static void warn(String detail, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.WARNING, detail, e); | |||
public static void warn(String msg, Throwable e) { | |||
log.warn(msg, e); | |||
} | |||
public static void trace(String format, Object... arguments) { | |||
log.trace(format, arguments); | |||
} | |||
public static void trace(String msg, Throwable e) { | |||
log.trace(msg, e); | |||
} | |||
public static void debug(String format, Object... arguments) { | |||
log.debug(format, arguments); | |||
} | |||
public static void debug(String msg, Throwable e) { | |||
log.debug(msg, e); | |||
} | |||
public static void error(String format, Object... arguments) { | |||
log.error(format, arguments); | |||
} | |||
public static void error(String msg, Throwable e) { | |||
log.error(msg, e); | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
/* | |||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 | |||
* | |||
* https://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 com.alibaba.csp.sentinel.log; | |||
import java.util.logging.Handler; | |||
import java.util.logging.Logger; | |||
/** | |||
* Default logger implementation. | |||
* @author xue8 | |||
*/ | |||
public class RecordLogLogging extends LogBase implements com.alibaba.csp.sentinel.log.Logger { | |||
private final Logger heliumRecordLog = Logger.getLogger("cspSentinelRecordLog"); | |||
private final String FILE_NAME = "sentinel-record.log"; | |||
private final Handler logHandler = makeLogger(FILE_NAME, heliumRecordLog); | |||
@Override | |||
public void info(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.INFO, format, arguments); | |||
} | |||
@Override | |||
public void info(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.INFO, msg, e); | |||
} | |||
@Override | |||
public void warn(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.WARNING, format, arguments); | |||
} | |||
@Override | |||
public void warn(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.WARNING, msg, e); | |||
} | |||
@Override | |||
public void trace(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.TRACE, format, arguments); | |||
} | |||
@Override | |||
public void trace(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.TRACE, msg, e); | |||
} | |||
@Override | |||
public void debug(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.DEBUG, format, arguments); | |||
} | |||
@Override | |||
public void debug(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.DEBUG, msg, e); | |||
} | |||
@Override | |||
public void error(String format, Object... arguments) { | |||
log(heliumRecordLog, logHandler, Level.ERROR, format, arguments); | |||
} | |||
@Override | |||
public void error(String msg, Throwable e) { | |||
log(heliumRecordLog, logHandler, Level.ERROR, msg, e); | |||
} | |||
} |
@@ -107,4 +107,14 @@ public class RecordLogTest { | |||
} | |||
// Because log only writes into the file, | |||
// can't read the log(file conflict), so no assertion in this unit test. | |||
@Test | |||
public void testMessageFormatter() { | |||
RecordLog.info("1 2 {} 4 {} 6", "3", "5"); | |||
RecordLog.info("1 2 {} 4 {} 6", "3"); | |||
RecordLog.info("1 2 {} 4 {} 6"); | |||
RecordLog.info("1 2 \\{} 4 {} 6", "5"); | |||
} | |||
} |
@@ -36,6 +36,7 @@ | |||
<module>sentinel-demo-zuul-gateway</module> | |||
<module>sentinel-demo-etcd-datasource</module> | |||
<module>sentinel-demo-spring-webmvc</module> | |||
<module>sentinel-demo-log-logback</module> | |||
</modules> | |||
<dependencies> | |||
@@ -0,0 +1,41 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<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> | |||
<artifactId>sentinel-demo</artifactId> | |||
<groupId>com.alibaba.csp</groupId> | |||
<version>1.7.2-SNAPSHOT</version> | |||
</parent> | |||
<modelVersion>4.0.0</modelVersion> | |||
<artifactId>sentinel-demo-log-logback</artifactId> | |||
<dependencies> | |||
<dependency> | |||
<groupId>ch.qos.logback</groupId> | |||
<artifactId>logback-classic</artifactId> | |||
<version>1.2.3</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>ch.qos.logback</groupId> | |||
<artifactId>logback-core</artifactId> | |||
<version>1.2.3</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>junit</groupId> | |||
<artifactId>junit</artifactId> | |||
<scope>test</scope> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.github.stefanbirkner</groupId> | |||
<artifactId>system-rules</artifactId> | |||
<version>RELEASE</version> | |||
<scope>test</scope> | |||
</dependency> | |||
</dependencies> | |||
</project> |
@@ -0,0 +1,90 @@ | |||
/* | |||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 | |||
* | |||
* https://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 com.alibaba.csp.sentinel.demo.log.logback; | |||
import com.alibaba.csp.sentinel.log.LogTarget; | |||
import com.alibaba.csp.sentinel.log.LogType; | |||
import com.alibaba.csp.sentinel.log.Logger; | |||
import org.slf4j.LoggerFactory; | |||
/** | |||
* This class is a demo shows how to create a customized logger implementation. | |||
* | |||
* <ul> | |||
* <li>1. Create a class which implements the {@link Logger} SPI interface</li> | |||
* <li>2. Use a {@link LogTarget} to specify the log type</li> | |||
* <li>3. Implement your own method </li> | |||
* <li>4. Add your logger in {@code com.alibaba.csp.sentinel.log.Logger} file which is stored in | |||
* {@code resources/META-INF/services/} directory </li> | |||
* </ul> | |||
* | |||
* @author xue8 | |||
*/ | |||
@LogTarget(value = LogType.COMMAND_CENTER_LOG) | |||
public class CommandCenterLogLoggerImpl implements Logger { | |||
private final org.slf4j.Logger logger = LoggerFactory.getLogger("commandCenterLogLogger"); | |||
@Override | |||
public void info(String format, Object... arguments) { | |||
logger.info(format, arguments); | |||
} | |||
@Override | |||
public void info(String msg, Throwable e) { | |||
logger.info(msg, e); | |||
} | |||
@Override | |||
public void warn(String format, Object... arguments) { | |||
logger.warn(format, arguments); | |||
} | |||
@Override | |||
public void warn(String msg, Throwable e) { | |||
logger.warn(msg, e); | |||
} | |||
@Override | |||
public void trace(String format, Object... arguments) { | |||
logger.trace(format, arguments); | |||
} | |||
@Override | |||
public void trace(String msg, Throwable e) { | |||
logger.trace(msg, e); | |||
} | |||
@Override | |||
public void debug(String format, Object... arguments) { | |||
logger.debug(format, arguments); | |||
} | |||
@Override | |||
public void debug(String msg, Throwable e) { | |||
logger.debug(msg, e); | |||
} | |||
@Override | |||
public void error(String format, Object... arguments) { | |||
logger.error(format, arguments); | |||
} | |||
@Override | |||
public void error(String msg, Throwable e) { | |||
logger.error(msg, e); | |||
} | |||
} |
@@ -0,0 +1,90 @@ | |||
/* | |||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 | |||
* | |||
* https://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 com.alibaba.csp.sentinel.demo.log.logback; | |||
import com.alibaba.csp.sentinel.log.LogTarget; | |||
import com.alibaba.csp.sentinel.log.LogType; | |||
import com.alibaba.csp.sentinel.log.Logger; | |||
import org.slf4j.LoggerFactory; | |||
/** | |||
* This class is a demo shows how to create a customized logger implementation. | |||
* | |||
* <ul> | |||
* <li>1. Create a class which implements the {@link Logger} SPI interface</li> | |||
* <li>2. Use a {@link LogTarget} to specify the log type</li> | |||
* <li>3. Implement your own method </li> | |||
* <li>4. Add your logger in {@code com.alibaba.csp.sentinel.log.Logger} file which is stored in | |||
* {@code resources/META-INF/services/} directory </li> | |||
* </ul> | |||
* | |||
* @author xue8 | |||
*/ | |||
@LogTarget(value = LogType.RECORD_LOG) | |||
public class RecordLogLoggerImpl implements Logger { | |||
private final org.slf4j.Logger logger = LoggerFactory.getLogger("recordLogLogger"); | |||
@Override | |||
public void info(String format, Object... arguments) { | |||
logger.info(format, arguments); | |||
} | |||
@Override | |||
public void info(String msg, Throwable e) { | |||
logger.info(msg, e); | |||
} | |||
@Override | |||
public void warn(String format, Object... arguments) { | |||
logger.warn(format, arguments); | |||
} | |||
@Override | |||
public void warn(String msg, Throwable e) { | |||
logger.warn(msg, e); | |||
} | |||
@Override | |||
public void trace(String format, Object... arguments) { | |||
logger.trace(format, arguments); | |||
} | |||
@Override | |||
public void trace(String msg, Throwable e) { | |||
logger.trace(msg, e); | |||
} | |||
@Override | |||
public void debug(String format, Object... arguments) { | |||
logger.debug(format, arguments); | |||
} | |||
@Override | |||
public void debug(String msg, Throwable e) { | |||
logger.debug(msg, e); | |||
} | |||
@Override | |||
public void error(String format, Object... arguments) { | |||
logger.error(format, arguments); | |||
} | |||
@Override | |||
public void error(String msg, Throwable e) { | |||
logger.error(msg, e); | |||
} | |||
} |
@@ -0,0 +1,2 @@ | |||
com.alibaba.csp.sentinel.demo.log.logback.RecordLogLoggerImpl | |||
com.alibaba.csp.sentinel.demo.log.logback.CommandCenterLogLoggerImpl |
@@ -0,0 +1,42 @@ | |||
<?xml version="1.0" encoding="UTF-8" ?> | |||
<configuration scan="false" scanPeriod="60000" debug="false"> | |||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |||
<layout class="ch.qos.logback.classic.PatternLayout"> | |||
<pattern>%-5level %logger - %msg%n</pattern> | |||
</layout> | |||
</appender> | |||
<appender name="FILE" class="ch.qos.logback.core.FileAppender"> | |||
<file>sentinel-record.log</file> | |||
<append>true</append> | |||
<encoder> | |||
<pattern>%-5level %logger - %msg%n</pattern> | |||
</encoder> | |||
</appender> | |||
<appender name="FILE2" class="ch.qos.logback.core.FileAppender"> | |||
<file>sentinel-command-center.log</file> | |||
<append>true</append> | |||
<encoder> | |||
<pattern>%-5level %logger - %msg%n</pattern> | |||
</encoder> | |||
</appender> | |||
<logger name="recordLogLogger" level="trace"> | |||
<appender-ref ref="STDOUT" /> | |||
<appender-ref ref="FILE" /> | |||
</logger> | |||
<logger name="commandCenterLogLogger" level="trace"> | |||
<appender-ref ref="STDOUT" /> | |||
<appender-ref ref="FILE2" /> | |||
</logger> | |||
<!--<root level="info">--> | |||
<!--<appender-ref ref="STDOUT" />--> | |||
<!--<appender-ref ref="FILE" />--> | |||
<!--</root>--> | |||
</configuration> | |||
@@ -0,0 +1,116 @@ | |||
/* | |||
* Copyright 1999-2019 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 | |||
* | |||
* https://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 com.alibaba.csp.sentinel.demo.log.logback; | |||
import com.alibaba.csp.sentinel.log.CommandCenterLog; | |||
import org.junit.Assert; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.contrib.java.lang.system.SystemOutRule; | |||
/** | |||
* @author xue8 | |||
*/ | |||
public class CommandCenterLogTest { | |||
@Rule | |||
public SystemOutRule log = new SystemOutRule().enableLog(); | |||
@Test | |||
public void testLog() { | |||
CommandCenterLog.info("init"); | |||
log.clearLog(); | |||
int count = 0; | |||
// info test | |||
while (count++ < 1000) { | |||
log.clearLog(); | |||
CommandCenterLog.info("Count {}", count); | |||
String str = String.format("INFO commandCenterLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
// warn test | |||
while (count++ < 2000) { | |||
log.clearLog(); | |||
CommandCenterLog.warn("Count {}", count); | |||
String str = String.format("WARN commandCenterLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
// trace test | |||
while (count++ < 3000) { | |||
log.clearLog(); | |||
CommandCenterLog.trace("Count {}", count); | |||
String str = String.format("TRACE commandCenterLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
// debug test | |||
while (count++ < 4000) { | |||
log.clearLog(); | |||
CommandCenterLog.debug("Count {}", count); | |||
String str = String.format("DEBUG commandCenterLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
// test error | |||
while (count++ < 5000) { | |||
log.clearLog(); | |||
CommandCenterLog.error("Count {}", count); | |||
String str = String.format("ERROR commandCenterLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
} | |||
@Test | |||
public void testLogException() { | |||
CommandCenterLog.info("init"); | |||
log.clearLog(); | |||
Exception e = new Exception("ex"); | |||
// info test | |||
CommandCenterLog.info("Error", e); | |||
// split the log for test | |||
String[] logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("INFO commandCenterLogLogger - Error", logSplit[0]); | |||
// warn test | |||
log.clearLog(); | |||
CommandCenterLog.warn("Error", e); | |||
logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("WARN commandCenterLogLogger - Error", logSplit[0]); | |||
// trace test | |||
log.clearLog(); | |||
CommandCenterLog.trace("Error", e); | |||
logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("TRACE commandCenterLogLogger - Error", logSplit[0]); | |||
// debug test | |||
log.clearLog(); | |||
CommandCenterLog.debug("Error", e); | |||
logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("DEBUG commandCenterLogLogger - Error", logSplit[0]); | |||
// error test | |||
log.clearLog(); | |||
CommandCenterLog.error("Error", e); | |||
logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("ERROR commandCenterLogLogger - Error", logSplit[0]); | |||
} | |||
} |
@@ -0,0 +1,115 @@ | |||
/* | |||
* Copyright 1999-2018 Alibaba Group Holding Ltd. | |||
* | |||
* Licensed 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 com.alibaba.csp.sentinel.demo.log.logback; | |||
import com.alibaba.csp.sentinel.log.RecordLog; | |||
import org.junit.Assert; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.contrib.java.lang.system.SystemOutRule; | |||
/** | |||
* @author xue8 | |||
*/ | |||
public class RecordLogTest { | |||
@Rule | |||
public SystemOutRule log = new SystemOutRule().enableLog(); | |||
@Test | |||
public void testLog() { | |||
RecordLog.info("init"); | |||
log.clearLog(); | |||
int count = 0; | |||
// info test | |||
while (count++ < 1000) { | |||
log.clearLog(); | |||
RecordLog.info("Count {}", count); | |||
String str = String.format("INFO recordLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
// warn test | |||
while (count++ < 2000) { | |||
log.clearLog(); | |||
RecordLog.warn("Count {}", count); | |||
String str = String.format("WARN recordLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
// trace test | |||
while (count++ < 3000) { | |||
log.clearLog(); | |||
RecordLog.trace("Count {}", count); | |||
String str = String.format("TRACE recordLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
// debug test | |||
while (count++ < 4000) { | |||
log.clearLog(); | |||
RecordLog.debug("Count {}", count); | |||
String str = String.format("DEBUG recordLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
// test error | |||
while (count++ < 5000) { | |||
log.clearLog(); | |||
RecordLog.error("Count {}", count); | |||
String str = String.format("ERROR recordLogLogger - Count %d" + System.lineSeparator(), count); | |||
Assert.assertEquals(str, log.getLog()); | |||
} | |||
} | |||
@Test | |||
public void testLogException() { | |||
RecordLog.info("init"); | |||
log.clearLog(); | |||
Exception e = new Exception("ex"); | |||
// info test | |||
RecordLog.info("Error", e); | |||
// split the log for test | |||
String[] logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("INFO recordLogLogger - Error", logSplit[0]); | |||
// warn test | |||
log.clearLog(); | |||
RecordLog.warn("Error", e); | |||
logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("WARN recordLogLogger - Error", logSplit[0]); | |||
// trace test | |||
log.clearLog(); | |||
RecordLog.trace("Error", e); | |||
logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("TRACE recordLogLogger - Error", logSplit[0]); | |||
// debug test | |||
log.clearLog(); | |||
RecordLog.debug("Error", e); | |||
logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("DEBUG recordLogLogger - Error", logSplit[0]); | |||
// error test | |||
log.clearLog(); | |||
RecordLog.error("Error", e); | |||
logSplit = log.getLog().split(System.lineSeparator()); | |||
Assert.assertEquals("ERROR recordLogLogger - Error", logSplit[0]); | |||
} | |||
} |