Skip to content

Add Jetty 12 native WebSocket tracing and fix upgrade span completion - #12674

Draft
ygree wants to merge 10 commits into
masterfrom
ygree/jetty-native-websockets
Draft

ygree wants to merge 10 commits into
masterfrom
ygree/jetty-native-websockets

Conversation

@ygree

@ygree ygree commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

What Does This Do

Adds tracing for Jetty 12's native WebSocket API:

  • Creates server-side websocket.receive and websocket.close spans for listener and annotated endpoints, including handlers returning boxed Void.
  • Creates websocket.send spans for both client and server sessions.
  • Supports full and fragmented text and binary messages, preserving handshake links, application context, and existing sampling behavior.
  • Tracks asynchronous callbacks independently, including overlapping messages and out-of-order completion, and records handler, send, and callback failures.
  • Finishes pending receive spans when the connection closes. Ends incomplete send messages while waiting for outstanding send callbacks so failures reported after closure are retained.

Also fixes Jetty HTTP client handshake spans left unfinished by successful WebSocket upgrades. Activates the handshake span during upgrade so client sessions capture its context, then finishes it with the HTTP 101 response.

Motivation

Jetty 12 native WebSocket endpoints need dedicated instrumentation to trace message processing, outbound sends, and close handlers. Fragmentation and asynchronous callbacks require per-message lifecycle tracking to avoid premature completion, mixed contexts, and lost errors.

Successful WebSocket upgrades bypass the HTTP client's normal response completion listeners, requiring explicit handshake span completion.

Additional Notes

Contributor Checklist

Jira ticket: FRAPMS-6125

@ygree ygree self-assigned this Sep 29, 2026
@ygree ygree added inst: jetty Jetty instrumentation inst: websocket WebSocket Instrumentation tag: ai generated Largely based on code generated by an AI or LLM labels Sep 29, 2026
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

🎯 Code Coverage (details)
• Patch Coverage: 100.00%
• Overall Coverage: 59.23% (-0.06%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 5052a0c | Docs | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.01 s 14.04 s [-1.0%; +0.6%] (no difference)
startup:insecure-bank:tracing:Agent 13.01 s 13.10 s [-1.5%; +0.1%] (no difference)
startup:petclinic:appsec:Agent 17.67 s 17.58 s [-0.4%; +1.5%] (no difference)
startup:petclinic:iast:Agent 17.54 s 17.63 s [-1.2%; +0.3%] (no difference)
startup:petclinic:profiling:Agent 17.49 s 17.49 s [-1.1%; +1.2%] (no difference)
startup:petclinic:sca:Agent 16.80 s 17.57 s [-8.5%; -0.4%] (maybe better)
startup:petclinic:tracing:Agent 16.62 s 16.82 s [-2.3%; -0.1%] (maybe better)

Commit: 5052a0c5 · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@ygree
ygree force-pushed the ygree/jetty-native-websockets branch 2 times, most recently from a44a0c1 to 3b33f1a Compare September 29, 2026 03:17

addTestSuiteForDir('latestDepTest', 'test')

tasks.named("compileMain_java17Java", JavaCompile) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Remove redundant settings. Additionally, I scanned the project for similar redundant settings and cleaned them up in #12689

@ygree
ygree force-pushed the ygree/jetty-native-websockets branch 5 times, most recently from a40e696 to 81e6e6c Compare September 29, 2026 22:45
Normalize text, binary, and close delegate return types to primitive void.

Simplify binary state synchronization under ReceiveContexts, preserve
separate text receiver locking, and resolve SpotBugs synchronization warnings.
Replace the binary template receiver with immutable handshake metadata.

Narrow the production dependency to jetty-websocket-jetty-common.
Add boxed-Void handler coverage and real-server receive tests verifying
links to the HTTP handshake span.
@ygree
ygree force-pushed the ygree/jetty-native-websockets branch 2 times, most recently from 50be9a5 to 1f751f6 Compare September 30, 2026 00:10
@ygree
ygree force-pushed the ygree/jetty-native-websockets branch from 31a2644 to 5052a0c Compare October 3, 2026 00:14
@ygree

ygree commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-03T01:38:05.690520Z 5052a0c Manual request
🔒 Security Review ✅ Completed 2026-10-03T01:32:12.490595Z 5052a0c Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 5052a0c550

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5052a0c550

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +74 to +75
if (payload != String.class && payload != ByteBuffer.class) {
return delegate;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Trace Reader and InputStream message handlers

For annotated native endpoints using Jetty's supported Reader or InputStream message signatures, the payload type fails this check and the original handle is returned unwrapped, so the handler executes without a websocket.receive span and its failures are not recorded. Jetty explicitly lists both streaming signatures as valid @OnWebSocketMessage patterns, so these handles need corresponding wrapping rather than being silently skipped.

Useful? React with 👍 / 👎.

AgentSpan span =
InstrumentationContext.get(Request.class, AgentSpan.class).get(response.getRequest());
try {
if (span != null && failure == null) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve failures swallowed by Jetty's upgrade method

When EndPoint.upgrade() fails after the HTTP 101 response, Jetty catches that throwable inside CoreClientUpgradeRequest.upgrade() and completes its session future exceptionally, so @Advice.Thrown is still null here; Jetty also marks the request upgraded, causing its response-completion path to skip listeners. The Jetty 12.0 implementation therefore makes this branch decorate and finish the handshake as a successful 101 even though connect() fails. The advice needs to observe that exceptional completion rather than treating every normal method return as a successful upgrade.

Useful? React with 👍 / 👎.

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

inst: jetty Jetty instrumentation inst: websocket WebSocket Instrumentation tag: ai generated Largely based on code generated by an AI or LLM

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant