Profiling cURL HTTP requests and Symfony Commands with Blackfire, when using the Symfony CLI
warning
In this post, I assume you already have a Symfony project that uses the Symfony CLI. If you're unfamiliar with Symfony CLI, you can refer to my French post about our new technical stack with Symfony CLI.
What is Blackfire?
Blackfire is a tool that allows you to profile your PHP applications.
You can use it for PHP scripts (like Symfony Commands) or for HTTP requests in your browser or via cURL. Blackfire provides detailed insights into the execution of your code, identifying bottlenecks and monitoring memory usage.
If you encounter any performance issues in your code, Blackfire is the most powerful tool to identify the root causes.
What's so special about the Symfony CLI
Symfony CLI comes with a Docker Compose integration and allows for per-project PHP version or settings.
This means you must use the Symfony CLI command symfony
to execute PHP scripts (e.g., symfony php ./my-script.php
) or a Symfony command (symfony console app:my-command
), depending on what you want to profile and how.
Profiling a PHP Script
To profile your PHP script, use blackfire run symfony php ./my-script.php
.
Profiling a Symfony command
For profiling Symfony commands, use blackfire run symfony console app:my-command
.
Profiling an HTTP request in your browser
You can use the Blackfire browser extension to profile an HTTP request in your browser.
After authenticating yourself to your Blackfire account, click on the extension icon, then the Profile
button.
tip
For profiling a POST
request or other methods involving data submission,
use Profile all requests
to automatically capture all HTTP requests during that period,
including XMLHttpRequest
and fetch
.
Profiling an HTTP request with cURL
Finally, this is the most interesting and complex part of the four.
Sometimes you might want to profile a cURL request (e.g.: you can change the request payload before sending it, scripting, ...), and for that, you can use blackfire curl
:
1$ blackfire curl https://my-symfony-app.wip 2 3(...) 4 5curl: (6) Could not resolve host: my-symfony-app.wip
What happened? To understand the problem, we must know how things work. How my-symfony-app.wip
can target a specific local web server?
Resolving local domain names
Here, my-symfony-app.wip
is a Local Domain Names.
To resolve local domain name to your web server (ran through symfony serve
), the Symfony CLI needs a Local Proxy.
Depending on your operating system and how you configured the Local Proxy, there is a high chance the Symfony CLI proxy is not globally configured.
It means you must tell cURL to use the Symfony Local Proxy to request your application.
Configure cURL to use a proxy
There are two ways to tell cURL to use a proxy:
- either pass the option
--proxy
followed by the proxy URL - either use environment variables
http_proxy
andhttps_proxy
(orHTTP_PROXY
andHTTPS_PROXY
, but we prefer the lowercase version)
It's a personal choice, but I prefer the second solution (env vars FTW).
Getting the Symfony Proxy URL
Before the Symfony CLI version 5.4.20, one programmatic way to get the Symfony Proxy URL is to play with file and string manipulations:
1$ echo $(cat ~/.symfony5/proxy.json | jq -r '(.host + ":" + (.port|tostring))') 2 3# will outputs something like "localhost:7080"
Since, there is a dedicated command to get the Symfony Proxy URL (thanks to me 😏):
1$ symfony local:proxy:url 2 3# will outputs something like "http://127.0.0.1:7080"
Using a Bash script wrapper
To simplify the process, we create a Bash script wrapper bin/blackfire
,
to automatically export HTTP_PROXY
and HTTPS_PROXY
environment variables before running Blackfire:
1#!/usr/bin/env bash 2 3# Check for Blackfire binary 4if [[ ! -x "$(command -v blackfire)" ]]; then 5 echo "Unable to find the Blackfire binary, please follow the installation instructions at https://www.notion.so/wamiz/Installation-b9dbc1a1f3a14ba29f3fa5031c60e57e" 6 exit 1; 7fi; 8 9export HTTP_PROXY=$(symfony proxy:url) 10export HTTPS_PROXY=$(symfony proxy:url) 11 12blackfire $@
This solution is easy to understand, maintain, share with your team, and update for additional options.
You can use it as follows:
1$ bin/blackfire curl https://my-symfony-app.wip 2$ bin/blackfire run symfony console app:my-command 3$ bin/blackfire run symfony php ./my-script.php
Bonus: Automatically Configure the Blackfire Environment
Although there is no global configuration option for the default Blackfire environnement, you can update the Bash script wrapper to automatically configure it:
1#!/usr/bin/env bash 2 3if [[ ! -x "$(command -v blackfire)" ]]; then 4 echo "Unable to find the Blackfire binary." 5 exit 1; 6fi; 7 8export HTTP_PROXY=$(symfony proxy:url) 9export HTTPS_PROXY=$(symfony proxy:url) 10 11ARGS=() 12for arg in "$@"; do 13 if [[ $arg == 'curl' ]] || [[ $arg == 'run' ]]; then 14 ARGS+=("$arg") 15 # Update your Blackfire environnement UUID here 16 ARGS+=("--env=aaaaaaaa-bbbb-cccc-dddd-efghijklmnop") 17 ARGS+=("--") 18 else 19 ARGS+=("$arg") 20 fi 21done 22 23blackfire ${ARGS[@]}