Skip to content

feat: add ambient trace context to exception events - #305

Merged
pauldambra merged 3 commits into
mainfrom
posthog/exception-trace-context
Oct 23, 2026
Merged

pauldambra merged 3 commits into
mainfrom
posthog/exception-trace-context

Conversation

@pauldambra

Copy link
Copy Markdown
Member

[Robot] Prepared with PostHog Desktop at a maintainer's request.

💡 Motivation and Context

Developers need to connect a captured error to the trace that contains the failing work.

  • Exception events now include the active OpenTelemetry span's $trace_id and $span_id.
  • IDs use fixed-width lowercase hex and retain leading zeros, including for unsampled spans.
  • Caller properties retain precedence. Missing, invalid, or unreadable context does not stop exception capture.
  • OpenTelemetry remains optional. A minor changeset covers the new behavior.

Note

This draft follows the proposed SDK contract and waits for agreement before merge.

💚 How did you test it?

  • Confirmed three new capture tests failed before implementation.
  • Ran the complete RSpec suite with the default bundle and the existing optional OpenTelemetry bundle.
  • Added parameterized capture tests for valid and invalid IDs, caller precedence, missing API, and lookup failures.
  • Ran real OpenTelemetry capture tests for sampled and unsampled spans, leading zeros, and context cleanup.
  • Ran RuboCop, the public API snapshot check, and a gem build on Ruby 3.3.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed. No existing scoped behavior document needs a change.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file. The changeset was added directly.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Codex, model gpt-6, used shell, Git, GitHub CLI, RSpec, and RuboCop. Skills: writing-tests, writing-pr-descriptions, and writing-user-facing-copy.

The change reads the application's active OpenTelemetry API at capture time. It adds no runtime dependency or public API.


Created with PostHog Desktop

Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96
@pauldambra pauldambra self-assigned this Oct 16, 2026
@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

posthog-ruby-async Compliance Report

Date: 2026-10-23T11:55:52.271335+00:00
Duration: 98064ms

⚠️ Some Tests Failed

46/47 tests passed, 1 failed


Capture Tests

✅ 30/30 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 106ms
Format Validation.Event Has Uuid ✅ 104ms
Format Validation.Event Has Lib Properties ✅ 106ms
Format Validation.Distinct Id Is String ✅ 105ms
Format Validation.Token Is Present ✅ 105ms
Format Validation.Custom Properties Preserved ✅ 105ms
Format Validation.Event Has Timestamp ✅ 106ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 6ms
Retry Behavior.Retries On 503 ✅ 5307ms
Retry Behavior.Does Not Retry On 400 ✅ 2107ms
Retry Behavior.Does Not Retry On 401 ✅ 2106ms
Retry Behavior.Respects Retry After Header ✅ 8113ms
Retry Behavior.Implements Backoff ✅ 15517ms
Retry Behavior.Retries On 500 ✅ 5211ms
Retry Behavior.Retries On 502 ✅ 5210ms
Retry Behavior.Retries On 504 ✅ 5208ms
Retry Behavior.Max Retries Respected ✅ 15721ms
Deduplication.Generates Unique Uuids ✅ 109ms
Deduplication.Preserves Uuid On Retry ✅ 5210ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10315ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5211ms
Deduplication.No Duplicate Events In Batch ✅ 108ms
Deduplication.Different Events Have Different Uuids ✅ 104ms
Compression.Sends Gzip When Enabled ✅ 103ms
Batch Format.Uses Proper Batch Structure ✅ 103ms
Batch Format.Flush With No Events Sends Nothing ✅ 3ms
Batch Format.Multiple Events Batched Together ✅ 105ms
Error Handling.Does Not Retry On 403 ✅ 2106ms
Error Handling.Does Not Retry On 413 ✅ 2106ms
Error Handling.Retries On 408 ✅ 5210ms

Feature_Flags Tests

⚠️ 16/17 tests passed, 1 failed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 105ms
Request Payload.Flags Request Uses V2 Query Param ✅ 105ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 105ms
Request Payload.Flags Request Omits Authorization Header ✅ 106ms
Request Payload.Token In Flags Body Matches Init ✅ 105ms
Request Payload.Groups Round Trip ✅ 103ms
Request Payload.Groups Default To Empty Object ✅ 104ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 105ms
Request Payload.Disable Geoip Omitted Defaults To False ❌ 103ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 104ms
Request Lifecycle.No Flags Request On Init Alone ✅ 1ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 104ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 108ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 104ms
Retry Behavior.Retries Flags On 502 ✅ 204ms
Retry Behavior.Retries Flags On 504 ✅ 205ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 106ms

Failures

request_payload.disable_geoip_omitted_defaults_to_false

Field 'geoip_disable' not found in /flags request body at path 'geoip_disable'. Available keys: ['distinct_id', 'groups', 'person_properties', 'group_properties', 'flag_keys_to_evaluate', 'token']

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

posthog-ruby-sync Compliance Report

Date: 2026-10-23T11:55:04.660873+00:00
Duration: 56285ms

⚠️ Some Tests Failed

39/47 tests passed, 8 failed


Capture Tests

