Browse Source

Flexible loggers' support through SPI mechanism with name `com.alibaba.csp.sentinel.log.Logger` (#1265)

* 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
xue8 GitHub 5 years ago
parent
commit
5f203aa79f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1476 additions and 38 deletions
  1. +58
    -17
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/CommandCenterLog.java
  2. +79
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/CommandCenterLogLogging.java
  3. +59
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/FormattingTuple.java
  4. +34
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/Level.java
  5. +4
    -5
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/LogBase.java
  6. +32
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/LogTarget.java
  7. +25
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/LogType.java
  8. +113
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/Logger.java
  9. +427
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/MessageFormatter.java
  10. +58
    -15
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/RecordLog.java
  11. +79
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/RecordLogLogging.java
  12. +11
    -1
      sentinel-core/src/test/java/com/alibaba/csp/sentinel/RecordLogTest.java
  13. +1
    -0
      sentinel-demo/pom.xml
  14. +41
    -0
      sentinel-demo/sentinel-demo-log-logback/pom.xml
  15. +90
    -0
      sentinel-demo/sentinel-demo-log-logback/src/main/java/com/alibaba/csp/sentinel/demo/log/logback/CommandCenterLogLoggerImpl.java
  16. +90
    -0
      sentinel-demo/sentinel-demo-log-logback/src/main/java/com/alibaba/csp/sentinel/demo/log/logback/RecordLogLoggerImpl.java
  17. +2
    -0
      sentinel-demo/sentinel-demo-log-logback/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.log.Logger
  18. +42
    -0
      sentinel-demo/sentinel-demo-log-logback/src/main/resources/logback.xml
  19. +116
    -0
      sentinel-demo/sentinel-demo-log-logback/src/test/java/com/alibaba/csp/sentinel/demo/log/logback/CommandCenterLogTest.java
  20. +115
    -0
      sentinel-demo/sentinel-demo-log-logback/src/test/java/com/alibaba/csp/sentinel/demo/log/logback/RecordLogTest.java

+ 58
- 17
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/CommandCenterLog.java View File

@@ -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);
}
}

+ 79
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/CommandCenterLogLogging.java View File

@@ -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);
}
}

+ 59
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/FormattingTuple.java View File

@@ -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;
}

}

+ 34
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/Level.java View File

@@ -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);
}
}

+ 4
- 5
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/LogBase.java View File

@@ -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) {


+ 32
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/LogTarget.java View File

@@ -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;
}

+ 25
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/LogType.java View File

@@ -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,
}

+ 113
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/Logger.java View File

@@ -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);

}

+ 427
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/MessageFormatter.java View File

@@ -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(&quot;Hi {}.&quot;, &quot;there&quot;)
* </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(&quot;Set {1,2,3} is not equal to {}.&quot;, &quot;1,2&quot;);
* </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(&quot;Set \\{} is not equal to {}.&quot;, &quot;1,2&quot;);
* </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(&quot;File name is C:\\\\{}.&quot;, &quot;file.zip&quot;);
* </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&uuml;lc&uuml;
* @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(&quot;Hi {}.&quot;, &quot;there&quot;);
* </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(&quot;Hi {}. My name is {}.&quot;, &quot;Alice&quot;, &quot;Bob&quot;);
* </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(']');
}

}

+ 58
- 15
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/RecordLog.java View File

@@ -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);
}

}

+ 79
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/log/RecordLogLogging.java View File

@@ -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);
}
}

+ 11
- 1
sentinel-core/src/test/java/com/alibaba/csp/sentinel/RecordLogTest.java View File

@@ -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");
}
}

+ 1
- 0
sentinel-demo/pom.xml View File

@@ -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>


+ 41
- 0
sentinel-demo/sentinel-demo-log-logback/pom.xml View File

@@ -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>

+ 90
- 0
sentinel-demo/sentinel-demo-log-logback/src/main/java/com/alibaba/csp/sentinel/demo/log/logback/CommandCenterLogLoggerImpl.java View File

@@ -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);
}

}

+ 90
- 0
sentinel-demo/sentinel-demo-log-logback/src/main/java/com/alibaba/csp/sentinel/demo/log/logback/RecordLogLoggerImpl.java View File

@@ -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);
}

}

+ 2
- 0
sentinel-demo/sentinel-demo-log-logback/src/main/resources/META-INF/services/com.alibaba.csp.sentinel.log.Logger View File

@@ -0,0 +1,2 @@
com.alibaba.csp.sentinel.demo.log.logback.RecordLogLoggerImpl
com.alibaba.csp.sentinel.demo.log.logback.CommandCenterLogLoggerImpl

+ 42
- 0
sentinel-demo/sentinel-demo-log-logback/src/main/resources/logback.xml View File

@@ -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>



+ 116
- 0
sentinel-demo/sentinel-demo-log-logback/src/test/java/com/alibaba/csp/sentinel/demo/log/logback/CommandCenterLogTest.java View File

@@ -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]);
}


}

+ 115
- 0
sentinel-demo/sentinel-demo-log-logback/src/test/java/com/alibaba/csp/sentinel/demo/log/logback/RecordLogTest.java View File

@@ -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]);
}

}

Loading…
Cancel
Save