Skip to content

feat: add initial implementation for Java Observability Plugin - #381

Open
Vadman97 wants to merge 8 commits into
mainfrom
vadim/java-plugin
Open

Vadman97 wants to merge 8 commits into
mainfrom
vadim/java-plugin

Conversation

@Vadman97

@Vadman97 Vadman97 commented Feb 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Add new Java O11y plugin.

How did you test this change?

ci

Are there any deployment considerations?


Note

Overview
Introduces launchdarkly-observability-java (0.1.0) as a new Gradle library under sdk/@launchdarkly/observability-java: an early-access LaunchDarkly Server SDK plugin that wires OpenTelemetry traces/logs/metrics to OTLP, registers TracingHook for flag-evaluation spans, and loads backend sampling rules via GraphQL (CustomSampler, export-time span/log filtering, child-span dropping, bounded regex handling).

Public surface includes ObservabilityPlugin, ObservabilityOptions, and LDObserve (safe no-op before init; avoids locking GlobalOpenTelemetry onto noop). OtelManager owns provider lifecycle, flush/shutdown, and optional manual start.

CI & release: dedicated workflows java-observability.yml (./gradlew :lib:build) and java-plugin-e2e.yml; turbo.yml path filters exclude the Java SDK and e2e/java-plugin from the Yarn monorepo job. Release Please registers the new component (gradle.properties).

e2e/java-plugin is a runnable Gradle app (composite build against :lib) that mocks OTLP/sampling and asserts flag spans, sampling keep/drop, sampling-ratio attributes, and pre-init behavior.

Reviewed by Cursor Bugbot for commit f57eeaf. Bugbot is set up for automated code reviews on this repo. Configure here.

@Vadman97
Vadman97 requested a review from a team as a code owner February 19, 2026 20:22
@Vadman97 Vadman97 changed the title Vadim/java plugin feat: add initial implementation for Java Observability Plugin Feb 19, 2026
@Vadman97 Vadman97 changed the title feat: add initial implementation for Java Observability Plugin feat: add initial implementation for Java Observability Plugin Feb 19, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 5 potential issues.

Comment thread sdk/@launchdarkly/observability-java/.gradle/buildOutputCleanup/cache.properties Outdated

@abelonogov-ld abelonogov-ld left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Most files could be used, but client sdk semantics was transfered to server code, especially when multithreading occurs

Comment thread sdk/@launchdarkly/observability-java/README.md Outdated
Comment thread sdk/@launchdarkly/observability-java/build.gradle.kts Outdated
cursoragent and others added 2 commits October 2, 2026 18:21
Keep the new Java observability package in release-please alongside the Flutter package added on main.

Co-authored-by: Vadim Korolik <vkorolik@launchdarkly.com>
Cache the sampling query, synchronize provider startup, keep sampling config across manual start, and attach launchdarkly.sampling.ratio on exported spans. Replace the Kotlin Gradle scripts with Groovy and drop the committed Gradle cache.

Co-authored-by: Vadim Korolik <vkorolik@launchdarkly.com>
Comment thread sdk/@launchdarkly/observability-java/lib/build.gradle Fixed
@cursor

cursor Bot commented Oct 2, 2026

Copy link
Copy Markdown

Addressed the review on client-SDK semantics in server code. Provider startup is single-threaded (OtelManager.initialize takes one lock), the sampling query is loaded once and shared across threads, sampling config fetched before LDObserve.start is kept and applied, regexes are compiled once, and sampling uses ThreadLocalRandom. PluginUserFlowTest runs an offline LDClient with the plugin against a local OTLP and sampling server.

The license link is the public Apache documentation endpoint, so it does not need to stay on plain HTTP.

Co-authored-by: Vadim Korolik <vkorolik@launchdarkly.com>
@Vadman97
Vadman97 requested a review from abelonogov-ld October 2, 2026 18:39

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread .github/workflows/java-observability.yml
Pre-init LDObserve calls use a local no-op and no longer install GlobalOpenTelemetry, so TracingHook still exports after init. Sampling patterns are length-capped, allowlisted, and rejected when they can ReDoS. Exclude the Java SDK from the Yarn path filter.

Co-authored-by: Vadim Korolik <vkorolik@launchdarkly.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f39b4b2. Configure here.

cursoragent and others added 2 commits October 2, 2026 18:54
Closing an inner group now marks its parent, so ((a+))+ is dropped the same way as (a+)+ and is not compiled on the export path.

Co-authored-by: Vadim Korolik <vkorolik@launchdarkly.com>
The e2e app starts a local collector, registers ObservabilityPlugin, and exits non-zero unless the flag span, a kept span, and a dropped span arrive after a pre-init LDObserve call.

Co-authored-by: Vadim Korolik <vkorolik@launchdarkly.com>
@abelonogov-ld

Copy link
Copy Markdown
Contributor

The public API needs opentelemetry-api, but the POM publishes it as runtime, recordLog will not compile in some when used. The e2e example hides this by declaring opentelemetry-api explicitly, and the README doesn't mention it. Fix: declare opentelemetry-api as api.

@abelonogov-ld

Copy link
Copy Markdown
Contributor

Android moved forward and this version depends on many month behind Android code.

Proxy and custom HTTP settings are ignored. GraphQLClient uses a bare HttpURLConnection, and the OTLP exporters don't take headers or a proxy. Android already exposes customHeaders. Servers behind egress proxies will fail to fetch sampling config and to export.

@abelonogov-ld

Copy link
Copy Markdown
Contributor

ObservabilityOptions has no resourceAttributes, no log-level threshold, no enabled flag

* the cached string, so a server process does not re-read the query for
* every request or every client.</p>
*/
public static String loadQuery(String resourcePath) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would prefer compile-timed strings here. Go, .NET, Android, Node already use them

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Server packaging is where resources go missing. Shaded jars with minimize(), ProGuard, and some app-server or OSGi classloaders can drop or hide non-class files. Plain jars and Spring Boot fat jars are fine, but a library shouldn't depend on that.

@abelonogov-ld

Copy link
Copy Markdown
Contributor

okhttp, okio and the Kotlin stdlib leak unshaded. The default OTLP exporter brings okhttp 4.12, okio 3.6 and kotlin-stdlib 1.9.10. The LaunchDarkly server SDK itself shades its Kotlin and gson (com/launchdarkly/shaded/kotlin/... in its jar) precisely so server apps don't get version clashes. This plugin undoes that. The fix is cheap: OTel ships opentelemetry-exporter-sender-jdk, which uses Java 11's built-in HttpClient, and this module already targets Java 11.

@abelonogov-ld

Copy link
Copy Markdown
Contributor

The artifact name is ambiguous. The Android artifact is also a Java library, and LaunchDarkly's Java server family uses launchdarkly-java-server-sdk-* (-otel, -redis-store). Something with "server" in it would be clearer. Decide before the first publish, because Maven coordinates are permanent.

@abelonogov-ld

Copy link
Copy Markdown
Contributor

We need server CI configuration, many of above issues would be caught if we have one

@abelonogov-ld

Copy link
Copy Markdown
Contributor

Server e2e app wasn't provided.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants