]> mj.ucw.cz Git - libucw.git/commitdiff
Logging: Rewritten the log-file module to implement log switching.
authorMartin Mares <mj@ucw.cz>
Fri, 13 Feb 2009 18:20:47 +0000 (19:20 +0100)
committerMartin Mares <mj@ucw.cz>
Fri, 13 Feb 2009 18:20:47 +0000 (19:20 +0100)
  o  log-file is a cross between the old libucw code and Tom's version.
  o  Introduced log_stream->udata for backend's flags.
  o  log_fork() moved to log.c.
  o  log_switch() and log_file() are not implemented yet.

ucw/lib.h
ucw/log-file.c
ucw/log.c
ucw/log.h

index 22db7ef1b9b047dc0e855d4d06f95c8bf930d855..8448eac5873af207f2a1e6b61321e4a3bc861811 100644 (file)
--- a/ucw/lib.h
+++ b/ucw/lib.h
@@ -110,11 +110,9 @@ void log_fork(void);                       /* Call after fork() to update log_pid */
 
 /* If the log name contains metacharacters for date and time, we switch the logs
  * automatically whenever the name changes. You can disable it and switch explicitly. */
-#if 0 // FIXME
 int log_switch(void);
 void log_switch_disable(void);
 void log_switch_enable(void);
-#endif
 
 void assert_failed(const char *assertion, const char *file, int line) NONRET;
 void assert_failed_noinfo(void) NONRET;
index 2df094989cdd45acd000d1a1eb219ee073c39fe2..fe85a270f94b1624090cda009c2d418b57c0c19b 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 #include <time.h>
-#include <errno.h>
 
-#if 0 // FIXME
+/*
+ *  Use of the private fields of struct log_stream:
+ *
+ *     idata   file descriptor
+ *     udata   various flags (FF_xxx)
+ *     pdata   original name with strftime escapes
+ *     name    current name of the log file
+ *             (a dynamically allocated buffer)
+ */
+
+enum log_file_flag {
+  FF_FORMAT_NAME = 1,          // Name contains strftime escapes
+  FF_CLOSE_FD = 2,             // Close the fd with the stream
+};
+
+#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 int
-do_log_switch(struct tm *tm)
+static void
+do_log_reopen(struct log_stream *ls, const char *name)
 {
-  int fd, l;
-  char name[log_filename_size];
-  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))
+  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 (ls->idata < 0)
+    ls->idata = fd;
+  else
     {
-      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);
+      dup2(fd, ls->idata);
       close(fd);
-      switched = 1;
     }
-  log_switch_nest--;
-  ucwlib_unlock();
-  return switched;
+  if (ls->name)
+    {
+      xfree(ls->name);
+      ls->name = NULL;         // We have to keep this consistent, die() below can invoke logging
+    }
+  ls->name = xstrdup(name);
 }
 
-int
-log_switch(void)
+static int
+do_log_switch(struct log_stream *ls, struct tm *tm)
 {
-  time_t tim = time(NULL);
-  return do_log_switch(localtime(&tim));
-}
+  if (!(ls->udata & FF_FORMAT_NAME))
+    {
+      if (ls->idata >= 0)
+       return 1;
+      else
+       {
+         do_log_reopen(ls, ls->pdata);
+         return 1;
+       }
+    }
 
-static void
-internal_log_switch(struct tm *tm)
-{
-  if (!log_switch_nest)
-    do_log_switch(tm);
-}
+  int buflen = strlen(ls->pdata) + MAX_EXPAND;
+  char name[buflen];
+  int switched = 0;
 
-void
-log_file(const char *name)
-{
-  if (name)
+  ucwlib_lock();
+  if (!log_switch_nest)                // Avoid infinite loops if we die when switching logs
     {
-      if (log_name_patt)
-       xfree(log_name_patt);
-      if (log_filename)
+      log_switch_nest++;
+      int l = strftime(name, buflen, ls->pdata, tm);
+      if (l < 0 || l >= buflen)
+       die("Error formatting log file name: %m");
+      if (!ls->name || strcmp(name, ls->name))
        {
-         xfree(log_filename);
-         log_filename = NULL;
+         do_log_reopen(ls, name);
+         switched = 1;
        }
-      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;
+      log_switch_nest--;
     }
+  ucwlib_unlock();
+  return switched;
 }
 
 void
-log_fork(void)
+log_file(const char *name)
 {
-  log_pid = getpid();
+  if (!name)
+    return;
+
+  // FIXME
+}
+
+int
+log_switch(void)
+{
+#if 0 // FIXME
+  time_t tim = time(NULL);
+  return do_log_switch(localtime(&tim));
+#else
+  return 0;
+#endif
 }
 
 void
