The PHP SDK allows to programmatically control Blackfire. We have already covered how to leverage the SDK in unit tests and how to use the SDK to profile consumers and daemons in previous chapters. This chapter outlines several advanced usages of the PHP SDK. Hopefully these examples will inspire you to create your own implementations. Your imagination is really the only limit here.
In a previous chapter, we used the LoopClient
class to instrument consumers:
1 2 3 4 5 6 7 8 9
while (true) {
$blackfire->startLoop($profileConfig);
consume();
$blackfire->endLoop();
usleep(400000);
}
If you read the documentation about how to profile consumers, you should be familiar with using signals to instrument your production code. It works like this:
1 2 3 4
use Blackfire\LoopClient;
$blackfire = new LoopClient(new Client(), 10);
$blackfire->setSignal(SIGUSR1);
startLoop() and endLoop() are effectively no-ops. This is perfect
for production.When the process receives the configured signal (SIGUSR1 in the example),
Blackfire instruments the code for the next 10 iterations (as configured
above), generates a profile, and disables instrumentation again.
When Blackfire's servers receive the profile, associated tests are run.
Whenever you want to better understand the status of one of your consumers, signal it once and be done. That gives you on-demand profiles. To profile consumers on a regular basis, configure a cron job that signals the process:
1 2
# generate a profile every hour
0 * * * * pkill -SIGUSR1 -f consumer.php
And you have it: a fully automated way to continuously profile consumers, monitor their intrinsic performance, and their performance evolution over time.
When using the browser extension or the Blackfire CLI tool to trigger a profile, there is no need to change the code. Blackfire takes care of everything for you. But what if you want to profile only part of the executed code? That's possible by explicitly marking the code you want to profile.
Do not confuse using the PHP SDK to manually create profiles (which does not need the browser extension or the CLI tool) with manually instrumenting the code with the SDK, which helps Blackfire generate precise profiles when triggered by the browser extension or CLI tool.
First, retrieve the current probe:
1 2
// Get the probe main instance
$probe = \BlackfireProbe::getMainInstance();
Then, call enable() to start the profiling and disable() to stop it:
1 2 3 4 5 6 7
// start profiling the code
$probe->enable();
// code that you want to profile
// stop the profiling
$probe->disable();
You do not need to install the Blackfire SDK to benefit from this feature
as the BlackfireProbe class is part of the Blackfire C extension.
You can mark as many sections as you want, but be warned that all sections are going to be part of the same call graph. Including too many unrelated sections will generate a convoluted, useless profile.
As soon as you explicitly call enable() in your code, Blackfire understands
that you want to control what to instrument and disables auto-instrumentation.
As with auto-instrumentation, profiling is only active when the code is run through the browser extension or the Blackfire CLI utility. If a profile has not been triggered, calls to the probe are just ignored.
Some projects consist of a set of micro-services written in PHP, all communicating via HTTP. When profiling a user-facing HTTP request for such a project, the call graph contains many HTTP calls for which Blackfire only displays the URL and the wall time. If one of the requests is slow, you need to manually trigger another profile against that micro-service in order to understand the bottlenecks.
Wouldn't it be great if you could automatically generate profiles for these API calls? The implementation depends on the HTTP library you are using to make your API calls, but the general idea looks like this:
1 2 3 4 5 6 7 8 9 10
$probe = \BlackfireProbe::getMainInstance();
if ($probe->getResponseLine()) {
$client = new \Blackfire\Client();
$request = $client->createRequest();
$header = 'X-Blackfire-Query: '.$request->getToken();
// add the header to the external HTTP request call
}
If you are using Guzzle, you can simplify the code as Blackfire provides a native integration:
1 2 3 4 5 6 7 8
$options = array();
$probe = \BlackfireProbe::getMainInstance();
if ($probe->getResponseLine()) {
$options['blackfire'] = true;
}
$response = $guzzle->request('GET', $url, $options);
You can find more information about profiling HTTP requests with the PHP SDK in the documentation.
Blackfire exposes a lot of features through the PHP SDK. This chapter showed you various ways to use the SDK to solve advanced use cases.