Skip to content

fix: exception recording for Symfony sub-requests in instrumentation#569

Open
jvdlaar wants to merge 2 commits into
open-telemetry:mainfrom
jvdlaar:fix/symfony-subrequest-exception-recording
Open

fix: exception recording for Symfony sub-requests in instrumentation#569
jvdlaar wants to merge 2 commits into
open-telemetry:mainfrom
jvdlaar:fix/symfony-subrequest-exception-recording

Conversation

@jvdlaar
Copy link
Copy Markdown

@jvdlaar jvdlaar commented May 6, 2026

Fixes open-telemetry/opentelemetry-php#1844

Based on #494 but then with a test.

I wasn't able to install the dependencies locally so I made some changes there. Also the version in the previous PR wasn't really working for me either as the tests kept failing.

I added a test with claude as I'm not really familiar with the internals of Symfony. I'm adding this version to our own codebase to verify it in production for a couple of days. So I'll report on the success of that soon.

@jvdlaar jvdlaar requested a review from a team as a code owner May 6, 2026 14:31
@welcome
Copy link
Copy Markdown

welcome Bot commented May 6, 2026

Thanks for opening your first pull request! If you haven't yet signed our Contributor License Agreement (CLA), then please do so that we can accept your contribution. A link should appear shortly in this PR if you have not already signed one.

@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented May 6, 2026

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: jvdlaar / name: Johnny van de Laar (ff02b7d)

@jvdlaar
Copy link
Copy Markdown
Author

jvdlaar commented May 7, 2026

Here is an otel output to show the output in the otel collector:

casco-otel-collector  | 2026-05-07T13:19:03.474Z        info    Traces  {"resource": {"service.instance.id": "f8ba3f65-c74f-4390-bd13-3c95bbd83158", "service.name": "otelcol-contrib", "service.version": "0.151.0"}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "traces", "resource spans": 1, "spans": 2}
casco-otel-collector  | 2026-05-07T13:19:03.474Z        info    ResourceSpans #0
casco-otel-collector  | Resource SchemaURL: https://opentelemetry.io/schemas/1.38.0
casco-otel-collector  | Resource attributes:
casco-otel-collector  |      -> service.name: Str(casco-agent)
casco-otel-collector  |      -> host.name: Str(936e5de6f9ce)
casco-otel-collector  |      -> host.arch: Str(x86_64)
casco-otel-collector  |      -> os.type: Str(linux)
casco-otel-collector  |      -> os.description: Str(6.17.0-23-generic)
casco-otel-collector  |      -> os.name: Str(Linux)
casco-otel-collector  |      -> os.version: Str(#23-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 11 23:29:57 UTC 2026)
casco-otel-collector  |      -> process.runtime.name: Str(fpm-fcgi)
casco-otel-collector  |      -> process.runtime.version: Str(8.5.3)
casco-otel-collector  |      -> process.pid: Int(7)
casco-otel-collector  |      -> process.executable.path: Str(/usr/local/sbin/php-fpm)
casco-otel-collector  |      -> process.owner: Str(www-data)
casco-otel-collector  |      -> telemetry.sdk.name: Str(opentelemetry)
casco-otel-collector  |      -> telemetry.sdk.language: Str(php)
casco-otel-collector  |      -> telemetry.sdk.version: Str(1.14.0)
casco-otel-collector  |      -> telemetry.distro.name: Str(opentelemetry-php-instrumentation)
casco-otel-collector  |      -> telemetry.distro.version: Str(1.2.1)
casco-otel-collector  | ScopeSpans #0
casco-otel-collector  | ScopeSpans SchemaURL: https://opentelemetry.io/schemas/1.32.0
casco-otel-collector  | InstrumentationScope io.opentelemetry.contrib.php.symfony
casco-otel-collector  | Span #0
casco-otel-collector  |     Trace ID       : eceaa3b87dc91aba3aa568b872a2dd97
casco-otel-collector  |     Parent ID      : 17c99195538efafc
casco-otel-collector  |     ID             : 71419797a394c1ae
casco-otel-collector  |     Name           : GET error_controller
casco-otel-collector  |     Kind           : Internal
casco-otel-collector  |     Start time     : 2026-05-07 13:19:03.449233014 +0000 UTC
casco-otel-collector  |     End time       : 2026-05-07 13:19:03.460891733 +0000 UTC
casco-otel-collector  |     Status code    : Unset
casco-otel-collector  |     Status message :
casco-otel-collector  |     DroppedAttributesCount: 0
casco-otel-collector  |     DroppedEventsCount: 0
casco-otel-collector  |     DroppedLinksCount: 0
casco-otel-collector  | Attributes:
casco-otel-collector  |      -> code.function.name: Str(Symfony\Component\HttpKernel\HttpKernel::handle)
casco-otel-collector  |      -> code.file.path: Str(/app/vendor/symfony/http-kernel/HttpKernel.php)
casco-otel-collector  |      -> code.line.number: Int(69)
casco-otel-collector  |      -> url.full: Str(http://listing.local.casco.io/leadflow-listing/1234)
casco-otel-collector  |      -> http.request.method: Str(GET)
casco-otel-collector  |      -> url.scheme: Str(http)
casco-otel-collector  |      -> url.path: Str(/leadflow-listing/1234)
casco-otel-collector  |      -> user_agent.original: Str(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36)
casco-otel-collector  |      -> server.address: Str(listing.local.casco.io)
casco-otel-collector  |      -> server.port: Int(80)
casco-otel-collector  |      -> http.response.status_code: Int(500)
casco-otel-collector  | Span #1
casco-otel-collector  |     Trace ID       : eceaa3b87dc91aba3aa568b872a2dd97
casco-otel-collector  |     Parent ID      :
casco-otel-collector  |     ID             : 17c99195538efafc
casco-otel-collector  |     Name           : GET leadflow_listing_by_id
casco-otel-collector  |     Kind           : Server
casco-otel-collector  |     Start time     : 2026-05-07 13:19:03.440842913 +0000 UTC
casco-otel-collector  |     End time       : 2026-05-07 13:19:03.46264085 +0000 UTC
casco-otel-collector  |     Status code    : Error
casco-otel-collector  |     Status message :
casco-otel-collector  |     DroppedAttributesCount: 0
casco-otel-collector  |     DroppedEventsCount: 0
casco-otel-collector  |     DroppedLinksCount: 0
casco-otel-collector  | Attributes:
casco-otel-collector  |      -> code.function.name: Str(Symfony\Component\HttpKernel\HttpKernel::handle)
casco-otel-collector  |      -> code.file.path: Str(/app/vendor/symfony/http-kernel/HttpKernel.php)
casco-otel-collector  |      -> code.line.number: Int(69)
casco-otel-collector  |      -> url.full: Str(http://listing.local.casco.io/leadflow-listing/1234)
casco-otel-collector  |      -> http.request.method: Str(GET)
casco-otel-collector  |      -> url.scheme: Str(http)
casco-otel-collector  |      -> url.path: Str(/leadflow-listing/1234)
casco-otel-collector  |      -> user_agent.original: Str(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36)
casco-otel-collector  |      -> server.address: Str(listing.local.casco.io)
casco-otel-collector  |      -> server.port: Int(80)
casco-otel-collector  |      -> http.route: Str(leadflow_listing_by_id)
casco-otel-collector  |      -> http.response.status_code: Int(500)
casco-otel-collector  |      -> network.protocol.version: Str(1.1)
casco-otel-collector  |      -> http.response.body.size: Int(107092)
casco-otel-collector  | Events:
casco-otel-collector  | SpanEvent #0
casco-otel-collector  |      -> Name: exception
casco-otel-collector  |      -> Timestamp: 2026-05-07 13:19:03.4465849 +0000 UTC
casco-otel-collector  |      -> DroppedAttributesCount: 0
casco-otel-collector  |      -> Attributes::
casco-otel-collector  |           -> exception.type: Str(Assert\InvalidArgumentException)
casco-otel-collector  |           -> exception.message: Str(Value "<FALSE>" is not TRUE.)
casco-otel-collector  |           -> exception.stacktrace: Str(Assert.InvalidArgumentException: Value "<FALSE>" is not TRUE.
casco-otel-collector  |         at Assert.Assertion.createException(Assertion.php:2728)
casco-otel-collector  |         at Assert.Assertion.true(Assertion.php:1812)
casco-otel-collector  |         at LeadflowApi.Api.LeadflowListingController.findByListingId(LeadflowListingController.php:36)
casco-otel-collector  |         at Symfony.Component.HttpKernel.HttpKernel.handleRaw(HttpKernel.php:183)
casco-otel-collector  |         at Symfony.Component.HttpKernel.HttpKernel.handle(HttpKernel.php:76)
casco-otel-collector  |         at Symfony.Component.HttpKernel.Kernel.handle(Kernel.php:193)
casco-otel-collector  |         at {main}(index.php:28))
casco-otel-collector  |         {"resource": {"service.instance.id": "f8ba3f65-c74f-4390-bd13-3c95bbd83158", "service.name": "otelcol-contrib", "service.version": "0.151.0"}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "traces"

@jvdlaar
Copy link
Copy Markdown
Author

jvdlaar commented May 7, 2026

Improved the traces a little bit such that it now also has a status on the first span:

casco-otel-collector  | 2026-05-07T14:12:07.055Z        info    Traces  {"resource": {"service.instance.id": "f8ba3f65-c74f-4390-bd13-3c95bbd83158", "service.name": "otelcol-contrib", "service.version": "0.151.0"}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "traces", "resource spans": 1, "spans": 2}
casco-otel-collector  | 2026-05-07T14:12:07.055Z        info    ResourceSpans #0
casco-otel-collector  | Resource SchemaURL: https://opentelemetry.io/schemas/1.38.0
casco-otel-collector  | Resource attributes:
casco-otel-collector  |      -> service.name: Str(casco-agent)
casco-otel-collector  |      -> host.name: Str(936e5de6f9ce)
casco-otel-collector  |      -> host.arch: Str(x86_64)
casco-otel-collector  |      -> os.type: Str(linux)
casco-otel-collector  |      -> os.description: Str(6.17.0-23-generic)
casco-otel-collector  |      -> os.name: Str(Linux)
casco-otel-collector  |      -> os.version: Str(#23-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 11 23:29:57 UTC 2026)
casco-otel-collector  |      -> process.runtime.name: Str(fpm-fcgi)
casco-otel-collector  |      -> process.runtime.version: Str(8.5.3)
casco-otel-collector  |      -> process.pid: Int(8)
casco-otel-collector  |      -> process.executable.path: Str(/usr/local/sbin/php-fpm)
casco-otel-collector  |      -> process.owner: Str(www-data)
casco-otel-collector  |      -> telemetry.sdk.name: Str(opentelemetry)
casco-otel-collector  |      -> telemetry.sdk.language: Str(php)
casco-otel-collector  |      -> telemetry.sdk.version: Str(1.14.0)
casco-otel-collector  |      -> telemetry.distro.name: Str(opentelemetry-php-instrumentation)
casco-otel-collector  |      -> telemetry.distro.version: Str(1.2.1)
casco-otel-collector  | ScopeSpans #0
casco-otel-collector  | ScopeSpans SchemaURL: https://opentelemetry.io/schemas/1.32.0
casco-otel-collector  | InstrumentationScope io.opentelemetry.contrib.php.symfony
casco-otel-collector  | Span #0
casco-otel-collector  |     Trace ID       : d5316056aed4803476e8d7e1312e2fbb
casco-otel-collector  |     Parent ID      : 83b338aa5d4ef503
casco-otel-collector  |     ID             : c47e294e8e44e733
casco-otel-collector  |     Name           : GET error_controller
casco-otel-collector  |     Kind           : Internal
casco-otel-collector  |     Start time     : 2026-05-07 14:12:06.896182274 +0000 UTC
casco-otel-collector  |     End time       : 2026-05-07 14:12:06.907260255 +0000 UTC
casco-otel-collector  |     Status code    : Error
casco-otel-collector  |     Status message :
casco-otel-collector  |     DroppedAttributesCount: 0
casco-otel-collector  |     DroppedEventsCount: 0
casco-otel-collector  |     DroppedLinksCount: 0
casco-otel-collector  | Attributes:
casco-otel-collector  |      -> code.function.name: Str(Symfony\Component\HttpKernel\HttpKernel::handle)
casco-otel-collector  |      -> code.file.path: Str(/app/vendor/symfony/http-kernel/HttpKernel.php)
casco-otel-collector  |      -> code.line.number: Int(69)
casco-otel-collector  |      -> url.full: Str(http://listing.local.casco.io/leadflow-listing/1234)
casco-otel-collector  |      -> http.request.method: Str(GET)
casco-otel-collector  |      -> url.scheme: Str(http)
casco-otel-collector  |      -> url.path: Str(/leadflow-listing/1234)
casco-otel-collector  |      -> user_agent.original: Str(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36)
casco-otel-collector  |      -> server.address: Str(listing.local.casco.io)
casco-otel-collector  |      -> server.port: Int(80)
casco-otel-collector  |      -> http.response.status_code: Int(500)
casco-otel-collector  | Span #1
casco-otel-collector  |     Trace ID       : d5316056aed4803476e8d7e1312e2fbb
casco-otel-collector  |     Parent ID      :
casco-otel-collector  |     ID             : 83b338aa5d4ef503
casco-otel-collector  |     Name           : GET leadflow_listing_by_id
casco-otel-collector  |     Kind           : Server
casco-otel-collector  |     Start time     : 2026-05-07 14:12:06.887771108 +0000 UTC
casco-otel-collector  |     End time       : 2026-05-07 14:12:06.908452069 +0000 UTC
casco-otel-collector  |     Status code    : Error
casco-otel-collector  |     Status message :
casco-otel-collector  |     DroppedAttributesCount: 0
casco-otel-collector  |     DroppedEventsCount: 0
casco-otel-collector  |     DroppedLinksCount: 0
casco-otel-collector  | Attributes:
casco-otel-collector  |      -> code.function.name: Str(Symfony\Component\HttpKernel\HttpKernel::handle)
casco-otel-collector  |      -> code.file.path: Str(/app/vendor/symfony/http-kernel/HttpKernel.php)
casco-otel-collector  |      -> code.line.number: Int(69)
casco-otel-collector  |      -> url.full: Str(http://listing.local.casco.io/leadflow-listing/1234)
casco-otel-collector  |      -> http.request.method: Str(GET)
casco-otel-collector  |      -> url.scheme: Str(http)
casco-otel-collector  |      -> url.path: Str(/leadflow-listing/1234)
casco-otel-collector  |      -> user_agent.original: Str(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36)
casco-otel-collector  |      -> server.address: Str(listing.local.casco.io)
casco-otel-collector  |      -> server.port: Int(80)
casco-otel-collector  |      -> http.route: Str(leadflow_listing_by_id)
casco-otel-collector  |      -> http.response.status_code: Int(500)
casco-otel-collector  |      -> network.protocol.version: Str(1.1)
casco-otel-collector  |      -> http.response.body.size: Int(107092)
casco-otel-collector  | Events:
casco-otel-collector  | SpanEvent #0
casco-otel-collector  |      -> Name: exception
casco-otel-collector  |      -> Timestamp: 2026-05-07 14:12:06.893810486 +0000 UTC
casco-otel-collector  |      -> DroppedAttributesCount: 0
casco-otel-collector  |      -> Attributes::
casco-otel-collector  |           -> exception.type: Str(Assert\InvalidArgumentException)
casco-otel-collector  |           -> exception.message: Str(Value "<FALSE>" is not TRUE.)
casco-otel-collector  |           -> exception.stacktrace: Str(Assert.InvalidArgumentException: Value "<FALSE>" is not TRUE.
casco-otel-collector  |         at Assert.Assertion.createException(Assertion.php:2728)
casco-otel-collector  |         at Assert.Assertion.true(Assertion.php:1812)
casco-otel-collector  |         at LeadflowApi.Api.LeadflowListingController.findByListingId(LeadflowListingController.php:36)
casco-otel-collector  |         at Symfony.Component.HttpKernel.HttpKernel.handleRaw(HttpKernel.php:183)
casco-otel-collector  |         at Symfony.Component.HttpKernel.HttpKernel.handle(HttpKernel.php:76)
casco-otel-collector  |         at Symfony.Component.HttpKernel.Kernel.handle(Kernel.php:193)
casco-otel-collector  |         at {main}(index.php:28))
casco-otel-collector  |         {"resource": {"service.instance.id": "f8ba3f65-c74f-4390-bd13-3c95bbd83158", "service.name": "otelcol-contrib", "service.version": "0.151.0"}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "traces"}

I just can't seem to get a status message on the spans. It adds it in the handleThrowable, but subsequently throws it away in the terminate.

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.

[opentelemetry-php-contrib] [Symfony auto-instrumentation] Exception events not recorded on spans when Symfony handles errors via sub-request

1 participant