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

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