Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions sapi/fpm/fpm/fpm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1547,8 +1547,21 @@ PHP_FUNCTION(fastcgi_finish_request) /* {{{ */
}
/* }}} */

/* {{{ proto array fpm_get_status
* Returns the status of the fastcgi process manager */
PHP_FUNCTION(fpm_get_status) /* {{{ */
{
int error = fpm_status_export_to_zval(return_value);
if(error){
Copy link
Member

Choose a reason for hiding this comment

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

CS: missing spaces... If you don't need to use error later then this should do:

if (fpm_status_export_to_zval(return_value)) {

RETURN_FALSE;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should verbose this error

Copy link
Author

Choose a reason for hiding this comment

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

I will do that

}
}
/* }}} */


static const zend_function_entry cgi_fcgi_sapi_functions[] = {
PHP_FE(fastcgi_finish_request, NULL)
PHP_FE(fpm_get_status, NULL)
PHP_FE_END
};

Expand Down
99 changes: 98 additions & 1 deletion sapi/fpm/fpm/fpm_status.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/* (c) 2009 Jerome Loyet */

#include "php.h"
#include "zend_long.h"
#include "SAPI.h"
#include <stdio.h>

Expand Down Expand Up @@ -45,6 +46,103 @@ int fpm_status_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
}
/* }}} */

int fpm_status_export_to_zval(zval *status)
{
struct fpm_scoreboard_s scoreboard, *scoreboard_p;
zval fpm_proc_stats, fpm_proc_stat;
time_t now_epoch;
struct timeval duration, now;
double cpu;
int i;


scoreboard_p = fpm_scoreboard_acquire(NULL, 1);
if (!scoreboard_p) {
zlog(ZLOG_NOTICE, "[pool %s] status: scoreboard already in use.", scoreboard_p->pool);
return -1;
}

/* copy the scoreboard not to bother other processes */
scoreboard = *scoreboard_p;
struct fpm_scoreboard_proc_s procs[scoreboard.nprocs];

struct fpm_scoreboard_proc_s *proc_p;
for(i=0; i<scoreboard.nprocs; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

cs: for () {}

proc_p = fpm_scoreboard_proc_acquire(scoreboard_p, i, 1);
if (!proc_p){
procs[i].used=-1;
continue;
}
procs[i] = *proc_p;
fpm_scoreboard_proc_release(proc_p);
}
fpm_scoreboard_release(scoreboard_p);

now_epoch = time(NULL);
fpm_clock_get(&now);

array_init(status);
add_assoc_string(status, "pool", scoreboard.pool);
add_assoc_string(status, "process-manager", PM2STR(scoreboard.pm));
add_assoc_long(status, "start-time", scoreboard.start_epoch);
add_assoc_long(status, "start-since", now_epoch - scoreboard.start_epoch);
add_assoc_long(status, "accepted-conn", scoreboard.requests);
#ifdef HAVE_FPM_LQ
add_assoc_long(status, "listen-queue", scoreboard.lq);
add_assoc_long(status, "max-listen-queue", scoreboard.lq_max);
add_assoc_long(status, "listen-queue-len", scoreboard.lq_len);
#endif
add_assoc_long(status, "idle-processes", scoreboard.idle);
add_assoc_long(status, "active-processes", scoreboard.active);
add_assoc_long(status, "total-processes", scoreboard.idle + scoreboard.active);
add_assoc_long(status, "max-active-processes", scoreboard.active_max);
add_assoc_long(status, "max-children-reached", scoreboard.max_children_reached);
add_assoc_long(status, "slow-requests", scoreboard.slow_rq);

array_init(&fpm_proc_stats);
for(i=0; i<scoreboard.nprocs; i++) {
if (!procs[i].used) {
continue;
}
proc_p = &procs[i];
#ifdef HAVE_FPM_LQ
/* prevent NaN */
if (procs[i].cpu_duration.tv_sec == 0 && procs[i].cpu_duration.tv_usec == 0) {
cpu = 0.;
} else {
cpu = (procs[i].last_request_cpu.tms_utime + procs[i].last_request_cpu.tms_stime + procs[i].last_request_cpu.tms_cutime + procs[i].last_request_cpu.tms_cstime) / fpm_scoreboard_get_tick() / (procs[i].cpu_duration.tv_sec + procs[i].cpu_duration.tv_usec / 1000000.) * 100.;
}
#endif

array_init(&fpm_proc_stat);
add_assoc_long(&fpm_proc_stat, "pid", procs[i].pid);
add_assoc_string(&fpm_proc_stat, "state", fpm_request_get_stage_name(procs[i].request_stage));
add_assoc_long(&fpm_proc_stat, "start-time", procs[i].start_epoch);
add_assoc_long(&fpm_proc_stat, "start-since", now_epoch - procs[i].start_epoch);
add_assoc_long(&fpm_proc_stat, "requests", procs[i].requests);
if (procs[i].request_stage == FPM_REQUEST_ACCEPTING) {
duration = procs[i].duration;
} else {
timersub(&now, &procs[i].accepted, &duration);
}
add_assoc_long(&fpm_proc_stat, "request-duration", duration.tv_sec * 1000000UL + duration.tv_usec);
add_assoc_string(&fpm_proc_stat, "request-method", procs[i].request_method[0] != '\0' ? procs[i].request_method : "-");
add_assoc_string(&fpm_proc_stat, "request-uri", procs[i].request_uri);
add_assoc_string(&fpm_proc_stat, "query-string", procs[i].query_string);
add_assoc_long(&fpm_proc_stat, "request-length", procs[i].content_length);
add_assoc_string(&fpm_proc_stat, "user", procs[i].auth_user[0] != '\0' ? procs[i].auth_user : "-");
add_assoc_string(&fpm_proc_stat, "script", procs[i].script_filename[0] != '\0' ? procs[i].script_filename : "-");
#ifdef HAVE_FPM_LQ
add_assoc_double(&fpm_proc_stat, "last-request-cpu", procs[i].request_stage == FPM_REQUEST_ACCEPTING ? cpu : 0.);
#endif
add_assoc_long(&fpm_proc_stat, "last-request-memory", procs[i].request_stage == FPM_REQUEST_ACCEPTING ? procs[i].memory : 0);
add_next_index_zval(&fpm_proc_stats, &fpm_proc_stat);
}
add_assoc_zval(status, "procs", &fpm_proc_stats);
return 0;
}
/* }}} */

