Skip to content

feat: add optional span context processor - #267

Open
pauldambra wants to merge 2 commits into
mainfrom
posthog/php-otel-span-context
Open

pauldambra wants to merge 2 commits into
mainfrom
posthog/php-otel-span-context

Conversation

@pauldambra

Copy link
Copy Markdown
Member

[Robot] Prepared with PostHog Desktop on behalf of @pauldambra.

💡 Motivation and Context

Backend developers need to connect a browser session to application spans when they investigate errors. Existing PHP request context only enriches analytics events.

  • Add the optional PostHog\OpenTelemetry\ContextSpanProcessor(Client $client) to the application's existing tracing provider.
  • Capture sessionId and posthogDistinctId on child spans when they start. Preserve explicit attributes and existing attributes at capacity.
  • Enrich the active request span when the registered client's withContext() scope starts. Keep OpenTelemetry optional and preserve application tracing setup.
  • Skip the active-span lookup in Fibers because uninitialized OpenTelemetry storage can return another execution path's span. Fiber child spans use their own context.
  • Require explicit context propagation into new Fibers and queue jobs. Recognize the canonical identity attributes only.

Tracks sdk-specs#128. Follows the proposed bridge contract in sdk-specs#129, with the documented incoming Fiber span limit.

💚 How did you test it?

  • PHPUnit regression cases cover request and child spans, explicit values, capacity, client and Fiber isolation, cleanup, opt-in registration, and lookup failures.
  • Real Laravel guide middleware uses Illuminate 12.70.0 requests and responses to check exported spans after success and failure.
  • A production Composer install checks operation without OpenTelemetry. Compatibility checks cover OpenTelemetry SDK 1.0.0 and 1.15.0.
  • Run the public API snapshot check, Composer validation, and PHP_CodeSniffer on changed PHP files.

The full PHPUnit suite reports existing deprecation notices. OpenTelemetry SDK 1.0.0 also emits nullable-parameter notices on PHP 8.5.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm change to generate a change intent file

🤖 Agent context

Autonomy: Human-driven (agent-assisted).

GPT-6 (Codex) implemented this change with PostHog Desktop. Skills: writing-tests, writing-code-comments, writing-user-facing-copy, writing-pr-descriptions, and backchannels.

The processor uses public OpenTelemetry span APIs. The Fiber limit avoids private context storage access and unsafe enrichment across execution paths. Human review is required.


Created with PostHog Desktop

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

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-lib_curl Compliance Report

Date: 2026-10-18T10:54:09.878886+00:00
Duration: 118840ms

✅ All Tests Passed!

47/47 tests passed


Capture Tests

✅ 30/30 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 28ms
Format Validation.Event Has Uuid ✅ 521ms
Format Validation.Event Has Lib Properties ✅ 524ms
Format Validation.Distinct Id Is String ✅ 523ms
Format Validation.Token Is Present ✅ 523ms
Format Validation.Custom Properties Preserved ✅ 523ms
Format Validation.Event Has Timestamp ✅ 523ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 525ms
Retry Behavior.Retries On 503 ✅ 5831ms
Retry Behavior.Does Not Retry On 400 ✅ 2526ms
Retry Behavior.Does Not Retry On 401 ✅ 2526ms
Retry Behavior.Respects Retry After Header ✅ 8529ms
Retry Behavior.Implements Backoff ✅ 16249ms
Retry Behavior.Retries On 500 ✅ 5633ms
Retry Behavior.Retries On 502 ✅ 5630ms
Retry Behavior.Retries On 504 ✅ 5634ms
Retry Behavior.Max Retries Respected ✅ 17047ms
Deduplication.Generates Unique Uuids ✅ 231ms
Deduplication.Preserves Uuid On Retry ✅ 5631ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10840ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5636ms
Deduplication.No Duplicate Events In Batch ✅ 530ms
Deduplication.Different Events Have Different Uuids ✅ 527ms
Compression.Sends Gzip When Enabled ✅ 525ms
Batch Format.Uses Proper Batch Structure ✅ 524ms
Batch Format.Flush With No Events Sends Nothing ✅ 519ms
Batch Format.Multiple Events Batched Together ✅ 513ms
Error Handling.Does Not Retry On 403 ✅ 2526ms
Error Handling.Does Not Retry On 413 ✅ 2527ms
Error Handling.Retries On 408 ✅ 5631ms

