Implement %M datestamping in log filenames.
authorPhil Pennock <pdp@exim.org>
Sun, 13 Feb 2011 05:31:49 +0000 (00:31 -0500)
committerPhil Pennock <pdp@exim.org>
Sun, 13 Feb 2011 05:31:49 +0000 (00:31 -0500)
Patch from Simon Arlott.

fixes bug 486

13 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/exim_monitor/em_globals.c
src/exim_monitor/em_main.c
src/src/expand.c
src/src/globals.c
src/src/globals.h
src/src/log.c
src/src/macros.h
src/src/readconf.c
src/src/string.c
src/src/tod.c

index b75e36b..bc9dd2e 100644 (file)
@@ -32110,8 +32110,10 @@ log_file_path = $spool_directory/log/%slog
 If you do not specify anything at build time or run time, that is where the
 logs are written.
 
-A log file path may also contain &`%D`& if datestamped log file names are in
-use &-- see section &<<SECTdatlogfil>>& below.
+.new
+A log file path may also contain &`%D`& or &`%M`& if datestamped log file names
+are in use &-- see section &<<SECTdatlogfil>>& below.
+.wen
 
 Here are some examples of possible settings:
 .display
@@ -32151,18 +32153,20 @@ renamed.
 
 
 
+.new
 .section "Datestamped log files" "SECTdatlogfil"
 .cindex "log" "datestamped files"
 Instead of cycling the main and reject log files by renaming them
 periodically, some sites like to use files whose names contain a datestamp,
-for example, &_mainlog-20031225_&. The datestamp is in the form &_yyyymmdd_&.
-Exim has support for this way of working. It is enabled by setting the
-&%log_file_path%& option to a path that includes &`%D`& at the point where the
-datestamp is required. For example:
+for example, &_mainlog-20031225_&. The datestamp is in the form &_yyyymmdd_& or
+&_yyyymm_&. Exim has support for this way of working. It is enabled by setting
+the &%log_file_path%& option to a path that includes &`%D`& or &`%M`& at the
+point where the datestamp is required. For example:
 .code
 log_file_path = /var/spool/exim/log/%slog-%D
 log_file_path = /var/log/exim-%s-%D.log
 log_file_path = /var/spool/exim/log/%D-%slog
+log_file_path = /var/log/exim/%s.%M
 .endd
 As before, &`%s`& is replaced by &"main"& or &"reject"&; the following are
 examples of names generated by the above examples:
@@ -32170,6 +32174,7 @@ examples of names generated by the above examples:
 /var/spool/exim/log/mainlog-20021225
 /var/log/exim-reject-20021225.log
 /var/spool/exim/log/20021225-mainlog
+/var/log/exim/main.200212
 .endd
 When this form of log file is specified, Exim automatically switches to new
 files at midnight. It does not make any attempt to compress old logs; you
@@ -32178,15 +32183,18 @@ run &'exicyclog'& with this form of logging.
 
 The location of the panic log is also determined by &%log_file_path%&, but it
 is not datestamped, because rotation of the panic log does not make sense.
-When generating the name of the panic log, &`%D`& is removed from the string.
-In addition, if it immediately follows a slash, a following non-alphanumeric
-character is removed; otherwise a preceding non-alphanumeric character is
-removed. Thus, the three examples above would give these panic log names:
+When generating the name of the panic log, &`%D`& or &`%M`& are removed from
+the string. In addition, if it immediately follows a slash, a following
+non-alphanumeric character is removed; otherwise a preceding non-alphanumeric
+character is removed. Thus, the four examples above would give these panic
+log names:
 .code
 /var/spool/exim/log/paniclog
 /var/log/exim-panic.log
 /var/spool/exim/log/paniclog
+/var/log/exim/panic
 .endd
+.wen
 
 
 .section "Logging to syslog" "SECID249"
index 439e80a..63a73c9 100644 (file)
@@ -48,6 +48,9 @@ PP/07 Bugzilla 1061: restrict error messages sent over SMTP to not reveal
       SQL string expansion failure details.
       Patch from Andrey Oktyabrski.
 
