X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Flog-file.c;h=b00f5b3a054304bc951bdd1cd8f55b5710ffc5d9;hb=4045f354d52664be1725f6bc9724e686e807c424;hp=2df094989cdd45acd000d1a1eb219ee073c39fe2;hpb=50f3497ac9b5b0178de03522b2cfcb5893e7ac2f;p=libucw.git diff --git a/ucw/log-file.c b/ucw/log-file.c index 2df09498..b00f5b3a 100644 --- a/ucw/log-file.c +++ b/ucw/log-file.c @@ -8,10 +8,12 @@ * of the GNU Lesser General Public License. */ -#include "ucw/lib.h" -#include "ucw/log.h" -#include "ucw/lfs.h" -#include "ucw/threads.h" +#include +#include +#include +#include +#include +#include #include #include @@ -20,83 +22,141 @@ #include #include -#if 0 // FIXME +struct file_stream { + struct log_stream ls; // ls.name is the current name of the log file + int fd; + uns flags; // FF_xxx + char *orig_name; // Original name with strftime escapes +}; + +#define MAX_EXPAND 64 // Maximum size of expansion of strftime escapes -static char *log_name_patt; -static int log_params; -static int log_filename_size; static int log_switch_nest; +static void +do_log_reopen(struct file_stream *fs, const char *name) +{ + int fd = ucw_open(name, O_WRONLY | O_CREAT | O_APPEND, 0666); + if (fd < 0) + die("Unable to open log file %s: %m", name); + if (fs->fd >= 0) + close(fs->fd); + fs->fd = fd; + if (fs->flags & FF_FD2_FOLLOWS) + dup2(fd, 2); + if (fs->ls.name) + { + xfree(fs->ls.name); + fs->ls.name = NULL; // We have to keep the stream consistent -- die() below can invoke logging + } + fs->ls.name = xstrdup(name); +} + static int -do_log_switch(struct tm *tm) +do_log_switch(struct file_stream *fs, struct tm *tm) { - int fd, l; - char name[log_filename_size]; + if (!(fs->flags & FF_FORMAT_NAME)) + { + if (fs->fd >= 0) + return 1; + else + { + do_log_reopen(fs, fs->orig_name); + return 1; + } + } + + int buflen = strlen(fs->orig_name) + MAX_EXPAND; + char name[buflen]; int switched = 0; - if (!log_name_patt || - log_filename[0] && !log_params) - return 0; ucwlib_lock(); - log_switch_nest++; - l = strftime(name, log_filename_size, log_name_patt, tm); - if (l < 0 || l >= log_filename_size) - die("Error formatting log file name: %m"); - if (strcmp(name, log_filename)) + if (!log_switch_nest) // Avoid infinite loops if we die when switching logs { - strcpy(log_filename, name); - fd = ucw_open(name, O_WRONLY | O_CREAT | O_APPEND, 0666); - if (fd < 0) - die("Unable to open log file %s: %m", name); - dup2(fd, 2); - close(fd); - switched = 1; + log_switch_nest++; + int l = strftime(name, buflen, fs->orig_name, tm); + if (l < 0 || l >= buflen) + die("Error formatting log file name: %m"); + if (!fs->ls.name || strcmp(name, fs->ls.name)) + { + do_log_reopen(fs, name); + switched = 1; + } + log_switch_nest--; } - log_switch_nest--; ucwlib_unlock(); return switched; } -int -log_switch(void) +static void +file_close(struct log_stream *ls) { - time_t tim = time(NULL); - return do_log_switch(localtime(&tim)); + struct file_stream *fs = (struct file_stream *) ls; + if ((fs->flags & FF_CLOSE_FD) && fs->fd >= 0) + close(fs->fd); + xfree(fs->ls.name); + xfree(fs->orig_name); } -static void -internal_log_switch(struct tm *tm) +static int +file_handler(struct log_stream *ls, struct log_msg *m) { - if (!log_switch_nest) - do_log_switch(tm); + struct file_stream *fs = (struct file_stream *) ls; + if ((fs->flags & FF_FORMAT_NAME) && m->tm) + do_log_switch(fs, m->tm); + + int r = write(fs->fd, m->m, m->m_len); + return ((r < 0) ? errno : 0); } -void -log_file(const char *name) +struct log_stream * +log_new_fd(int fd, uns flags) { - if (name) - { - if (log_name_patt) - xfree(log_name_patt); - if (log_filename) - { - xfree(log_filename); - log_filename = NULL; - } - log_name_patt = xstrdup(name); - log_params = !!strchr(name, '%'); - log_filename_size = strlen(name) + 64; /* 63 is an upper bound on expansion of % escapes */ - log_filename = xmalloc(log_filename_size); - log_filename[0] = 0; - log_switch(); - log_switch_hook = internal_log_switch; - } + struct log_stream *ls = log_new_stream(sizeof(struct file_stream)); + struct file_stream *fs = (struct file_stream *) ls; + fs->fd = fd; + fs->flags = flags; + ls->msgfmt = LSFMT_DEFAULT; + ls->handler = file_handler; + ls->close = file_close; + ls->name = xmalloc(16); + snprintf(ls->name, 16, "fd%d", fd); + return ls; } -void -log_fork(void) +struct log_stream * +log_new_file(const char *path, uns flags) { - log_pid = getpid(); + struct log_stream *ls = log_new_stream(sizeof(struct file_stream)); + struct file_stream *fs = (struct file_stream *) ls; + fs->fd = -1; + fs->orig_name = xstrdup(path); + if (strchr(path, '%')) + fs->flags = FF_FORMAT_NAME; + fs->flags |= FF_CLOSE_FD | flags; + ls->msgfmt = LSFMT_DEFAULT; + ls->handler = file_handler; + ls->close = file_close; + + time_t now = time(NULL); + struct tm *tm = localtime(&now); + ASSERT(tm); + do_log_switch(fs, tm); // die()'s on errors + return ls; +} + +int +log_switch(void) +{ + time_t now = time(NULL); + struct tm *tm = localtime(&now); + ASSERT(tm); + + int switched = 0; + for (int i=0; i < log_streams_after; i++) + if (log_streams.ptr[i]->handler == file_handler) + switched |= do_log_switch((struct file_stream *) log_streams.ptr[i], tm); + return switched; } void @@ -112,57 +172,13 @@ log_switch_enable(void) log_switch_nest--; } -#endif - -/* destructor for standard files */ -static void ls_fdfile_close(struct log_stream *ls) -{ - ASSERT(ls); - close(ls->idata); - if(ls->name) - xfree(ls->name); -} - -/* handler for standard files */ -static int ls_fdfile_handler(struct log_stream* ls, const char *m, uns cat UNUSED) -{ - int len = strlen(m); - int r = write(ls->idata, m, len); - /* TODO: check the errors here? */ - if (r!=len) - return errno; - return 0; -} - -/* assign log to a file descriptor */ -/* initialize with the default formatting, does NOT close the descriptor */ -struct log_stream *ls_fdfile_new(int fd) +void +log_file(const char *name) { - struct log_stream *ls=log_new_stream(); - ls->idata=fd; - ls->msgfmt=LSFMT_DEFAULT; - ls->handler=ls_fdfile_handler; - return ls; -} + if (!name) + return; -/* open() a file (append mode) */ -/* initialize with the default formatting */ -struct log_stream *ls_file_new(const char *path) -{ - struct log_stream *ls; - int fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0666); - if (fd<0) - { - msg(L_ERROR, "Opening logfile '%s' failed: %m.", path); - return NULL; - } - ls = log_new_stream(); - ls->name = xstrdup(path); - ls->idata = fd; - ls->msgfmt = LSFMT_DEFAULT; - ls->handler = ls_fdfile_handler; - ls->close = ls_fdfile_close; - return ls; + log_set_default_stream(log_new_file(name, FF_FD2_FOLLOWS)); } #ifdef TEST @@ -171,8 +187,11 @@ int main(int argc, char **argv) { log_init(argv[0]); log_file("/proc/self/fd/1"); + // struct log_stream *ls = log_new_fd(1, 0); + // struct log_stream *ls = log_new_file("/tmp/quork-%Y%m%d-%H%M%S", 0); for (int i=1; i