Add documentation in the reference guide on the new spring-geode-starter-logging module.
Resolves gh-71.
This commit is contained in:
@@ -46,7 +46,10 @@ asciidoctor {
|
||||
'docs-src-dir' : rootProject.projectDir.path + '/spring-geode-docs/src/main/java',
|
||||
'docs-resources-dir' : rootProject.projectDir.path + '/spring-geode-docs/src/main/resources',
|
||||
'examples-dir' : rootProject.projectDir.path + '/spring-geode-examples',
|
||||
'samples-dir' : rootProject.projectDir.path + '/spring-geode-samples'
|
||||
'samples-dir' : rootProject.projectDir.path + '/spring-geode-samples',
|
||||
'starter-logging-dir' : rootProject.projectDir.path + '/spring-geode-starter-logging',
|
||||
'starter-logging-src-dir' : rootProject.projectDir.path + '/spring-geode-starter-logging/src/main/src',
|
||||
'starter-logging-resources-dir' : rootProject.projectDir.path + '/spring-geode-starter-logging/src/main/resources'
|
||||
}
|
||||
|
||||
javadoc {
|
||||
|
||||
@@ -235,6 +235,7 @@ include::functions.adoc[]
|
||||
include::continuous-query.adoc[]
|
||||
include::data-serialization.adoc[]
|
||||
include::security.adoc[]
|
||||
include::logging.adoc[]
|
||||
include::actuator.adoc[]
|
||||
include::session.adoc[]
|
||||
include::cloudfoundry.adoc[]
|
||||
|
||||
368
spring-geode-docs/src/docs/asciidoc/logging.adoc
Normal file
368
spring-geode-docs/src/docs/asciidoc/logging.adoc
Normal file
@@ -0,0 +1,368 @@
|
||||
[[geode-logging]]
|
||||
== Logging
|
||||
|
||||
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 {apache-geode-docs}/reference/topics/gemfire_properties.html[Documentation]
|
||||
for a complete list of valid `Properties`, including the `Properties` used to configure logging.
|
||||
|
||||
Unfortunately, this also means the _Spring Data for Apache Geode & Pivotal GemFire_ (SDG)
|
||||
{spring-data-geode-javadoc}/org/springframework/data/gemfire/config/annotation/EnableLogging.html[`@EnableLogging`]
|
||||
annotation no longer has any effect on Apache Geode or Pivotal GemFire logging either and is the reason it has been
|
||||
https://jira.spring.io/browse/DATAGEODE-299[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
|
||||
[source,txt]
|
||||
----
|
||||
$ java -classpath ...:/path/to/MySpringBootApacheGeodeClientCacheApplication.jar -Dgemfire.log-level=DEBUG
|
||||
example.app.MySpringBootApacheGeodeClientCacheApplication
|
||||
----
|
||||
|
||||
.Externalized configuration using Apache Geode `gemfire.properties`
|
||||
[source,properties]
|
||||
----
|
||||
# Apache Geode/Pivotal GemFire only/specific properties
|
||||
log-level=INFO
|
||||
----
|
||||
|
||||
.Externalized configuration using Spring Boot `application.properties`
|
||||
[source,properties]
|
||||
----
|
||||
spring.data.gemfire.cache.log-level=DEBUG
|
||||
----
|
||||
|
||||
Or:
|
||||
|
||||
[source,properties]
|
||||
----
|
||||
spring.data.gemfire.logging.level=DEBUG
|
||||
----
|
||||
|
||||
.Java configuration using SDG's `@EnableLogging` annotation
|
||||
[source,java]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@EnableLogging(logLevel = "DEBUG")
|
||||
class MySpringBootApacheGeodeClientApplication {
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
That is to say, none of the approaches above have any effect without the **new** SBDG logging starter.
|
||||
|
||||
[[geode-logging-configuration]]
|
||||
=== Configure Apache Geode & Pivotal GemFire Logging
|
||||
|
||||
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 `geode-log4j` module covers the required configuration for steps 1-3 above and uses Apache Log4j
|
||||
(i.e. `org.apache.logging.log4j:log4j-core`) as the logging provider. The `geode-log4j` module even provides a default,
|
||||
`log4j2.xml` configuration file to configure Loggers, Appenders and log levels for Apache Geode.
|
||||
|
||||
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.
|
||||
|
||||
[[geode-logging-configuration-log-levels]]
|
||||
==== 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,
|
||||
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
|
||||
[source,xml]
|
||||
----
|
||||
<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
|
||||
[source,text]
|
||||
----
|
||||
$ java -classpath ...:/path/to/MySpringBootApplication.jar -Dspring.boot.data.gemfire.log.level=DEBUG
|
||||
package.to.MySpringBootApplicationClass
|
||||
----
|
||||
|
||||
NOTE: Setting JVM System Properties 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 Apache Geode logging in Spring Boot `application.properties`:
|
||||
|
||||
.Setting the log-level in `application.properties`
|
||||
[source,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.
|
||||
|
||||
[[geode-logging-configuration-composition]]
|
||||
==== Composing Logging Configuration
|
||||
|
||||
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
|
||||
[source,xml]
|
||||
----
|
||||
include::{starter-logging-resources-dir}/logback-include.xml[]
|
||||
----
|
||||
|
||||
Then, this Logback configuration snippet can be included in an application-specific, _Logback_ XML configuration file
|
||||
as follows:
|
||||
|
||||
.logback.xml
|
||||
[source,xml]
|
||||
----
|
||||
include::{starter-logging-resources-dir}/logback.xml[]
|
||||
----
|
||||
|
||||
|
||||
[[geode-logging-slf4j-logback-api-support]]
|
||||
=== SLF4J & Logback API Support
|
||||
|
||||
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:
|
||||
|
||||
* Resolve a reference to the _Logback_ `LoggingContext`
|
||||
* Resolve the SLF4J ROOT `Logger` as a _Logback_ `Logger`
|
||||
* Lookup `Appenders` by name and required type
|
||||
* Add/Remove `Appenders` to `Loggers`
|
||||
* And even 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,
|
||||
another useful utility during automated testing.
|
||||
|
||||
In addition to the `LogbackSupport` class, SBDG also provides some custom _Logback_ `Appenders`.
|
||||
|
||||
[[geode-logging-slf4j-logback-api-support-appender-composite]]
|
||||
==== CompositeAppender
|
||||
|
||||
The `org.springframework.geode.logging.slf4j.logback.CompositeAppender` class is an implementation of _Logback_
|
||||
`Appender` and the https://en.wikipedia.org/wiki/Composite_pattern[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`
|
||||
[source,java]
|
||||
----
|
||||
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`
|
||||
[source,java]
|
||||
----
|
||||
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.
|
||||
|
||||
[[geode-logging-slf4j-logback-api-support-appender-delegate]]
|
||||
==== DelegatingAppender
|
||||
|
||||
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`
|
||||
[source,java]
|
||||
----
|
||||
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));
|
||||
----
|
||||
|
||||
[[geode-logging-slf4j-logback-api-support-appender-string]]
|
||||
==== StringAppender
|
||||
|
||||
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
|
||||
[source,java]
|
||||
----
|
||||
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.
|
||||
Reference in New Issue
Block a user