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, but how can you achieve periodic builds for consumers? As you might have guessed, this is a matter of configuring a cron job:
1 2
# generate a profile every hour
0 * * * * pkill -SIGUSR1 -f consumer.php
If you want to be notified whenever some tests fail, create builds and configure a notification channel to receive build statuses and reports.
The PHP SDK provides everything you need to start builds programmatically (see
below), but LoopClient
makes it even easier. Call generateBuilds()
and
pass it the environment name or UUID:
1
$blackfire->generateBuilds('ENV_NAME_OR_UUID');
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.
Creating builds via the SDK is another very powerful feature, which looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// create a build
$build = $blackfire->startBuild('example_env', array('title' => 'Build from PHP'));
// create a scenario
$scenario = $blackfire->startScenario($build, array('title' => 'My first scenario'));
// add some profiles to the scenario, see below
// end the scenario and fetch the report
$report = $blackfire->closeScenario($scenario);
// end the build
$blackfire->closeBuild($build);
// print the report URL
print $report->getUrl();
Attaching profiles to a build can be done via the profile configuration:
1 2 3 4 5
// create a configuration
$config = new \Blackfire\Profile\Configuration();
// attach the scenario
$config->setScenario($scenario);
How do you generate profiles now? There are so many ways that it is up to you!
Use the SDK to generate profiles for the current executed code:
1 2 3 4 5 6 7 8
// generate a profile via the SDK
$probe = $blackfire->createProbe($config);
// some PHP code you want to profile
$blackfire->endProbe($probe);
// generate some other profiles if that makes sense
Or use Guzzle for HTTP requests:
1 2 3 4
// generate a profile with Guzzle
$response = $guzzle->request('GET', $url, array(
'blackfire' => $config,
));
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.
The next logical step for the last recipe would be to generate dynamic scenarios and store the results in build, taking flexibility to the next level. This is a great topic for the next chapter.