+PP/08 Bugzilla 486: implement %M datestamping in log filenames.
+      Patch from Simon Arlott.
+
 
 Exim version 4.74
 -----------------
index 46fd6c4..6159bf4 100644 (file)
@@ -22,6 +22,9 @@ Version 4.75
     false.  When true, if the external delivery command exits on a signal then
     Exim will freeze the message in the queue, instead of generating a bounce.
 
+ 3. Log filenames may now use %M as an escape, instead of %D (still available).
+    The %M pattern expands to yyyymm, providing month-level resolution.
+
 
 Version 4.74
 ------------
index b333a94..a9e4980 100644 (file)
@@ -209,6 +209,8 @@ uschar *smtp_active_hostname   = NULL;
 BOOL    split_spool_directory  = FALSE;
 uschar *spool_directory        = US SPOOL_DIRECTORY;
 int     string_datestamp_offset=-1;
+int     string_datestamp_length= 0;
+int     string_datestamp_type  = -1;
 
 BOOL    timestamps_utc         = FALSE;
 BOOL    tls_certificate_verified = FALSE;
index 2756ab0..187dba3 100644 (file)
@@ -645,8 +645,8 @@ stripchart_init();
 only, and we can't tail the log. If not, open the log file and position to the
 end of it. Before doing so, we have to detect whether the log files are
 datestamped, and if so, sort out the name. The string in log_file already has
-%s replaced by "main"; if datestamping is occurring, %D will be present. In
-fact, we don't need to test explicitly - just process the string with
+%s replaced by "main"; if datestamping is occurring, %D or %M will be present.
+In fact, we don't need to test explicitly - just process the string with
 string_format.
 
 Once opened, save the file's inode so that we can detect when the file is
index 287129c..1fd4335 100644 (file)
@@ -1587,7 +1587,7 @@ while (last > first)
     return tod_stamp(tod_zulu);
 
     case vtype_todlf:                          /* Log file datestamp tod */
