root/sapi/fpm/fpm/fpm_status.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fpm_status_init_child
  2. fpm_status_handle_request

   1 
   2         /* $Id$ */
   3         /* (c) 2009 Jerome Loyet */
   4 
   5 #include "php.h"
   6 #include "SAPI.h"
   7 #include <stdio.h>
   8 
   9 #include "fpm_config.h"
  10 #include "fpm_scoreboard.h"
  11 #include "fpm_status.h"
  12 #include "fpm_clock.h"
  13 #include "fpm_scoreboard.h"
  14 #include "zlog.h"
  15 #include "fpm_atomic.h"
  16 #include "fpm_conf.h"
  17 #include "fpm_php.h"
  18 #include <ext/standard/html.h>
  19 
  20 static char *fpm_status_uri = NULL;
  21 static char *fpm_status_ping_uri = NULL;
  22 static char *fpm_status_ping_response = NULL;
  23 
  24 
  25 int fpm_status_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
  26 {
  27         if (!wp || !wp->config) {
  28                 zlog(ZLOG_ERROR, "unable to init fpm_status because conf structure is NULL");
  29                 return -1;
  30         }
  31 
  32         if (wp->config->pm_status_path) {
  33                 fpm_status_uri = strdup(wp->config->pm_status_path);
  34         }
  35 
  36         if (wp->config->ping_path) {
  37                 if (!wp->config->ping_response) {
  38                         zlog(ZLOG_ERROR, "[pool %s] ping is set (%s) but ping.response is not set.", wp->config->name, wp->config->ping_path);
  39                         return -1;
  40                 }
  41                 fpm_status_ping_uri = strdup(wp->config->ping_path);
  42                 fpm_status_ping_response = strdup(wp->config->ping_response);
  43         }
  44 
  45         return 0;
  46 }
  47 /* }}} */
  48 
  49 int fpm_status_handle_request(void) /* {{{ */
  50 {
  51         struct fpm_scoreboard_s scoreboard, *scoreboard_p;
  52         struct fpm_scoreboard_proc_s proc;
  53         char *buffer, *time_format, time_buffer[64];
  54         time_t now_epoch;
  55         int full, encode;
  56         char *short_syntax, *short_post;
  57         char *full_pre, *full_syntax, *full_post, *full_separator;
  58         zend_string *_GET_str;
  59 
  60         if (!SG(request_info).request_uri) {
  61                 return 0;
  62         }
  63 
  64         /* PING */
  65         if (fpm_status_ping_uri && fpm_status_ping_response && !strcmp(fpm_status_ping_uri, SG(request_info).request_uri)) {
  66                 fpm_request_executing();
  67                 sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
  68                 sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
  69                 sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
  70                 SG(sapi_headers).http_response_code = 200;
  71 
  72                 /* handle HEAD */
  73                 if (SG(request_info).headers_only) {
  74                         return 1;
  75                 }
  76 
  77                 PUTS(fpm_status_ping_response);
  78                 return 1;
  79         }
  80 
  81         /* STATUS */
  82         if (fpm_status_uri && !strcmp(fpm_status_uri, SG(request_info).request_uri)) {
  83                 fpm_request_executing();
  84 
  85                 scoreboard_p = fpm_scoreboard_get();
  86                 if (!scoreboard_p) {
  87                         zlog(ZLOG_ERROR, "status: unable to find or access status shared memory");
  88                         SG(sapi_headers).http_response_code = 500;
  89                         sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
  90                         sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
  91                         sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
  92                         PUTS("Internal error. Please review log file for errors.");
  93                         return 1;
  94                 }
  95 
  96                 if (!fpm_spinlock(&scoreboard_p->lock, 1)) {
  97                         zlog(ZLOG_NOTICE, "[pool %s] status: scoreboard already in used.", scoreboard_p->pool);
  98                         SG(sapi_headers).http_response_code = 503;
  99                         sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
 100                         sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
 101                         sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
 102                         PUTS("Server busy. Please try again later.");
 103                         return 1;
 104                 }
 105                 /* copy the scoreboard not to bother other processes */
 106                 scoreboard = *scoreboard_p;
 107                 fpm_unlock(scoreboard_p->lock);
 108 
 109                 if (scoreboard.idle < 0 || scoreboard.active < 0) {
 110                         zlog(ZLOG_ERROR, "[pool %s] invalid status values", scoreboard.pool);
 111                         SG(sapi_headers).http_response_code = 500;
 112                         sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
 113                         sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
 114                         sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
 115                         PUTS("Internal error. Please review log file for errors.");
 116                         return 1;
 117                 }
 118 
 119                 /* send common headers */
 120                 sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
 121                 sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
 122                 SG(sapi_headers).http_response_code = 200;
 123 
 124                 /* handle HEAD */
 125                 if (SG(request_info).headers_only) {
 126                         return 1;
 127                 }
 128 
 129                 /* full status ? */
 130                 _GET_str = zend_string_init("_GET", sizeof("_GET")-1, 0);
 131                 full = (fpm_php_get_string_from_table(_GET_str, "full") != NULL);
 132                 short_syntax = short_post = NULL;
 133                 full_separator = full_pre = full_syntax = full_post = NULL;
 134                 encode = 0;
 135 
 136                 /* HTML */
 137                 if (fpm_php_get_string_from_table(_GET_str, "html")) {
 138                         sapi_add_header_ex(ZEND_STRL("Content-Type: text/html"), 1, 1);
 139                         time_format = "%d/%b/%Y:%H:%M:%S %z";
 140                         encode = 1;
 141 
 142                         short_syntax =
 143                                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
 144                                 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
 145                                 "<head><title>PHP-FPM Status Page</title></head>\n"
 146                                 "<body>\n"
 147                                 "<table>\n"
 148                                         "<tr><th>pool</th><td>%s</td></tr>\n"
 149                                         "<tr><th>process manager</th><td>%s</td></tr>\n"
 150                                         "<tr><th>start time</th><td>%s</td></tr>\n"
 151                                         "<tr><th>start since</th><td>%lu</td></tr>\n"
 152                                         "<tr><th>accepted conn</th><td>%lu</td></tr>\n"
 153 #ifdef HAVE_FPM_LQ
 154                                         "<tr><th>listen queue</th><td>%u</td></tr>\n"
 155                                         "<tr><th>max listen queue</th><td>%u</td></tr>\n"
 156                                         "<tr><th>listen queue len</th><td>%d</td></tr>\n"
 157 #endif
 158                                         "<tr><th>idle processes</th><td>%d</td></tr>\n"
 159                                         "<tr><th>active processes</th><td>%d</td></tr>\n"
 160                                         "<tr><th>total processes</th><td>%d</td></tr>\n"
 161                                         "<tr><th>max active processes</th><td>%d</td></tr>\n"
 162                                         "<tr><th>max children reached</th><td>%u</td></tr>\n"
 163                                         "<tr><th>slow requests</th><td>%lu</td></tr>\n"
 164                                 "</table>\n";
 165 
 166                         if (!full) {
 167                                 short_post = "</body></html>";
 168                         } else {
 169                                 full_pre =
 170                                         "<table border=\"1\">\n"
 171                                         "<tr>"
 172                                                 "<th>pid</th>"
 173                                                 "<th>state</th>"
 174                                                 "<th>start time</th>"
 175                                                 "<th>start since</th>"
 176                                                 "<th>requests</th>"
 177                                                 "<th>request duration</th>"
 178                                                 "<th>request method</th>"
 179                                                 "<th>request uri</th>"
 180                                                 "<th>content length</th>"
 181                                                 "<th>user</th>"
 182                                                 "<th>script</th>"
 183 #ifdef HAVE_FPM_LQ
 184                                                 "<th>last request cpu</th>"
 185 #endif
 186                                                 "<th>last request memory</th>"
 187                                         "</tr>\n";
 188 
 189                                 full_syntax =
 190                                         "<tr>"
 191                                                 "<td>%d</td>"
 192                                                 "<td>%s</td>"
 193                                                 "<td>%s</td>"
 194                                                 "<td>%lu</td>"
 195                                                 "<td>%lu</td>"
 196                                                 "<td>%lu</td>"
 197                                                 "<td>%s</td>"
 198                                                 "<td>%s%s%s</td>"
 199                                                 "<td>%zu</td>"
 200                                                 "<td>%s</td>"
 201                                                 "<td>%s</td>"
 202 #ifdef HAVE_FPM_LQ
 203                                                 "<td>%.2f</td>"
 204 #endif
 205                                                 "<td>%zu</td>"
 206                                         "</tr>\n";
 207 
 208                                 full_post = "</table></body></html>";
 209                         }
 210 
 211                 /* XML */
 212                 } else if (fpm_php_get_string_from_table(_GET_str, "xml")) {
 213                         sapi_add_header_ex(ZEND_STRL("Content-Type: text/xml"), 1, 1);
 214                         time_format = "%s";
 215                         encode = 1;
 216 
 217                         short_syntax =
 218                                 "<?xml version=\"1.0\" ?>\n"
 219                                 "<status>\n"
 220                                 "<pool>%s</pool>\n"
 221                                 "<process-manager>%s</process-manager>\n"
 222                                 "<start-time>%s</start-time>\n"
 223                                 "<start-since>%lu</start-since>\n"
 224                                 "<accepted-conn>%lu</accepted-conn>\n"
 225 #ifdef HAVE_FPM_LQ
 226                                 "<listen-queue>%u</listen-queue>\n"
 227                                 "<max-listen-queue>%u</max-listen-queue>\n"
 228                                 "<listen-queue-len>%d</listen-queue-len>\n"
 229 #endif
 230                                 "<idle-processes>%d</idle-processes>\n"
 231                                 "<active-processes>%d</active-processes>\n"
 232                                 "<total-processes>%d</total-processes>\n"
 233                                 "<max-active-processes>%d</max-active-processes>\n"
 234                                 "<max-children-reached>%u</max-children-reached>\n"
 235                                 "<slow-requests>%lu</slow-requests>\n";
 236 
 237                                 if (!full) {
 238                                         short_post = "</status>";
 239                                 } else {
 240                                         full_pre = "<processes>\n";
 241                                         full_syntax =
 242                                                 "<process>"
 243                                                         "<pid>%d</pid>"
 244                                                         "<state>%s</state>"
 245                                                         "<start-time>%s</start-time>"
 246                                                         "<start-since>%lu</start-since>"
 247                                                         "<requests>%lu</requests>"
 248                                                         "<request-duration>%lu</request-duration>"
 249                                                         "<request-method>%s</request-method>"
 250                                                         "<request-uri>%s%s%s</request-uri>"
 251                                                         "<content-length>%zu</content-length>"
 252                                                         "<user>%s</user>"
 253                                                         "<script>%s</script>"
 254 #ifdef HAVE_FPM_LQ
 255                                                         "<last-request-cpu>%.2f</last-request-cpu>"
 256 #endif
 257                                                         "<last-request-memory>%zu</last-request-memory>"
 258                                                 "</process>\n"
 259                                         ;
 260                                         full_post = "</processes>\n</status>";
 261                                 }
 262 
 263                         /* JSON */
 264                 } else if (fpm_php_get_string_from_table(_GET_str, "json")) {
 265                         sapi_add_header_ex(ZEND_STRL("Content-Type: application/json"), 1, 1);
 266                         time_format = "%s";
 267 
 268                         short_syntax =
 269                                 "{"
 270                                 "\"pool\":\"%s\","
 271                                 "\"process manager\":\"%s\","
 272                                 "\"start time\":%s,"
 273                                 "\"start since\":%lu,"
 274                                 "\"accepted conn\":%lu,"
 275 #ifdef HAVE_FPM_LQ
 276                                 "\"listen queue\":%u,"
 277                                 "\"max listen queue\":%u,"
 278                                 "\"listen queue len\":%d,"
 279 #endif
 280                                 "\"idle processes\":%d,"
 281                                 "\"active processes\":%d,"
 282                                 "\"total processes\":%d,"
 283                                 "\"max active processes\":%d,"
 284                                 "\"max children reached\":%u,"
 285                                 "\"slow requests\":%lu";
 286 
 287                         if (!full) {
 288                                 short_post = "}";
 289                         } else {
 290                                 full_separator = ",";
 291                                 full_pre = ", \"processes\":[";
 292 
 293                                 full_syntax = "{"
 294                                         "\"pid\":%d,"
 295                                         "\"state\":\"%s\","
 296                                         "\"start time\":%s,"
 297                                         "\"start since\":%lu,"
 298                                         "\"requests\":%lu,"
 299                                         "\"request duration\":%lu,"
 300                                         "\"request method\":\"%s\","
 301                                         "\"request uri\":\"%s%s%s\","
 302                                         "\"content length\":%zu,"
 303                                         "\"user\":\"%s\","
 304                                         "\"script\":\"%s\","
 305 #ifdef HAVE_FPM_LQ
 306                                         "\"last request cpu\":%.2f,"
 307 #endif
 308                                         "\"last request memory\":%zu"
 309                                         "}";
 310 
 311                                 full_post = "]}";
 312                         }
 313 
 314                 /* TEXT */
 315                 } else {
 316                         sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
 317                         time_format = "%d/%b/%Y:%H:%M:%S %z";
 318 
 319                         short_syntax =
 320                                 "pool:                 %s\n"
 321                                 "process manager:      %s\n"
 322                                 "start time:           %s\n"
 323                                 "start since:          %lu\n"
 324                                 "accepted conn:        %lu\n"
 325 #ifdef HAVE_FPM_LQ
 326                                 "listen queue:         %u\n"
 327                                 "max listen queue:     %u\n"
 328                                 "listen queue len:     %d\n"
 329 #endif
 330                                 "idle processes:       %d\n"
 331                                 "active processes:     %d\n"
 332                                 "total processes:      %d\n"
 333                                 "max active processes: %d\n"
 334                                 "max children reached: %u\n"
 335                                 "slow requests:        %lu\n";
 336 
 337                                 if (full) {
 338                                         full_syntax =
 339                                                 "\n"
 340                                                 "************************\n"
 341                                                 "pid:                  %d\n"
 342                                                 "state:                %s\n"
 343                                                 "start time:           %s\n"
 344                                                 "start since:          %lu\n"
 345                                                 "requests:             %lu\n"
 346                                                 "request duration:     %lu\n"
 347                                                 "request method:       %s\n"
 348                                                 "request URI:          %s%s%s\n"
 349                                                 "content length:       %zu\n"
 350                                                 "user:                 %s\n"
 351                                                 "script:               %s\n"
 352 #ifdef HAVE_FPM_LQ
 353                                                 "last request cpu:     %.2f\n"
 354 #endif
 355                                                 "last request memory:  %zu\n";
 356                                 }
 357                 }
 358 
 359                 strftime(time_buffer, sizeof(time_buffer) - 1, time_format, localtime(&scoreboard.start_epoch));
 360                 now_epoch = time(NULL);
 361                 spprintf(&buffer, 0, short_syntax,
 362                                 scoreboard.pool,
 363                                 PM2STR(scoreboard.pm),
 364                                 time_buffer,
 365                                 now_epoch - scoreboard.start_epoch,
 366                                 scoreboard.requests,
 367 #ifdef HAVE_FPM_LQ
 368                                 scoreboard.lq,
 369                                 scoreboard.lq_max,
 370                                 scoreboard.lq_len,
 371 #endif
 372                                 scoreboard.idle,
 373                                 scoreboard.active,
 374                                 scoreboard.idle + scoreboard.active,
 375                                 scoreboard.active_max,
 376                                 scoreboard.max_children_reached,
 377                                 scoreboard.slow_rq);
 378 
 379                 PUTS(buffer);
 380                 efree(buffer);
 381                 zend_string_release(_GET_str);
 382 
 383                 if (short_post) {
 384                         PUTS(short_post);
 385                 }
 386 
 387                 /* no need to test the var 'full' */
 388                 if (full_syntax) {
 389                         int i, first;
 390                         zend_string *tmp_query_string;
 391                         char *query_string;
 392                         struct timeval duration, now;
 393 #ifdef HAVE_FPM_LQ
 394                         float cpu;
 395 #endif
 396 
 397                         fpm_clock_get(&now);
 398 
 399                         if (full_pre) {
 400                                 PUTS(full_pre);
 401                         }
 402 
 403                         first = 1;
 404                         for (i=0; i<scoreboard_p->nprocs; i++) {
 405                                 if (!scoreboard_p->procs[i] || !scoreboard_p->procs[i]->used) {
 406                                         continue;
 407                                 }
 408                                 proc = *scoreboard_p->procs[i];
 409 
 410                                 if (first) {
 411                                         first = 0;
 412                                 } else {
 413                                         if (full_separator) {
 414                                                 PUTS(full_separator);
 415                                         }
 416                                 }
 417 
 418                                 query_string = NULL;
 419                                 tmp_query_string = NULL;
 420                                 if (proc.query_string[0] != '\0') {
 421                                         if (!encode) {
 422                                                 query_string = proc.query_string;
 423                                         } else {
 424                                                 tmp_query_string = php_escape_html_entities_ex((unsigned char *)proc.query_string, strlen(proc.query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT, NULL, 1);
 425                                                 query_string = ZSTR_VAL(tmp_query_string);
 426                                         }
 427                                 }
 428 
 429 #ifdef HAVE_FPM_LQ
 430                                 /* prevent NaN */
 431                                 if (proc.cpu_duration.tv_sec == 0 && proc.cpu_duration.tv_usec == 0) {
 432                                         cpu = 0.;
 433                                 } else {
 434                                         cpu = (proc.last_request_cpu.tms_utime + proc.last_request_cpu.tms_stime + proc.last_request_cpu.tms_cutime + proc.last_request_cpu.tms_cstime) / fpm_scoreboard_get_tick() / (proc.cpu_duration.tv_sec + proc.cpu_duration.tv_usec / 1000000.) * 100.;
 435                                 }
 436 #endif
 437 
 438                                 if (proc.request_stage == FPM_REQUEST_ACCEPTING) {
 439                                         duration = proc.duration;
 440                                 } else {
 441                                         timersub(&now, &proc.accepted, &duration);
 442                                 }
 443                                 strftime(time_buffer, sizeof(time_buffer) - 1, time_format, localtime(&proc.start_epoch));
 444                                 spprintf(&buffer, 0, full_syntax,
 445                                         proc.pid,
 446                                         fpm_request_get_stage_name(proc.request_stage),
 447                                         time_buffer,
 448                                         now_epoch - proc.start_epoch,
 449                                         proc.requests,
 450                                         duration.tv_sec * 1000000UL + duration.tv_usec,
 451                                         proc.request_method[0] != '\0' ? proc.request_method : "-",
 452                                         proc.request_uri[0] != '\0' ? proc.request_uri : "-",
 453                                         query_string ? "?" : "",
 454                                         query_string ? query_string : "",
 455                                         proc.content_length,
 456                                         proc.auth_user[0] != '\0' ? proc.auth_user : "-",
 457                                         proc.script_filename[0] != '\0' ? proc.script_filename : "-",
 458 #ifdef HAVE_FPM_LQ
 459                                         proc.request_stage == FPM_REQUEST_ACCEPTING ? cpu : 0.,
 460 #endif
 461                                         proc.request_stage == FPM_REQUEST_ACCEPTING ? proc.memory : 0);
 462                                 PUTS(buffer);
 463                                 efree(buffer);
 464 
 465                                 if (tmp_query_string) {
 466                                         zend_string_free(tmp_query_string);
 467                                 }
 468                         }
 469 
 470                         if (full_post) {
 471                                 PUTS(full_post);
 472                         }
 473                 }
 474 
 475                 return 1;
 476         }
 477 
 478         return 0;
 479 }
 480 /* }}} */
 481 

/* [<][>][^][v][top][bottom][index][help] */