⚠️ 23/30 tests passed, 7 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 10ms
Format Validation.Event Has Uuid ✅ 6ms
Format Validation.Event Has Lib Properties ✅ 6ms
Format Validation.Distinct Id Is String ✅ 10ms
Format Validation.Token Is Present ✅ 8ms
Format Validation.Custom Properties Preserved ✅ 7ms
Format Validation.Event Has Timestamp ✅ 7ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 7ms
Retry Behavior.Retries On 503 ✅ 5377ms
Retry Behavior.Does Not Retry On 400 ❌ 7ms
Retry Behavior.Does Not Retry On 401 ❌ 5ms
Retry Behavior.Respects Retry After Header ✅ 8016ms
Retry Behavior.Implements Backoff ❌ 311ms
Retry Behavior.Retries On 500 ✅ 5144ms
Retry Behavior.Retries On 502 ✅ 5116ms
Retry Behavior.Retries On 504 ✅ 5144ms
Retry Behavior.Max Retries Respected ❌ 629ms
Deduplication.Generates Unique Uuids ✅ 22ms
Deduplication.Preserves Uuid On Retry ✅ 5154ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10307ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5162ms
Deduplication.No Duplicate Events In Batch ✅ 18ms
Deduplication.Different Events Have Different Uuids ✅ 9ms
Compression.Sends Gzip When Enabled ✅ 7ms
Batch Format.Uses Proper Batch Structure ✅ 7ms
Batch Format.Flush With No Events Sends Nothing ✅ 3ms
Batch Format.Multiple Events Batched Together ❌ 19ms
Error Handling.Does Not Retry On 403 ❌ 6ms
Error Handling.Does Not Retry On 413 ❌ 5ms
Error Handling.Retries On 408 ✅ 5113ms

Failures

retry_behavior.does_not_retry_on_400

500, message='Internal Server Error', url='http://sdk-adapter:8080/capture'

retry_behavior.does_not_retry_on_401

500, message='Internal Server Error', url='http://sdk-adapter:8080/capture'

retry_behavior.implements_backoff

500, message='Internal Server Error', url='http://sdk-adapter:8080/capture'

retry_behavior.max_retries_respected

500, message='Internal Server Error', url='http://sdk-adapter:8080/capture'

batch_format.multiple_events_batched_together

Expected 1 requests, got 5

error_handling.does_not_retry_on_403

500, message='Internal Server Error', url='http://sdk-adapter:8080/capture'

error_handling.does_not_retry_on_413

500, message='Internal Server Error', url='http://sdk-adapter:8080/capture'

Feature_Flags Tests

⚠️ 16/17 tests passed, 1 failed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 10ms
Request Payload.Flags Request Uses V2 Query Param ✅ 9ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 9ms
Request Payload.Flags Request Omits Authorization Header ✅ 8ms
Request Payload.Token In Flags Body Matches Init ✅ 6ms
Request Payload.Groups Round Trip ✅ 7ms
Request Payload.Groups Default To Empty Object ✅ 7ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 7ms
Request Payload.Disable Geoip Omitted Defaults To False ❌ 7ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 6ms
Request Lifecycle.No Flags Request On Init Alone ✅ 3ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 6ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 9ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 8ms
Retry Behavior.Retries Flags On 502 ✅ 110ms
Retry Behavior.Retries Flags On 504 ✅ 109ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 8ms

Failures

request_payload.disable_geoip_omitted_defaults_to_false

Field 'geoip_disable' not found in /flags request body at path 'geoip_disable'. Available keys: ['distinct_id', 'groups', 'person_properties', 'group_properties', 'flag_keys_to_evaluate', 'token']

@pauldambra
pauldambra marked this pull request as ready for review October 16, 2026 11:58
@pauldambra
pauldambra requested a review from a team as a code owner October 16, 2026 11:58

@pauldambra pauldambra left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Note

🤖 Automated comment by QA Swarm — not written by a human

One request context priority defect found. See the inline comment.

Comment thread lib/posthog/client.rb
Generated-By: PostHog Desktop
Task-Id: 5681be44-4986-48db-b140-1bda88f75f96
@pauldambra

Copy link
Copy Markdown
Member Author

Note

🤖 Automated comment by QA Swarm — not written by a human

Review by a first-pass reviewer and focused follow-up reviews.

Verdict: ✅ APPROVE (round 2 @ 5b0177d)

No open code findings. Request and caller trace properties keep priority over derived IDs. This review does not remove the proposed SDK spec agreement hold.

Key findings

  • Fixed request trace property priority in 5b0177d6. Five of the seven regression cases failed before the fix. All seven pass after it. Both full bundles, RuboCop, and the public API check passed.
  • The second review found no further defect. The simplify review found no useful change.

Convergence

The first reviewer traced the request property merge defect. A second model accepted the small fix before it was applied. The follow-up review confirmed the final behavior.

Reviewer summaries

Reviewer Assessment
Router, gpt-6-sol Low danger, high confidence. The final fix preserves string and symbol request keys, nil and empty values, and explicit caller priority. No further review was needed.
Previous rounds (1)

Round 1 @ 9e7ace6: one request property priority defect. Fixed in 5b0177d after second-model validation.


Automated by QA Swarm — not a human review

Generated-By: PostHog Desktop
Task-Id: e73c8b25-9501-4f04-9fd8-e82415e1f9f9
@pauldambra
pauldambra merged commit f1aca86 into main Oct 23, 2026
25 checks passed
@pauldambra
pauldambra deleted the posthog/exception-trace-context branch October 23, 2026 12:12
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.

2 participants