Feature_Flags Tests

✅ 17/17 tests passed

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

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-fork_curl Compliance Report

Date: 2026-10-18T10:53:56.752027+00:00
Duration: 112386ms

⚠️ Some Tests Failed

36/47 tests passed, 11 failed


Capture Tests

⚠️ 19/30 tests passed, 11 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 33ms
Format Validation.Event Has Uuid ✅ 528ms
Format Validation.Event Has Lib Properties ✅ 530ms
Format Validation.Distinct Id Is String ✅ 531ms
Format Validation.Token Is Present ✅ 530ms
Format Validation.Custom Properties Preserved ✅ 531ms
Format Validation.Event Has Timestamp ✅ 529ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 531ms
Retry Behavior.Retries On 503 ❌ 5534ms
Retry Behavior.Does Not Retry On 400 ✅ 2533ms
Retry Behavior.Does Not Retry On 401 ✅ 2531ms
Retry Behavior.Respects Retry After Header ❌ 5536ms
Retry Behavior.Implements Backoff ❌ 15535ms
Retry Behavior.Retries On 500 ❌ 5049ms
Retry Behavior.Retries On 502 ❌ 5533ms
Retry Behavior.Retries On 504 ❌ 5534ms
Retry Behavior.Max Retries Respected ❌ 15547ms
Deduplication.Generates Unique Uuids ✅ 539ms
Deduplication.Preserves Uuid On Retry ❌ 5534ms
Deduplication.Preserves Uuid And Timestamp On Retry ❌ 10542ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ❌ 5539ms
Deduplication.No Duplicate Events In Batch ✅ 536ms
Deduplication.Different Events Have Different Uuids ✅ 532ms
Compression.Sends Gzip When Enabled ✅ 531ms
Batch Format.Uses Proper Batch Structure ✅ 532ms
Batch Format.Flush With No Events Sends Nothing ✅ 518ms
Batch Format.Multiple Events Batched Together ✅ 521ms
Error Handling.Does Not Retry On 403 ✅ 2533ms
Error Handling.Does Not Retry On 413 ✅ 2533ms
Error Handling.Retries On 408 ❌ 5534ms

Failures

retry_behavior.retries_on_503

Expected at least 3 requests, got 1

retry_behavior.respects_retry_after_header

Expected at least 2 requests, got 1

retry_behavior.implements_backoff

Expected at least 3 requests, got 1

retry_behavior.retries_on_500

Expected at least 2 requests, got 1

retry_behavior.retries_on_502

Expected at least 2 requests, got 1

retry_behavior.retries_on_504

Expected at least 2 requests, got 1

retry_behavior.max_retries_respected

Expected 4 requests, got 1

deduplication.preserves_uuid_on_retry

Need at least 2 requests to check retry

deduplication.preserves_uuid_and_timestamp_on_retry

Expected at least 3 requests, got 1

deduplication.preserves_uuid_and_timestamp_on_batch_retry

Expected at least 2 requests, got 1

error_handling.retries_on_408

Expected at least 2 requests, got 1

Feature_Flags Tests

✅ 17/17 tests passed

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

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-socket Compliance Report

Date: 2026-10-18T10:54:36.178474+00:00
Duration: 149730ms

⚠️ Some Tests Failed

36/47 tests passed, 11 failed


Capture Tests

