From 5842a4147f25c9108d3a123d2304bd1d02b6acc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Loyet?= Date: Tue, 5 Jul 2011 19:22:45 +0000 Subject: [PATCH] - FR #52052: Added partial syslog support (on error_log only) --- NEWS | 3 + sapi/fpm/fpm/fpm_conf.c | 221 ++++++++++++++++++++++++++++++++++++--- sapi/fpm/fpm/fpm_conf.h | 5 + sapi/fpm/fpm/fpm_stdio.c | 28 ++++- sapi/fpm/fpm/zlog.c | 70 +++++++++---- sapi/fpm/fpm/zlog.h | 8 ++ sapi/fpm/php-fpm.conf.in | 15 +++ 7 files changed, 313 insertions(+), 37 deletions(-) diff --git a/NEWS b/NEWS index d5537447011..d77ebd10f67 100644 --- a/NEWS +++ b/NEWS @@ -132,6 +132,9 @@ PHP NEWS getallheaders(), apache_request_headers() and apache_response_headers() . Improved performance of FastCGI request parsing. +- Improved PHP-FPM SAPI: + . Added partial syslog support (on error_log only). FR #52052. (fat) + - Improved core functions: . number_format() no longer truncates multibyte decimal points and thousand separators to the first byte. FR #53457. (Adam) diff --git a/sapi/fpm/fpm/fpm_conf.c b/sapi/fpm/fpm/fpm_conf.c index 6a37ae27f4f..a7ad4d25511 100644 --- a/sapi/fpm/fpm/fpm_conf.c +++ b/sapi/fpm/fpm/fpm_conf.c @@ -31,6 +31,7 @@ #include "zend_ini_scanner.h" #include "zend_globals.h" #include "zend_stream.h" +#include "php_syslog.h" #include "fpm.h" #include "fpm_conf.h" @@ -58,8 +59,16 @@ static char *fpm_conf_set_string(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_log_level(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_rlimit_core(zval *value, void **config, intptr_t offset); static char *fpm_conf_set_pm(zval *value, void **config, intptr_t offset); +#ifdef HAVE_SYSLOG_H +static char *fpm_conf_set_syslog_facility(zval *value, void **config, intptr_t offset); +#endif -struct fpm_global_config_s fpm_global_config = { .daemonize = 1 }; +struct fpm_global_config_s fpm_global_config = { + .daemonize = 1, +#ifdef HAVE_SYSLOG_H + .syslog_facility = -1 +#endif +}; static struct fpm_worker_pool_s *current_wp = NULL; static int ini_recursion = 0; static char *ini_filename = NULL; @@ -67,15 +76,19 @@ static int ini_lineno = 0; static char *ini_include = NULL; static struct ini_value_parser_s ini_fpm_global_options[] = { - { "emergency_restart_threshold", &fpm_conf_set_integer, GO(emergency_restart_threshold) }, - { "emergency_restart_interval", &fpm_conf_set_time, GO(emergency_restart_interval) }, - { "process_control_timeout", &fpm_conf_set_time, GO(process_control_timeout) }, - { "daemonize", &fpm_conf_set_boolean, GO(daemonize) }, - { "pid", &fpm_conf_set_string, GO(pid_file) }, - { "error_log", &fpm_conf_set_string, GO(error_log) }, - { "log_level", &fpm_conf_set_log_level, 0 }, - { "rlimit_files", &fpm_conf_set_integer, GO(rlimit_files) }, - { "rlimit_core", &fpm_conf_set_rlimit_core, GO(rlimit_core) }, + { "emergency_restart_threshold", &fpm_conf_set_integer, GO(emergency_restart_threshold) }, + { "emergency_restart_interval", &fpm_conf_set_time, GO(emergency_restart_interval) }, + { "process_control_timeout", &fpm_conf_set_time, GO(process_control_timeout) }, + { "daemonize", &fpm_conf_set_boolean, GO(daemonize) }, + { "pid", &fpm_conf_set_string, GO(pid_file) }, + { "error_log", &fpm_conf_set_string, GO(error_log) }, + { "log_level", &fpm_conf_set_log_level, GO(log_level) }, +#ifdef HAVE_SYSLOG_H + { "syslog.ident", &fpm_conf_set_string, GO(syslog_ident) }, + { "syslog.facility", &fpm_conf_set_syslog_facility, GO(syslog_facility) }, +#endif + { "rlimit_files", &fpm_conf_set_integer, GO(rlimit_files) }, + { "rlimit_core", &fpm_conf_set_rlimit_core, GO(rlimit_core) }, { 0, 0, 0 } }; @@ -252,25 +265,178 @@ static char *fpm_conf_set_time(zval *value, void **config, intptr_t offset) /* { static char *fpm_conf_set_log_level(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); + int log_level; if (!strcasecmp(val, "debug")) { - fpm_globals.log_level = ZLOG_DEBUG; + log_level = ZLOG_DEBUG; } else if (!strcasecmp(val, "notice")) { - fpm_globals.log_level = ZLOG_NOTICE; + log_level = ZLOG_NOTICE; } else if (!strcasecmp(val, "warning") || !strcasecmp(val, "warn")) { - fpm_globals.log_level = ZLOG_WARNING; + log_level = ZLOG_WARNING; } else if (!strcasecmp(val, "error")) { - fpm_globals.log_level = ZLOG_ERROR; + log_level = ZLOG_ERROR; } else if (!strcasecmp(val, "alert")) { - fpm_globals.log_level = ZLOG_ALERT; + log_level = ZLOG_ALERT; } else { return "invalid value for 'log_level'"; } + * (int *) ((char *) *config + offset) = log_level; return NULL; } /* }}} */ +#ifdef HAVE_SYSLOG_H +static char *fpm_conf_set_syslog_facility(zval *value, void **config, intptr_t offset) /* {{{ */ +{ + char *val = Z_STRVAL_P(value); + int *conf = (int *) ((char *) *config + offset); + +#ifdef LOG_AUTH + if (!strcasecmp(val, "AUTH")) { + *conf = LOG_AUTH; + return NULL; + } +#endif + +#ifdef LOG_AUTHPRIV + if (!strcasecmp(val, "AUTHPRIV")) { + *conf = LOG_AUTHPRIV; + return NULL; + } +#endif + +#ifdef LOG_CRON + if (!strcasecmp(val, "CRON")) { + *conf = LOG_CRON; + return NULL; + } +#endif + +#ifdef LOG_DAEMON + if (!strcasecmp(val, "DAEMON")) { + *conf = LOG_DAEMON; + return NULL; + } +#endif + +#ifdef LOG_FTP + if (!strcasecmp(val, "FTP")) { + *conf = LOG_FTP; + return NULL; + } +#endif + +#ifdef LOG_KERN + if (!strcasecmp(val, "KERN")) { + *conf = LOG_KERN; + return NULL; + } +#endif + +#ifdef LOG_LPR + if (!strcasecmp(val, "LPR")) { + *conf = LOG_LPR; + return NULL; + } +#endif + +#ifdef LOG_MAIL + if (!strcasecmp(val, "MAIL")) { + *conf = LOG_MAIL; + return NULL; + } +#endif + +#ifdef LOG_NEWS + if (!strcasecmp(val, "NEWS")) { + *conf = LOG_NEWS; + return NULL; + } +#endif + +#ifdef LOG_SYSLOG + if (!strcasecmp(val, "SYSLOG")) { + *conf = LOG_SYSLOG; + return NULL; + } +#endif + +#ifdef LOG_USER + if (!strcasecmp(val, "USER")) { + *conf = LOG_USER; + return NULL; + } +#endif + +#ifdef LOG_UUCP + if (!strcasecmp(val, "UUCP")) { + *conf = LOG_UUCP; + return NULL; + } +#endif + +#ifdef LOG_LOCAL0 + if (!strcasecmp(val, "LOCAL0")) { + *conf = LOG_LOCAL0; + return NULL; + } +#endif + +#ifdef LOG_LOCAL1 + if (!strcasecmp(val, "LOCAL1")) { + *conf = LOG_LOCAL1; + return NULL; + } +#endif + +#ifdef LOG_LOCAL2 + if (!strcasecmp(val, "LOCAL2")) { + *conf = LOG_LOCAL2; + return NULL; + } +#endif + +#ifdef LOG_LOCAL3 + if (!strcasecmp(val, "LOCAL3")) { + *conf = LOG_LOCAL3; + return NULL; + } +#endif + +#ifdef LOG_LOCAL4 + if (!strcasecmp(val, "LOCAL4")) { + *conf = LOG_LOCAL4; + return NULL; + } +#endif + +#ifdef LOG_LOCAL5 + if (!strcasecmp(val, "LOCAL5")) { + *conf = LOG_LOCAL5; + return NULL; + } +#endif + +#ifdef LOG_LOCAL6 + if (!strcasecmp(val, "LOCAL6")) { + *conf = LOG_LOCAL6; + return NULL; + } +#endif + +#ifdef LOG_LOCAL7 + if (!strcasecmp(val, "LOCAL7")) { + *conf = LOG_LOCAL7; + return NULL; + } +#endif + + return "invalid value"; +} +/* }}} */ +#endif + static char *fpm_conf_set_rlimit_core(zval *value, void **config, intptr_t offset) /* {{{ */ { char *val = Z_STRVAL_P(value); @@ -794,11 +960,26 @@ static int fpm_conf_post_process(TSRMLS_D) /* {{{ */ fpm_evaluate_full_path(&fpm_global_config.pid_file, NULL, PHP_LOCALSTATEDIR, 0); } + fpm_globals.log_level = fpm_global_config.log_level; + if (!fpm_global_config.error_log) { fpm_global_config.error_log = strdup("log/php-fpm.log"); } - fpm_evaluate_full_path(&fpm_global_config.error_log, NULL, PHP_LOCALSTATEDIR, 0); +#ifdef HAVE_SYSLOG_H + if (!fpm_global_config.syslog_ident) { + fpm_global_config.syslog_ident = strdup("php-fpm"); + } + + if (fpm_global_config.syslog_facility < 0) { + fpm_global_config.syslog_facility = LOG_DAEMON; + } + + if (strcasecmp(fpm_global_config.error_log, "syslog") != 0) +#endif + { + fpm_evaluate_full_path(&fpm_global_config.error_log, NULL, PHP_LOCALSTATEDIR, 0); + } if (0 > fpm_stdio_open_error_log(0)) { return -1; @@ -832,6 +1013,10 @@ static void fpm_conf_cleanup(int which, void *arg) /* {{{ */ free(fpm_global_config.error_log); fpm_global_config.pid_file = 0; fpm_global_config.error_log = 0; +#ifdef HAVE_SYSLOG_H + free(fpm_global_config.syslog_ident); + fpm_global_config.syslog_ident = 0; +#endif free(fpm_globals.config); } /* }}} */ @@ -1152,6 +1337,10 @@ static void fpm_conf_dump() /* {{{ */ zlog(ZLOG_NOTICE, "\tdaemonize = %s", BOOL2STR(fpm_global_config.daemonize)); zlog(ZLOG_NOTICE, "\terror_log = %s", STR2STR(fpm_global_config.error_log)); zlog(ZLOG_NOTICE, "\tlog_level = %s", zlog_get_level_name(fpm_globals.log_level)); +#ifdef HAVE_SYSLOG_H + zlog(ZLOG_NOTICE, "\tsyslog.ident = %s", STR2STR(fpm_global_config.syslog_ident)); + zlog(ZLOG_NOTICE, "\tsyslog.facility = %d", fpm_global_config.syslog_facility); /* FIXME: convert to string */ +#endif zlog(ZLOG_NOTICE, "\tprocess_control_timeout = %ds", fpm_global_config.process_control_timeout); zlog(ZLOG_NOTICE, "\temergency_restart_interval = %ds", fpm_global_config.emergency_restart_interval); zlog(ZLOG_NOTICE, "\temergency_restart_threshold = %d", fpm_global_config.emergency_restart_threshold); diff --git a/sapi/fpm/fpm/fpm_conf.h b/sapi/fpm/fpm/fpm_conf.h index 2152527eea4..87a5cd332b6 100644 --- a/sapi/fpm/fpm/fpm_conf.h +++ b/sapi/fpm/fpm/fpm_conf.h @@ -25,6 +25,11 @@ struct fpm_global_config_s { int daemonize; char *pid_file; char *error_log; + int log_level; +#ifdef HAVE_SYSLOG_H + char *syslog_ident; + int syslog_facility; +#endif int rlimit_files; int rlimit_core; }; diff --git a/sapi/fpm/fpm/fpm_stdio.c b/sapi/fpm/fpm/fpm_stdio.c index 571f3074b53..4948194f84f 100644 --- a/sapi/fpm/fpm/fpm_stdio.c +++ b/sapi/fpm/fpm/fpm_stdio.c @@ -11,6 +11,8 @@ #include #include +#include "php_syslog.h" + #include "fpm.h" #include "fpm_children.h" #include "fpm_events.h" @@ -42,8 +44,10 @@ int fpm_stdio_init_main() /* {{{ */ int fpm_stdio_init_final() /* {{{ */ { if (fpm_global_config.daemonize) { - if (fpm_globals.error_log_fd != STDERR_FILENO) { - /* there might be messages to stderr from libevent, we need to log them all */ + /* prevent duping if logging to syslog */ + if (fpm_globals.error_log_fd > 0 && fpm_globals.error_log_fd != STDERR_FILENO) { + + /* there might be messages to stderr from other parts of the code, we need to log them all */ if (0 > dup2(fpm_globals.error_log_fd, STDERR_FILENO)) { zlog(ZLOG_SYSERROR, "dup2() failed"); return -1; @@ -57,7 +61,14 @@ int fpm_stdio_init_final() /* {{{ */ int fpm_stdio_init_child(struct fpm_worker_pool_s *wp) /* {{{ */ { - close(fpm_globals.error_log_fd); +#ifdef HAVE_SYSLOG_H + if (fpm_globals.error_log_fd == ZLOG_SYSLOG) { + closelog(); /* ensure to close syslog not to interrupt with PHP syslog code */ + } else +#endif + if (fpm_globals.error_log_fd > 0) { + close(fpm_globals.error_log_fd); + } fpm_globals.error_log_fd = -1; zlog_set_fd(-1); @@ -249,6 +260,17 @@ int fpm_stdio_open_error_log(int reopen) /* {{{ */ { int fd; +#ifdef HAVE_SYSLOG_H + if (!strcasecmp(fpm_global_config.error_log, "syslog")) { + openlog(fpm_global_config.syslog_ident, LOG_PID | LOG_CONS, fpm_global_config.syslog_facility); + fpm_globals.error_log_fd = ZLOG_SYSLOG; + if (fpm_global_config.daemonize) { + zlog_set_fd(fpm_globals.error_log_fd); + } + return 0; + } +#endif + fd = open(fpm_global_config.error_log, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); if (0 > fd) { zlog(ZLOG_SYSERROR, "open(\"%s\") failed", fpm_global_config.error_log); diff --git a/sapi/fpm/fpm/zlog.c b/sapi/fpm/fpm/zlog.c index 6b062eb8ae2..b127ec16f67 100644 --- a/sapi/fpm/fpm/zlog.c +++ b/sapi/fpm/fpm/zlog.c @@ -12,6 +12,8 @@ #include #include +#include "php_syslog.h" + #include "zlog.h" #include "fpm.h" @@ -22,13 +24,23 @@ static int zlog_level = ZLOG_NOTICE; static int launched = 0; static const char *level_names[] = { - [ZLOG_DEBUG] = "DEBUG", - [ZLOG_NOTICE] = "NOTICE", - [ZLOG_WARNING] = "WARNING", - [ZLOG_ERROR] = "ERROR", - [ZLOG_ALERT] = "ALERT", + [ZLOG_DEBUG] = "DEBUG", + [ZLOG_NOTICE] = "NOTICE", + [ZLOG_WARNING] = "WARNING", + [ZLOG_ERROR] = "ERROR", + [ZLOG_ALERT] = "ALERT", }; +#ifdef HAVE_SYSLOG_H +const int syslog_priorities[] = { + [ZLOG_DEBUG] = LOG_DEBUG, + [ZLOG_NOTICE] = LOG_NOTICE, + [ZLOG_WARNING] = LOG_WARNING, + [ZLOG_ERROR] = LOG_ERR, + [ZLOG_ALERT] = LOG_ALERT, +}; +#endif + const char *zlog_get_level_name(int log_level) /* {{{ */ { if (log_level < 0) { @@ -94,18 +106,30 @@ void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* } saved_errno = errno; - if (!fpm_globals.is_child) { - gettimeofday(&tv, 0); - len = zlog_print_time(&tv, buf, buf_size); - } - if (zlog_level == ZLOG_DEBUG) { - if (!fpm_globals.is_child) { - len += snprintf(buf + len, buf_size - len, "%s: pid %d, %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], getpid(), function, line); +#ifdef HAVE_SYSLOG_H + if (zlog_fd == ZLOG_SYSLOG /* && !fpm_globals.is_child */) { + len = 0; + if (zlog_level == ZLOG_DEBUG) { + len += snprintf(buf, buf_size, "[%s] %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line); } else { - len += snprintf(buf + len, buf_size - len, "%s: %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line); + len += snprintf(buf, buf_size, "[%s] ", level_names[flags & ZLOG_LEVEL_MASK]); + } + } else +#endif + { + if (!fpm_globals.is_child) { + gettimeofday(&tv, 0); + len = zlog_print_time(&tv, buf, buf_size); + } + if (zlog_level == ZLOG_DEBUG) { + if (!fpm_globals.is_child) { + len += snprintf(buf + len, buf_size - len, "%s: pid %d, %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], getpid(), function, line); + } else { + len += snprintf(buf + len, buf_size - len, "%s: %s(), line %d: ", level_names[flags & ZLOG_LEVEL_MASK], function, line); + } + } else { + len += snprintf(buf + len, buf_size - len, "%s: ", level_names[flags & ZLOG_LEVEL_MASK]); } - } else { - len += snprintf(buf + len, buf_size - len, "%s: ", level_names[flags & ZLOG_LEVEL_MASK]); } if (len > buf_size - 1) { @@ -135,9 +159,19 @@ void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) /* len = buf_size - 1; } - buf[len++] = '\n'; - write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len); - if (zlog_fd != STDERR_FILENO && zlog_fd > -1 && !launched && (flags & ZLOG_LEVEL_MASK) >= ZLOG_NOTICE) { +#ifdef HAVE_SYSLOG_H + if (zlog_fd == ZLOG_SYSLOG) { + buf[len] = '\0'; + php_syslog(syslog_priorities[zlog_level], "%s", buf); + buf[len++] = '\n'; + } else +#endif + { + buf[len++] = '\n'; + write(zlog_fd > -1 ? zlog_fd : STDERR_FILENO, buf, len); + } + + if (zlog_fd != STDERR_FILENO && zlog_fd != -1 && !launched && (flags & ZLOG_LEVEL_MASK) >= ZLOG_NOTICE) { write(STDERR_FILENO, buf, len); } } diff --git a/sapi/fpm/fpm/zlog.h b/sapi/fpm/fpm/zlog.h index a83e329023e..e6a5c019a88 100644 --- a/sapi/fpm/fpm/zlog.h +++ b/sapi/fpm/fpm/zlog.h @@ -19,6 +19,10 @@ size_t zlog_print_time(struct timeval *tv, char *timebuf, size_t timebuf_len); void zlog_ex(const char *function, int line, int flags, const char *fmt, ...) __attribute__ ((format(printf,4,5))); +#ifdef HAVE_SYSLOG_H +extern const int syslog_priorities[]; +#endif + enum { ZLOG_DEBUG = 1, ZLOG_NOTICE = 2, @@ -33,4 +37,8 @@ enum { #define ZLOG_SYSERROR (ZLOG_ERROR | ZLOG_HAVE_ERRNO) +#ifdef HAVE_SYSLOG_H +#define ZLOG_SYSLOG -2 +#endif + #endif diff --git a/sapi/fpm/php-fpm.conf.in b/sapi/fpm/php-fpm.conf.in index 2997ac67f92..00db9e340e7 100644 --- a/sapi/fpm/php-fpm.conf.in +++ b/sapi/fpm/php-fpm.conf.in @@ -25,10 +25,25 @@ ;pid = run/php-fpm.pid ; Error log file +; If it's set to "syslog", log is sent to syslogd instead of being written +; in a local file. ; Note: the default prefix is @EXPANDED_LOCALSTATEDIR@ ; Default Value: log/php-fpm.log ;error_log = log/php-fpm.log +; syslog_facility is used to specify what type of program is logging the +; message. This lets syslogd specify that messages from different facilities +; will be handled differently. +; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON) +; Default Value: daemon +;syslog.facility = daemon + +; syslog_ident is prepended to every message. If you have multiple FPM +; instances running on the same server, you can change the default value +; which must suit common needs. +; Default Value: php-fpm +;syslog.ident = php-fpm + ; Log level ; Possible Values: alert, error, warning, notice, debug ; Default Value: notice