1 /* (c) 2009 Jerome Loyet */
2
3 #include "php.h"
4 #include "zend_long.h"
5 #include "SAPI.h"
6 #include <stdio.h>
7
8 #include "fpm_config.h"
9 #include "fpm_scoreboard.h"
10 #include "fpm_status.h"
11 #include "fpm_clock.h"
12 #include "zlog.h"
13 #include "fpm_atomic.h"
14 #include "fpm_conf.h"
15 #include "fpm_php.h"
16 #include <ext/standard/html.h>
17
18 static char *fpm_status_uri = NULL;
19 static char *fpm_status_ping_uri = NULL;
20 static char *fpm_status_ping_response = NULL;
21
22
fpm_status_init_child(struct fpm_worker_pool_s * wp)23 int fpm_status_init_child(struct fpm_worker_pool_s *wp) /* {{{ */
24 {
25 if (!wp || !wp->config) {
26 zlog(ZLOG_ERROR, "unable to init fpm_status because conf structure is NULL");
27 return -1;
28 }
29
30 if (wp->config->pm_status_path) {
31 fpm_status_uri = strdup(wp->config->pm_status_path);
32 }
33
34 if (wp->config->ping_path) {
35 if (!wp->config->ping_response) {
36 zlog(ZLOG_ERROR, "[pool %s] ping is set (%s) but ping.response is not set.", wp->config->name, wp->config->ping_path);
37 return -1;
38 }
39 fpm_status_ping_uri = strdup(wp->config->ping_path);
40 fpm_status_ping_response = strdup(wp->config->ping_response);
41 }
42
43 return 0;
44 }
45 /* }}} */
46
fpm_status_export_to_zval(zval * status)47 int fpm_status_export_to_zval(zval *status)
48 {
49 struct fpm_scoreboard_s scoreboard, *scoreboard_p;
50 zval fpm_proc_stats, fpm_proc_stat;
51 time_t now_epoch;
52 struct timeval duration, now;
53 double cpu;
54 int i;
55
56 scoreboard_p = fpm_scoreboard_acquire(NULL, 1);
57 if (!scoreboard_p) {
58 zlog(ZLOG_NOTICE, "[pool %s] status: scoreboard already in use.", scoreboard_p->pool);
59 return -1;
60 }
61
62 /* copy the scoreboard not to bother other processes */
63 scoreboard = *scoreboard_p;
64 struct fpm_scoreboard_proc_s procs[scoreboard.nprocs];
65
66 struct fpm_scoreboard_proc_s *proc_p;
67 for(i=0; i<scoreboard.nprocs; i++) {
68 proc_p = fpm_scoreboard_proc_acquire(scoreboard_p, i, 1);
69 if (!proc_p){
70 procs[i].used=-1;
71 continue;
72 }
73 procs[i] = *proc_p;
74 fpm_scoreboard_proc_release(proc_p);
75 }
76 fpm_scoreboard_release(scoreboard_p);
77
78 now_epoch = time(NULL);
79 fpm_clock_get(&now);
80
81 array_init(status);
82 add_assoc_string(status, "pool", scoreboard.pool);
83 add_assoc_string(status, "process-manager", PM2STR(scoreboard.pm));
84 add_assoc_long(status, "start-time", scoreboard.start_epoch);
85 add_assoc_long(status, "start-since", now_epoch - scoreboard.start_epoch);
86 add_assoc_long(status, "accepted-conn", scoreboard.requests);
87 add_assoc_long(status, "listen-queue", scoreboard.lq);
88 add_assoc_long(status, "max-listen-queue", scoreboard.lq_max);
89 add_assoc_long(status, "listen-queue-len", scoreboard.lq_len);
90 add_assoc_long(status, "idle-processes", scoreboard.idle);
91 add_assoc_long(status, "active-processes", scoreboard.active);
92 add_assoc_long(status, "total-processes", scoreboard.idle + scoreboard.active);
93 add_assoc_long(status, "max-active-processes", scoreboard.active_max);
94 add_assoc_long(status, "max-children-reached", scoreboard.max_children_reached);
95 add_assoc_long(status, "slow-requests", scoreboard.slow_rq);
96
97 array_init(&fpm_proc_stats);
98 for(i=0; i<scoreboard.nprocs; i++) {
99 if (!procs[i].used) {
100 continue;
101 }
102 proc_p = &procs[i];
103 /* prevent NaN */
104 if (procs[i].cpu_duration.tv_sec == 0 && procs[i].cpu_duration.tv_usec == 0) {
105 cpu = 0.;
106 } else {
107 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.;
108 }
109
110 array_init(&fpm_proc_stat);
111 add_assoc_long(&fpm_proc_stat, "pid", procs[i].pid);
112 add_assoc_string(&fpm_proc_stat, "state", fpm_request_get_stage_name(procs[i].request_stage));
113 add_assoc_long(&fpm_proc_stat, "start-time", procs[i].start_epoch);
114 add_assoc_long(&fpm_proc_stat, "start-since", now_epoch - procs[i].start_epoch);
115 add_assoc_long(&fpm_proc_stat, "requests", procs[i].requests);
116 if (procs[i].request_stage == FPM_REQUEST_ACCEPTING) {
117 duration = procs[i].duration;
118 } else {
119 timersub(&now, &procs[i].accepted, &duration);
120 }
121 add_assoc_long(&fpm_proc_stat, "request-duration", duration.tv_sec * 1000000UL + duration.tv_usec);
122 add_assoc_string(&fpm_proc_stat, "request-method", procs[i].request_method[0] != '\0' ? procs[i].request_method : "-");
123 add_assoc_string(&fpm_proc_stat, "request-uri", procs[i].request_uri);
124 add_assoc_string(&fpm_proc_stat, "query-string", procs[i].query_string);
125 add_assoc_long(&fpm_proc_stat, "request-length", procs[i].content_length);
126 add_assoc_string(&fpm_proc_stat, "user", procs[i].auth_user[0] != '\0' ? procs[i].auth_user : "-");
127 add_assoc_string(&fpm_proc_stat, "script", procs[i].script_filename[0] != '\0' ? procs[i].script_filename : "-");
128 add_assoc_double(&fpm_proc_stat, "last-request-cpu", procs[i].request_stage == FPM_REQUEST_ACCEPTING ? cpu : 0.);
129 add_assoc_long(&fpm_proc_stat, "last-request-memory", procs[i].request_stage == FPM_REQUEST_ACCEPTING ? procs[i].memory : 0);
130 add_next_index_zval(&fpm_proc_stats, &fpm_proc_stat);
131 }
132 add_assoc_zval(status, "procs", &fpm_proc_stats);
133 return 0;
134 }
135 /* }}} */
136
fpm_status_handle_request(void)137 int fpm_status_handle_request(void) /* {{{ */
138 {
139 struct fpm_scoreboard_s scoreboard, *scoreboard_p;
140 struct fpm_scoreboard_proc_s proc;
141 char *buffer, *time_format, time_buffer[64];
142 time_t now_epoch;
143 int full, encode, has_start_time;
144 char *short_syntax, *short_post;
145 char *full_pre, *full_syntax, *full_post, *full_separator;
146 zend_string *_GET_str;
147
148 if (!SG(request_info).request_uri) {
149 return 0;
150 }
151
152 /* PING */
153 if (fpm_status_ping_uri && fpm_status_ping_response && !strcmp(fpm_status_ping_uri, SG(request_info).request_uri)) {
154 fpm_request_executing();
155 sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
156 sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
157 sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
158 SG(sapi_headers).http_response_code = 200;
159
160 /* handle HEAD */
161 if (SG(request_info).headers_only) {
162 return 1;
163 }
164
165 PUTS(fpm_status_ping_response);
166 return 1;
167 }
168
169 /* STATUS */
170 if (fpm_status_uri && !strcmp(fpm_status_uri, SG(request_info).request_uri)) {
171 fpm_request_executing();
172
173 scoreboard_p = fpm_scoreboard_get();
174 if (scoreboard_p->shared) {
175 scoreboard_p = scoreboard_p->shared;
176 }
177 if (!scoreboard_p) {
178 zlog(ZLOG_ERROR, "status: unable to find or access status shared memory");
179 SG(sapi_headers).http_response_code = 500;
180 sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
181 sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
182 sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
183 PUTS("Internal error. Please review log file for errors.");
184 return 1;
185 }
186
187 if (!fpm_spinlock(&scoreboard_p->lock, 1)) {
188 zlog(ZLOG_NOTICE, "[pool %s] status: scoreboard already in used.", scoreboard_p->pool);
189 SG(sapi_headers).http_response_code = 503;
190 sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
191 sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
192 sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
193 PUTS("Server busy. Please try again later.");
194 return 1;
195 }
196 /* copy the scoreboard not to bother other processes */
197 scoreboard = *scoreboard_p;
198 fpm_unlock(scoreboard_p->lock);
199
200 if (scoreboard.idle < 0 || scoreboard.active < 0) {
201 zlog(ZLOG_ERROR, "[pool %s] invalid status values", scoreboard.pool);
202 SG(sapi_headers).http_response_code = 500;
203 sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
204 sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
205 sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
206 PUTS("Internal error. Please review log file for errors.");
207 return 1;
208 }
209
210 /* send common headers */
211 sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1);
212 sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1);
213 SG(sapi_headers).http_response_code = 200;
214
215 /* handle HEAD */
216 if (SG(request_info).headers_only) {
217 return 1;
218 }
219
220 /* full status ? */
221 _GET_str = zend_string_init("_GET", sizeof("_GET")-1, 0);
222 full = (fpm_php_get_string_from_table(_GET_str, "full") != NULL);
223 short_syntax = short_post = NULL;
224 full_separator = full_pre = full_syntax = full_post = NULL;
225 encode = 0;
226 has_start_time = 1;
227
228 /* HTML */
229 if (fpm_php_get_string_from_table(_GET_str, "html")) {
230 sapi_add_header_ex(ZEND_STRL("Content-Type: text/html"), 1, 1);
231 time_format = "%d/%b/%Y:%H:%M:%S %z";
232 encode = 1;
233
234 short_syntax =
235 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
236 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
237 "<head><title>PHP-FPM Status Page</title></head>\n"
238 "<body>\n"
239 "<table>\n"
240 "<tr><th>pool</th><td>%s</td></tr>\n"
241 "<tr><th>process manager</th><td>%s</td></tr>\n"
242 "<tr><th>start time</th><td>%s</td></tr>\n"
243 "<tr><th>start since</th><td>%lu</td></tr>\n"
244 "<tr><th>accepted conn</th><td>%lu</td></tr>\n"
245 "<tr><th>listen queue</th><td>%d</td></tr>\n"
246 "<tr><th>max listen queue</th><td>%d</td></tr>\n"
247 "<tr><th>listen queue len</th><td>%u</td></tr>\n"
248 "<tr><th>idle processes</th><td>%d</td></tr>\n"
249 "<tr><th>active processes</th><td>%d</td></tr>\n"
250 "<tr><th>total processes</th><td>%d</td></tr>\n"
251 "<tr><th>max active processes</th><td>%d</td></tr>\n"
252 "<tr><th>max children reached</th><td>%u</td></tr>\n"
253 "<tr><th>slow requests</th><td>%lu</td></tr>\n"
254 "</table>\n";
255
256 if (!full) {
257 short_post = "</body></html>";
258 } else {
259 full_pre =
260 "<table border=\"1\">\n"
261 "<tr>"
262 "<th>pid</th>"
263 "<th>state</th>"
264 "<th>start time</th>"
265 "<th>start since</th>"
266 "<th>requests</th>"
267 "<th>request duration</th>"
268 "<th>request method</th>"
269 "<th>request uri</th>"
270 "<th>content length</th>"
271 "<th>user</th>"
272 "<th>script</th>"
273 "<th>last request cpu</th>"
274 "<th>last request memory</th>"
275 "</tr>\n";
276
277 full_syntax =
278 "<tr>"
279 "<td>%d</td>"
280 "<td>%s</td>"
281 "<td>%s</td>"
282 "<td>%lu</td>"
283 "<td>%lu</td>"
284 "<td>%lu</td>"
285 "<td>%s</td>"
286 "<td>%s%s%s</td>"
287 "<td>%zu</td>"
288 "<td>%s</td>"
289 "<td>%s</td>"
290 "<td>%.2f</td>"
291 "<td>%zu</td>"
292 "</tr>\n";
293
294 full_post = "</table></body></html>";
295 }
296
297 /* XML */
298 } else if (fpm_php_get_string_from_table(_GET_str, "xml")) {
299 sapi_add_header_ex(ZEND_STRL("Content-Type: text/xml"), 1, 1);
300 time_format = "%s";
301 encode = 1;
302
303 short_syntax =
304 "<?xml version=\"1.0\" ?>\n"
305 "<status>\n"
306 "<pool>%s</pool>\n"
307 "<process-manager>%s</process-manager>\n"
308 "<start-time>%s</start-time>\n"
309 "<start-since>%lu</start-since>\n"
310 "<accepted-conn>%lu</accepted-conn>\n"
311 "<listen-queue>%d</listen-queue>\n"
312 "<max-listen-queue>%d</max-listen-queue>\n"
313 "<listen-queue-len>%u</listen-queue-len>\n"
314 "<idle-processes>%d</idle-processes>\n"
315 "<active-processes>%d</active-processes>\n"
316 "<total-processes>%d</total-processes>\n"
317 "<max-active-processes>%d</max-active-processes>\n"
318 "<max-children-reached>%u</max-children-reached>\n"
319 "<slow-requests>%lu</slow-requests>\n";
320
321 if (!full) {
322 short_post = "</status>";
323 } else {
324 full_pre = "<processes>\n";
325 full_syntax =
326 "<process>"
327 "<pid>%d</pid>"
328 "<state>%s</state>"
329 "<start-time>%s</start-time>"
330 "<start-since>%lu</start-since>"
331 "<requests>%lu</requests>"
332 "<request-duration>%lu</request-duration>"
333 "<request-method>%s</request-method>"
334 "<request-uri>%s%s%s</request-uri>"
335 "<content-length>%zu</content-length>"
336 "<user>%s</user>"
337 "<script>%s</script>"
338 "<last-request-cpu>%.2f</last-request-cpu>"
339 "<last-request-memory>%zu</last-request-memory>"
340 "</process>\n"
341 ;
342 full_post = "</processes>\n</status>";
343 }
344
345 /* JSON */
346 } else if (fpm_php_get_string_from_table(_GET_str, "json")) {
347 sapi_add_header_ex(ZEND_STRL("Content-Type: application/json"), 1, 1);
348 time_format = "%s";
349
350 short_syntax =
351 "{"
352 "\"pool\":\"%s\","
353 "\"process manager\":\"%s\","
354 "\"start time\":%s,"
355 "\"start since\":%lu,"
356 "\"accepted conn\":%lu,"
357 "\"listen queue\":%d,"
358 "\"max listen queue\":%d,"
359 "\"listen queue len\":%u,"
360 "\"idle processes\":%d,"
361 "\"active processes\":%d,"
362 "\"total processes\":%d,"
363 "\"max active processes\":%d,"
364 "\"max children reached\":%u,"
365 "\"slow requests\":%lu";
366
367 if (!full) {
368 short_post = "}";
369 } else {
370 full_separator = ",";
371 full_pre = ", \"processes\":[";
372
373 full_syntax = "{"
374 "\"pid\":%d,"
375 "\"state\":\"%s\","
376 "\"start time\":%s,"
377 "\"start since\":%lu,"
378 "\"requests\":%lu,"
379 "\"request duration\":%lu,"
380 "\"request method\":\"%s\","
381 "\"request uri\":\"%s%s%s\","
382 "\"content length\":%zu,"
383 "\"user\":\"%s\","
384 "\"script\":\"%s\","
385 "\"last request cpu\":%.2f,"
386 "\"last request memory\":%zu"
387 "}";
388
389 full_post = "]}";
390 }
391
392 /* OpenMetrics */
393 } else if (fpm_php_get_string_from_table(_GET_str, "openmetrics")) {
394 sapi_add_header_ex(ZEND_STRL("Content-Type: application/openmetrics-text; version=1.0.0; charset=utf-8"), 1, 1);
395 time_format = "%s";
396
397 short_syntax =
398 "# HELP phpfpm_up Could pool %s using a %s PM on PHP-FPM be reached?\n"
399 "# TYPE phpfpm_up gauge\n"
400 "phpfpm_up 1\n"
401 "# HELP phpfpm_start_since The number of seconds since FPM has started.\n"
402 "# TYPE phpfpm_start_since counter\n"
403 "phpfpm_start_since %lu\n"
404 "# HELP phpfpm_accepted_connections The number of requests accepted by the pool.\n"
405 "# TYPE phpfpm_accepted_connections counter\n"
406 "phpfpm_accepted_connections %lu\n"
407 "# HELP phpfpm_listen_queue The number of requests in the queue of pending connections.\n"
408 "# TYPE phpfpm_listen_queue gauge\n"
409 "phpfpm_listen_queue %d\n"
410 "# HELP phpfpm_max_listen_queue The maximum number of requests in the queue of pending connections since FPM has started.\n"
411 "# TYPE phpfpm_max_listen_queue counter\n"
412 "phpfpm_max_listen_queue %d\n"
413 "# TYPE phpfpm_listen_queue_length gauge\n"
414 "# HELP phpfpm_listen_queue_length The size of the socket queue of pending connections.\n"
415 "phpfpm_listen_queue_length %u\n"
416 "# HELP phpfpm_idle_processes The number of idle processes.\n"
417 "# TYPE phpfpm_idle_processes gauge\n"
418 "phpfpm_idle_processes %d\n"
419 "# HELP phpfpm_active_processes The number of active processes.\n"
420 "# TYPE phpfpm_active_processes gauge\n"
421 "phpfpm_active_processes %d\n"
422 "# HELP phpfpm_total_processes The number of idle + active processes.\n"
423 "# TYPE phpfpm_total_processes gauge\n"
424 "phpfpm_total_processes %d\n"
425 "# HELP phpfpm_max_active_processes The maximum number of active processes since FPM has started.\n"
426 "# TYPE phpfpm_max_active_processes counter\n"
427 "phpfpm_max_active_processes %d\n"
428 "# HELP phpfpm_max_children_reached The number of times, the process limit has been reached, when pm tries to start more children (works only for pm 'dynamic' and 'ondemand').\n"
429 "# TYPE phpfpm_max_children_reached counter\n"
430 "phpfpm_max_children_reached %u\n"
431 "# HELP phpfpm_slow_requests The number of requests that exceeded your 'request_slowlog_timeout' value.\n"
432 "# TYPE phpfpm_slow_requests counter\n"
433 "phpfpm_slow_requests %lu\n";
434
435 has_start_time = 0;
436 if (!full) {
437 short_post = "";
438 } else {
439 full_separator = "";
440 full_pre = "";
441 full_syntax = "";
442 full_post = "";
443 }
444
445 /* TEXT */
446 } else {
447 sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1);
448 time_format = "%d/%b/%Y:%H:%M:%S %z";
449
450 short_syntax =
451 "pool: %s\n"
452 "process manager: %s\n"
453 "start time: %s\n"
454 "start since: %lu\n"
455 "accepted conn: %lu\n"
456 "listen queue: %d\n"
457 "max listen queue: %d\n"
458 "listen queue len: %u\n"
459 "idle processes: %d\n"
460 "active processes: %d\n"
461 "total processes: %d\n"
462 "max active processes: %d\n"
463 "max children reached: %u\n"
464 "slow requests: %lu\n";
465
466 if (full) {
467 full_syntax =
468 "\n"
469 "************************\n"
470 "pid: %d\n"
471 "state: %s\n"
472 "start time: %s\n"
473 "start since: %lu\n"
474 "requests: %lu\n"
475 "request duration: %lu\n"
476 "request method: %s\n"
477 "request URI: %s%s%s\n"
478 "content length: %zu\n"
479 "user: %s\n"
480 "script: %s\n"
481 "last request cpu: %.2f\n"
482 "last request memory: %zu\n";
483 }
484 }
485
486 now_epoch = time(NULL);
487 if (has_start_time) {
488 strftime(time_buffer, sizeof(time_buffer) - 1, time_format, localtime(&scoreboard.start_epoch));
489 spprintf(&buffer, 0, short_syntax,
490 scoreboard.pool,
491 PM2STR(scoreboard.pm),
492 time_buffer,
493 (unsigned long) (now_epoch - scoreboard.start_epoch),
494 scoreboard.requests,
495 scoreboard.lq,
496 scoreboard.lq_max,
497 scoreboard.lq_len,
498 scoreboard.idle,
499 scoreboard.active,
500 scoreboard.idle + scoreboard.active,
501 scoreboard.active_max,
502 scoreboard.max_children_reached,
503 scoreboard.slow_rq);
504 } else {
505 spprintf(&buffer, 0, short_syntax,
506 scoreboard.pool,
507 PM2STR(scoreboard.pm),
508 (unsigned long) (now_epoch - scoreboard.start_epoch),
509 scoreboard.requests,
510 scoreboard.lq,
511 scoreboard.lq_max,
512 scoreboard.lq_len,
513 scoreboard.idle,
514 scoreboard.active,
515 scoreboard.idle + scoreboard.active,
516 scoreboard.active_max,
517 scoreboard.max_children_reached,
518 scoreboard.slow_rq);
519 }
520
521 PUTS(buffer);
522 efree(buffer);
523 zend_string_release_ex(_GET_str, 0);
524
525 if (short_post) {
526 PUTS(short_post);
527 }
528
529 /* no need to test the var 'full' */
530 if (full_syntax) {
531 unsigned int i;
532 int first;
533 zend_string *tmp_query_string;
534 char *query_string;
535 struct timeval duration, now;
536 float cpu;
537
538 fpm_clock_get(&now);
539
540 if (full_pre) {
541 PUTS(full_pre);
542 }
543
544 first = 1;
545 for (i=0; i<scoreboard_p->nprocs; i++) {
546 if (!scoreboard_p->procs[i].used) {
547 continue;
548 }
549 proc = scoreboard_p->procs[i];
550
551 if (first) {
552 first = 0;
553 } else {
554 if (full_separator) {
555 PUTS(full_separator);
556 }
557 }
558
559 query_string = NULL;
560 tmp_query_string = NULL;
561 if (proc.query_string[0] != '\0') {
562 if (!encode) {
563 query_string = proc.query_string;
564 } else {
565 tmp_query_string = php_escape_html_entities_ex((const unsigned char *) proc.query_string, strlen(proc.query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT, NULL, /* double_encode */ 1, /* quiet */ 0);
566 query_string = ZSTR_VAL(tmp_query_string);
567 }
568 }
569
570 /* prevent NaN */
571 if (proc.cpu_duration.tv_sec == 0 && proc.cpu_duration.tv_usec == 0) {
572 cpu = 0.;
573 } else {
574 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.;
575 }
576
577 if (proc.request_stage == FPM_REQUEST_ACCEPTING) {
578 duration = proc.duration;
579 } else {
580 timersub(&now, &proc.accepted, &duration);
581 }
582 strftime(time_buffer, sizeof(time_buffer) - 1, time_format, localtime(&proc.start_epoch));
583 spprintf(&buffer, 0, full_syntax,
584 (int) proc.pid,
585 fpm_request_get_stage_name(proc.request_stage),
586 time_buffer,
587 (unsigned long) (now_epoch - proc.start_epoch),
588 proc.requests,
589 duration.tv_sec * 1000000UL + duration.tv_usec,
590 proc.request_method[0] != '\0' ? proc.request_method : "-",
591 proc.request_uri[0] != '\0' ? proc.request_uri : "-",
592 query_string ? "?" : "",
593 query_string ? query_string : "",
594 proc.content_length,
595 proc.auth_user[0] != '\0' ? proc.auth_user : "-",
596 proc.script_filename[0] != '\0' ? proc.script_filename : "-",
597 proc.request_stage == FPM_REQUEST_ACCEPTING ? cpu : 0.,
598 proc.request_stage == FPM_REQUEST_ACCEPTING ? proc.memory : 0);
599 PUTS(buffer);
600 efree(buffer);
601
602 if (tmp_query_string) {
603 zend_string_free(tmp_query_string);
604 }
605 }
606
607 if (full_post) {
608 PUTS(full_post);
609 }
610 }
611
612 return 1;
613 }
614
615 return 0;
616 }
617 /* }}} */
618