Skip to content

Java: Otel implementation #3962

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7a934eb
java: otel implementation
prateek-kumar-improving May 24, 2025
148ba48
java: otel implementation
prateek-kumar-improving May 24, 2025
51abe72
java: otel implementation
prateek-kumar-improving May 25, 2025
68d41d3
java: otel implementation
prateek-kumar-improving May 25, 2025
0e183fd
java: otel implementation
prateek-kumar-improving May 25, 2025
b130fc9
java: otel implementation
prateek-kumar-improving May 25, 2025
7fdeeaf
java: otel implementation
prateek-kumar-improving May 25, 2025
728d736
Merge branch 'main' into java/otel-new
prateek-kumar-improving May 25, 2025
229b93e
java: otel implementation
prateek-kumar-improving May 25, 2025
b1622ef
java: otel implementation
prateek-kumar-improving May 25, 2025
7b22b11
java: otel implementation
prateek-kumar-improving May 25, 2025
91e8cd9
java: otel implementation
prateek-kumar-improving May 26, 2025
45f468b
java: otel implementation
prateek-kumar-improving May 26, 2025
6560422
java: otel implementation
prateek-kumar-improving May 26, 2025
db2735e
java: otel implementation
prateek-kumar-improving May 26, 2025
a7d4595
java: otel implementation
prateek-kumar-improving May 26, 2025
5980fc8
java: otel implementation
prateek-kumar-improving May 26, 2025
cb0441e
java: otel implementation
prateek-kumar-improving May 26, 2025
365a6db
java: otel implementation
prateek-kumar-improving May 26, 2025
f7ccf45
java: otel implementation
prateek-kumar-improving May 26, 2025
f473ba5
java: otel implementation
prateek-kumar-improving May 26, 2025
29d04d8
java: otel implementation
prateek-kumar-improving May 26, 2025
6b0b0a1
Merge branch 'main' into java/otel-new
prateek-kumar-improving May 26, 2025
a1c92be
OTEL update tests
prateek-kumar-improving May 26, 2025
73950b5
OTEL update tests
prateek-kumar-improving May 26, 2025
df3071f
Merge branch 'main' into java/otel-new
prateek-kumar-improving May 26, 2025
a397b9c
Java: OpenTelemetry update tests
prateek-kumar-improving May 27, 2025
d723171
Java: OpenTelemetry update tests
prateek-kumar-improving May 27, 2025
f3092a0
Java: OpenTelemetry update tests
prateek-kumar-improving May 27, 2025
b3ab351
Java: fix opentelemetry tests
prateek-kumar-improving May 27, 2025
e046c3d
Java: fix opentelemetry tests
prateek-kumar-improving May 27, 2025
96bd766
Java: fix opentelemetry tests
prateek-kumar-improving May 27, 2025
6351524
Merge branch 'main' into java/otel-new
prateek-kumar-improving May 27, 2025
c9c6eda
Java: fix opentelemetry tests
prateek-kumar-improving May 28, 2025
3b00c7c
Java: fix opentelemetry tests
prateek-kumar-improving May 28, 2025
0ad7807
Java: fix opentelemetry tests
prateek-kumar-improving May 28, 2025
166899e
Java: Opentelemetry changelog.md file updated
prateek-kumar-improving May 28, 2025
e6b0f40
Java: fix opentelemetry tests
prateek-kumar-improving May 28, 2025
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
* Java: Add error restore command ([#3905](https://github.com/valkey-io/valkey-glide/pull/3905))
* Core: Add reference counting to Script container to support multiple instances ([#3897](https://github.com/valkey-io/valkey-glide/pull/3897))
* Java: Implement support for Insecure TLS authentication mode([#3386](https://github.com/valkey-io/valkey-glide/pull/3386))
* Java: Otel implementation ([#3962](https://github.com/valkey-io/valkey-glide/pull/3962))

#### Breaking Changes

Expand Down
360 changes: 360 additions & 0 deletions java/client/src/main/java/glide/api/OpenTelemetry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,360 @@
/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.api;

import glide.api.logging.Logger;
import glide.api.models.exceptions.ConfigurationException;
import glide.ffi.resolvers.OpenTelemetryResolver;
import java.util.Random;

/** OpenTelemetry integration for Valkey GLIDE. */
public class OpenTelemetry {
private static OpenTelemetry instance = null;
private static OpenTelemetryConfig openTelemetryConfig = null;
private static final Random random = new Random();

/** Configuration for OpenTelemetry integration. */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could use am example usage doc either in the config class or the init function

public static class OpenTelemetryConfig {
private TracesConfig traces;
private MetricsConfig metrics;
private Long flushIntervalMs;

/**
* Creates a new OpenTelemetryConfig builder.
*
* @return A new OpenTelemetryConfig builder
*/
public static Builder builder() {
return new Builder();
}

/** Builder for OpenTelemetryConfig. */
public static class Builder {
private TracesConfig traces;
private MetricsConfig metrics;
private Long flushIntervalMs = 5000L; // Default value

/**
* Sets the traces configuration.
*
* @param traces The traces configuration
* @return This builder
*/
public Builder traces(TracesConfig traces) {
this.traces = traces;
return this;
}

/**
* Sets the metrics configuration.
*
* @param metrics The metrics configuration
* @return This builder
*/
public Builder metrics(MetricsConfig metrics) {
this.metrics = metrics;
return this;
}

/**
* Sets the flush interval in milliseconds.
*
* @param flushIntervalMs The flush interval in milliseconds
* @return This builder
*/
public Builder flushIntervalMs(Long flushIntervalMs) {
this.flushIntervalMs = flushIntervalMs;
return this;
}

/**
* Builds the OpenTelemetryConfig.
*
* @return The built OpenTelemetryConfig
*/
public OpenTelemetryConfig build() {
OpenTelemetryConfig config = new OpenTelemetryConfig();
config.traces = this.traces;
config.metrics = this.metrics;
config.flushIntervalMs = this.flushIntervalMs;
return config;
}
}

/**
* Gets the traces configuration.
*
* @return The traces configuration
*/
public TracesConfig getTraces() {
return traces;
}

/**
* Gets the metrics configuration.
*
* @return The metrics configuration
*/
public MetricsConfig getMetrics() {
return metrics;
}

/**
* Gets the flush interval in milliseconds.
*
* @return The flush interval in milliseconds
*/
public Long getFlushIntervalMs() {
return flushIntervalMs;
}
}

/** Configuration for OpenTelemetry traces. */
public static class TracesConfig {
private String endpoint;
private Integer samplePercentage;

/**
* Creates a new TracesConfig builder.
*
* @return A new TracesConfig builder
*/
public static Builder builder() {
return new Builder();
}

/** Builder for TracesConfig. */
public static class Builder {
private String endpoint;
private Integer samplePercentage = 1; // Default value

/**
* Sets the endpoint for traces.
*
* @param endpoint The endpoint for traces
* @return This builder
*/
public Builder endpoint(String endpoint) {
this.endpoint = endpoint;
return this;
}

/**
* Sets the sample percentage for traces.
*
* @param samplePercentage The sample percentage for traces
* @return This builder
*/
public Builder samplePercentage(Integer samplePercentage) {
this.samplePercentage = samplePercentage;
return this;
}

/**
* Builds the TracesConfig.
*
* @return The built TracesConfig
*/
public TracesConfig build() {
TracesConfig config = new TracesConfig();
config.endpoint = this.endpoint;
config.samplePercentage = this.samplePercentage;
return config;
}
}

/**
* Gets the endpoint for traces.
*
* @return The endpoint for traces
*/
public String getEndpoint() {
return endpoint;
}

/**
* Gets the sample percentage for traces.
*
* @return The sample percentage for traces
*/
public Integer getSamplePercentage() {
return samplePercentage;
}

/**
* Sets the sample percentage for traces.
*
* @param samplePercentage The sample percentage for traces
*/
public void setSamplePercentage(Integer samplePercentage) {
this.samplePercentage = samplePercentage;
}
}

/** Configuration for OpenTelemetry metrics. */
public static class MetricsConfig {
private String endpoint;

/**
* Creates a new MetricsConfig builder.
*
* @return A new MetricsConfig builder
*/
public static Builder builder() {
return new Builder();
}

/** Builder for MetricsConfig. */
public static class Builder {
private String endpoint;

/**
* Sets the endpoint for metrics.
*
* @param endpoint The endpoint for metrics
* @return This builder
*/
public Builder endpoint(String endpoint) {
this.endpoint = endpoint;
return this;
}

/**
* Builds the MetricsConfig.
*
* @return The built MetricsConfig
*/
public MetricsConfig build() {
MetricsConfig config = new MetricsConfig();
config.endpoint = this.endpoint;
return config;
}
}

/**
* Gets the endpoint for metrics.
*
* @return The endpoint for metrics
*/
public String getEndpoint() {
return endpoint;
}
}

/**
* Example usage: ```java import glide.api.OpenTelemetry;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix markdown symbols like ```

*
* <p>OpenTelemetry.init( OpenTelemetry.OpenTelemetryConfig.builder() .traces(
* OpenTelemetry.TracesConfig.builder() .endpoint("http://localhost:4318/v1/traces")
* .samplePercentage(10) // Optional, defaults to 1 .build() ) .metrics(
* OpenTelemetry.MetricsConfig.builder() .endpoint("http://localhost:4318/v1/metrics") .build() )
* .flushIntervalMs(5000L) // Optional, defaults to 5000 .build() ); ```
*
* <p>Initialize the OpenTelemetry instance
*
* @param config The OpenTelemetry configuration
*/
public static void init(OpenTelemetryConfig config) {
if (instance == null) {
internalInit(config);
Logger.log(Logger.Level.INFO, "GlideOpenTelemetry", "OpenTelemetry initialized");
return;
}

Logger.log(Logger.Level.WARN, "GlideOpenTelemetry", "OpenTelemetry already initialized");
}

private static void internalInit(OpenTelemetryConfig config) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at least one of traces or metrics must be provided

openTelemetryConfig = config;

String tracesEndpoint = null;
int tracesSamplePercentage = -1;
if (config.getTraces() != null) {
tracesEndpoint = config.getTraces().getEndpoint();
if (config.getTraces().getSamplePercentage() != null) {
tracesSamplePercentage = config.getTraces().getSamplePercentage();
}
}

String metricsEndpoint = null;
if (config.getMetrics() != null) {
metricsEndpoint = config.getMetrics().getEndpoint();
}

long flushIntervalMs =
config.getFlushIntervalMs() != null ? config.getFlushIntervalMs() : 5000L;

OpenTelemetryResolver.initOpenTelemetry(
tracesEndpoint, tracesSamplePercentage, metricsEndpoint, flushIntervalMs);

instance = new OpenTelemetry();
}

/**
* Check if the OpenTelemetry instance is initialized
*
* @return True if the OpenTelemetry instance is initialized, false otherwise
*/
public static boolean isInitialized() {
return instance != null;
}

/**
* Get the sample percentage for traces
*
* @return The sample percentage for traces only if OpenTelemetry is initialized and the traces
* config is set, otherwise null.
*/
public static Integer getSamplePercentage() {
if (openTelemetryConfig != null && openTelemetryConfig.getTraces() != null) {
return openTelemetryConfig.getTraces().getSamplePercentage();
}
return null;
}

/**
* Determines if the current request should be sampled for OpenTelemetry tracing. Uses the
* configured sample percentage to randomly decide whether to create a span for this request.
*
* @return true if the request should be sampled, false otherwise
*/
public static boolean shouldSample() {
Integer percentage = getSamplePercentage();
return isInitialized() && percentage != null && random.nextDouble() * 100 < percentage;
}

/**
* Set the percentage of requests to be sampled and traced. Must be a value between 0 and 100.
* This setting only affects traces, not metrics.
*
* @param percentage The sample percentage 0-100
* @throws ConfigurationException if OpenTelemetry is not initialized or traces config is not set
* @remarks This method can be called at runtime to change the sampling percentage without
* reinitializing OpenTelemetry.
*/
public static void setSamplePercentage(int percentage) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might need write protection here since it's technically possible for this to be called after a command has been executed but hasn't reached getPercentage()?

if (openTelemetryConfig == null || openTelemetryConfig.getTraces() == null) {
throw new ConfigurationException("OpenTelemetry config traces not initialized");
}

openTelemetryConfig.getTraces().setSamplePercentage(percentage);
}

/**
* Creates a new OpenTelemetry span with the given name.
*
* @param name The name of the span
* @return A pointer to the span
*/
public static long createSpan(String name) {
return OpenTelemetryResolver.createLeakedOtelSpan(name);
}

/**
* Drops an OpenTelemetry span.
*
* @param spanPtr The pointer to the span
*/
public static void dropSpan(long spanPtr) {
OpenTelemetryResolver.dropOtelSpan(spanPtr);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */
package glide.api.models.exceptions;

/**
* Exception thrown when there is an issue with the client configuration. This exception indicates
* that the client configuration is invalid or incompatible with the requested operation.
*/
public class ConfigurationException extends GlideException {
/**
* Constructs a new ConfigurationException with the specified detail message.
*
* @param message the detail message (which is saved for later retrieval by the getMessage()
* method)
*/
public ConfigurationException(String message) {
super(message);
}

/**
* Constructs a new ConfigurationException with the specified detail message and cause.
*
* @param message the detail message (which is saved for later retrieval by the getMessage()
* method)
* @param cause the cause (which is saved for later retrieval by the getCause() method)
*/
public ConfigurationException(String message, Throwable cause) {
super(message);
initCause(cause);
}
}
Loading
Loading