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