Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This project provides both the [core Spring Data Valkey library](spring-data-val
* Exception translation to Spring's portable Data Access exception hierarchy for driver exceptions.
* `ValkeyTemplate` that provides a high level abstraction for performing various Valkey operations, exception translation and serialization support.
* Pubsub support (such as a MessageListenerContainer for message-driven POJOs). Available with Jedis and Lettuce, with Valkey GLIDE support WIP for version 1.0.0.
* OpenTelemetry instrumentation support when using the Valkey GLIDE client for emitting traces and metrics for Valkey operations.
* Valkey Sentinel support is currently available in Jedis and Lettuce, while support in Valkey GLIDE is planned for a future release.
* Reactive API using Lettuce.
* JDK, String, JSON and Spring Object/XML mapping serializers.
Expand All @@ -29,6 +30,7 @@ This project provides both the [core Spring Data Valkey library](spring-data-val
* Support for multiple Valkey drivers ([Valkey GLIDE](https://github.com/valkey-io/valkey-glide), [Lettuce](https://github.com/lettuce-io/lettuce-core), and [Jedis](https://github.com/redis/jedis)).
* Connection pooling configuration for all supported clients.
* Valkey Cluster auto-configuration and support.
* Property-based OpenTelemetry configuration for Valkey GLIDE, enabling automatic trace and metric export without application code changes.
* Valkey Sentinel configuration support (Lettuce and Jedis only).
* SSL/TLS connection support with Spring Boot SSL bundles.
* Spring Boot Actuator health indicators and metrics for Valkey connections.
Expand Down
55 changes: 55 additions & 0 deletions examples/boot-telemetry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Spring Boot + Valkey-GLIDE + OpenTelemetry

This example demonstrates using **Spring Boot** with **Spring Data Valkey**, backed by the **Valkey-GLIDE** client, with **OpenTelemetry tracing and metrics enabled via configuration**.

On startup, the application executes a small number of Valkey `SET` / `GET` commands using `StringValkeyTemplate`. Each command is automatically instrumented by GLIDE and exported via OpenTelemetry.

---

## How it works

- Spring Boot auto-configures all Valkey beans
- Valkey-GLIDE is selected using `client-type=valkeyglide`
- OpenTelemetry is enabled inside GLIDE using Spring Boot properties
- An OpenTelemetry Collector is started using Docker Compose
- Traces and metrics are exported through the collector

No explicit OpenTelemetry SDK or client setup code is required.

---

## Running the example

```bash
../../mvnw clean compile exec:java
````

Docker Compose is started automatically and kept running after the application exits.

---

## Key configuration properties

```properties
spring.data.valkey.client-type=valkeyglide

spring.data.valkey.valkey-glide.open-telemetry.enabled=true
spring.data.valkey.valkey-glide.open-telemetry.traces-endpoint=http://localhost:4318/v1/traces
spring.data.valkey.valkey-glide.open-telemetry.metrics-endpoint=http://localhost:4318/v1/metrics

spring.docker.compose.lifecycle-management=start-only
```

---

## Inspecting OpenTelemetry

```bash
docker logs -f spring-boot-opentelemetry-otel-collector-1
```

If yoy change the configuration of the docker shutdown the existing containers first and then run the example again:

```bash
docker compose down --remove-orphans
```
10 changes: 10 additions & 0 deletions examples/boot-telemetry/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
services:

otel-collector:
image: otel/opentelemetry-collector-contrib:latest
command: ["--config=/etc/otelcol/config.yaml"]
volumes:
- ./otel-collector-config.yaml:/etc/otelcol/config.yaml:ro
ports:
- "4318:4318" # OTLP HTTP receiver
- "4317:4317" # OTLP gRPC receiver
36 changes: 36 additions & 0 deletions examples/boot-telemetry/otel-collector-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317 # OTLP gRPC endpoint
http:
endpoint: 0.0.0.0:4318 # OTLP HTTP endpoint (used by Spring Boot)

processors:
batch: {} # Required for efficient exporting

exporters:
debug:
verbosity: detailed # Optional: remove in production

# Uncomment the following exporters to enable AWS X-Ray and CloudWatch exporting
# awsxray:
# region: "us-east-1" # X-Ray traces

# awsemf:
# region: "us-east-1"
# log_group_name: "/spring/metrics" # Change to your CloudWatch log group
# namespace: "opentelemetry" # CloudWatch metrics namespace


service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [debug] # [awsxray, debug] # Uncomment awsxray to enable X-Ray exporting

metrics:
receivers: [otlp]
processors: [batch]
exporters: [debug] # [awsemf, debug] # Uncomment awsemf to enable CloudWatch exporting
53 changes: 53 additions & 0 deletions examples/boot-telemetry/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.valkey.springframework</groupId>
<artifactId>spring-data-valkey-examples</artifactId>
<version>0.1.0</version>
</parent>

<artifactId>spring-data-valkey-example-boot-telemetry</artifactId>
<name>Spring Data Valkey - Spring Boot OpenTelemetry Example</name>

<properties>
<exec.mainClass>example.boottelemetry.SpringBootTelemetryExample</exec.mainClass>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.valkey.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-valkey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
</dependency>
</dependencies>

<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.1</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>example.boottelemetry.SpringBootTelemetryExample</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package example.boottelemetry;

import io.valkey.springframework.data.valkey.core.StringValkeyTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* Minimal Spring Boot example that demonstrates OpenTelemetry integration
* with Valkey-GLIDE via {@link StringValkeyTemplate}.
*
* <p>This example exists to verify and showcase that Valkey commands executed
* through Spring Data Valkey automatically emit OpenTelemetry signals when
* OpenTelemetry is enabled via application properties.</p>
*
* <p>Telemetry is emitted while the application runs and Valkey commands are
* executed. Traces can be inspected via the configured OpenTelemetry backend,
* for example by viewing the collector logs:</p>
*
* <pre>
* docker logs -f spring-boot-opentelemetry-otel-collector-1
* </pre>
*/
@SpringBootApplication
public class SpringBootTelemetryExample implements CommandLineRunner {

@Autowired
private StringValkeyTemplate valkeyTemplate;

public static void main(String[] args) {
SpringApplication.run(SpringBootTelemetryExample.class, args);
}

@Override
public void run(String... args) {

// Increase this number to generate more Valkey commands/traces
int iterations = 10;
for (int i = 0; i < iterations; i++) {
String key = "key" + i;
String value = "value" + i;

valkeyTemplate.opsForValue().set(key, value);
String readBack = valkeyTemplate.opsForValue().get(key);

// System.out.println("Iteration " + i + ": " + key + "=" + readBack);
}

System.out.println("Completed " + iterations + " iterations of Valkey commands.");
}
}
16 changes: 16 additions & 0 deletions examples/boot-telemetry/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
spring.data.valkey.host=localhost
spring.data.valkey.port=6379
spring.data.valkey.client-type=valkeyglide

# Keep the Docker Compose services running after the example stops
# Provide the option to inspect the services if needed
# Run `docker logs -f spring-boot-opentelemetry-otel-collector-1` to see the OpenTelemetry Collector logs
# If you changed the docker logs run `docker compose down --remove-orphans` to stop and remove the containers
spring.docker.compose.lifecycle-management=start-only

# Enable OpenTelemetry inside GLIDE
spring.data.valkey.valkey-glide.open-telemetry.enabled=true
spring.data.valkey.valkey-glide.open-telemetry.traces-endpoint=http://localhost:4318/v1/traces
spring.data.valkey.valkey-glide.open-telemetry.metrics-endpoint=http://localhost:4318/v1/metrics
spring.data.valkey.valkey-glide.open-telemetry.sample-percentage=10
spring.data.valkey.valkey-glide.open-telemetry.flush-interval-ms=1000
16 changes: 16 additions & 0 deletions examples/boot-telemetry/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
</appender>

<logger name="io.valkey.springframework.data" level="error" />

<root level="info">
<appender-ref ref="console" />
</root>

</configuration>
1 change: 1 addition & 0 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<module>cache</module>
<module>cluster</module>
<module>collections</module>
<module>telemetry</module>
<module>operations</module>
<module>pipeline</module>
<module>quickstart</module>
Expand Down
31 changes: 31 additions & 0 deletions examples/telemetry/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.valkey.springframework</groupId>
<artifactId>spring-data-valkey-examples</artifactId>
<version>0.1.0</version>
</parent>

<artifactId>spring-data-valkey-example-telemetry</artifactId>
<name>Spring Data Valkey - OpenTelemetry Example</name>

<properties>
<exec.mainClass>example.telemetry.OpenTelemetryExample</exec.mainClass>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>example.telemetry.OpenTelemetryExample</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2025 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 example.telemetry;

import io.valkey.springframework.data.valkey.connection.ValkeyStandaloneConfiguration;
import io.valkey.springframework.data.valkey.connection.valkeyglide.ValkeyGlideClientConfiguration;
import io.valkey.springframework.data.valkey.connection.valkeyglide.ValkeyGlideClientConfiguration.OpenTelemetryForGlide;
import io.valkey.springframework.data.valkey.connection.valkeyglide.ValkeyGlideConnectionFactory;
import io.valkey.springframework.data.valkey.core.StringValkeyTemplate;

/**
* Minimal example that demonstrates how to enable and emit OpenTelemetry traces
* from Valkey-GLIDE using {@link StringValkeyTemplate}.
*
* <p>This example exists to validate and showcase the OpenTelemetry integration
* in Valkey-GLIDE by executing a small number of Valkey commands and exporting
* traces to an OpenTelemetry Collector.</p>
*
* <p>Telemetry is emitted while the application runs and Valkey commands are
* executed. Traces can be inspected via the configured OpenTelemetry backend,
* for example by viewing the collector logs:</p>
*
* <pre>
* docker logs -f spring-boot-opentelemetry-otel-collector-1
* </pre>
*/
public class OpenTelemetryExample {

public static void main(String[] args) {

ValkeyStandaloneConfiguration standaloneConfig =
new ValkeyStandaloneConfiguration();

// Change the default tracesEndpoint / metricsEndpoint if needed
OpenTelemetryForGlide openTelemetry =
OpenTelemetryForGlide.defaults();

ValkeyGlideClientConfiguration clientConfig =
ValkeyGlideClientConfiguration.builder()
.useOpenTelemetry(openTelemetry)
.build();

ValkeyGlideConnectionFactory connectionFactory =
new ValkeyGlideConnectionFactory(standaloneConfig, clientConfig);

connectionFactory.afterPropertiesSet();

try {
StringValkeyTemplate template =
new StringValkeyTemplate(connectionFactory);

// Increase this number to generate more Valkey commands/traces
int iterations = 10;
for (int i = 0; i < iterations; i++) {
String key = "key" + i;
String value = "value" + i;

template.opsForValue().set(key, value);
String readBack = template.opsForValue().get(key);

// System.out.println("Iteration " + i + ": " + key + "=" + readBack);
}

System.out.println("Completed " + iterations + " iterations of Valkey commands.");

} finally {
connectionFactory.destroy();
}
}
}
Loading