⚠️ 19/30 tests passed, 11 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 26ms
Format Validation.Event Has Uuid ✅ 520ms
Format Validation.Event Has Lib Properties ✅ 522ms
Format Validation.Distinct Id Is String ✅ 522ms
Format Validation.Token Is Present ✅ 522ms
Format Validation.Custom Properties Preserved ✅ 521ms
Format Validation.Event Has Timestamp ✅ 522ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 522ms
Retry Behavior.Retries On 503 ❌ 9229ms
Retry Behavior.Does Not Retry On 400 ✅ 2528ms
Retry Behavior.Does Not Retry On 401 ✅ 2525ms
Retry Behavior.Respects Retry After Header ❌ 9232ms
Retry Behavior.Implements Backoff ❌ 19246ms
Retry Behavior.Retries On 500 ❌ 9235ms
Retry Behavior.Retries On 502 ❌ 9232ms
Retry Behavior.Retries On 504 ❌ 9237ms
Retry Behavior.Max Retries Respected ❌ 19245ms
Deduplication.Generates Unique Uuids ✅ 531ms
Deduplication.Preserves Uuid On Retry ❌ 9232ms
Deduplication.Preserves Uuid And Timestamp On Retry ❌ 14239ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ❌ 9237ms
Deduplication.No Duplicate Events In Batch ✅ 531ms
Deduplication.Different Events Have Different Uuids ✅ 525ms
Compression.Sends Gzip When Enabled ✅ 522ms
Batch Format.Uses Proper Batch Structure ✅ 522ms
Batch Format.Flush With No Events Sends Nothing ✅ 518ms
Batch Format.Multiple Events Batched Together ✅ 513ms
Error Handling.Does Not Retry On 403 ✅ 2524ms
Error Handling.Does Not Retry On 413 ✅ 2525ms
Error Handling.Retries On 408 ❌ 5529ms

Failures

retry_behavior.retries_on_503

Expected at least 3 requests, got 1

retry_behavior.respects_retry_after_header

Expected at least 2 requests, got 1

retry_behavior.implements_backoff

Expected at least 3 requests, got 1

retry_behavior.retries_on_500

Expected at least 2 requests, got 1

retry_behavior.retries_on_502

Expected at least 2 requests, got 1

retry_behavior.retries_on_504

Expected at least 2 requests, got 1

retry_behavior.max_retries_respected

Expected 4 requests, got 1

deduplication.preserves_uuid_on_retry

Need at least 2 requests to check retry

deduplication.preserves_uuid_and_timestamp_on_retry

Expected at least 3 requests, got 1

deduplication.preserves_uuid_and_timestamp_on_batch_retry

Expected at least 2 requests, got 1

error_handling.retries_on_408

Expected at least 2 requests, got 1

Feature_Flags Tests

✅ 17/17 tests passed

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

@pauldambra

pauldambra commented Oct 17, 2026 •

Copy link
Copy Markdown
Member Author

Note

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

Verdict: ✅ APPROVE (privacy round @ f6701b3)

A client with no project key keeps request context but adds no span attributes. Review found that the first version also hid getContext() for disabled clients, which already ships on main; the gate now lives only in the internal span helper.

Checks

Full suite passes (810 tests). Public API is unchanged. Remaining test deprecations and two long-line warnings also exist on main and are not part of this PR.

Earlier rounds

Verdict: ✅ APPROVE (round 1 @ aa3464c)

No remaining actionable finding in the reviewed change. Per-client registration, explicit attributes, and optional runtime support were checked. The documented incoming Fiber span limit remains.

Key findings

  • None remain in this revision. Existing focused tests and completed independent review coverage were reused.
  • Human review and the shared specification decision remain required. This comment does not approve a merge or release.

Convergence

No remaining duplicate finding.

Reviewer summaries

Reviewer Assessment
Router (gpt-6-sol) Complexity HIGH, confidence HIGH. Completed independent API and concurrency coverage was reused. No further delegation was needed.

Automated by QA Swarm. Human review is required. This comment does not approve a merge or release.

Generated-By: PostHog Desktop
Task-Id: bfd18848-e498-4352-a58a-b9ba85de4198

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.

1 participant