Restructure the Spring Boot for Apache Geode project to mirror Spring Boot's project structure.
Resolves gh-60.
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import ch.qos.logback.core.Appender;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import ch.qos.logback.core.Context;
|
||||
|
||||
/**
|
||||
* {@link CompositeAppender} is an {@link Appender} implementation implementing
|
||||
* the <a href="https://en.wikipedia.org/wiki/Composite_pattern">Composite Software Design Pattern</a>
|
||||
*
|
||||
* The {@literal Composite Software Design Pattern} enables two or more {@link Appender} objects to be composed
|
||||
* and treated as a single instance of {@link Appender}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see ch.qos.logback.core.Appender
|
||||
* @see ch.qos.logback.core.AppenderBase
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class CompositeAppender<T> extends AppenderBase<T> {
|
||||
|
||||
protected static final String DEFAULT_NAME = "composite";
|
||||
|
||||
private final Appender<T> one;
|
||||
private final Appender<T> two;
|
||||
|
||||
/**
|
||||
* Factory method used to compose two {@link Appender} objects into a {@literal Composite} {@link Appender}.
|
||||
*
|
||||
* @param <T> {@link Class type} of {@link Appender} to compose.
|
||||
* @param one first {@link Appender} to compose.
|
||||
* @param two second {@link Appender} to compose.
|
||||
* @return {@link Appender} one if {@link Appender} two is {@literal null};
|
||||
* Return {@link Appender} two if {@link Appender} one is {@literal null}.
|
||||
* Otherwise, return a {@literal Composite} {@link Appender} composed of {@link Appender} one
|
||||
* and {@link Appender} two.
|
||||
* @see ch.qos.logback.core.Appender
|
||||
*/
|
||||
public static <T> Appender<T> compose(Appender<T> one, Appender<T> two) {
|
||||
return one == null ? two : two == null ? one : new CompositeAppender<>(one, two);
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes an array of {@link Appender Appenders} into a {@link CompositeAppender}.
|
||||
*
|
||||
* This operation is null-safe.
|
||||
*
|
||||
* @param <T> {@link Class type} of the logging events processed by the {@link Appender Appenders}.
|
||||
* @param appenders array of {@link Appender Appenders} to compose; may be {@literal null}.
|
||||
* @return a composition of the array of {@link Appender Appenders}; returns {@literal null} if the array is empty.
|
||||
* @see #compose(Iterable)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Appender<T> compose(Appender<T>... appenders) {
|
||||
|
||||
List<Appender<T>> resolvedAppenders = appenders != null
|
||||
? Arrays.asList(appenders)
|
||||
: Collections.emptyList();
|
||||
|
||||
return compose(resolvedAppenders);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes the {@link Iterable} of {@link Appender Appenders} into a {@link CompositeAppender}.
|
||||
*
|
||||
* This operation is null-safe.
|
||||
*
|
||||
* @param <T> {@link Class type} of the logging events processed by the {@link Appender Appenders}.
|
||||
* @param appenders {@link Iterable} of {@link Appender Appenders} to compose; may be {@literal null}.
|
||||
* @return a composition of the {@link Iterable} of {@link Appender Appenders}; returns {@literal null}
|
||||
* if the {@link Iterable} is {@literal null} or empty.
|
||||
* @see #compose(Appender, Appender)
|
||||
* @see java.lang.Iterable
|
||||
*/
|
||||
public static <T> Appender<T> compose(Iterable<Appender<T>> appenders) {
|
||||
|
||||
Appender<T> currentAppender = null;
|
||||
|
||||
appenders = appenders != null ? appenders : Collections::emptyIterator;
|
||||
|
||||
for (Appender<T> appender : appenders) {
|
||||
currentAppender = compose(currentAppender, appender);
|
||||
}
|
||||
|
||||
return currentAppender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of {@link CompositeAppender} composed of {@link Appender} one and {@link Appender} two.
|
||||
*
|
||||
* @param one first {@link Appender} in the composite.
|
||||
* @param two second {@link Appender} in the composite.
|
||||
* @see ch.qos.logback.core.Appender
|
||||
*/
|
||||
private CompositeAppender(Appender<T> one, Appender<T> two) {
|
||||
|
||||
this.one = one;
|
||||
this.two = two;
|
||||
this.name = DEFAULT_NAME;
|
||||
this.started = true;
|
||||
}
|
||||
|
||||
protected Appender<T> getAppenderOne() {
|
||||
return this.one;
|
||||
}
|
||||
|
||||
protected Appender<T> getAppenderTwo() {
|
||||
return this.two;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContext(Context context) {
|
||||
|
||||
super.setContext(context);
|
||||
|
||||
getAppenderOne().setContext(context);
|
||||
getAppenderTwo().setContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getContext() {
|
||||
|
||||
Context context = super.getContext();
|
||||
|
||||
context = context != null ? context : getAppenderOne().getContext();
|
||||
context = context != null ? context : getAppenderTwo().getContext();
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(T eventObject) {
|
||||
getAppenderOne().doAppend(eventObject);
|
||||
getAppenderTwo().doAppend(eventObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.core.Appender;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import ch.qos.logback.core.Context;
|
||||
import ch.qos.logback.core.helpers.NOPAppender;
|
||||
|
||||
/**
|
||||
* {@link DelegatingAppender} is an SLF4J {@link Appender} that delegates to the configured {@link Appender}.
|
||||
*
|
||||
* If no {@link Appender} was configured, then the {@link DelegatingAppender} delegates to the {@link NOPAppender}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see ch.qos.logback.core.Appender
|
||||
* @see ch.qos.logback.core.AppenderBase
|
||||
* @see ch.qos.logback.core.helpers.NOPAppender
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class DelegatingAppender<T> extends AppenderBase<T> {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected static final Appender DEFAULT_APPENDER = new NOPAppender<>();
|
||||
|
||||
protected static final String DEFAULT_NAME = "delegate";
|
||||
|
||||
public DelegatingAppender() {
|
||||
|
||||
Optional.ofNullable(LoggerFactory.getILoggerFactory())
|
||||
.filter(it -> Objects.isNull(DEFAULT_APPENDER.getContext()))
|
||||
.filter(Context.class::isInstance)
|
||||
.map(Context.class::cast)
|
||||
.ifPresent(DEFAULT_APPENDER::setContext);
|
||||
|
||||
this.name = DEFAULT_NAME;
|
||||
}
|
||||
|
||||
private volatile Appender<T> appender;
|
||||
|
||||
public void setAppender(Appender<T> appender) {
|
||||
this.appender = appender;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Appender<T> getAppender() {
|
||||
|
||||
Appender<T> configuredAppender = this.appender;
|
||||
|
||||
return configuredAppender != null
|
||||
? configuredAppender
|
||||
: DEFAULT_APPENDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(T eventObject) {
|
||||
getAppender().doAppend(eventObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.geode.logging.slf4j.logback.support.LogbackSupport;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import ch.qos.logback.core.Context;
|
||||
|
||||
/**
|
||||
* {@link StringAppender} is a {@link Appender} implementation that captures all log events/statements in-memory
|
||||
* appended to a {@link String} using optionally either a builder or a buffer.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.lang.StringBuilder
|
||||
* @see java.lang.StringBuffer
|
||||
* @see ch.qos.logback.core.Appender
|
||||
* @see ch.qos.logback.core.AppenderBase
|
||||
* @see ch.qos.logback.core.Context
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StringAppender extends AppenderBase<ILoggingEvent> {
|
||||
|
||||
protected static final String DEFAULT_NAME = "string";
|
||||
protected static final String NEWLINE = "\n";
|
||||
|
||||
@FunctionalInterface
|
||||
interface StringAppenderWrapper {
|
||||
|
||||
void append(CharSequence charSequence);
|
||||
|
||||
default void clear() { }
|
||||
|
||||
}
|
||||
|
||||
protected static class StringBufferAppenderWrapper implements StringAppenderWrapper {
|
||||
|
||||
protected static StringBufferAppenderWrapper create() {
|
||||
return new StringBufferAppenderWrapper();
|
||||
}
|
||||
|
||||
private final StringBuffer stringBuffer = new StringBuffer();
|
||||
|
||||
@Override
|
||||
public void append(CharSequence charSequence) {
|
||||
this.stringBuffer.append(charSequence);
|
||||
this.stringBuffer.append(NEWLINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.stringBuffer.delete(0, this.stringBuffer.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.lang.String toString() {
|
||||
return this.stringBuffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
protected static class StringBuilderAppenderWrapper implements StringAppenderWrapper {
|
||||
|
||||
protected static StringBuilderAppenderWrapper create() {
|
||||
return new StringBuilderAppenderWrapper();
|
||||
}
|
||||
|
||||
private final StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public void append(CharSequence charSequence) {
|
||||
this.stringBuilder.append(charSequence);
|
||||
this.stringBuilder.append(NEWLINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.stringBuilder.delete(0, this.stringBuilder.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public java.lang.String toString() {
|
||||
return this.stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
|
||||
public static class Builder {
|
||||
|
||||
private static final boolean DEFAULT_REPLACE = false;
|
||||
|
||||
private boolean replace = false;
|
||||
private boolean useSynchronization = false;
|
||||
|
||||
private Context context;
|
||||
|
||||
private DelegatingAppender delegate;
|
||||
|
||||
private ch.qos.logback.classic.Logger logger;
|
||||
|
||||
private String name;
|
||||
|
||||
public Builder applyTo(DelegatingAppender<?> delegate) {
|
||||
return applyTo(delegate, DEFAULT_REPLACE);
|
||||
}
|
||||
|
||||
public Builder applyTo(DelegatingAppender<?> delegate, boolean replace) {
|
||||
this.delegate = delegate;
|
||||
this.replace = replace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder applyTo(Logger logger) {
|
||||
|
||||
return LogbackSupport.toLogbackLogger(logger)
|
||||
.map(this::applyTo)
|
||||
.orElse(this);
|
||||
}
|
||||
|
||||
public Builder applyTo(ch.qos.logback.classic.Logger logger) {
|
||||
this.logger = logger;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setContext(Context context) {
|
||||
this.context = context;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder useSynchronization() {
|
||||
this.useSynchronization = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
private Optional<DelegatingAppender> getDelegate() {
|
||||
return Optional.ofNullable(this.delegate);
|
||||
}
|
||||
|
||||
private Optional<ch.qos.logback.classic.Logger> getLogger() {
|
||||
return Optional.ofNullable(this.logger);
|
||||
}
|
||||
|
||||
private Context resolveContext() {
|
||||
|
||||
return this.context != null
|
||||
? this.context
|
||||
: Optional.ofNullable(LoggerFactory.getILoggerFactory())
|
||||
.filter(Context.class::isInstance)
|
||||
.map(Context.class::cast)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private String resolveName() {
|
||||
return this.name != null && !this.name.trim().isEmpty() ? this.name : DEFAULT_NAME;
|
||||
}
|
||||
|
||||
private StringAppenderWrapper resolveStringAppenderWrapper() {
|
||||
|
||||
return this.useSynchronization
|
||||
? StringBufferAppenderWrapper.create()
|
||||
: StringBuilderAppenderWrapper.create();
|
||||
}
|
||||
|
||||
public StringAppender build() {
|
||||
|
||||
StringAppender stringAppender =
|
||||
new StringAppender(resolveStringAppenderWrapper());
|
||||
|
||||
stringAppender.setContext(resolveContext());
|
||||
stringAppender.setName(resolveName());
|
||||
|
||||
getDelegate().ifPresent(delegate -> {
|
||||
|
||||
Appender appender = this.replace ? stringAppender
|
||||
: CompositeAppender.compose(delegate.getAppender(), stringAppender);
|
||||
|
||||
delegate.setAppender(appender);
|
||||
});
|
||||
|
||||
getLogger().ifPresent(logger -> logger.addAppender(stringAppender));
|
||||
|
||||
return stringAppender;
|
||||
}
|
||||
|
||||
public StringAppender buildAndStart() {
|
||||
|
||||
StringAppender stringAppender = build();
|
||||
|
||||
stringAppender.start();
|
||||
|
||||
return stringAppender;
|
||||
}
|
||||
}
|
||||
|
||||
private final StringAppenderWrapper stringAppenderWrapper;
|
||||
|
||||
protected StringAppender(StringAppenderWrapper stringAppenderWrapper) {
|
||||
|
||||
if (stringAppenderWrapper == null) {
|
||||
throw new IllegalArgumentException("StringAppenderWrapper must not be null");
|
||||
}
|
||||
|
||||
this.stringAppenderWrapper = stringAppenderWrapper;
|
||||
}
|
||||
|
||||
public String getLogOutput() {
|
||||
return getStringAppenderWrapper().toString();
|
||||
}
|
||||
|
||||
protected StringAppenderWrapper getStringAppenderWrapper() {
|
||||
return this.stringAppenderWrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(ILoggingEvent loggingEvent) {
|
||||
|
||||
Optional.ofNullable(loggingEvent)
|
||||
.map(event -> preProcessLogMessage(toString(event)))
|
||||
.filter(this::isValidLogMessage)
|
||||
.ifPresent(getStringAppenderWrapper()::append);
|
||||
}
|
||||
|
||||
protected boolean isValidLogMessage(String message) {
|
||||
return message != null && !message.isEmpty();
|
||||
}
|
||||
|
||||
protected String preProcessLogMessage(String message) {
|
||||
return message != null ? message.trim() : null;
|
||||
}
|
||||
|
||||
protected String toString(ILoggingEvent loggingEvent) {
|
||||
return loggingEvent != null ? loggingEvent.getFormattedMessage() : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.impl.StaticLoggerBinder;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
|
||||
/**
|
||||
* Abstract utility class containing functionality for invoking SLF4J and Logback APIs.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.slf4j.ILoggerFactory
|
||||
* @see org.slf4j.Logger
|
||||
* @see org.slf4j.LoggerFactory
|
||||
* @see ch.qos.logback.classic.LoggerContext
|
||||
* @see ch.qos.logback.core.Appender
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class LogbackSupport {
|
||||
|
||||
protected static final Function<Logger, Optional<ch.qos.logback.classic.Logger>> slf4jLoggerToLogbackLoggerConverter =
|
||||
logger -> Optional.ofNullable(logger)
|
||||
.filter(ch.qos.logback.classic.Logger.class::isInstance)
|
||||
.map(ch.qos.logback.classic.Logger.class::cast);
|
||||
|
||||
protected static final String CONSOLE_APPENDER_NAME = "console";
|
||||
protected static final String DELEGATE_APPENDER_NAME = "delegate";
|
||||
|
||||
protected static final String ILLEGAL_LOGGER_TYPE_EXCEPTION_MESSAGE =
|
||||
"[%1$s] Logger type [%2$s] is not a Logback Logger";
|
||||
|
||||
protected static final String ROOT_LOGGER_NAME = Logger.ROOT_LOGGER_NAME;
|
||||
|
||||
protected static final String SPRING_BOOT_LOGGING_SYSTEM_CLASS_NAME =
|
||||
"org.springframework.boot.logging.LoggingSystem";
|
||||
|
||||
protected static final String UNRESOLVABLE_APPENDER_EXCEPTION_MESSAGE =
|
||||
"Could not resolve Appender with name [%1$s] as type [%2$s] from Logger [%3$s]";
|
||||
|
||||
/**
|
||||
* Disables Spring Boot's logging initialization, auto-configuration.
|
||||
*/
|
||||
public static void suppressSpringBootLogbackInitialization() {
|
||||
requireLoggerContext().putObject(SPRING_BOOT_LOGGING_SYSTEM_CLASS_NAME, new Object());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state of the SLF4J Logback logging provider and system.
|
||||
*/
|
||||
public static void resetLogback() {
|
||||
|
||||
try {
|
||||
resetLoggerContext();
|
||||
resetLoggerFactory();
|
||||
resetStaticLoggerBinder();
|
||||
}
|
||||
catch (Throwable cause) {
|
||||
throw new IllegalStateException("Failed to reset Logback", cause);
|
||||
}
|
||||
}
|
||||
|
||||
private static void resetLoggerContext() {
|
||||
|
||||
resolveLoggerContext().ifPresent(loggerContext -> {
|
||||
loggerContext.reset();
|
||||
loggerContext.getStatusManager().clear();
|
||||
});
|
||||
}
|
||||
|
||||
private static void resetLoggerFactory() throws Exception {
|
||||
|
||||
Method loggerFactoryReset = LoggerFactory.class.getDeclaredMethod("reset");
|
||||
|
||||
loggerFactoryReset.setAccessible(true);
|
||||
loggerFactoryReset.invoke(null);
|
||||
}
|
||||
|
||||
private static void resetStaticLoggerBinder() throws Exception {
|
||||
|
||||
Method staticLoggerBinderReset = StaticLoggerBinder.class.getDeclaredMethod("reset");
|
||||
|
||||
staticLoggerBinderReset.setAccessible(true);
|
||||
staticLoggerBinderReset.invoke(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the SLF4J, Logback {@link LoggerContext}.
|
||||
*
|
||||
* If the {@link LoggerContext} could not be resolve then the returned {@link Optional}
|
||||
* will be {@link Optional#empty() empty}.
|
||||
*
|
||||
* @return an {@link Optional} {@link LoggerContext}.
|
||||
* @see ch.qos.logback.classic.LoggerContext
|
||||
*/
|
||||
public static Optional<LoggerContext> resolveLoggerContext() {
|
||||
|
||||
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
|
||||
|
||||
LoggerContext resolvedLoggerContext = loggerFactory instanceof LoggerContext
|
||||
? (LoggerContext) loggerFactory
|
||||
: null;
|
||||
|
||||
return Optional.ofNullable(resolvedLoggerContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires a {@link LoggerContext} otherwise throws an {@link IllegalStateException}.
|
||||
*
|
||||
* @return the required {@link LoggerContext}.
|
||||
* @throws IllegalStateException if the {@link LoggerContext} could not be resolved.
|
||||
* @see #resolveLoggerContext()
|
||||
*/
|
||||
public static LoggerContext requireLoggerContext() {
|
||||
|
||||
return resolveLoggerContext()
|
||||
.orElseThrow(() -> new IllegalStateException("LoggerContext is required"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the {@link Logger#ROOT_LOGGER_NAME Root} {@link Logger}.
|
||||
*
|
||||
* @return an {@link Optional} {@link Logger} for the logging provider's {@literal ROOT} {@link Logger}.
|
||||
* @see org.slf4j.Logger
|
||||
*/
|
||||
public static Optional<Logger> resolveRootLogger() {
|
||||
return Optional.ofNullable(LoggerFactory.getLogger(ROOT_LOGGER_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires the SLF4J Logback {@literal ROOT} {@link Logger} otherwise throws an {@link IllegalStateException}.
|
||||
*
|
||||
* @return the configured SLF4J Logback {@literal ROOT} {@link Logger}.
|
||||
* @throws IllegalStateException if the SLF4J Logback {@literal ROOT} {@link Logger} could not be resolved
|
||||
* or the {@literal ROOT} {@link Logger} is not a SLF4J Logback {@literal ROOT} {@link Logger}.
|
||||
* @see ch.qos.logback.classic.Logger
|
||||
* @see #resolveRootLogger()
|
||||
*/
|
||||
public static ch.qos.logback.classic.Logger requireLogbackRootLogger() {
|
||||
|
||||
return resolveRootLogger()
|
||||
.filter(ch.qos.logback.classic.Logger.class::isInstance)
|
||||
.map(ch.qos.logback.classic.Logger.class::cast)
|
||||
.orElseThrow(() -> new IllegalStateException(String.format(ILLEGAL_LOGGER_TYPE_EXCEPTION_MESSAGE,
|
||||
ROOT_LOGGER_NAME, nullSafeTypeName(resolveRootLogger().orElse(null)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an {@link Appender} with the given {@link String name} from the given {@link Logger}.
|
||||
*
|
||||
* @param <T> {@link Class type} of the {@link Appender}.
|
||||
* @param <E> {@link Class type} of the logging event.
|
||||
* @param logger SLF4J {@link Logger} from which to resolve the {@link Appender}.
|
||||
* @param appenderName a {@link String} containing the name of the {@link Appender} to resolve.
|
||||
* @param appenderType required {@link Class type} of the {@link Appender} to resolve.
|
||||
* @return an {@link Optional} {@link Appender} with the given {@link String name} from the {@link Logger}.
|
||||
* @see ch.qos.logback.core.Appender
|
||||
* @see java.util.Optional
|
||||
* @see org.slf4j.Logger
|
||||
*/
|
||||
public static <E, T extends Appender<E>> Optional<T> resolveAppender(ch.qos.logback.classic.Logger logger,
|
||||
String appenderName, Class<T> appenderType) {
|
||||
|
||||
appenderType = nullSafeAppenderType(appenderType);
|
||||
|
||||
return Optional.ofNullable(logger)
|
||||
.map(it -> it.getAppender(appenderName))
|
||||
.filter(appenderType::isInstance)
|
||||
.map(appenderType::cast);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requires an {@link Appender} with the given {@link String name} having the specified {@link Class type}
|
||||
* from the given {@link Logger}.
|
||||
*
|
||||
* @param <T> {@link Class type} of the {@link Appender}.
|
||||
* @param <E> {@link Class type} of the {@link Object Objects} processed by the {@link Appender}.
|
||||
* @param logger {@link Logger} from which to resolve the {@link Appender}.
|
||||
* @param appenderName {@link String} containing the name of the {@link Appender}.
|
||||
* @param appenderType required {@link Class type} of the {@link Appender}.
|
||||
* @return the resolved {@link Appender}.
|
||||
* @throws IllegalStateException if an {@link Appender} with {@link String name} and required {@link Class type}
|
||||
* could not be resolved from the given {@link Logger}.
|
||||
* @see ch.qos.logback.classic.Logger
|
||||
* @see ch.qos.logback.core.Appender
|
||||
*/
|
||||
public static <E, T extends Appender<E>> T requireAppender(ch.qos.logback.classic.Logger logger,
|
||||
String appenderName, Class<T> appenderType) {
|
||||
|
||||
return resolveAppender(logger, appenderName, appenderType)
|
||||
.orElseThrow(() -> new IllegalStateException(String.format(UNRESOLVABLE_APPENDER_EXCEPTION_MESSAGE,
|
||||
appenderName, nullSafeTypeName(appenderType), nullSafeLoggerName(logger))));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private static <E, T extends Appender<E>> Class<T> nullSafeAppenderType(Class<T> appenderType) {
|
||||
return appenderType != null ? appenderType : (Class) Appender.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@link Appender} to the given {@link Logger}.
|
||||
*
|
||||
* @param logger {@link Logger} to add the {@link Appender} to.
|
||||
* @param appender {@link Appender} to add to the {@link Logger}.
|
||||
* @return a boolean value indicating whether the {@link Appender} was successfully added to the {@link Logger}.
|
||||
* @see ch.qos.logback.classic.Logger
|
||||
* @see ch.qos.logback.core.Appender
|
||||
*/
|
||||
public static boolean addAppender(ch.qos.logback.classic.Logger logger, Appender<ILoggingEvent> appender) {
|
||||
|
||||
return Optional.ofNullable(logger)
|
||||
.filter(it -> Objects.nonNull(appender))
|
||||
.map(it -> {
|
||||
it.addAppender(appender);
|
||||
return logger.getAppender(appender.getName());
|
||||
})
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the {@link Appender} with the specified {@link String name} from the given {@link Logger}.
|
||||
*
|
||||
* @param logger {@link Logger} from which to remove the {@link Appender}.
|
||||
* @param appenderName {@link String name} of the {@link Appender} to remove from the {@link Logger}.
|
||||
* @return a boolean value indicating whether the targeted {@link Appender} was removed from
|
||||
* the given {@link Logger}.
|
||||
* @see ch.qos.logback.classic.Logger
|
||||
* @see ch.qos.logback.core.Appender
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public static boolean removeAppender(ch.qos.logback.classic.Logger logger, String appenderName) {
|
||||
|
||||
return Optional.ofNullable(logger)
|
||||
.map(it -> it.getAppender(appenderName))
|
||||
.filter(appender -> appender.getName().equals(appenderName))
|
||||
.map(appender -> { appender.stop(); return appender; })
|
||||
.map(appender -> logger.detachAppender(appender))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the {@literal console} {@link Appender} from the given {@link Logger}.
|
||||
*
|
||||
* @param logger {@link Logger} from which to remove the {@literal console} {@link Appender}.
|
||||
* @return {@literal true} if the {@literal console} {@link Appender} was registered with
|
||||
* and successfully remove from the given {@link Logger}.
|
||||
* @see #removeAppender(ch.qos.logback.classic.Logger, String)
|
||||
*/
|
||||
public static boolean removeConsoleAppender(ch.qos.logback.classic.Logger logger) {
|
||||
return removeAppender(logger, CONSOLE_APPENDER_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the {@literal delegate} {@link Appender} from the given {@link Logger}.
|
||||
*
|
||||
* @param logger {@link Logger} from which to remove the {@literal delegate} {@link Appender}.
|
||||
* @return {@literal true} if the {@literal delegate} {@link Appender} was registered with
|
||||
* and successfully remove from the given {@link Logger}.
|
||||
* @see #removeAppender(ch.qos.logback.classic.Logger, String)
|
||||
*/
|
||||
public static boolean removeDelegateAppender(ch.qos.logback.classic.Logger logger) {
|
||||
return removeAppender(logger, DELEGATE_APPENDER_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an SLF4J {@link Logger} to a Logback {@link ch.qos.logback.classic.Logger}.
|
||||
*
|
||||
* @param logger SLF4J {@link Logger} to convert.
|
||||
* @return an {@link Optional} Logback {@link ch.qos.logback.classic.Logger} for the given SLF4J {@link Logger}
|
||||
* iff the SLF4J {@link Logger} is {@literal not-null} and is a Logback {@link ch.qos.logback.classic.Logger}.
|
||||
* @see java.util.Optional
|
||||
* @see ch.qos.logback.classic.Logger
|
||||
* @see org.slf4j.Logger
|
||||
*/
|
||||
public static Optional<ch.qos.logback.classic.Logger> toLogbackLogger(Logger logger) {
|
||||
return slf4jLoggerToLogbackLoggerConverter.apply(logger);
|
||||
}
|
||||
|
||||
private static String nullSafeLoggerName(Logger logger) {
|
||||
return logger != null ? logger.getName() : null;
|
||||
}
|
||||
|
||||
private static Class<?> nullSafeType(Object obj) {
|
||||
return obj != null ? obj.getClass() : null;
|
||||
}
|
||||
|
||||
private static String nullSafeTypeName(Class<?> type) {
|
||||
return type != null ? type.getName() : null;
|
||||
}
|
||||
|
||||
private static String nullSafeTypeName(Object obj) {
|
||||
return nullSafeTypeName(nullSafeType(obj));
|
||||
}
|
||||
|
||||
private static String nullSafeTypeSimpleName(Class<?> type) {
|
||||
return type != null ? type.getSimpleName() : null;
|
||||
}
|
||||
|
||||
private static String nullSafeTypeSimpleName(Object obj) {
|
||||
return nullSafeTypeSimpleName(nullSafeType(obj));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<included>
|
||||
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="delegate" class="org.springframework.geode.logging.slf4j.logback.DelegatingAppender"/>
|
||||
|
||||
<logger name="com.gemstone.gemfire" level="${spring.boot.data.gemfire.log.level:-INFO}"/>
|
||||
<logger name="org.apache.geode" level="${spring.boot.data.gemfire.log.level:-INFO}"/>
|
||||
<logger name="org.jgroups" level="${spring.boot.data.gemfire.jgroups.log.level:-ERROR}"/>
|
||||
|
||||
</included>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration debug="false">
|
||||
|
||||
<statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
|
||||
|
||||
<include resource="logback-include.xml"/>
|
||||
|
||||
<root level="${logback.root.log.level:-INFO}">
|
||||
<appender-ref ref="console"/>
|
||||
<appender-ref ref="delegate"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport;
|
||||
import org.springframework.data.gemfire.tests.logging.slf4j.logback.TestAppender;
|
||||
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.util.ContextInitializer;
|
||||
import ch.qos.logback.core.Appender;
|
||||
|
||||
/**
|
||||
* Abstract base class for testing the spring-geode-starter-logging and spring-gemfire-starter modules.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.slf4j.Logger
|
||||
* @see org.slf4j.LoggerFactory
|
||||
* @see org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport
|
||||
* @see org.springframework.data.gemfire.tests.logging.slf4j.logback.TestAppender
|
||||
* @see ch.qos.logback.classic.Level
|
||||
* @see ch.qos.logback.classic.LoggerContext
|
||||
* @see ch.qos.logback.classic.util.ContextInitializer
|
||||
* @see ch.qos.logback.core.Appender
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public abstract class AbstractLoggingIntegrationTests extends IntegrationTestsSupport {
|
||||
|
||||
protected static final String APACHE_GEODE_LOGGER_NAME = "org.apache.geode";
|
||||
protected static final String SPRING_BOOT_DATA_GEMFIRE_LOG_LEVEL_PROPERTY = "spring.boot.data.gemfire.log.level";
|
||||
|
||||
private Logger apacheGeodeLogger = LoggerFactory.getLogger(APACHE_GEODE_LOGGER_NAME);
|
||||
|
||||
private TestAppender testAppender;
|
||||
|
||||
protected TestAppender getTestAppender() {
|
||||
|
||||
assertThat(this.testAppender).describedAs("TestAppender could not be resolved").isNotNull();
|
||||
|
||||
return this.testAppender;
|
||||
}
|
||||
|
||||
protected Level getTestLogLevel() {
|
||||
return Level.INFO;
|
||||
}
|
||||
|
||||
public void assertApacheGeodeLoggerLogLevel(Level logLevel) {
|
||||
|
||||
Optional.ofNullable(this.apacheGeodeLogger)
|
||||
.filter(ch.qos.logback.classic.Logger.class::isInstance)
|
||||
.map(ch.qos.logback.classic.Logger.class::cast)
|
||||
.map(logger -> {
|
||||
assertThat(logger.getLevel()).isEqualTo(logLevel);
|
||||
return logger;
|
||||
})
|
||||
.orElseThrow(() -> newIllegalStateException("'org.apache.geode' Logger not found"));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
configureLogging();
|
||||
configureRootLoggerDelegatingAppender();
|
||||
logMessages();
|
||||
}
|
||||
|
||||
private void configureLogging() {
|
||||
|
||||
System.setProperty(SPRING_BOOT_DATA_GEMFIRE_LOG_LEVEL_PROPERTY, getTestLogLevel().toString());
|
||||
|
||||
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
|
||||
|
||||
assertThat(loggerFactory).isInstanceOf(LoggerContext.class);
|
||||
|
||||
LoggerContext loggerContext = (LoggerContext) loggerFactory;
|
||||
|
||||
try {
|
||||
new ContextInitializer(loggerContext).autoConfig();
|
||||
}
|
||||
catch (Exception cause) {
|
||||
throw newIllegalStateException("Failed to configure and initialize SLF4J/Logback logging context", cause);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void configureRootLoggerDelegatingAppender() {
|
||||
|
||||
Logger rootLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
|
||||
assertThat(rootLogger).isInstanceOf(ch.qos.logback.classic.Logger.class);
|
||||
|
||||
ch.qos.logback.classic.Logger logbackRootLogger = (ch.qos.logback.classic.Logger) rootLogger;
|
||||
|
||||
Appender<?> delegateAppender = logbackRootLogger.getAppender("delegate");
|
||||
|
||||
assertThat(delegateAppender).isNotNull();
|
||||
assertThat(delegateAppender.getName()).isEqualTo("delegate");
|
||||
|
||||
this.testAppender = new TestAppender();
|
||||
this.testAppender.start();
|
||||
|
||||
((DelegatingAppender) delegateAppender).setAppender(this.testAppender);
|
||||
|
||||
assertThat(((DelegatingAppender) delegateAppender).getAppender()).isSameAs(this.testAppender);
|
||||
}
|
||||
|
||||
public void logMessages() {
|
||||
|
||||
assertThat(this.apacheGeodeLogger).isNotNull();
|
||||
|
||||
this.apacheGeodeLogger.debug("DEBUG TEST");
|
||||
this.apacheGeodeLogger.info("INFO TEST");
|
||||
this.apacheGeodeLogger.error("ERROR TEST");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
|
||||
Optional.ofNullable(this.testAppender).ifPresent(it -> {
|
||||
it.clear();
|
||||
it.stop();
|
||||
});
|
||||
|
||||
System.clearProperty(SPRING_BOOT_DATA_GEMFIRE_LOG_LEVEL_PROPERTY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import ch.qos.logback.core.Appender;
|
||||
import ch.qos.logback.core.Context;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link CompositeAppender}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.springframework.geode.logging.slf4j.logback.CompositeAppender
|
||||
* @see ch.qos.logback.core.Appender
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class CompositeAppenderUnitTests {
|
||||
|
||||
@Mock
|
||||
private Appender mockAppenderOne;
|
||||
|
||||
@Mock
|
||||
private Appender mockAppenderTwo;
|
||||
|
||||
@Test
|
||||
public void composeIsNullSafe() {
|
||||
assertThat(CompositeAppender.compose(null, null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeSingleAppenderReturnsTheAppender() {
|
||||
|
||||
assertThat(CompositeAppender.compose(this.mockAppenderOne, null)).isEqualTo(this.mockAppenderOne);
|
||||
assertThat(CompositeAppender.compose(null, this.mockAppenderTwo)).isEqualTo(this.mockAppenderTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeTwoAppendersReturnsCompositeAppender() {
|
||||
|
||||
Appender<?> composite = CompositeAppender.compose(this.mockAppenderOne, this.mockAppenderTwo);
|
||||
|
||||
assertThat(composite).isInstanceOf(CompositeAppender.class);
|
||||
assertThat((((CompositeAppender<?>) composite).getAppenderOne())).isEqualTo(this.mockAppenderOne);
|
||||
assertThat((((CompositeAppender<?>) composite).getAppenderTwo())).isEqualTo(this.mockAppenderTwo);
|
||||
assertThat(composite.getName()).isEqualTo(CompositeAppender.DEFAULT_NAME);
|
||||
assertThat(composite.isStarted()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeAppenderArray() {
|
||||
|
||||
Appender mockAppenderOne = mock(Appender.class);
|
||||
Appender mockAppenderTwo = mock(Appender.class);
|
||||
Appender mockAppenderThree = mock(Appender.class);
|
||||
|
||||
Appender composite = CompositeAppender.compose(mockAppenderOne, mockAppenderTwo, mockAppenderThree);
|
||||
|
||||
assertThat(composite).isInstanceOf(CompositeAppender.class);
|
||||
|
||||
Appender appenderOne = ((CompositeAppender) composite).getAppenderOne();
|
||||
Appender appenderTwo = ((CompositeAppender) composite).getAppenderTwo();
|
||||
|
||||
assertThat(appenderOne).isInstanceOf(CompositeAppender.class);
|
||||
assertThat(appenderTwo).isEqualTo(mockAppenderThree);
|
||||
assertThat(((CompositeAppender) appenderOne).getAppenderOne()).isEqualTo(mockAppenderOne);
|
||||
assertThat(((CompositeAppender) appenderOne).getAppenderTwo()).isEqualTo(mockAppenderTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeAppenderArrayWithOneAppender() {
|
||||
assertThat(CompositeAppender.compose(this.mockAppenderOne)).isSameAs(this.mockAppenderOne);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeAppenderArrayWithZeroAppenders() {
|
||||
assertThat(CompositeAppender.compose()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeAppenderArrayIsNullSafe() {
|
||||
assertThat(CompositeAppender.compose((Appender[]) null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeAppenderIterable() {
|
||||
|
||||
Appender mockAppenderOne = mock(Appender.class);
|
||||
Appender mockAppenderTwo = mock(Appender.class);
|
||||
Appender mockAppenderThree = mock(Appender.class);
|
||||
|
||||
Appender composite =
|
||||
CompositeAppender.compose(Arrays.asList(mockAppenderOne, mockAppenderTwo, mockAppenderThree));
|
||||
|
||||
assertThat(composite).isInstanceOf(CompositeAppender.class);
|
||||
|
||||
Appender appenderOne = ((CompositeAppender) composite).getAppenderOne();
|
||||
Appender appenderTwo = ((CompositeAppender) composite).getAppenderTwo();
|
||||
|
||||
assertThat(appenderOne).isInstanceOf(CompositeAppender.class);
|
||||
assertThat(appenderTwo).isEqualTo(mockAppenderThree);
|
||||
assertThat(((CompositeAppender) appenderOne).getAppenderOne()).isEqualTo(mockAppenderOne);
|
||||
assertThat(((CompositeAppender) appenderOne).getAppenderTwo()).isEqualTo(mockAppenderTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeAppenderIterableWithOneAppender() {
|
||||
assertThat(CompositeAppender.compose(Collections.singletonList(this.mockAppenderTwo)))
|
||||
.isSameAs(this.mockAppenderTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeAppenderIterableWithZeroAppenders() {
|
||||
assertThat(CompositeAppender.compose(Collections.emptyList())).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeAppenderIterableIsNullSafe() {
|
||||
assertThat(CompositeAppender.compose((Iterable<Appender<Object>>) null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setContextConfiguresContextOnCompositeAppenderAndComposedAppenders() {
|
||||
|
||||
Context mockContext = mock(Context.class);
|
||||
|
||||
Appender compositeAppender = CompositeAppender.compose(this.mockAppenderOne, this.mockAppenderTwo);
|
||||
|
||||
assertThat(compositeAppender).isInstanceOf(CompositeAppender.class);
|
||||
|
||||
compositeAppender.setContext(mockContext);
|
||||
|
||||
assertThat(compositeAppender.getContext()).isEqualTo(mockContext);
|
||||
|
||||
verify(this.mockAppenderOne, times(1)).setContext(eq(mockContext));
|
||||
verify(this.mockAppenderTwo, times(1)).setContext(eq(mockContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getContextReturnsConfiguredContext() {
|
||||
|
||||
Context mockContext = mock(Context.class);
|
||||
|
||||
Appender compositeAppender = CompositeAppender.compose(this.mockAppenderOne, this.mockAppenderTwo);
|
||||
|
||||
assertThat(compositeAppender).isInstanceOf(CompositeAppender.class);
|
||||
|
||||
compositeAppender.setContext(mockContext);
|
||||
|
||||
assertThat(compositeAppender.getContext()).isEqualTo(mockContext);
|
||||
|
||||
verify(this.mockAppenderOne, never()).getContext();
|
||||
verify(this.mockAppenderTwo, never()).getContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getContextReturnsAppenderOneContext() {
|
||||
|
||||
Context mockContext = mock(Context.class);
|
||||
|
||||
doReturn(mockContext).when(this.mockAppenderOne).getContext();
|
||||
|
||||
Appender compositeAppender = CompositeAppender.compose(this.mockAppenderOne, this.mockAppenderTwo);
|
||||
|
||||
assertThat(compositeAppender).isInstanceOf(CompositeAppender.class);
|
||||
assertThat(compositeAppender.getContext()).isEqualTo(mockContext);
|
||||
|
||||
verify(this.mockAppenderOne, times(1)).getContext();
|
||||
verify(this.mockAppenderTwo, never()).getContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getContextReturnsAppenderTwoContext() {
|
||||
|
||||
Context mockContext = mock(Context.class);
|
||||
|
||||
doReturn(mockContext).when(this.mockAppenderTwo).getContext();
|
||||
|
||||
Appender compositeAppender = CompositeAppender.compose(this.mockAppenderOne, this.mockAppenderTwo);
|
||||
|
||||
assertThat(compositeAppender).isInstanceOf(CompositeAppender.class);
|
||||
assertThat(compositeAppender.getContext()).isEqualTo(mockContext);
|
||||
|
||||
verify(this.mockAppenderOne, times(1)).getContext();
|
||||
verify(this.mockAppenderTwo, times(1)).getContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendCallsAppenderOneAppendAndAppenderTwoAppend() {
|
||||
|
||||
Appender compositeAppender = CompositeAppender.compose(this.mockAppenderOne, this.mockAppenderTwo);
|
||||
|
||||
assertThat(compositeAppender).isInstanceOf(CompositeAppender.class);
|
||||
|
||||
((CompositeAppender<Object>) compositeAppender).append("TEST");
|
||||
|
||||
verify(this.mockAppenderOne, times(1)).doAppend(eq("TEST"));
|
||||
verify(this.mockAppenderTwo, times(1)).doAppend(eq("TEST"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.gemfire.tests.logging.slf4j.logback.TestAppender;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
/**
|
||||
* Integration Tests testing the {@literal org.apache.geode} {@link org.slf4j.Logger}
|
||||
* with log level {@link Level#DEBUG}.
|
||||
*
|
||||
* <code>
|
||||
* -Dspring.boot.data.gemfire.log.level=DEBUG
|
||||
* </code>
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.data.gemfire.tests.logging.slf4j.logback.TestAppender
|
||||
* @see org.springframework.geode.logging.slf4j.logback.AbstractLoggingIntegrationTests
|
||||
* @see ch.qos.logback.classic.Level#DEBUG
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class DebugLoggingIntegrationTests extends AbstractLoggingIntegrationTests {
|
||||
|
||||
@Override
|
||||
protected Level getTestLogLevel() {
|
||||
return Level.DEBUG;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logLevelIsSetToDebug() {
|
||||
assertApacheGeodeLoggerLogLevel(Level.DEBUG);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logMessagesAtDebug() {
|
||||
|
||||
TestAppender testAppender = getTestAppender();
|
||||
|
||||
assertThat(testAppender.lastLogMessage()).isEqualTo("ERROR TEST");
|
||||
assertThat(testAppender.lastLogMessage()).isEqualTo("INFO TEST");
|
||||
assertThat(testAppender.lastLogMessage()).isEqualTo("DEBUG TEST");
|
||||
assertThat(testAppender.lastLogMessage()).isNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.qos.logback.core.Appender;
|
||||
import ch.qos.logback.core.helpers.NOPAppender;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link DelegatingAppender}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.geode.logging.slf4j.logback.DelegatingAppender
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class DelegatingAppenderUnitTests {
|
||||
|
||||
@Test
|
||||
public void delegatingAppenderDefaultsNameToDelegate() {
|
||||
assertThat(new DelegatingAppender<>().getName()).isEqualTo(DelegatingAppender.DEFAULT_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delegatingAppenderDefaultsToNoOpAppender() {
|
||||
assertThat(new DelegatingAppender<>().getAppender()).isInstanceOf(NOPAppender.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void delegatingAppenderDelegatesToMockAppender() {
|
||||
|
||||
Appender mockAppender = mock(Appender.class);
|
||||
|
||||
DelegatingAppender delegatingAppender = new DelegatingAppender<>();
|
||||
|
||||
delegatingAppender.setAppender(mockAppender);
|
||||
|
||||
assertThat(delegatingAppender.getAppender()).isSameAs(mockAppender);
|
||||
|
||||
delegatingAppender.append("TEST");
|
||||
|
||||
verify(mockAppender, times(1)).doAppend(eq("TEST"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.gemfire.tests.logging.slf4j.logback.TestAppender;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
/**
|
||||
* Integration Tests testing the {@literal org.apache.geode} {@link org.slf4j.Logger}
|
||||
* with the default log level {@link Level#INFO}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.data.gemfire.tests.logging.slf4j.logback.TestAppender
|
||||
* @see org.springframework.geode.logging.slf4j.logback.AbstractLoggingIntegrationTests
|
||||
* @see ch.qos.logback.classic.Level#INFO
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class InfoLoggingIntegrationTests extends AbstractLoggingIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void logLevelIsSetToInfo() {
|
||||
assertApacheGeodeLoggerLogLevel(Level.INFO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logsMessagesAtInfo() {
|
||||
|
||||
TestAppender testAppender = getTestAppender();
|
||||
|
||||
assertThat(testAppender.lastLogMessage()).isEqualTo("ERROR TEST");
|
||||
assertThat(testAppender.lastLogMessage()).isEqualTo("INFO TEST");
|
||||
assertThat(testAppender.lastLogMessage()).isNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.gemfire.tests.logging.slf4j.logback.TestAppender;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
|
||||
/**
|
||||
* Integration Tests testing the {@literal org.apache.geode} {@link org.slf4j.Logger}
|
||||
* with no logging enabled, i.e. {@link Level#OFF}.
|
||||
*
|
||||
* <code>
|
||||
* -Dspring.boot.data.gemfire.log.level=DEBUG
|
||||
* </code>
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.data.gemfire.tests.logging.slf4j.logback.TestAppender
|
||||
* @see org.springframework.geode.logging.slf4j.logback.AbstractLoggingIntegrationTests
|
||||
* @see ch.qos.logback.classic.Level#OFF
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class NoLoggingIntegrationTests extends AbstractLoggingIntegrationTests {
|
||||
|
||||
@Override
|
||||
protected Level getTestLogLevel() {
|
||||
return Level.OFF;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logLevelIsSetToOff() {
|
||||
assertApacheGeodeLoggerLogLevel(Level.OFF);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void logsNoMessages() {
|
||||
|
||||
TestAppender testAppender = getTestAppender();
|
||||
|
||||
assertThat(testAppender.lastLogMessage()).isNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright 2017-present the original author or authors.
|
||||
*
|
||||
* 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 org.springframework.geode.logging.slf4j.logback;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
import ch.qos.logback.core.Context;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link StringAppender}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.springframework.geode.logging.slf4j.logback.StringAppender
|
||||
* @see ch.qos.logback.classic.Logger
|
||||
* @see ch.qos.logback.core.Appender
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public class StringAppenderUnitTests {
|
||||
|
||||
@Mock
|
||||
private StringAppender.StringAppenderWrapper mockWrapper;
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).detachAndStopAllAppenders();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildStringAppender() {
|
||||
|
||||
StringAppender stringAppender = new StringAppender.Builder().build();
|
||||
|
||||
assertThat(stringAppender).isNotNull();
|
||||
assertThat(stringAppender.isStarted()).isFalse();
|
||||
assertThat(stringAppender.getContext()).isEqualTo(LoggerFactory.getILoggerFactory());
|
||||
assertThat(stringAppender.getName()).isEqualTo(StringAppender.DEFAULT_NAME);
|
||||
assertThat(stringAppender.getStringAppenderWrapper())
|
||||
.isInstanceOf(StringAppender.StringBuilderAppenderWrapper.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildStringAppenderApplyToDelegateUsingReplace() {
|
||||
|
||||
DelegatingAppender delegate = spy(new DelegatingAppender());
|
||||
|
||||
StringAppender stringAppender = new StringAppender.Builder()
|
||||
.applyTo(delegate, true)
|
||||
.build();
|
||||
|
||||
assertThat(stringAppender).isNotNull();
|
||||
assertThat(stringAppender.isStarted()).isFalse();
|
||||
assertThat(stringAppender.getName()).isEqualTo(StringAppender.DEFAULT_NAME);
|
||||
|
||||
verify(delegate, times(1)).setAppender(eq(stringAppender));
|
||||
|
||||
assertThat(delegate.getAppender()).isEqualTo(stringAppender);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildAndStartStringAppender() {
|
||||
|
||||
Context mockContext = mock(Context.class);
|
||||
|
||||
DelegatingAppender delegate = spy(new DelegatingAppender());
|
||||
|
||||
Logger rootLogger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||
|
||||
StringAppender stringAppender = new StringAppender.Builder()
|
||||
.applyTo(delegate)
|
||||
.applyTo(rootLogger)
|
||||
.setContext(mockContext)
|
||||
.setName("TestStringAppender")
|
||||
.useSynchronization()
|
||||
.buildAndStart();
|
||||
|
||||
assertThat(stringAppender).isNotNull();
|
||||
assertThat(stringAppender.isStarted()).isTrue();
|
||||
assertThat(stringAppender.getContext()).isEqualTo(mockContext);
|
||||
assertThat(stringAppender.getName()).isEqualTo("TestStringAppender");
|
||||
assertThat(stringAppender.getStringAppenderWrapper())
|
||||
.isInstanceOf(StringAppender.StringBufferAppenderWrapper.class);
|
||||
assertThat(rootLogger.getAppender("TestStringAppender")).isEqualTo(stringAppender);
|
||||
|
||||
verify(delegate, times(1)).setAppender(isA(CompositeAppender.class));
|
||||
|
||||
Appender compositeAppender = delegate.getAppender();
|
||||
|
||||
assertThat(compositeAppender).isInstanceOf(CompositeAppender.class);
|
||||
assertThat(((CompositeAppender) compositeAppender).getAppenderOne()).isEqualTo(DelegatingAppender.DEFAULT_APPENDER);
|
||||
assertThat(((CompositeAppender) compositeAppender).getAppenderTwo()).isEqualTo(stringAppender);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructStringAppender() {
|
||||
|
||||
StringAppender.StringAppenderWrapper mockWrapper = mock(StringAppender.StringAppenderWrapper.class);
|
||||
|
||||
StringAppender appender = new StringAppender(mockWrapper);
|
||||
|
||||
assertThat(appender).isNotNull();
|
||||
assertThat(appender.getStringAppenderWrapper()).isEqualTo(mockWrapper);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructStringAppenderWithNullWrapper() {
|
||||
|
||||
try {
|
||||
new StringAppender(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("StringAppenderWrapper must not be null");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendCallsConfiguredStringAppenderWrapper() {
|
||||
|
||||
ILoggingEvent mockEvent = mock(ILoggingEvent.class);
|
||||
|
||||
StringAppender appender = spy(new StringAppender(this.mockWrapper));
|
||||
|
||||
doReturn(this.mockWrapper).when(appender).getStringAppenderWrapper();
|
||||
doReturn("TEST").when(appender).toString(eq(mockEvent));
|
||||
|
||||
appender.append(mockEvent);
|
||||
|
||||
verify(this.mockWrapper, times(1)).append(eq("TEST"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendIgnoresBlankEmptyAndNullStrings() {
|
||||
|
||||
ILoggingEvent mockEvent = mock(ILoggingEvent.class);
|
||||
|
||||
StringAppender appender = spy(new StringAppender(this.mockWrapper));
|
||||
|
||||
doReturn(this.mockWrapper).when(appender).getStringAppenderWrapper();
|
||||
doReturn(" ").doReturn("").doReturn(null)
|
||||
.when(appender).toString(eq(mockEvent));
|
||||
|
||||
appender.append(mockEvent);
|
||||
appender.append(mockEvent);
|
||||
appender.append(mockEvent);
|
||||
|
||||
verify(appender, times(3)).toString(eq(mockEvent));
|
||||
verify(appender, times(1)).preProcessLogMessage(eq(" "));
|
||||
verify(appender, times(1)).preProcessLogMessage(eq(""));
|
||||
verify(appender, times(1)).preProcessLogMessage(eq(null));
|
||||
verify(this.mockWrapper, never()).append(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void appendIsNullSafe() {
|
||||
|
||||
StringAppender appender = spy(new StringAppender(this.mockWrapper));
|
||||
|
||||
doReturn(this.mockWrapper).when(appender).getStringAppenderWrapper();
|
||||
|
||||
appender.append(null);
|
||||
|
||||
verify(appender, never()).toString(any(ILoggingEvent.class));
|
||||
verify(this.mockWrapper, never()).append(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyStringIsNotValidLogMessage() {
|
||||
|
||||
StringAppender appender = new StringAppender(this.mockWrapper);
|
||||
|
||||
assertThat(appender.isValidLogMessage("")).isFalse();
|
||||
assertThat(appender.isValidLogMessage(null)).isFalse(); }
|
||||
|
||||
@Test
|
||||
public void nonEmptyStringIsValidLogMessage() {
|
||||
|
||||
StringAppender appender = new StringAppender(this.mockWrapper);
|
||||
|
||||
assertThat(appender.isValidLogMessage("TEST")).isTrue();
|
||||
assertThat(appender.isValidLogMessage("_")).isTrue();
|
||||
assertThat(appender.isValidLogMessage(" ")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preProcessLogMessageIsNullSafe() {
|
||||
assertThat(new StringAppender(this.mockWrapper).preProcessLogMessage(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preProcessLogMessageTrimsMessage() {
|
||||
|
||||
StringAppender appender = new StringAppender(this.mockWrapper);
|
||||
|
||||
assertThat(appender.preProcessLogMessage("TEST")).isEqualTo("TEST");
|
||||
assertThat(appender.preProcessLogMessage(" MOCK ")).isEqualTo("MOCK");
|
||||
assertThat(appender.preProcessLogMessage("J UNK ")).isEqualTo("J UNK");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringCallsLoggingEventFormattedMessage() {
|
||||
|
||||
ILoggingEvent mockEvent = mock(ILoggingEvent.class);
|
||||
|
||||
when(mockEvent.getFormattedMessage()).thenReturn("TEST");
|
||||
|
||||
assertThat(new StringAppender(this.mockWrapper).toString(mockEvent)).isEqualTo("TEST");
|
||||
|
||||
verify(mockEvent, times(1)).getFormattedMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringIsNullSafe() {
|
||||
assertThat(new StringAppender(this.mockWrapper).toString(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getLogOutputCallsStringAppenderWrapperToString() {
|
||||
|
||||
doReturn("TEST").when(this.mockWrapper).toString();
|
||||
|
||||
assertThat(new StringAppender(this.mockWrapper).getLogOutput()).isEqualTo("TEST");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration debug="false">
|
||||
|
||||
<include resource="logback-include.xml"/>
|
||||
|
||||
<root level="${logback.root.log.level:-ERROR}">
|
||||
<appender-ref ref="delegate"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user