cl_log: Restore old logfile open/seek/write/close behaviour. This patch actually does not completely revert commit 2435:ada347da564d, but adds a layer to support both, open/write/close and and open-once, write, close/open-for signal handlers
It also changes a marco into a static function. And also uses system IO (open/close/write) instead of libc IO (fopen/fclose/fwrite). Libc IO has a buffer, which is not suitable for log files (in case of a stonith, all the buffer and which might large, will be missing in log files. Signed-off-by: Bernd Schubert <bschub...@ddn.com> diff --git a/lib/clplumbing/cl_log.c b/lib/clplumbing/cl_log.c --- a/lib/clplumbing/cl_log.c +++ b/lib/clplumbing/cl_log.c @@ -74,6 +74,7 @@ static IPC_Message* ChildLogIPCMessage(i static void FreeChildLogIPCMessage(IPC_Message* msg); static gboolean send_dropped_message(gboolean use_pri_str, IPC_Channel *chan); static int cl_set_logging_wqueue_maxlen(int qlen); +static char * syslog_timestamp(TIME_T t); static int use_logging_daemon = FALSE; static int conn_logd_time = 0; @@ -92,6 +93,10 @@ int debug_level = 0; static GDestroyNotify destroy_logging_channel_callback; static void (*create_logging_channel_callback)(IPC_Channel* chan); static gboolean logging_chan_in_main_loop = FALSE; +static gboolean have_signal_handler = FALSE; + +static int debug_fd = -1; +static int log_fd = -1; /*********************** *debug use only, do not use this function in your program @@ -477,54 +482,79 @@ prio2str(int priority) "(undef)" : log_prio[logpri]; } -/* print log line to a FILE *f */ -#define print_logline(fp,entity,entity_pid,ts,pristr,buf) { \ - fprintf(fp, "%s[%d]: %s ",entity,entity_pid,ha_timestamp(ts)); \ - if (pristr) \ - fprintf(fp,"%s: %s\n",pristr,buf); \ - else \ - fprintf(fp,"%s\n",buf); \ - } +/* print log line to a string */ +static char * +logline(char *dest, int max_length, const char * entity, + int entity_pid, TIME_T ts, const char * pristr, const char * msg) +{ + static struct utsname un; + + uname(&un); + + if (!syslogformatfile) { + snprintf(dest, max_length, "%s[%d]: %s %s: %s" + , entity, entity_pid + , ha_timestamp(ts) + , (pristr ? pristr : "") + , msg); + } else { + /* + * Jul 14 21:45:18 beam logd: [1056]: info: setting log file to /dev/null + */ + snprintf(dest, max_length, "%s %s %s: [%d]: %s%s%s\n" + , syslog_timestamp(ts) + , un.nodename, entity, entity_pid + , (pristr ? pristr : "") + , (pristr ? ": " : "") + , msg); + } + + return dest; +} -static char * syslog_timestamp(TIME_T t); +/* print log line to the given file handle */ +static void +print_logline(FILE* fh, const char * entity, + int entity_pid, TIME_T ts, const char * pristr, const char * buf) +{ + char log_str[MAXLINE]; + + logline(log_str, MAXLINE, entity, entity_pid, ts, pristr, buf); + fprintf(fh, "%s\n", log_str); +} static void -append_log(FILE * fp, const char * entity, int entity_pid -, TIME_T timestamp, const char * pristr, const char * msg) +append_log(int fd, const char * entity, int entity_pid, + TIME_T ts, const char * pristr, const char * msg) { - static int got_uname = FALSE; - static struct utsname un; - - if (!syslogformatfile) { - print_logline(fp, entity, entity_pid, timestamp, pristr, msg); - return; + char log_str[MAXLINE]; + int rc; + + logline(log_str, MAXLINE, entity, entity_pid, ts, pristr, msg); + + /* write() is better here, as fprintf() and fwrite() may use + * a rather large libc buffer which we would need to flush */ + rc = write(fd, log_str, strlen(log_str)); + if (rc == -1) { + /* writing to the log file failed, try stderr */ + syslog(LOG_ERR, "Failed to write to log file: %s\n", + strerror(errno)); } - if (!got_uname) { - uname(&un); - } - /* - * Jul 14 21:45:18 beam logd: [1056]: info: setting log file to /dev/null - */ - fprintf(fp, "%s %s %s: [%d]: %s%s%s\n" - , syslog_timestamp(timestamp) - , un.nodename, entity, entity_pid - , (pristr ? pristr : "") - , (pristr ? ": " : "") - , msg); } /* * Just open the given file name */ -static FILE * +static int open_log_file(const char * fname) { - FILE * fp = fopen(fname ,"a"); - if (!fp) { + int mode = S_IRUSR | S_IWUSR | S_IRGRP; + int fd = open(fname, O_WRONLY | O_APPEND | O_CREAT, mode); + if (!fd) { syslog(LOG_ERR, "Failed to open log file %s: %s\n" , fname, strerror(errno)); } - return fp; + return fd; } /* @@ -562,26 +592,20 @@ cl_direct_log(int priority, const char* } if (debugfile_name != NULL) { - static FILE * debug_fp = NULL; - if (!debug_fp) { - /* As performance optimization we keep the file-handle - * open all the time */ - debug_fp = open_log_file(debugfile_name); + if (debug_fd != -1) { + debug_fd = open_log_file(debugfile_name); } - if (debug_fp) - append_log(debug_fp ,entity, entity_pid, ts, pristr, + if (debug_fd != -1) + append_log(debug_fd ,entity, entity_pid, ts, pristr, buf); } if (priority != LOG_DEBUG && logfile_name != NULL) { - static FILE * log_fp = NULL; - if (!log_fp) { - /* As performance optimization we keep the file-handle - * open all the time */ - log_fp = open_log_file(logfile_name); + if (log_fd != -1) { + log_fd = open_log_file(logfile_name); } - if (log_fp) - append_log(log_fp ,entity, entity_pid, ts, pristr, + if (log_fd != -1) + append_log(log_fd ,entity, entity_pid, ts, pristr, buf); } @@ -589,6 +613,17 @@ cl_direct_log(int priority, const char* return_to_dropped_privs(); } + /* As performance optimization we try to keep the file descriptor + * open all the time, but as logrotation needs to work, the calling + * program needs a signal handler. Therefore we close fd's, if the + * caller did not tell us it has the signal handler */ + if (have_signal_handler == FALSE) { + close(debug_fd); + close(log_fd); + debug_fd = -1; + log_fd = -1; + } + return; } _______________________________________________ Pacemaker mailing list: Pacemaker@oss.clusterlabs.org http://oss.clusterlabs.org/mailman/listinfo/pacemaker Project Home: http://www.clusterlabs.org Getting started: http://www.clusterlabs.org/doc/Cluster_from_Scratch.pdf Bugs: http://developerbugs.linux-foundation.org/enter_bug.cgi?product=Pacemaker