-    return tod_stamp(tod_log_datestamp);
+    return tod_stamp(tod_log_datestamp_daily);
 
     case vtype_reply:                          /* Get reply address */
     s = find_header(US"reply-to:", exists_only, newsize, TRUE,
index 8631c7d..3882a30 100644 (file)
@@ -1164,6 +1164,8 @@ BOOL    srs_usetimestamp       = TRUE;
 #endif
 BOOL    strict_acl_vars        = FALSE;
 int     string_datestamp_offset= -1;
+int     string_datestamp_length= 0;
+int     string_datestamp_type  = -1;
 BOOL    strip_excess_angle_brackets = FALSE;
 BOOL    strip_trailing_dot     = FALSE;
 uschar *submission_domain      = NULL;
index bdc9bcf..cc9021e 100644 (file)
@@ -744,6 +744,8 @@ extern BOOL    srs_usetimestamp;       /* SRS use timestamp flag */
 #endif
 extern BOOL    strict_acl_vars;        /* ACL variables have to be set before being used */
 extern int     string_datestamp_offset;/* After insertion by string_format */
+extern int     string_datestamp_length;/* After insertion by string_format */
+extern int     string_datestamp_type;  /* After insertion by string_format */
 extern BOOL    strip_excess_angle_brackets; /* Surrounding route-addrs */
 extern BOOL    strip_trailing_dot;     /* Remove dots at ends of domains */
 extern uschar *submission_domain;      /* Domain for submission mode */
index 67a3d85..0995621 100644 (file)
@@ -255,11 +255,12 @@ if (type == lt_process)
 
 /* The names of the other three logs are controlled by file_path. The panic log
 is written to the same directory as the main and reject logs, but its name does
-not have a datestamp. The use of datestamps is indicated by %D in file_path.
-When opening the panic log, if %D is present, we remove the datestamp from the
-generated name; if it is at the start, remove a following non-alphameric
-character as well; otherwise, remove a preceding non-alphameric character. This
-is definitely kludgy, but it sort of does what people want, I hope. */
+not have a datestamp. The use of datestamps is indicated by %D/%M in file_path.
+When opening the panic log, if %D or %M is present, we remove the datestamp
+from the generated name; if it is at the start, remove a following
+non-alphanumeric character as well; otherwise, remove a preceding
+non-alphanumeric character. This is definitely kludgy, but it sort of does what
+people want, I hope. */
 
 else
   {
@@ -307,7 +308,7 @@ else
   else if (string_datestamp_offset >= 0)
     {
     uschar *from = buffer + string_datestamp_offset;
-    uschar *to = from + Ustrlen(tod_stamp(tod_log_datestamp));
+    uschar *to = from + string_datestamp_length;
     if (from == buffer || from[-1] == '/')
       {
       if (!isalnum(*to)) to++;
@@ -858,7 +859,7 @@ if ((flags & LOG_MAIN) != 0 &&
 
     if (mainlog_datestamp != NULL)
       {
-      uschar *nowstamp = tod_stamp(tod_log_datestamp);
+      uschar *nowstamp = tod_stamp(string_datestamp_type);
       if (Ustrncmp (mainlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
         {
         (void)close(mainlogfd);       /* Close the file */
@@ -981,7 +982,7 @@ if ((flags & LOG_REJECT) != 0)
 
     if (rejectlog_datestamp != NULL)
       {
-      uschar *nowstamp = tod_stamp(tod_log_datestamp);
+      uschar *nowstamp = tod_stamp(string_datestamp_type);
       if (Ustrncmp (rejectlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
         {
         (void)close(rejectlogfd);       /* Close the file */
index 3f24025..610221f 100644 (file)
@@ -191,8 +191,9 @@ enum { RESET_NEXT, RESET_ANSWERS, RESET_AUTHORITY, RESET_ADDITIONAL };
 
 /* Argument values for the time-of-day function */
 
-enum { tod_log, tod_log_bare, tod_log_zone, tod_log_datestamp,
-       tod_zone, tod_full, tod_bsdin, tod_mbx, tod_epoch, tod_zulu };
+enum { tod_log, tod_log_bare, tod_log_zone, tod_log_datestamp_daily,
+       tod_log_datestamp_monthly, tod_zone, tod_full, tod_bsdin,
+       tod_mbx, tod_epoch, tod_zulu };
 
 /* For identifying types of driver */
 
index b9d3747..f5e895a 100644 (file)
@@ -3038,8 +3038,8 @@ if (s == NULL)
 spool_directory = s;
 
 /* Expand log_file_path, which must contain "%s" in any component that isn't
-the null string or "syslog". It is also allowed to contain one instance of %D.
-However, it must NOT contain % followed by anything else. */
+the null string or "syslog". It is also allowed to contain one instance of %D
+or %M. However, it must NOT contain % followed by anything else. */
 
 if (*log_file_path != 0)
   {
@@ -3063,7 +3063,7 @@ if (*log_file_path != 0)
     t = Ustrchr(sss, '%');
     if (t != NULL)
       {
-      if (t[1] != 'D' || Ustrchr(t+2, '%') != NULL)
+      if ((t[1] != 'D' && t[1] != 'M') || Ustrchr(t+2, '%') != NULL)
         log_write(0, LOG_MAIN|LOG_PANIC_DIE, "log_file_path \"%s\" contains "
           "unexpected \"%%\" character", s);
       }
index e7a3b92..49ffc96 100644 (file)
@@ -1039,7 +1039,7 @@ as a va_list item.
 The formats are the usual printf() ones, with some omissions (never used) and
 two additions for strings: %S forces lower case, and %#s or %#S prints nothing
 for a NULL string. Without the # "NULL" is printed (useful in debugging). There
-is also the addition of %D, which inserts the date in the form used for
+is also the addition of %D and %M, which insert the date in the form used for
 datestamped log files.
 
 Arguments:
@@ -1075,6 +1075,8 @@ uschar *p = buffer;
 uschar *last = buffer + buflen - 1;
 
 string_datestamp_offset = -1;  /* Datestamp not inserted */
+string_datestamp_length = 0;   /* Datestamp not inserted */
+string_datestamp_type = 0;     /* Datestamp not inserted */
 
 /* Scan the format and handle the insertions */
 
@@ -1229,19 +1231,31 @@ while (*fp != 0)
     *p++ = va_arg(ap, int);
     break;
 
-    case 'D':                   /* Insert datestamp for log file names */
-    s = CS tod_stamp(tod_log_datestamp);
+    case 'D':                   /* Insert daily datestamp for log file names */
+    s = CS tod_stamp(tod_log_datestamp_daily);
     string_datestamp_offset = p - buffer;   /* Passed back via global */
+    string_datestamp_length = Ustrlen(s);   /* Passed back via global */
+    string_datestamp_type = tod_log_datestamp_daily;
+    slen = string_datestamp_length;
+    goto INSERT_STRING;
+
+    case 'M':                   /* Insert monthly datestamp for log file names */
+    s = CS tod_stamp(tod_log_datestamp_monthly);
+    string_datestamp_offset = p - buffer;   /* Passed back via global */
+    string_datestamp_length = Ustrlen(s);   /* Passed back via global */
+    string_datestamp_type = tod_log_datestamp_monthly;
+    slen = string_datestamp_length;
     goto INSERT_STRING;
 
     case 's':
     case 'S':                   /* Forces *lower* case */
     s = va_arg(ap, char *);
 
-    INSERT_STRING:              /* Come to from %D above */
     if (s == NULL) s = null;
     slen = Ustrlen(s);
 
+    INSERT_STRING:              /* Come to from %D or %M above */
+
     /* If the width is specified, check that there is a precision
     set; if not, set it to the width to prevent overruns of long
     strings. */
index 85f7e78..2077111 100644 (file)
@@ -34,17 +34,18 @@ a leading zero for the full stamp, since Ustrftime() doesn't provide this
 option.
 
 Argument:  type of timestamp required:
-             tod_bsdin          BSD inbox format
-             tod_epoch          Unix epoch format
-             tod_full           full date and time
-             tod_log            log file data line format,
-                                  with zone if log_timezone is TRUE
-             tod_log_bare       always without zone
-             tod_log_datestamp  for log file names when datestamped
-             tod_log_zone       always with zone
-             tod_mbx            MBX inbox format
-             tod_zone           just the timezone offset
-             tod_zulu           time in 8601 zulu format
+             tod_bsdin                  BSD inbox format
+             tod_epoch                  Unix epoch format
+             tod_full                   full date and time
+             tod_log                    log file data line format,
+                                          with zone if log_timezone is TRUE
+             tod_log_bare               always without zone
+             tod_log_datestamp_daily    for log file names when datestamped daily
+             tod_log_datestamp_monthly  for log file names when datestamped monthly
+             tod_log_zone               always with zone
+             tod_mbx                    MBX inbox format
+             tod_zone                   just the timezone offset
+             tod_zulu                   time in 8601 zulu format
 
 Returns:   pointer to fixed buffer containing the timestamp
 */
@@ -91,16 +92,25 @@ switch(type)
   /* Format used as suffix of log file name when 'log_datestamp' is active. For
   testing purposes, it changes the file every second. */
 
-  case tod_log_datestamp:
   #ifdef TESTING_LOG_DATESTAMP
+  case tod_log_datestamp_daily:
+  case tod_log_datestamp_monthly:
   (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d",
     1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min);
+  break;
+
   #else
+  case tod_log_datestamp_daily:
   (void) sprintf(CS timebuf, "%04d%02d%02d",
     1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday);
-  #endif
   break;
 
+  case tod_log_datestamp_monthly:
+  (void) sprintf(CS timebuf, "%04d%02d",
+    1900 + t->tm_year, 1 + t->tm_mon);
+  break;
+  #endif
+
   /* Format used in BSD inbox separator lines. Sort-of documented in RFC 976
   ("UUCP Mail Interchange Format Standard") but only by example, not by
   explicit definition. The examples show no timezone offsets, and some MUAs