Skip to content

Conversation

@smaddock
Copy link
Contributor

First attempt at auto-instrumentation for the client side of https://reactphp.org/http/

Tried to copy the structure and functionality I saw implemented here for Guzzle and HTTPlug, but let me know if I missed something, or those are out of date, the name needs to change, or you need anything else.

Had one of the ReactPHP core maintainers (@WyriHaximus) help iron out some kinks.

Examples are included for a few different ways of implementing the ReactPHP HTTP Browser.

Integration test covers 93% of the actual auto-instrumentation file (everything specific to ReactPHP.)

PHP_VERSION=8.3 make all is passing on this PR.

@smaddock smaddock requested a review from a team as a code owner May 13, 2025 01:14
@welcome
Copy link

welcome bot commented May 13, 2025

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

linux-foundation-easycla bot commented May 13, 2025

CLA Signed

The committers listed above are authorized under a signed CLA.

@brettmc
Copy link
Contributor

brettmc commented May 13, 2025

I guess the first question is, can this be (or could it be in the future) an auto-instrumentation for more parts of react? i.e., the framework/ecosystem, rather than just this component? Are there other components that could be useful to hook?

@brettmc
Copy link
Contributor

brettmc commented May 13, 2025

Two things are missing that I can see:

  • add to the top-level .github/workflows/php.yml so that the tests will be run
  • add to the top-level .gitsplit.yml so that we can publish to packagist

@smaddock
Copy link
Contributor Author

I guess the first question is, can this be (or could it be in the future) an auto-instrumentation for more parts of react? i.e., the framework/ecosystem, rather than just this component? Are there other components that could be useful to hook?

Absolutely. The other half of the HTTP library is a server, so that’s an obvious choice for what to instrument next. There are underlying socket and stream interfaces that might be beneficial to instrument for non-HTTP use-cases along with UDP and DNS interfaces, although it would be redundant if you instrumented all of them. At a higher level the async fibers could be auto instrumented, although I’m not sure how useful that would be as it is more in the weeds of how an application is built, and auto-instrumentation is more for the “edges”.

@smaddock
Copy link
Contributor Author

Two things are missing that I can see:

  • add to the top-level .github/workflows/php.yml so that the tests will be run
  • add to the top-level .gitsplit.yml so that we can publish to packagist

Updated

@codecov
Copy link

codecov bot commented May 13, 2025

Codecov Report

Attention: Patch coverage is 99.28058% with 1 line in your changes missing coverage. Please review.

Project coverage is 82.05%. Comparing base (e728534) to head (98bb078).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
...mentation/ReactPHP/src/ReactPHPInstrumentation.php 99.25% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##               main     #368      +/-   ##
============================================
+ Coverage     81.60%   82.05%   +0.44%     
- Complexity     1722     1771      +49     
============================================
  Files           133      136       +3     
  Lines          7269     7461     +192     
============================================
+ Hits           5932     6122     +190     
- Misses         1337     1339       +2     
Flag Coverage Δ
Aws 92.59% <ø> (ø)
Context/Swoole 0.00% <ø> (ø)
Instrumentation/CakePHP 20.40% <ø> (ø)
Instrumentation/CodeIgniter 73.55% <ø> (ø)
Instrumentation/Doctrine 92.72% <ø> (ø)
Instrumentation/ExtAmqp 88.48% <ø> (ø)
Instrumentation/ExtRdKafka 86.11% <ø> (ø)
Instrumentation/Guzzle 69.13% <ø> (ø)
Instrumentation/HttpAsyncClient 78.04% <ø> (ø)
Instrumentation/IO 70.68% <ø> (ø)
Instrumentation/Laravel 63.91% <ø> (ø)
Instrumentation/MongoDB 74.28% <ø> (ø)
Instrumentation/MySqli 95.81% <ø> (ø)
Instrumentation/PDO 94.21% <ø> (ø)
Instrumentation/Psr14 76.47% <ø> (ø)
Instrumentation/Psr15 89.15% <ø> (ø)
Instrumentation/Psr16 97.50% <ø> (ø)
Instrumentation/Psr18 77.46% <ø> (ø)
Instrumentation/Psr3 67.01% <ø> (ø)
Instrumentation/Psr6 97.61% <ø> (ø)
Instrumentation/ReactPHP 99.28% <99.28%> (?)
Instrumentation/Slim 86.11% <ø> (ø)
Instrumentation/Symfony 84.74% <ø> (ø)
Instrumentation/Yii 77.50% <ø> (ø)
Logs/Monolog 100.00% <ø> (ø)
Propagation/Instana 98.11% <ø> (?)
Propagation/ServerTiming 100.00% <ø> (ø)
Propagation/TraceResponse 100.00% <ø> (ø)
ResourceDetectors/Azure 91.66% <ø> (ø)
ResourceDetectors/Container 93.02% <ø> (ø)
Sampler/RuleBased 33.51% <ø> (ø)
Shims/OpenTracing 92.45% <ø> (ø)
Symfony 87.81% <ø> (ø)
Utils/Test 87.53% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...Instrumentation/ReactPHP/src/HeadersPropagator.php 100.00% <100.00%> (ø)
...mentation/ReactPHP/src/ReactPHPInstrumentation.php 99.25% <99.25%> (ø)

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e728534...98bb078. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@smaddock
Copy link
Contributor Author