@@ -112,56 +128,66 @@ log_switch_enable(void)
   log_switch_nest--;
 }
 
-#endif
-
 /* destructor for standard files */
-static void ls_fdfile_close(struct log_stream *ls)
+static void
+file_close(struct log_stream *ls)
 {
-  ASSERT(ls);
-  close(ls->idata);
-  if(ls->name)
-    xfree(ls->name);
+  if ((ls->udata & FF_CLOSE_FD) && ls->idata >= 0)
+    close(ls->idata);
+  xfree(ls->name);
 }
 
 /* handler for standard files */
-static int ls_fdfile_handler(struct log_stream* ls, const char *m, uns cat UNUSED)
+static int
+file_handler(struct log_stream *ls, const char *m, uns cat UNUSED)
 {
+  if (ls->udata & FF_FORMAT_NAME)
+    {
+      // FIXME: pass the time
+      time_t now = time(NULL);
+      struct tm *tm = localtime(&now);
+      do_log_switch(ls, tm);
+    }
+
   int len = strlen(m);
   int r = write(ls->idata, m, len);
-  /* TODO: check the errors here? */
-  if (r!=len)
-    return errno;
+  /* FIXME: check for errors here? */
   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)
+struct log_stream *
+log_new_fd(int fd)
 {
-  struct log_stream *ls=log_new_stream();
-  ls->idata=fd;
-  ls->msgfmt=LSFMT_DEFAULT;
-  ls->handler=ls_fdfile_handler;
+  struct log_stream *ls = log_new_stream();
+  ls->idata = fd;
+  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;
 }
 
 /* open() a file (append mode) */
 /* initialize with the default formatting */
-struct log_stream *ls_file_new(const char *path)
+struct log_stream *
+log_new_file(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;
+  struct log_stream *ls = log_new_stream();
+  ls->idata = -1;
+  ls->pdata = (void *) path;
+  if (strchr(path, '%'))
+    ls->udata = FF_FORMAT_NAME;
+  ls->udata |= FF_CLOSE_FD;
   ls->msgfmt = LSFMT_DEFAULT;
-  ls->handler = ls_fdfile_handler;
-  ls->close = ls_fdfile_close;
+  ls->handler = file_handler;
+  ls->close = file_close;
+
+  time_t now = time(NULL);
+  struct tm *tm = localtime(&now);
+  do_log_switch(ls, tm);               // die()'s on errors
   return ls;
 }
 
@@ -170,9 +196,11 @@ struct log_stream *ls_file_new(const char *path)
 int main(int argc, char **argv)
 {
   log_init(argv[0]);
-  log_file("/proc/self/fd/1");
+  // log_file("/proc/self/fd/1");
+  // struct log_stream *ls = log_new_fd(1);
+  struct log_stream *ls = log_new_file("/tmp/quork-%Y%m%d-%H%M%S");
   for (int i=1; i<argc; i++)
-    msg(L_INFO, argv[i]);
+    msg(L_INFO | ls->regnum, argv[i]);
   return 0;
 }
 
index 075caffbaba7175c340d5ac23c12d2a9cce7d8ad..49b92d4dc8aa82e5424c1e86315245946746e02d 100644 (file)
--- a/ucw/log.c
+++ b/ucw/log.c
@@ -316,11 +316,20 @@ log_init(const char *argv0)
     }
 }
 
+void
+log_fork(void)
+{
+  log_pid = getpid();
+}
+
 #ifdef TEST
 
+#include <syslog.h>
+
 int main(void)
 {
-  msg(L_INFO, "Brum <%300s>", ":-)");
+  struct log_stream *ls = log_new_syslog(LOG_USER, "syslog");
+  msg(L_INFO | ls->regnum, "Brum <%300s>", ":-)");
   return 0;
 }
 
index 93d422b7e6a5be4a09707bd883758cc585f67a09..e4642a535de6fb300bcd0c51c3350bc1e155ec99 100644 (file)
--- a/ucw/log.h
+++ b/ucw/log.h
@@ -25,6 +25,7 @@ struct log_stream
   /* arbitrary data for filter/handler */
   int idata;
   void *pdata;
+  uns udata;
   /* severity levels to accept - bitmask of (1<<LEVEL) */
   int levels;
   /* if filter returns nonzero, discard the message */
@@ -170,11 +171,11 @@ extern int log_streams_after;
 
 /* assign log to a file descriptor */
 /* initialize with the default formatting, does NOT close the descriptor */
-struct log_stream *ls_fdfile_new(int fd);
+struct log_stream *log_new_fd(int fd);
 
 /* open() a file (append mode) */
 /* initialize with the default formatting */
-struct log_stream *ls_file_new(const char *path);
+struct log_stream *log_new_file(const char *path);
 
 
 /**** syslog */