static int fd_stdout[2];
static int fd_stderr[2];
-static void fpm_stdio_cleanup(int which, void *arg) /* {{{ */
-{
- zlog_cleanup();
-}
-/* }}} */
-
int fpm_stdio_init_main() /* {{{ */
{
int fd = open("/dev/null", O_RDWR);
zlog(ZLOG_SYSERROR, "failed to init stdio: open(\"/dev/null\")");
return -1;
}
- if (0 > fpm_cleanup_add(FPM_CLEANUP_PARENT, fpm_stdio_cleanup, 0)) {
- return -1;
- }
if (0 > dup2(fd, STDIN_FILENO) || 0 > dup2(fd, STDOUT_FILENO)) {
zlog(ZLOG_SYSERROR, "failed to init stdio: dup2()");
}
/* }}} */
+int fpm_stdio_flush_child() /* {{{ */
+{
+ return write(STDERR_FILENO, "\0", 1);
+}
+/* }}} */
+
static void fpm_stdio_child_said(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
{
static const int max_buf_size = 1024;
struct fpm_event_s *event;
int fifo_in = 1, fifo_out = 1;
int in_buf = 0;
- int read_fail = 0;
+ int read_fail = 0, finish_log_stream = 0;
int res;
- struct zlog_stream stream;
+ struct zlog_stream *log_stream;
if (!arg) {
return;
event = &child->ev_stderr;
}
- zlog_stream_init_ex(&stream, ZLOG_WARNING, STDERR_FILENO);
- zlog_stream_set_decorating(&stream, child->wp->config->decorate_workers_output);
- zlog_stream_set_wrapping(&stream, ZLOG_TRUE);
- zlog_stream_set_msg_prefix(&stream, "[pool %s] child %d said into %s: ",
- child->wp->config->name, (int) child->pid, is_stdout ? "stdout" : "stderr");
- zlog_stream_set_msg_quoting(&stream, ZLOG_TRUE);
+ if (!child->log_stream) {
+ log_stream = child->log_stream = malloc(sizeof(struct zlog_stream));
+ zlog_stream_init_ex(log_stream, ZLOG_WARNING, STDERR_FILENO);
+ zlog_stream_set_decorating(log_stream, child->wp->config->decorate_workers_output);
+ zlog_stream_set_wrapping(log_stream, ZLOG_TRUE);
+ zlog_stream_set_msg_prefix(log_stream, "[pool %s] child %d said into %s: ",
+ child->wp->config->name, (int) child->pid, is_stdout ? "stdout" : "stderr");
+ zlog_stream_set_msg_quoting(log_stream, ZLOG_TRUE);
+ } else {
+ log_stream = child->log_stream;
+ }
while (fifo_in || fifo_out) {
if (fifo_in) {
}
} else {
in_buf += res;
+ /* if buffer ends with \0, then the stream will be finished */
+ if (!buf[in_buf - 1]) {
+ finish_log_stream = 1;
+ in_buf--;
+ }
}
}
if (nl) {
/* we should print each new line int the new message */
int out_len = nl - buf;
- zlog_stream_str(&stream, buf, out_len);
- zlog_stream_finish(&stream);
+ zlog_stream_str(log_stream, buf, out_len);
+ zlog_stream_finish(log_stream);
/* skip new line */
out_len++;
/* move data in the buffer */
in_buf -= out_len;
} else if (in_buf == max_buf_size - 1 || !fifo_in) {
/* we should print if no more space in the buffer or no more data to come */
- zlog_stream_str(&stream, buf, in_buf);
+ zlog_stream_str(log_stream, buf, in_buf);
in_buf = 0;
}
}
}
if (read_fail) {
- zlog_stream_set_msg_suffix(&stream, NULL, ", pipe is closed");
- zlog_stream_close(&stream);
+ zlog_stream_set_msg_suffix(log_stream, NULL, ", pipe is closed");
+ zlog_stream_finish(log_stream);
if (read_fail < 0) {
zlog(ZLOG_SYSERROR, "unable to read what child say");
}
close(child->fd_stderr);
child->fd_stderr = -1;
}
- } else {
- zlog_stream_close(&stream);
+ } else if (finish_log_stream) {
+ zlog_stream_finish(log_stream);
}
}
/* }}} */
static int zlog_level = ZLOG_NOTICE;
static int zlog_limit = ZLOG_DEFAULT_LIMIT;
static zlog_bool zlog_buffering = ZLOG_DEFAULT_BUFFERING;
-static struct zlog_stream_buffer zlog_buffer = {NULL, 0};
static int launched = 0;
static void (*external_logger)(int, char *, size_t) = NULL;
}
/* }}} */
-void zlog_cleanup() /* {{{ */
-{
- if (zlog_buffer.data) {
- free(zlog_buffer.data);
- zlog_buffer.data = NULL;
- zlog_buffer.size = 0;
- }
-}
-/* }}} */
-
static inline size_t zlog_truncate_buf(char *buf, size_t buf_size, size_t space_left) /* {{{ */
{
memcpy(buf + buf_size - sizeof("...") + 1 - space_left, "...", sizeof("...") - 1);
buf = realloc(stream->buf.data, size);
} else {
size = MIN(zlog_limit, MAX(size, needed));
- if (stream->shared_buffer && zlog_buffer.data) {
- if (zlog_buffer.size < size) {
- buf = realloc(stream->buf.data, size);
- } else {
- buf = zlog_buffer.data;
- size = zlog_buffer.size;
- }
- } else {
- buf = malloc(size);
- }
+ buf = malloc(size);
}
if (buf == NULL) {
stream->buf.data = buf;
stream->buf.size = size;
- if (stream->shared_buffer) {
- zlog_buffer.data = buf;
- zlog_buffer.size = size;
- }
return 1;
}
stream->prefix_buffer = (flags & ZLOG_LEVEL_MASK) >= zlog_level &&
(stream->use_fd || stream->use_stderr || stream->use_syslog);
stream->fd = fd > -1 ? fd : STDERR_FILENO;
- stream->shared_buffer = external_logger == NULL;
}
/* }}} */
void zlog_stream_destroy(struct zlog_stream *stream) /* {{{ */
{
- if (!stream->shared_buffer && stream->buf.data != NULL) {
+ if (stream->buf.data != NULL) {
free(stream->buf.data);
}
if (stream->msg_prefix != NULL) {
--- /dev/null
+--TEST--
+FPM: Buffered worker output decorated log with multiple continuous messages
+--SKIPIF--
+<?php include "skipif.inc"; ?>
+--FILE--
+<?php
+
+require_once "tester.inc";
+
+$cfg = <<<EOT
+[global]
+error_log = {{FILE:LOG}}
+[unconfined]
+listen = {{ADDR}}
+pm = dynamic
+pm.max_children = 5
+pm.start_servers = 1
+pm.min_spare_servers = 1
+pm.max_spare_servers = 3
+catch_workers_output = yes
+EOT;
+
+$code = <<<EOT
+<?php
+file_put_contents('php://stderr', "msg 1 - ");
+usleep(1);
+file_put_contents('php://stderr', "msg 2 - ");
+usleep(1);
+file_put_contents('php://stderr', "msg 3");
+EOT;
+
+$tester = new FPM\Tester($cfg, $code);
+$tester->start();
+$tester->expectLogStartNotices();
+$tester->request()->expectEmptyBody();
+$tester->request()->expectEmptyBody();
+$tester->terminate();
+$tester->expectLogLine('msg 1 - msg 2 - msg 3');
+$tester->expectLogLine('msg 1 - msg 2 - msg 3');
+$tester->close();
+
+?>
+Done
+--EXPECT--
+Done
+--CLEAN--
+<?php
+require_once "tester.inc";
+FPM\Tester::clean();
+?>
\ No newline at end of file