[[geode-samples-boot-actuator]]
= Spring Boot Actuator for Apache Geode
:geode-version: {apache-geode-doc-version}
:geode-name: Apache Geode
:geode-docs: https://geode.apache.org/docs/guide/{geode-version}
:images-dir: ./images
:spring-boot-docs: https://docs.spring.io/spring-boot/docs/current/reference/html
:spring-framework-docs: https://docs.spring.io/spring/docs/current/spring-framework-reference
:toc: left
:toclevels: 2
:stylesdir: ../
:highlightjsdir: ../js/highlight
:docinfodir: guides


This guide walks through using {spring-boot-docs}/production-ready.html[Spring Boot Actuator] to assess the state
of your running {geode-name}, Spring Boot application.

The goal for SBDG's Spring Boot Actuator integration is to enable users to effectively manage and monitor their
Spring Boot applications using {geode-name} in a production environment.

In particular, SBDG's integration with Spring Boot Actuator currently focuses on enabling
{spring-boot-docs}/production-ready-endpoints.html#production-ready-health[Health Information]
for your application.  In the future, SBDG will provide dedicated support for https://micrometer.io/[Micrometer] metrics.

This guide assumes you are already familiar with Spring Boot and {geode-name}.

TIP: Refer to the link:../index.html#actuator[Spring Boot Actuator] chapter in the reference documentation
for more information.