smaddock commented May 14, 2025

Hmm. I wonder why make all didn’t catch those errors. I’ll look into it in a bit. Obviously missed something with code coverage too.

Edit: figured out how to use make as intended.

@brettmc
Copy link
Contributor

brettmc commented May 14, 2025

Absolutely. The other half of the HTTP library is a server, so that’s an obvious choice for what to instrument next.

Cool, that makes sense. I just wanted to check whether we shouldn't be naming this "React" to allow for other components, but the current approach seems sensible.

@smaddock
Copy link
Contributor Author

smaddock commented May 14, 2025

Absolutely. The other half of the HTTP library is a server, so that’s an obvious choice for what to instrument next.

Cool, that makes sense. I just wanted to check whether we shouldn't be naming this "React" to allow for other components, but the current approach seems sensible.

I debated between the current name and "ReactPHP"; I don't think I really have a preference. @WyriHaximus Maybe that naming discrepancy would be a candidate for deptrac?

@smaddock
Copy link
Contributor Author

Hmm. I wonder why make all didn’t catch those errors. I’ll look into it in a bit. Obviously missed something with code coverage too.

Okay, hopefully I got it right this time. Can we try the tests again?

@smaddock
Copy link
Contributor Author

Okay can we try once more please?

@smaddock
Copy link
Contributor Author

Woohoo! The tests for this component finally passed.

@WyriHaximus
Copy link

I guess the first question is, can this be (or could it be in the future) an auto-instrumentation for more parts of react? i.e., the framework/ecosystem, rather than just this component? Are there other components that could be useful to hook?

The HTTP component is the most high-level one, the rest are mainly building blocks for it and other context aware protocols. I'm also maintaining https://github.com/jakubkulhan/bunny/ and would love to see/do an autoinstrumentation for it. There is https://github.com/friends-of-reactphp/mysql and https://github.com/voryx/PgAsync on a database level, and https://github.com/clue/reactphp-redis/ for redis. I'm unsure if we should all put them into one component or split them across several.

I'm also reading up on all of this, how it works etc. One thing I need to figure out is how it all plays with (nested) fibers.

Absolutely. The other half of the HTTP library is a server, so that’s an obvious choice for what to instrument next.

Cool, that makes sense. I just wanted to check whether we shouldn't be naming this "React" to allow for other components, but the current approach seems sensible.

I debated between the current name and "ReactPHP"; I don't think I really have a preference. @WyriHaximus Maybe that naming discrepancy would be a candidate for deptrac?

With ReactJS becoming known as react we wanted to emphasise that we're a different project so we always put the PHP behind it.

I guess the first question is, can this be (or could it be in the future) an auto-instrumentation for more parts of react? i.e., the framework/ecosystem, rather than just this component? Are there other components that could be useful to hook?

Absolutely. The other half of the HTTP library is a server

Yes, yes please.

Having a look at the code as well now, will add some comments. Haven't fully caught up on everything so I might be asking obvious questions.

