Sdk telemetry header - #114
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
WalkthroughThe SDK now emits anonymous telemetry headers by default. It stores the last completed call per client, supports opt-out through the builder, serializes telemetry using structured fields, and keeps customer telemetry adapters independent. ChangesSDK telemetry
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client as ChargebeeClient
participant Executor as TelemetryExecutor
participant Emitter as SdkTelemetryEmitter
participant Transport as API transport
Client->>Executor: execute request
Executor->>Emitter: emit SDK telemetry
Emitter->>Transport: send request with prior-call header
Transport-->>Emitter: response or API error
Emitter->>Client: record completed snapshot
Possibly related PRs
🚥 Pre-merge checks | ❌ 1❌ Failed checks (1 warning)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/java/com/chargebee/v4/telemetry/SdkTelemetryHeaderBuilder.java`:
- Around line 110-141: Update appendBareParam to use the value unquoted only
when isSfToken returns true; otherwise serialize it with escapeSfString. Ensure
values containing characters outside the RFC 9651 sf-string ASCII range are
rejected, including validation in the path also covered by the related call
site, and update the test expectation so versions such as 4.14.0 are emitted as
escaped sf-strings.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Enterprise
Run ID: 369497c2-82fe-419c-9cdc-afdea5fc43ea
📒 Files selected for processing (13)
README.mdsrc/main/java/com/chargebee/v4/client/ChargebeeClient.javasrc/main/java/com/chargebee/v4/telemetry/SdkTelemetryEmitter.javasrc/main/java/com/chargebee/v4/telemetry/SdkTelemetryHeader.javasrc/main/java/com/chargebee/v4/telemetry/SdkTelemetryHeaderBuilder.javasrc/main/java/com/chargebee/v4/telemetry/SdkTelemetrySnapshot.javasrc/main/java/com/chargebee/v4/telemetry/SdkTelemetryState.javasrc/main/java/com/chargebee/v4/telemetry/TelemetryAdapterExecutor.javasrc/main/java/com/chargebee/v4/telemetry/TelemetryExecutor.javasrc/main/java/com/chargebee/v4/telemetry/TelemetrySupport.javasrc/test/java/com/chargebee/v4/telemetry/SdkTelemetryEmitterTest.javasrc/test/java/com/chargebee/v4/telemetry/SdkTelemetryHeaderBuilderTest.javasrc/test/java/com/chargebee/v4/telemetry/TelemetryExecutorTest.java
| /** Emits a bare {@code key=value}, or a quoted sf-string when the value needs escaping. */ | ||
| private static boolean appendBareParam(StringBuilder segment, String key, String value) { | ||
| if (!isNotBlank(value)) { | ||
| return false; | ||
| } | ||
| if (containsInvalidSfStringChar(value)) { | ||
| return false; | ||
| } | ||
| String trimmed = value.trim(); | ||
| String serialized = isBareSafe(trimmed) ? trimmed : escapeSfString(trimmed); | ||
| if (serialized == null) { | ||
| return false; | ||
| } | ||
| segment.append(';').append(key).append('=').append(serialized); | ||
| return true; | ||
| } | ||
|
|
||
| /** Whether {@code value} can be emitted unquoted without corrupting the sf-list. */ | ||
| private static boolean isBareSafe(String value) { | ||
| for (int i = 0; i < value.length(); i++) { | ||
| char ch = value.charAt(i); | ||
| if (ch == '"' | ||
| || ch == '\\' | ||
| || ch == ',' | ||
| || ch == ';' | ||
| || ch == '=' | ||
| || Character.isWhitespace(ch)) { | ||
| return false; | ||
| } | ||
| } | ||
| return !value.isEmpty(); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Serialize only valid structured-field values.
appendBareParam emits version=4.14.0 for normal SDK versions. This is not a valid sf-token or sf-decimal. The telemetry server can reject the complete header.
Use an sf-token only when isSfToken returns true. Otherwise, emit an escaped sf-string. Reject all characters outside the RFC 9651 sf-string ASCII range. Update the test that expects the unquoted version.
Proposed fix
- String serialized = isBareSafe(trimmed) ? trimmed : escapeSfString(trimmed);
+ String serialized = isSfToken(trimmed) ? trimmed : escapeSfString(trimmed);- if (ch == '\0' || ch == '\n' || ch == '\r') {
+ if (ch < 0x20 || ch > 0x7E) {
return true;
}Also applies to: 186-195
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/com/chargebee/v4/telemetry/SdkTelemetryHeaderBuilder.java`
around lines 110 - 141, Update appendBareParam to use the value unquoted only
when isSfToken returns true; otherwise serialize it with escapeSfString. Ensure
values containing characters outside the RFC 9651 sf-string ASCII range are
rejected, including validation in the path also covered by the related call
site, and update the test expectation so versions such as 4.14.0 are emitted as
escaped sf-strings.
TBA
Added opt-out SDK telemetry with per-client state and RFC 9651
Preferheaders. Added telemetry emission for sync and async requests, including status, errors, request IDs, timing, and feature tokens. Separated SDK telemetry from customer adapters. Added documentation and comprehensive tests.