[#index-link]
link:../index.html[Index]

link:../index.html#geode-samples[Back to Samples]

[[geode-samples-boot-actuator-example]]
== Example Application

This guide additionally provides a working {github-samples-url}/boot/actuator[example application] to review some of
the Actuator Health Endpoints.

The example application is a simple Temperature Monitoring Service, simulating a real-world, Internet of Things (IOT)
Use Case (UC).  Essentially, the application collects temperature readings from different temperature sensors (devices)
and uses the readings to monitor fluctuations in temperatures so that someone or something can respond accordingly.
The sensor devices could be located around the world in multiple locations in the planet's oceans.

[[geode-samples-boot-actuator-example-temperaturereading]]
=== TemperatureReading

First, we start by modeling a temperature reading, which stores the temperature in Fahrenheit along with a timestamp
for when the reading was measured.

Clearly, a more practical example would store the temperature measurement as a `double` or `BigDecimal` along with
the ability to support different scales (Celsius, Fahrenheit, Kelvin).

However in this case, we simply model the `TemperatureReading` as:

.TemperatureReading class
[source,java]
----
include::{samples-dir}/boot/actuator/src/main/java/example/app/temp/model/TemperatureReading.java[tags=class]
----

The `TemperatureReading` class is annotated with SDG's `@Region` mapping annotation to declare the {geode-name} Region
in which `TemperatureReadings` will be persisted.

[[geode-samples-boot-actuator-example-temperatureevent]]
=== TemperatureEvent

A key concern of our application is to "monitor" temperature readings.  Therefore, we need some way to capture
temperature change events.

For that, we introduce the simple `TemperatureEvent` base class:

.TemperatureEvent class
[source,java]
----
include::{samples-dir}/boot/actuator/src/main/java/example/app/temp/event/TemperatureEvent.java[tags=class]
----

`TemperatureEvent` is a Spring `ApplicationEvent` capable of being published to to Spring `@EventListeners` registered
in the Spring application context.

Additionally, we provide 2 subclasses: `BoilingTemperatureEvent` and `FreezingTemperatureEvent` to further classify
temperature changes.

[[geode-samples-boot-actuator-example-temperaturereadingrepository]]
=== TemperatureReadingRepository

To perform basic data access operations (e.g. CRUD) and simple queries on `TemperatureReadings`, we create
a Spring Data _Repository_:

.TemperatureReadingRepository interface
[source,java]
----
include::{samples-dir}/boot/actuator/src/main/java/example/app/temp/repo/TemperatureReadingRepository.java[tags=class]
----

The _Repository_ showcases a an example, derived query methods, `findByTimestampGreaterThanAndTimestampLessThan(..)`
along with 2 `@Query` annotated query methods using raw OQL queries.

[[geode-samples-boot-actuator-example-temperaturemonitor]]
=== TemperatureMonitor service class

To receive temperature change events, we need a class to monitor changes.  This capability is built on {geode-name}'s
{geode-docs}/developing/continuous_querying/chapter_overview.html[Continuous Query (CQ)] functionality.

With {geode-name} you can register an (OQL) Query with the servers in the cluster that runs continuously, sending
notifications back to the client anytime data changes to match the predicate in our query, or queries.

For our purposes, we will simply monitor the temperature anytime it rises above boiling (212 °F)
or drops below freezing (32 °F):

.TemperatureMonitor class
[source,java]
----
include::{samples-dir}/boot/actuator/src/main/java/example/app/temp/service/TemperatureMonitor.java[tags=class]
----

When the temperature changes, triggering our queries, we receive an event and publish an appropriate `TemperatureEvent`
by using the Spring container's `ApplicationEventPublisher`, which has been injected into the monitor class.

The 2 OQL queries have been defined to query the "TemperatureReadings" Region and fire anytime the temperature
rises is above boiling (212 °F) or drops below freezing (32 °F).

[[geode-samples-boot-actuator-example-temperaturesensor]]
=== TemperatureSensor service class

Of course, we need a simulator to generate temperatures.

For that we have the `TemperatureSensor` class:

.TemperatureSensor class
[source,java]
----
include::{samples-dir}/boot/actuator/src/main/java/example/app/temp/service/TemperatureSensor.java[tags=class]
----

To generate a stream of temperatures, we use Spring's {spring-framework-docs}/integration.html#scheduling[Scheduling Service]
along with a `Random` stream of `ints` provided via an `Iterator`, as seen in the `readTemperature()` method.

The `readTemperature()` method is then storing the *new* `TemperatureReading` in the "TemperatureReadings" Region
as designated by our `TemperatureReading` model class's, `@Region` annotation declaration:

.@Region declaration
[source,java]
----
@Region("TemperatureReadings")
public class TemperatureReading {  }
----

Additionally, the `readTempeature()` method uses our `TemperatureReadingRepository` to perform the necessary
data access operations.

[[geode-samples-boot-actuator-example-server]]
=== Server

Now, we need a couple of main application classes to actually have the application do something useful.

We start with an Spring Boot, {geode-name} Server application functioning as the temperature sensor (device)
using the `TemperatureSensor` class:

.BootGeodeServerApplication main class
[source,java]
----
include::{samples-dir}/boot/actuator/src/main/java/example/app/temp/geode/server/BootGeodeServerApplication.java[tags=class]
----

This class is annotated with `@SpringBootApplication` making it a proper Spring Boot application. It uses Spring Boot's
`SpringApplicationBuilder` to configure and bootstrap the server application.

This class is also annotated with SDG's `@CacheServerApplication` making it a proper {geode-name} Server with a peer
`Cache` instance along with a `CacheServer` to accept client connections.  This effectively overrides SBDG's default
`ClientCache` instance.

Additionally, the class enables several other features, such as Spring's _Scheduling Service_, {geode-name} Statistics,
and entity-defined Regions making the creation of our server-side, partitioned "TemperatureReadings" Region simple.

By enabling {geode-name} statistics, we allow Spring Boot's Actuator, `HealthIndicators` to collect metrics about
our running {geode-name} Server as well.

Because we have enabled scheduling (with `@EnableScheduling`) and declared the `TemperatureSensor` class as a bean
in the Spring application context, the application will immediately start generating temperature readings, which are
recorded to the "TemperatureReadings" Region.

Finally, our class registers a couple {geode-name} Region Indexes to make the Actuator `HealthIndicator` information
more interesting, particularly since we are running continuous queries.

This is a Servlet-based application as well since our Actuator, `HealthIndicator` endpoints are exposed via HTTP.

TIP: There are multiple ways to configure and bootstrap an {geode-name} Server, and the server-side of our application.
Using Spring Boot is one of the easier ways.

[[geode-samples-boot-actuator-example-client]]
=== Client

Next, we need a client functioning as the "monitor" in our Temperature Service application.

.BootGeodeClientApplication main class
[source,java]
----
include::{samples-dir}/boot/actuator/src/main/java/example/app/temp/geode/client/BootGeodeClientApplication.java[tags=class]
----

Again, this class is also annotated with `@SpringBootApplication` making it a proper Spring Boot application.  It too
uses Spring Boot's `SpringApplicationBuilder` class to configure and bootstrap the client application.

Unlike our server, this class is not annotated with any SDG `@*Cache*Application` annotations since SBDG provides us
a `ClientCache` instance by default. We want this application to be a client in our setup.

Like our server, we enable entity-defined Regions to easily and quickly create the client `PROXY` Region
for "TemperatureReadings", which will send/receive data to/from the server-side Region by the same name.

And, like our server application, we declare a bean of type `TemperatureMonitor` in the Spring application context
to receive the `TemperatureReading` events. This enables the CQ registration and event handlers
to sets things in motion.

Probably the most interesting part is that we an `@EventListener` to receive the `TemperatureEvents` to log
the `TemperatureReadings` to `System.err`.

[[geode-samples-boot-actuator-example-run]]
== Run the Example

It is time to run the example.

First, we need to start the server.

You can run the server from your IDE (e.g. IntelliJ IDEA) by creating a run profile configuration for the
`example.app.temp.geode.server.BootGeodeServerApplication` class. Make sure to set the JVM argument to activate the
"_server_" Spring Profile: `-Dspring.profiles.active=server`.

Alternatively, you can run the server from the command-line using the `gradlew` command:

`$ gradlew :spring-geode-samples-boot-actuator:runServer`

The `gradlew` command and `runServer` Gradle Task sets the configuration (e.g. Spring Profile) for you. The `gradlew`
command is ran in the directory where you cloned the `spring-boot-data-geode` project (**not** in
`spring-boot-data-geode/spring-geode-samples/boot/actuator/`).

If you wish to adjust the log levels of {geode-name} or Spring Boot while running the client and server applications,
then you can set the log levels of the individual Loggers (i.e. `org.apache` and `org.springframework`)
in `src/main/resources/logback.xml`:

.spring-geode-samples/boot/actuator/src/main/resources/logback.xml
[source,java]
----
include::{samples-dir}/boot/actuator/src/main/resources/logback.xml[]
----


Running the server from your IDE:

.Run the server
[source,txt]
----
/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/bin/java -server -ea -Dspring.profiles.active=server
  ... example.app.temp.geode.server.BootGeodeServerApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.9.RELEASE)

TEMPERATURE READING [99 °F]
TEMPERATURE READING [-17 °F]
TEMPERATURE READING [67 °F]
TEMPERATURE READING [9 °F]
TEMPERATURE READING [102 °F]
TEMPERATURE READING [10 °F]
...
----

After the server starts and begins to log temperature readings (as shown above), then start the client.

The client can be ran in the same manner as the server, from your IDE or from the command-line using `gradlew`.

To run the client in your IDE (e.g. IntelliJ IDEA) then create a run profile configuration for the
`example.app.temp.geode.client.BootGeodeClientApplication` and set the JVM argument to activate the "_client_"
Spring Profile: `-Dspring.profiles.active=client".

Alternatively, you can run the client from the command-line using the following command:

`$ gradlew :spring-geode-samples-boot-actuator:bootRun`

NOTE: The client must be run in a separate terminal, unless you ran the server as a background process with the `&`
on Linux/UNIX based systems.  See https://linuxize.com/post/how-to-run-linux-commands-in-background/[here]
for more details.

Running the client from your IDE:

.Run the client
[source,txt]
----
/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/bin/java -server -ea -Dspring.profiles.active=client
  ... example.app.temp.geode.client.BootGeodeClientApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.9.RELEASE)

COLD TEMPERATURE READING [-22 °F]
COLD TEMPERATURE READING [25 °F]
HOT TEMPERATURE READING [305 °F]
COLD TEMPERATURE READING [-82 °F]
HOT TEMPERATURE READING [295 °F]
HOT TEMPERATURE READING [326 °F]
HOT TEMPERATURE READING [378 °F]
COLD TEMPERATURE READING [-4 °F]
...
----

You should only see boiling and freezing temperatures logged to the client's console. This is because our client
only "monitors" and logs temperature readings above or below a certain threshold (boiling/freezing), as defined by
the Continuous Queries (CQ).

Both the server and client will continue to run, generating and logging temperatures, until you stop the JVM processes.

[[geode-samples-boot-actuator-example-monitor]]
== Monitoring our Example with Spring Boot Actuator, HealthIndicator Endpoints

After the application has been running for some time, we can inspect the Spring Boot Actuator, HealthIndicator Endpoints
provided by SBDG to monitor our application's health and runtime performance in addition to basic configuration
meta-data used to configure {geode-name} at runtime.

[[geode-samples-boot-actuator-example-monitor-client]]
=== Client Health Information

To navigate to the client applications Actuator Health endpoints, open a Web Browser (e.g. Google Chrome) to:

`http://localhost:9191/actuator/health`

This will output a JSON document similar to:

image::{images-dir}/client-actuator-health-endpoints.png[]

We can see details on our client "TemperatureReadings" Region:

image::{images-dir}/client-actuator-health-region-endpoint.png[]

As well as our CQs:

image::{images-dir}/client-actuator-health-cq-endpoint.png[]

When you hit refresh, the metrics will update.

[[geode-samples-boot-actuator-example-monitor-server]]
=== Server Health Information

To navigate to the server applications Actuator Health endpoint, open a Web Browser (e.g. Google Chrome) to:

`http://localhost:8181/actuator/health`

This will output a JSON document similar to:

image::{images-dir}/server-actuator-health-endpoints.png[]

We can see details of the server "TemperatureReadings" Region:

image::{images-dir}/server-actuator-health-region-endpoint.png[]

As well as our Indexes:

image::{images-dir}/server-actuator-health-indexes-endpoint.png[]

And our CacheServer serving clients:

image::{images-dir}/server-actuator-health-cacheserver-endpoint.png[]

When you hit refresh, the metrics will update.

[[geode-samples-boot-actuator-enabling]]
== Enabling Spring Boot Actuator

All of this was made possible by including the following dependency on our application classpath:

.Maven POM
[source,xml]
----
<dependency>
  <groupId>org.springframework.geode</groupId>
  <artifactId>spring-geode-starter-actuator</artifactId>
</dependency>
----

Additionally, in Spring Boot `application.properties`, you must enable the following:

.Spring Boot `application.properties`
[source,txt]
----
management.endpoint.health.show-details=always
----

[[geode-samples-boot-actuator-conclusion]]
== Conclusion

Hopefully this guide has shown you how to use the Spring Boot Actuator feature for {geode-name}.

You are encouraged to read more about {spring-boot-docs}/production-ready.html[Spring Boot's Actuator] functionality.

Additionally, you can find out more about {geode-name} Statistics
in the {geode-docs}/managing/statistics/chapter_overview.html[User Guide].

link:../index.html#geode-samples[Back to Samples]