int fpm_status_handle_request(void) /* {{{ */
{
struct fpm_scoreboard_s scoreboard, *scoreboard_p;
Expand Down Expand Up @@ -478,4 +576,3 @@ int fpm_status_handle_request(void) /* {{{ */
return 0;
}
/* }}} */

1 change: 1 addition & 0 deletions sapi/fpm/fpm/fpm_status.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ void fpm_status_increment_accepted_conn(struct fpm_shm_s *shm);
void fpm_status_set_pm(struct fpm_shm_s *shm, int pm);
void fpm_status_update_max_children_reached(struct fpm_shm_s *shm, unsigned int max_children_reached);
void fpm_status_increment_max_children_reached(struct fpm_shm_s *shm);
int fpm_status_export_to_zval(zval *status);
int fpm_status_handle_request(void);

extern struct fpm_shm_s *fpm_status_shm;
Expand Down
132 changes: 132 additions & 0 deletions sapi/fpm/tests/025.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
--TEST--
FPM: Test fpm_get_status function
--SKIPIF--
<?php include "skipif.inc"; ?>
Copy link
Contributor

Choose a reason for hiding this comment

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

require is preferable, as is safer 🛡️

--FILE--
<?php

include "include.inc";

$logfile = __DIR__.'/php-fpm.log.tmp';
$srcfile = __DIR__.'/php-fpm.tmp.php';
$port = 9000+PHP_INT_SIZE;

$cfg = <<<EOT
[global]
error_log = $logfile
[unconfined]
listen = 127.0.0.1:$port
pm = dynamic
pm.max_children = 5
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 3
EOT;

$code = <<<EOT
<?php
echo "Test Start\n";
var_dump(fpm_get_status());
echo "Test End\n";
EOT;
file_put_contents($srcfile, $code);

$fpm = run_fpm($cfg, $tail);
if (is_resource($fpm)) {
fpm_display_log($tail, 2);
try {
$req = run_request('127.0.0.1', $port, $srcfile);
echo strstr($req, "Test Start");
echo "Request ok\n";
} catch (Exception $e) {
echo "Request error\n";
}
proc_terminate($fpm);
fpm_display_log($tail, -1);
fclose($tail);
proc_close($fpm);
}

?>
Done
--EXPECTF--
[%s] NOTICE: fpm is running, pid %d
[%s] NOTICE: ready to handle connections
Test Start
array(15) {
["pool"]=>
string(10) "unconfined"
["process-manager"]=>
string(7) "dynamic"
["start-time"]=>
int(%d)
["start-since"]=>
int(%d)
["accepted-conn"]=>
int(1)
["listen-queue"]=>
int(0)
["max-listen-queue"]=>
int(0)
["listen-queue-len"]=>
int(128)
["idle-processes"]=>
int(0)
["active-processes"]=>
int(1)
["total-processes"]=>
int(1)
["max-active-processes"]=>
int(1)
["max-children-reached"]=>
int(0)
["slow-requests"]=>
int(0)
["procs"]=>
array(1) {
[0]=>
array(14) {
["pid"]=>
int(%d)
["state"]=>
string(7) "Running"
["start-time"]=>
int(%d)
["start-since"]=>
int(%d)
["requests"]=>
int(1)
["request-duration"]=>
int(%d)
["request-method"]=>
string(3) "GET"
["request-uri"]=>
string(%d) "%s"
["query-string"]=>
string(0) ""
["request-length"]=>
int(0)
["user"]=>
string(1) "-"
["script"]=>
string(%d) "%s"
["last-request-cpu"]=>
float(0)
["last-request-memory"]=>
int(0)
}
}
}
Test End

Request ok
[%s] NOTICE: Terminating ...
[%s] NOTICE: exiting, bye-bye!
Done
--CLEAN--
<?php
$logfile = __DIR__.'/php-fpm.log.tmp';
$srcfile = __DIR__.'/php-fpm.tmp.php';
@unlink($logfile);
@unlink($srcfile);
?>