This topic explains how to configure Spring Boot for VMware Tanzu GemFire logging.
To obtain log output from VMware GemFire, VMware GemFire requires a logging provider declared on your Spring Boot application classpath. Consequently, this also means the old VMware GemFire Properties
(such as log-level
) no longer have any effect, regardless of whether the property is specified in gemfire.properties
, in Spring Boot application.properties
, or even as a JVM System Property (-Dgemfire.log-level
).
Tip: See VMware GemFire’s documentation for a complete list of valid
Properties
, including the properties used to configure logging.
Configure VMware GemFire Logging
Three things are required to get VMware GemFire to log output:
-
You must declare a logging provider (such as Logback, or Log4j) on your Spring Boot application classpath.
-
(optional) You can declare an adapter (a bridge JAR) between Log4j and your logging provider if your declared logging provider is not Apache Log4j.
For example, if you use the SLF4J API to log output from your Spring Boot application and use Logback as your logging provider or implementation, you must include the
org.apache.logging.log4j.log4j-to-slf4j
adapter or bridge JAR as well.Internally, VMware GemFire uses the Apache Log4j API to log output from GemFire components. Therefore, you must bridge Log4j to any other logging provider (such as Logback) that is not Log4j (
log4j-core
). If you use Log4j as your logging provider, you need not declare an adapter or bridge JAR on your Spring Boot application classpath. -
Finally, you must supply logging provider configuration to configure Loggers, Appenders, log levels, and other details.
For example, when you use Logback, you must provide a
logback.xml
configuration file on your Spring Boot application classpath or in the filesystem. Alternatively, you can use other means to configure your logging provider and get VMware GemFire to log output.
If you declare Spring Boot’s own org.springframework.boot:spring-boot-starter-logging
on your application classpath, it covers steps 1 and 2 above.
The spring-boot-starter-logging
dependency declares Logback as the logging provider and automatically adapts (bridges) java.util.logging
(JUL) and Apache Log4j to SLF4J. However, you still need to supply logging provider configuration (such as a logback.xml
file for Logback) to configure logging not only for your Spring Boot application but for VMware GemFire as well.
Note: If no user-specified logging configuration is supplied, Logback will apply default configuration using the
BasicConfigurator
. See Logbackfor complete details.
Spring Boot for Tanzu GemFire has simplified the setup of VMware GemFire logging. You need only declare the com.vmware.gemfire:spring-boot-logging...
dependency on your Spring Boot application classpath.
Unlike VMware GemFire’s default Log4j XML configuration file (log4j2.xml
from geode-log4j
), Spring Boot for Tanzu GemFire’s provided logback.xml
configuration file is properly parameterized, letting you adjust log levels, add Appenders as well as adjust other logging settings.
In addition, Spring Boot for Tanzu GemFire’s provided Logback configuration uses templates so that you can compose your own logging configuration while still including snippets from Spring Boot for Tanzu GemFire’s provided logging configuration, such as Loggers and Appenders.
Configuring Log Levels
One of the most common logging tasks is to adjust the log level of one or more Loggers or the ROOT Logger. However, you may want to only adjust the log level for specific components of your Spring Boot application, such as for VMware GemFire, by setting the log level for only the Logger that logs VMware GemFire events.
Spring Boot for Tanzu GemFire’s Logback configuration defines three Loggers to control the log output from VMware GemFire:
Example VMware GemFire Loggers by Name
<comfiguration>
<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:-WARN}"/>
</comfiguration>
The com.gemstone.gemfire
Logger covers old GemFire components that are still present in VMware GemFire for backwards compatibility. By default, it logs output at INFO
. This Logger’s use should be mostly unnecessary.
The org.apache.geode
Logger is the primary Logger used to control log output from all VMware GemFire components during the runtime operation of VMware GemFire. By default, it logs output at INFO
.
The org.jgroups
Logger is used to log output from VMware GemFire’s message distribution and membership system. VMware GemFire uses JGroups for membership and message distribution between peer members (nodes) in the cluster (distributed system). By default, JGroups logs output at WARN
.
You can configure the log level for the com.gemstone.gemfire
and org.apache.geode
Loggers by setting the spring.boot.data.gemfire.log.level
property. You can independently configure the org.jgroups
Logger by setting the spring.boot.data.gemfire.jgroups.log.level
property.
You can set the Spring Boot for Tanzu GemFire logging properties on the command line as JVM System properties when you run your Spring Boot application:
Example - Setting the log-level from the CLI
$ java -classpath ...:/path/to/MySpringBootApplication.jar -Dspring.boot.data.gemfire.log.level=DEBUG
package.to.MySpringBootApplicationClass
Note: Setting JVM System properties by using
$ java -jar MySpringBootApplication.jar -Dspring.boot.data.gemfire.log.level=DEBUG
is not supported by the Java Runtime Environment (JRE).
Alternatively, you can configure and control VMware GemFire logging in Spring Boot application.properties
:
Example - Setting the log-level in Spring Boot application.properties
spring.boot.data.gemfire.log.level=DEBUG
For backwards compatibility, Spring Boot for Tanzu GemFire additionally supports the Spring Data for VMware GemFire logging properties as well, by using either of the following properties:
Example - Setting log-level using Spring Data for VMware GemFire Properties
spring.data.gemfire.cache.log-level=DEBUG
spring.data.gemfire.logging.level=DEBUG
Composing Logging Configuration
As mentioned earlier, Spring Boot for Tanzu GemFire lets you compose your own logging configuration from Spring Boot for Tanzu GemFire’s default Logback configuration metadata.
Spring Boot for Tanzu GemFire conveniently bundles the Properties, Loggers and Appenders from Spring Boot for Tanzu GemFire’s logging starter into several template files that you can include into your own custom Logback XML configuration file.
The Logback configuration template files are broken down into:
-
org/springframework/geode/logging/slf4j/logback/properties-include.xml
-
org/springframework/geode/logging/slf4j/logback/loggers-include.xml
-
org/springframework/geode/logging/slf4j/logback/appenders-include.xml
Warning: As of Spring Boot for Tanzu GemFire 3.0,the logback-include.xml file was removed.
The properties-include.xml
defines Logback “local” scoped properties or variables common to Spring Boot for Tanzu GemFire’s configuration of VMware GemFire logging.
Example - properties-include.xml
<?xml version="1.0" encoding="UTF-8"?>
<included>
<property name="SPRING_BOOT_LOG_CHARSET" value="${SPRING_BOOT_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
<property name="SPRING_BOOT_LOG_PATTERN" value="${SPRING_BOOT_LOG_PATTERN:-%d %5p %40.40c:%4L - %msg%n}"/>
<property name="APACHE_GEODE_LOG_CHARSET" value="${APACHE_GEODE_LOG_CHARSET:-${file.encoding:-UTF-8}}"/>
<property name="APACHE_GEODE_LOG_PATTERN" value="${APACHE_GEODE_LOG_PATTERN:-[%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread>] %message%n%throwable%n}"/>
</included>
The loggers-include.xml
file defines the Loggers
used to log output from VMware GemFire components.
Example - loggers-include.xml
<?xml version="1.0" encoding="UTF-8"?>
<included>
<logger name="com.gemstone.gemfire" level="${spring.boot.data.gemfire.log.level:-INFO}" additivity="false">
<appender-ref ref="${spring.geode.logging.appender-ref:-CONSOLE}"/>
<appender-ref ref="delegate"/>
</logger>
<logger name="org.apache.geode" level="${spring.boot.data.gemfire.log.level:-INFO}" additivity="false">
<appender-ref ref="${spring.geode.logging.appender-ref:-CONSOLE}"/>
<appender-ref ref="delegate"/>
</logger>
<logger name="org.jgroups" level="${spring.boot.data.gemfire.jgroups.log.level:-WARN}" additivity="false">
<appender-ref ref="${spring.geode.logging.appender-ref:-CONSOLE}"/>
<appender-ref ref="delegate"/>
</logger>
</included>
The appenders-include.xml
file defines Appenders to send the log output to. If Spring Boot is on the application classpath, then Spring Boot logging configuration will define the “CONSOLE” Appender
, otherwise, Spring Boot for Tanzu GemFire will provide a default definition.
The “geode” Appender
defines the VMware GemFire logging pattern as seen in VMware GemFire’s Log4j configuration.
Example - appenders-include.xml
<?xml version="1.0" encoding="UTF-8"?>
<included>
<if condition='property("bootPresent").equals("false")'>
<then>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>${SPRING_BOOT_LOG_CHARSET}</charset>
<pattern>${SPRING_BOOT_LOG_PATTERN}</pattern>
</encoder>
</appender>
</then>
</if>
<appender name="delegate" class="org.springframework.geode.logging.slf4j.logback.DelegatingAppender"/>
<appender name="geode" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>${APACHE_GEODE_LOG_CHARSET}</charset>
<pattern>${APACHE_GEODE_LOG_PATTERN}</pattern>
</encoder>
</appender>
</included>
Then you can include any of Spring Boot for Tanzu GemFire’S Logback configuration metadata files as needed in your application-specific Logback XML configuration file, as follows:
Example - application-specific logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/geode/logging/slf4j/logback/properties-include.xml"/>
<include resource="org/springframework/geode/logging/slf4j/logback/appender-include.xml"/>
<logger name="org.apache.geode" level="INFO" additivity="false">
<appender-ref ref="geode"/>
</logger>
<root level="${logback.root.log.level:-INFO}">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="delegate"/>
</root>
</configuration>
Customizing Logging Configuration
It is now possible to customize the configuration of VMware GemFire logging using properties defined in a spring-geode-logging.properties
file included on the Spring Boot application classpath.
Any of the properties defined in org/springframework/geode/logging/slf4j/logback/properties-include.xml
(shown above), such as APACHE_GEODE_LOG_PATTERN
, or the spring.geode.logging.appender-ref
property, can be set.
For instance, and by default, VMware GemFire components log output using the Spring Boot log pattern. However, if you prefer the fine-grained details of VMware GemFire’s logging behavior, you can change the Appender
used by the VMware GemFire Logger's
to use the pre-defined “geode” Appender
instead. Simply set the spring-geode.logging.appender-ref
property to “geode” in a spring-geode-logging.properties
file on your Spring Boot application classpath, as follows:
Example - spring-geode-logging.properties
# spring-geode-logging.properties
spring.geode.logging.appender-ref=geode
Alternatively, if you want to configure the log output of your entire Spring Boot application, including log output from all VMware GemFire components, then you can set the SPRING_BOOT_LOG_PATTERN
property, or Spring Boot’s CONSOLE_LOG_PATTERN
property, in spring-geode-logging.properties
, as follows:
Example - spring-geode-logging.properties
# spring-geode-logging.properties
CONSOLE_LOG_PATTERN=TEST - %msg%n
Note: The
spring-geode-logging.properties
file is only recognized when thespring-boot-logging...
module is used.
SLF4J and Logback API Support
Spring Boot for Tanzu GemFire provides additional support when working with the SLF4J and Logback APIs. This support is available when you declare the com.vmware.boot:spring-boot-logging...
dependency on your Spring Boot application classpath.
One of the main supporting classes from the spring-boot-logging...
is the org.springframework.geode.logging.slf4j.logback.LogbackSupport
class. This class provides methods to:
-
Resolve a reference to the Logback
LoggingContext
. -
Resolve the SLF4J ROOT
Logger
as a LogbackLogger
. -
Look up
Appenders
by name and required type. -
Add or remove
Appenders
toLoggers
. -
Reset the state of the Logback logging system, which can prove to be most useful during testing.
LogbackSupport
can even suppress the auto-configuration of Logback performed by Spring Boot on startup, which is another useful utility during automated testing.
In addition to the LogbackSupport
class, Spring Boot for Tanzu GemFire also provides some custom Logback Appenders
.
CompositeAppender
The org.springframework.geode.logging.slf4j.logback.CompositeAppender
class is an implementation of the Logback Appender
interface and the Composite software design pattern.
CompositeAppender
lets developers compose multiple Appenders and use them as if they were a single Appender
.
For example, you could compose both the Logback ConsoleAppender
and FileAppender
into one Appender
:
Example - Composing multiple Appenders
class LoggingConfiguration {
Appender<ILoggingEvent> compositeAppender() {
ConsoleAppender<ILoggingEvent> consoleAppender = new ConsoleAppender<>();
FileAppender<ILoggingEvent> fileAppender = new FileAppender<>();
Appender<ILoggingEvent> compositeAppender = CompositeAppender.compose(consoleAppender, fileAppender);
return compositeAppender;
}
}
// do something with the compositeAppender
You could then add the CompositeAppender
to a named Logger
:
Example - Register CompositeAppender
on “named” Logger
void registerAppenderOnLogger() {
Logger namedLogger = LoggerFactory.getLogger("loggerName");
LogbackSupport.toLogbackLogger(namedLogger)
.ifPresent(it -> LogbackSupport.addAppender(it, compositeAppender()));
}
In this case, the named Logger
logs events (or log messages) to both the console and file Appenders.
You can compose an array or Iterable
of Appenders
by using either the CompositeAppender.compose(:Appender<T>[])
method or the CompositeAppender.compose(:Iterable<Appender<T>>)
method.
DelegatingAppender
The org.springframework.geode.logging.slf4j.logback.DelegatingAppender
is a pass-through Logback Appender
implementation that wraps another Logback Appender
or collection of Appenders
, such as the ConsoleAppender
, a FileAppender
, a SocketAppender
, or others. By default, the DelegatingAppender
delegates to the NOPAppender
, thereby doing no actual work.
By default, Spring Boot for Tanzu GemFire registers the org.springframework.geode.logging.slf4j.logback.DelegatingAppender
with the ROOT Logger
, which can be useful for testing purposes.
With a reference to a DelegatingAppender
, you can add any Appender
(even a CompositeAppender
) as the delegate:
Example - Add ConsoleAppender
as the “delegate” for the DelegatingAppender
class LoggerConfiguration {
void setupDelegation() {
ConsoleAppender consoleAppender = new ConsoleAppender();
LogbackSupport.resolveLoggerContext().ifPresent(consoleAppender::setContext);
consoleAppender.setImmediateFlush(true);
consoleAppender.start();
LogbackSupport.resolveRootLogger()
.flatMap(LogbackSupport::toLogbackLogger)
.flatMap(rootLogger -> LogbackSupport.resolveAppender(rootLogger,
LogbackSupport.DELEGATE_APPENDER_NAME, DelegatingAppender.class))
.ifPresent(delegateAppender -> delegateAppender.setAppender(consoleAppender));
}
}
StringAppender
The org.springframework.geode.logging.slf4j.logback.StringAppender
stores a log message in-memory, appended to a String
.
The StringAppender
is useful for testing purposes. For instance, you can use the StringAppender
to assert that a Logger
used by certain application components logged messages at the appropriately configured log level while other log messages were not logged.
Consider the following example:
Example - StringAppender
in Action
class ApplicationComponent {
private final Logger logger = LoggerFactory.getLogger(getClass());
public void someMethod() {
logger.debug("Some debug message");
// ...
}
public void someOtherMethod() {
logger.info("Some info message");
}
}
// Assuming the ApplicationComponent Logger was configured with log-level 'INFO', then...
class ApplicationComponentUnitTests {
private final ApplicationComponent applicationComponent = new ApplicationComponent();
private final Logger logger = LoggerFactory.getLogger(ApplicationComponent.class);
private StringAppender stringAppender;
@Before
public void setup() {
LogbackSupport.toLogbackLogger(logger)
.map(Logger::getLevel)
.ifPresent(level -> assertThat(level).isEqualTo(Level.INFO));
stringAppender = new StringAppender.Builder()
.applyTo(logger)
.build();
}
@Test
public void someMethodDoesNotLogDebugMessage() {
applicationComponent.someMethod();
assertThat(stringAppender.getLogOutput).doesNotContain("Some debug message");
}
@Test
public void someOtherMethodLogsInfoMessage() {
applicationComponent.someOtherMethod();
assertThat(stringAppender.getLogOutput()).contains("Some info message");
}
}
There are many other uses for the StringAppender
and you can use it safely in a multi-Threaded context by calling StringAppender.Builder.useSynchronization()
.
When combined with other Spring Boot for Tanzu GemFire provided Appenders
in conjunction with the LogbackSupport
class, you have a lot of power both in application code as well as in your tests.
Content feedback and comments