Comment on lines 34 to 36
hook(
Transaction::class,
'send',
Copy link

@WyriHaximus WyriHaximus May 14, 2025

Choose a reason for hiding this comment

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

This hook call is for the extension to intercept and do its magic, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

that's right, it registers the pre/post callbacks via the zend observer API, so that they are executed when that function is called.

Choose a reason for hiding this comment

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

Is this the preferred way, even for maintainers, to implement things? Because I do like that this doesn't add any code to projects directly and keeps the instrumentation isolated from a package's logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@WyriHaximus from https://opentelemetry.io/docs/specs/otel/overview/#instrumentation-libraries

The inspiration of the project is to make every library and application observable out of the box by having them call OpenTelemetry API directly. However, many libraries will not have such integration, and as such there is a need for a separate library

@smaddock
Copy link
Contributor Author

smaddock commented May 15, 2025

I guess the first question is, can this be (or could it be in the future) an auto-instrumentation for more parts of react? i.e., the framework/ecosystem, rather than just this component? Are there other components that could be useful to hook?

The HTTP component is the most high-level one, the rest are mainly building blocks for it and other context aware protocols. I'm also maintaining https://github.com/jakubkulhan/bunny/ and would love to see/do an autoinstrumentation for it. There is https://github.com/friends-of-reactphp/mysql and https://github.com/voryx/PgAsync on a database level, and https://github.com/clue/reactphp-redis/ for redis. I'm unsure if we should all put them into one component or split them across several.

I'm not a maintainer of any of the repos discussed here, so just my opinion, but from what I've read in the OpenTelemetry docs, the preferred approach for library maintainers would be to instrument their library's code directly. They would have more control over the signals generated, performance would be better, and it would be maintained by those who know how to maintain it the best.

Beyond instrumenting core PHP extensions and PSRs, it feels like the auto-instrumentation libraries in this repo are more of a kickstart until OpenTelemetry is more widely adopted.

(And since I don't control the ReactPHP code, this was a way for me to get the instrumentation I needed—even if OpenTelemetry rejected my PR, I could change the namespace and use it in our projects internally. That said, I also use Christian's Redis package, so I'll probably end up writing something for that too... maybe for that I'll see if he's open to a PR to add the instrumentation directly. 🤷 )

I debated between the current name and "ReactPHP"; I don't think I really have a preference.

With ReactJS becoming known as react we wanted to emphasise that we're a different project so we always put the PHP behind it.

I will update the naming from react-http/ReactHttp to reactphp/ReactPHP.

Edit: This has been changed.

The other half of the HTTP library is a server

Yes, yes please.

I have not used the server side; perhaps this is something @WyriHaximus you would consider adding once you're more familiar with OpenTelemetry?

@smaddock smaddock requested review from Nevay and brettmc May 15, 2025 04:31
@smaddock
Copy link
Contributor Author

smaddock commented May 15, 2025

Attention: Patch coverage is 92.06349% with 10 lines in your changes missing coverage. Please review.

Are there other Instrumentation components that have integration tests for the lines I’m missing coverage on? They seem to be almost universal but I was not seeing any existing tests for them.

Edit: I found coverage for everything except the hook::post() "bail if scope or context is not set" return.

@smaddock
Copy link
Contributor Author

@WyriHaximus
Copy link

I guess the first question is, can this be (or could it be in the future) an auto-instrumentation for more parts of react? i.e., the framework/ecosystem, rather than just this component? Are there other components that could be useful to hook?

The HTTP component is the most high-level one, the rest are mainly building blocks for it and other context aware protocols. I'm also maintaining https://github.com/jakubkulhan/bunny/ and would love to see/do an autoinstrumentation for it. There is https://github.com/friends-of-reactphp/mysql and https://github.com/voryx/PgAsync on a database level, and https://github.com/clue/reactphp-redis/ for redis. I'm unsure if we should all put them into one component or split them across several.

I'm not a maintainer of any of the repos discussed here, so just my opinion, but from what I've read in the OpenTelemetry docs, the preferred approach for library maintainers would be to instrument their library's code directly. They would have more control over the signals generated, performance would be better, and it would be maintained by those who know how to maintain it the best.

Beyond instrumenting core PHP extensions and PSRs, it feels like the auto-instrumentation libraries in this repo are more of a kickstart until OpenTelemetry is more widely adopted.

(And since I don't control the ReactPHP code, this was a way for me to get the instrumentation I needed—even if OpenTelemetry rejected my PR, I could change the namespace and use it in our projects internally. That said, I also use Christian's Redis package, so I'll probably end up writing something for that too... maybe for that I'll see if he's open to a PR to add the instrumentation directly. 🤷 )

IMHO lets focus on getting this in first, then look at the server part, and then figure out the rest. If @clue isn't open to it, I'm down to set it up through another package, whether that is here, or I host it. The same goes for the other databases I mentioned. I have no problem slapping another package at it.

I debated between the current name and "ReactPHP"; I don't think I really have a preference.

With ReactJS becoming known as react we wanted to emphasise that we're a different project so we always put the PHP behind it.

I will update the naming from react-http/ReactHttp to reactphp/ReactPHP.

Edit: This has been changed.

<3 👍

The other half of the HTTP library is a server

Yes, yes please.

I have not used the server side; perhaps this is something @WyriHaximus you would consider adding once you're more familiar with OpenTelemetry?

I'm down for that. Let me start with Bunny in one of my projects, which also does HTTP calls, so I can test the work here and get familiar with OT's systems. And figure out all the things 👍 . Thanks again for doing this @smaddock, it make me look at something I've been wanted to look at for ages but never got around doing 😅 .

@smaddock smaddock requested review from Nevay and brettmc May 16, 2025 04:49
@smaddock
Copy link
Contributor Author

This is hopefully getting pretty close. Thank you @brettmc @Nevay and @WyriHaximus for working with me on this lengthy PR discussion and for all the feedback; I really appreciate it!

Questions I still have:

  1. Should the examples stay where they are or move up to <contrib-root>/examples?
  2. Does the examples/README.md fulfill the two paragraphs under https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-client-span-duration or do we need to rework the library to instrument at a much lower level?
  3. Does a version number for this library need to be added somewhere or is that handled automatically?
  4. Should I manually add the badges to the README.md or is that handled automatically?
  5. Is there any other housekeeping needed for the first release of a new instrumentation library?

Once this is approved, if the Curl, Guzzle, and HttpAsyncClient libraries don't have specific maintainers, I'd kind of like to update those with some of the same changes y'all recommended here.

@brettmc
Copy link
Contributor

brettmc commented May 19, 2025

Should the examples stay where they are or move up to /examples?

I think where they are is fine, it makes sense for them to be with the associated code. The original examples dir was from back when we had a small number of packages.

Does the examples/README.md fulfill the two paragraphs under https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-client-span-duration or do we need to rework the library to instrument at a much lower level?

Do you mean the two dot points about when the span should start&finish? Can you paste-quote in the bits that concern you?

Does a version number for this library need to be added somewhere or is that handled automatically?

Automatically, i'll tag and release an initial version once it's merged

Should I manually add the badges to the README.md or is that handled automatically?

You should add

Is there any other housekeeping needed for the first release of a new instrumentation library?

I don't think so. gitsplit entry is the most important, and you've done that. I'll let you test dev-main and report back before tagging an initial 0.1.0 version.

@smaddock
Copy link
Contributor Author

Does the examples/README.md fulfill the two paragraphs under https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-client-span-duration or do we need to rework the library to instrument at a much lower level?

Do you mean the two dot points about when the span should start&finish? Can you paste-quote in the bits that concern you?

Specifically:

If there is any possibility for application code to not fully read the HTTP response (and for the HTTP client library to then have to clean up the HTTP response asynchronously), the HTTP client span SHOULD NOT be ended in this cleanup phase, and instead SHOULD end at some point after the HTTP response headers are fully read (or fail to be read).

and also:

Because of the potential for confusion around this, HTTP client library instrumentations SHOULD document their behavior around ending HTTP client spans.

@Nevay brought up earlier that the behavior of the spans differs based on how the Browser is called. I documented the differences in examples/README.md but it was unclear to me if that was sufficient or if we needed to make the span behavior consistent for all invocations (which I don’t even know if that is possible, but it would require instrumenting the lower level socket instead of how I am currently instrumenting the HTTP transaction level.)

@brettmc brettmc merged commit 9392573 into open-telemetry:main May 21, 2025
134 of 140 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in PHP Prioritized Backlog May 21, 2025
@brettmc
Copy link
Contributor

brettmc commented May 21, 2025

https://packagist.org/packages/open-telemetry/opentelemetry-auto-reactphp

@smaddock
Copy link
Contributor Author

smaddock commented May 21, 2025

@brettmc I'm using the Guzzle library here:

// http_build_query(parse_str()) is not idempotent, so using Guzzle’s Query class for now
if ($queryString !== '') {
$queryParameters = Query::parse($queryString);

Open to other suggestions though!

@smaddock smaddock deleted the react-http branch May 21, 2025 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants