Skip to content

Comments

feat: add support for client reports#1192

Open
giortzisg wants to merge 27 commits intomasterfrom
feat/client-reports
Open

feat: add support for client reports#1192
giortzisg wants to merge 27 commits intomasterfrom
feat/client-reports

Conversation

@giortzisg
Copy link
Contributor

Description

add support for client reports.

Issues

Changelog Entry Instructions

To add a custom changelog entry, uncomment the section above. Supports:

  • Single entry: just write text
  • Multiple entries: use bullet points
  • Nested bullets: indent 4+ spaces

For more details: custom changelog entries

Reminders

@giortzisg giortzisg self-assigned this Feb 10, 2026
@linear
Copy link

linear bot commented Feb 10, 2026

GO-94 Add client reports

@github-actions
Copy link

github-actions bot commented Feb 10, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


Breaking Changes 🛠

  • Add support for go 1.26 by giortzisg in #1193
    • bump minimum supported go version to 1.24

New Features ✨

  • Add support for client reports by giortzisg in #1192
  • Log specific message for RequestEntityTooLarge by giortzisg in #1185

Bug Fixes 🐛

  • Ensure correct signal delivery on multi-client setups by giortzisg in #1190

Internal Changes 🔧

Deps

  • Bump golang.org/x/crypto to 0.48.0 by giortzisg in #1196
  • Use go1.24.0 by giortzisg in #1195
  • Bump github.com/gofiber/fiber/v2 from 2.52.9 to 2.52.11 in /fiber by dependabot in #1191
  • Bump getsentry/craft from 2.19.0 to 2.20.1 by dependabot in #1187

Other

  • Add omitzero and remove custom serialization by giortzisg in #1197
  • Rename Telemetry Processor components by giortzisg in #1186

🤖 This preview updates automatically when you update the PR.

@giortzisg giortzisg marked this pull request as ready for review February 12, 2026 12:45
Comment on lines +749 to 759
recordSpanOutcome(t.reporter, report.ReasonRateLimitBackoff, event)
return
}

request, err := getRequestFromEvent(ctx, event, t.dsn)
request, err := getRequestFromEvent(ctx, event, t.dsn, t.reporter)
if err != nil {
t.reporter.RecordOne(report.ReasonInternalError, category)
recordSpanOutcome(t.reporter, report.ReasonInternalError, event)
return
}

Copy link

Choose a reason for hiding this comment

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

Bug: reporter.TakeReport() is called before the HTTP request is sent. If the request fails, the client reports are lost because they were already removed from the aggregator.
Severity: HIGH

Suggested Fix

Only call reporter.TakeReport() and attach the client report to the envelope after confirming the HTTP request was successful. Alternatively, if the request fails, re-add the taken report back to the aggregator so it can be sent with a future request.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: transport.go#L743-L759

Potential issue: In both `HTTPTransport` and `HTTPSyncTransport`, client reports are
retrieved from the aggregator via `reporter.TakeReport()` and attached to the event
envelope before the HTTP request is attempted. If this request subsequently fails due to
a network error, a server-side error (like a 500), or any other reason, the reports are
permanently lost. They have been removed from the aggregator but were never successfully
delivered, leading to under-reporting of dropped events.

Comment on lines 768 to 773
response, err := t.client.Do(request)
if err != nil {
debuglog.Printf("There was an issue with sending an event: %v", err)
t.reporter.RecordOne(report.ReasonNetworkError, category)
recordSpanOutcome(t.reporter, report.ReasonNetworkError, event)
return
Copy link

Choose a reason for hiding this comment

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

Bug: The asynchronous HTTPTransport fails to record a ReasonNetworkError in client reports when an HTTP request fails due to a network issue, unlike the synchronous transport.
Severity: MEDIUM

Suggested Fix

In the HTTPTransport worker, when t.client.Do(item.request) returns an error, call t.reporter.RecordOne(report.ReasonNetworkError, category) to record the dropped event before continuing the loop, mirroring the behavior of HTTPSyncTransport.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: transport.go#L768-L773

Potential issue: The asynchronous `HTTPTransport` does not record a client report when a
network error occurs during an event submission. The `t.client.Do(item.request)` call is
followed by a `continue` statement in the error path, but there is no call to
`t.reporter.RecordOne(report.ReasonNetworkError, ...)`. This leads to an under-counting
of dropped events caused by network issues. The synchronous `HTTPSyncTransport`
correctly handles this case, creating an inconsistency between the two transports.

Copy link

@cursor cursor bot left a comment

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 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

atomic.AddInt64(&b.dropped, int64(droppedCount))
if b.onDropped != nil {
for _, di := range oldestBucket.items {
b.recordDroppedItem(di)
Copy link

Choose a reason for hiding this comment

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

Dropped items not recorded when callback is unset

Medium Severity

In BucketedBuffer.handleOverflow for OverflowPolicyDropOldest, the recordDroppedItem calls for old bucket items are nested inside the if b.onDropped != nil block. Since onDropped is only ever set in tests (via SetDroppedCallback), these client report recordings never execute in production. Compare with RingBuffer, where recordDroppedItem is correctly placed outside the onDropped guard, and with the other overflow cases in BucketedBuffer itself (OverflowPolicyDropNewest, default) which also correctly record outside the guard.

Fix in Cursor Fix in Web

transport: transport,
dsn: dsn,
sdkInfo: sdkInfo,
reporter: report.GetAggregator(dsn.String()),
Copy link

Choose a reason for hiding this comment

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

Scheduler registry lookup uses normalized DSN key

Medium Severity

The Scheduler looks up the aggregator using dsn.String() (the parsed/reconstructed DSN), but the Client registers it using options.Dsn (the raw user-provided string). If the original DSN contains a redundant default port (e.g. https://key@host:443/1), Dsn.String() normalizes it to https://key@host/1, causing the lookup to return nil. The scheduler would then silently skip all client report recording and periodic sending. The ring buffers in setupTelemetryProcessor correctly use client.options.Dsn, making this inconsistency specific to the scheduler.

Additional Locations (1)

Fix in Cursor Fix in Web

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.

Add client reports

1 participant