Apache Geode 1.9.2
was modularized to separate its use of the Apache Log4j API to log output in Geode code from
the underlying implementation of logging, which uses Apache Log4j as the logging provider by default.
Prior to 1.9.2
, the Apache Log4j API (i.e. log4j-api
) along with the Apache Log4j provider (i.e. log4j-core
)
were automatically pulled in by Apache Geode core (i.e. org.apache.geode:geode-core
) thereby making it problematic
to change logging providers when using Apache Geode in Spring Boot applications.
However, now, in order to get any log output from Apache Geode whatsoever, Apache Geode requires a logging provider on
your Spring Boot application classpath. Consequently, this also means the old Apache Geode Properties
,
e.g. log-level
no longer have any effect, regardless of whether the property (e.g. log-level
) is specified in
gemfire.properties
, in Spring Boot application.properties
or even as a JVM System Property, -Dgemfire.log-level
.
![]() | Tip |
---|---|
Refer to Apache Geode’s Documentation
for a complete list of valid |
Unfortunately, this also means the Spring Data for Apache Geode & Pivotal GemFire (SDG)
@EnableLogging
annotation no longer has any effect on Apache Geode or Pivotal GemFire logging either and is the reason it has been
deprecated. The reason @EnableLogging
no longer has any effect on
logging is because this annotation’s attributes and associated SDG properties indirectly sets the corresponding
Apache Geode or Pivotal GemFire properties, which again, are useless from Apache Geode 1.9.2
onward.
By way of example, and to make this concrete, none of the following approaches have any effect on Apache Geode or Pivotal GemFire logging:
Command-line configuration.
$ java -classpath ...:/path/to/MySpringBootApacheGeodeClientCacheApplication.jar -Dgemfire.log-level=DEBUG example.app.MySpringBootApacheGeodeClientCacheApplication
Externalized configuration using Apache Geode gemfire.properties
.
# Apache Geode/Pivotal GemFire only/specific properties log-level=INFO
Externalized configuration using Spring Boot application.properties
.
spring.data.gemfire.cache.log-level=DEBUG
Or:
spring.data.gemfire.logging.level=DEBUG
Java configuration using SDG’s @EnableLogging
annotation.
@SpringBootApplication @EnableLogging(logLevel = "DEBUG") class MySpringBootApacheGeodeClientApplication { // ... }
That is to say, none of the approaches above have any effect without the new SBDG logging starter.
So, how do you configure logging for Apache Geode and Pivotal GemFire?
Effectively, 3 things are required to get Apache Geode or Pivotal GemFire to log output:
1) First, you must declare a logging provider on your Spring Boot application classpath (e.g. Logback).
2) (optional) Next, you must declare an adapter, or 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 along with Logback as your
logging provider/implementation, then you must include the org.apache.logging.log4j.log4j-to-slf4j
adapter/bridge JAR
dependency as well.
Internally, Apache Geode uses the Apache Log4j API to log output from Geode components. Therefore, you must bridge Log4j
to any other logging provider (e.g. Logback) that is not Log4j (i.e. log4j-core
). If you are using Log4j as your
logging provider then you do not need to declare an adapter/bridge JAR on your Spring Boot application classpath.
3) Finally, you must supply logging provider configuration to configure Loggers, Appenders, log levels, etc.
For example, when using 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
Apache Geode to log output.
![]() | Note |
---|---|
Apache Geode’s |
If you declare Spring Boot’s own org.springframework.boot:spring-boot-starter-logging
on your application classpath
then this will cover Steps 1 and 2 above.
The spring-boot-starter-logging
dependency declares Logback as the logging provider and automatically adapts,
or 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 also for Apache Geode as well.
SBDG has simplified the setup of Apache Geode and Pivotal GemFire logging. Simply declare the
org.springframework.geode:spring-geode-starter-logging
dependency on your Spring Boot application classpath!
Unlike Apache Geode’s default Log4j XML configuration file (i.e. log4j2.xml
), SBDG’s provided logback.xml
configuration file is properly parameterized enabling you to adjust log levels as well as add Appenders.
In addition, SBDG’s provided Logback configuration uses templates so you can compose your own logging configuration while still "including" snippets from SBDG’s provided logging configuration metadata, such as Loggers and Appenders.
One of the most common logging tasks is to adjust the log-level of one or more Loggers, or the ROOT Logger. However, a user may only want to adjust the log-level for specific components of his/her Spring Boot application, such as for Apache Geode, by setting the log-level for only the Logger that logs Apache Geode events.
SBDG’s Logback configuration defines 3 Loggers to control the log output from Apache Geode:
Apache Geode Loggers by name.
<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}"/>
The com.gemstone.gemfire
Logger is a legacy Logger covering old Pivotal GemFire bits still present in Apache Geode
for backwards compatibility reasons. This Logger’s use should be largely unnecessary.
The org.apache.geode
Logger is the primary Logger used to control log output from all Apache Geode components
during the runtime operation of Apache Geode. Both this Logger and the legacy com.gemstone.gemfire
Logger default
log output to INFO
.
The org.jgroups
Logger is used to log output from Apache Geode’s message distribution and membership system.
Apache Geode uses JGroups for membership and message distribution between peer members (nodes) in the cluster
(distributed system). By default, JGroups log messages are logged at ERROR
.
The log-level for the com.gemstone.gemfire
and org.apache.geode
Loggers are configured with the
spring.boot.data.gemfire.log.level
property. The org.jgroups
Logger is independently configured with the
spring.boot.data.gemfire.jgroups.log.level
property.
The SBDG logging properties can be set on the command-line as JVM System Properties when running your Spring Boot application:
Setting the log-level from the command-line.
$ java -classpath ...:/path/to/MySpringBootApplication.jar -Dspring.boot.data.gemfire.log.level=DEBUG package.to.MySpringBootApplicationClass
![]() | Note |
---|---|
Setting JVM System Properties using |
Alternatively, you can configure and control Apache Geode logging in Spring Boot application.properties
:
Setting the log-level in application.properties
.
spring.boot.data.gemfire.log.level=DEBUG
For backwards compatibility, SBDG additionally supports the old Spring Data for Apache Geode (SDG) logging properties as well, using either:
spring.data.gemfire.cache.log-level=DEBUG
Or:
spring.data.gemfire.logging.level=DEBUG
If you previously used either of these SDG based logging properties, they will continue to work as designed in
SBDG 1.3
or later.
As mentioned earlier, SBDG allows you to compose your own logging configuration from SBDG’s default, provided Logback configuration metadata.
SBDG conveniently bundles the Loggers and Appenders from SBDG’s logging starter into a template file that you can include into your own, custom Logback XML configuration file.
The Logback template file appears as follows:
logback-include.xml.
<?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>
Then, this Logback configuration snippet can be included in an application-specific, Logback XML configuration file as follows:
logback.xml.
<?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>
SBDG provides additional support when working with the SLF4J and Logback APIs. This support is available when you
declare the org.springframework.geode:spring-geode-starter-logging
dependency on your Spring Boot application
classpath.
One of the main supporting classes from the spring-geode-starter-logger
is the org.springframework.geode.logging.slf4j.logback.LogbackSupport
class. This class provides methods to:
LoggingContext
Logger
as a Logback Logger
Appenders
by name and required type
Appenders
to Loggers
LogbackSupport
can even suppress the auto-configuration of Logback performed by Spring Boot on startup,
another useful utility during automated testing.
In addition to the LogbackSupport
class, SBDG also provides some custom Logback Appenders
.
The org.springframework.geode.logging.slf4j.logback.CompositeAppender
class is an implementation of Logback
Appender
and the Composite Software Design Pattern.
CompositeAppender
enables developers to 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 using:
Composing multiple Appenders
.
ConsoleAppender<ILoggingEvent> consoleAppender = ...;
FileAppender<ILoggingEvent> fileAppender = ...;
Appender<ILoggingEvent> compositeAppender = CompositeAppender.compose(consoleAppender, fileAppender);
// do something with the compositeAppender
You could then add the CompositeAppender
to a "named" Logger
by doing:
Register CompositeAppender
on "named" Logger
.
Logger namedLogger = LoggerFactory.getLogger("loggerName");
LogbackSupport.toLogbackLogger(namedLogger)
.ifPresent(it -> LogbackSupport.addAppender(it, compositeAppender));
In this case, the "named" Logger
will log events (or log messages) to both the Console and File Appenders
.
It is simple to compose an array or Iterable
of Appenders
by using either the
CompositeAppender.compose(:Appender<T>[])
method or the CompositeAppender.compose(:Iterable<Appender<T>>)
method.
The org.springframework.geode.logging.slf4j.logback.DelegatingAppender
is a pass-through Logback Appender
implementation wrapping another Logback Appender
, or collection of Appenders
doing actual work, like the
ConsoleAppender
, a FileAppender
or a SocketAppender
, etc. By default, the DelegatingAppender
delegates
to the NOPAppender
thereby doing no actual work.
By default, SBDG registers the org.springframework.geode.logging.slfj4.logback.DelegatingAppender
with
the ROOT Logger
, which can be useful for testing purposes.
With a reference to a DelegatingAppender
, you can add any Appender
as the delegate, even a CompositeAppender
:
Add ConsoleAppender
as the "delegate" for the DelegatingAppender
.
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));
The org.springframework.geode.logging.slf4j.logback.StringAppender
stores log message in-memory, appended to
a String
.
The StringAppender
is very 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.
For 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 it can be used safely in a multi-Threaded context by calling
StringAppender.Builder.useSynchronization()
.
When combined with other SBDG provided Appenders
in conjunction with the LogbackSupport
class, you have a lot of
power both in application code as well as your tests.