128.io

Generating stacktrace on SIGHUP in PHP

2022-01-09

Context

A long-running process was consuming high CPU, and I needed to figure out what was happening. Adding the ability to generate a stack trace by sending the process a signal helped isolate what was going on.

Code

This script demonstrates how a stack trace can be generated when a PHP process receives the SIGHUP signal. Trapping other signals would work as well.

<?php

declare(strict_types=1);

pcntl_async_signals(true);

pcntl_signal(SIGHUP, function ($signal) {
    echo "HUP! {$signal} \n";
    error_log((new Exception())->getTraceAsString());
});

(new class
{
    function __invoke()
    {
        printf("kill -s HUP %d\n", getmypid());

        while (true) {
            sleep(255);
        }
    }
})();

Example

An example of the script in action:

# Running the script will print a command to run to send a signal to the
# running process.

$ php script.php

kill -s HUP 867403

# In another terminal, we run the command while the script is running:

$ kill -s HUP 867403

# The original process outputs that it received the signal, and prints a
# stack trace of the code that was executing when the signal was
# received.

HUP! 1
#0 /path/to/script.php(18): {closure}()
#1 /path/to/script.php(12): class@anonymous->__invoke()
#2 {main}