mirror of
				https://gitlab.labs.nic.cz/labs/bird.git
				synced 2024-05-11 16:54:54 +00:00 
			
		
		
		
	Unix: Implement log file size limit / log rotation
Allow to specify log file size limit and ensure that log file is rotated to secondary name to avoid exceeding of log size limit. The patch also fixes a bug related to keeping old fds open after reconfiguration and using old fds after 'configure undo'.
This commit is contained in:
		@@ -11,13 +11,16 @@ CF_HDR
 | 
			
		||||
#include "sysdep/unix/unix.h"
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
CF_DEFINES
 | 
			
		||||
 | 
			
		||||
static struct log_config *this_log;
 | 
			
		||||
 | 
			
		||||
CF_DECLS
 | 
			
		||||
 | 
			
		||||
CF_KEYWORDS(LOG, SYSLOG, ALL, DEBUG, TRACE, INFO, REMOTE, WARNING, ERROR, AUTH, FATAL, BUG, STDERR, SOFT)
 | 
			
		||||
CF_KEYWORDS(NAME, CONFIRM, UNDO, CHECK, TIMEOUT, DEBUG, LATENCY, LIMIT, WATCHDOG, WARNING)
 | 
			
		||||
 | 
			
		||||
%type <i> log_mask log_mask_list log_cat cfg_timeout
 | 
			
		||||
%type <g> log_file
 | 
			
		||||
%type <t> cfg_name
 | 
			
		||||
%type <tf> timeformat_which
 | 
			
		||||
%type <t> syslog_name
 | 
			
		||||
@@ -26,11 +29,11 @@ CF_GRAMMAR
 | 
			
		||||
 | 
			
		||||
conf: log_config ;
 | 
			
		||||
 | 
			
		||||
log_config: LOG log_file log_mask ';' {
 | 
			
		||||
    struct log_config *c = cfg_allocz(sizeof(struct log_config));
 | 
			
		||||
    c->fh = $2;
 | 
			
		||||
    c->mask = $3;
 | 
			
		||||
    add_tail(&new_config->logfiles, &c->n);
 | 
			
		||||
log_begin: { this_log = cfg_allocz(sizeof(struct log_config)); };
 | 
			
		||||
 | 
			
		||||
log_config: LOG log_begin log_file log_mask ';' {
 | 
			
		||||
    this_log->mask = $4;
 | 
			
		||||
    add_tail(&new_config->logfiles, &this_log->n);
 | 
			
		||||
  }
 | 
			
		||||
 ;
 | 
			
		||||
 | 
			
		||||
@@ -39,14 +42,21 @@ syslog_name:
 | 
			
		||||
 | { $$ = bird_name; }
 | 
			
		||||
 ;
 | 
			
		||||
 | 
			
		||||
log_limit:
 | 
			
		||||
   /* empty */
 | 
			
		||||
 | expr text { this_log->limit = $1; this_log->backup = $2; }
 | 
			
		||||
 ;
 | 
			
		||||
 | 
			
		||||
log_file:
 | 
			
		||||
   text {
 | 
			
		||||
     struct rfile *f = rf_open(new_config->pool, $1, "a");
 | 
			
		||||
     if (!f) cf_error("Unable to open log file '%s': %m", $1);
 | 
			
		||||
     $$ = rf_file(f);
 | 
			
		||||
   text log_limit {
 | 
			
		||||
     this_log->rf = rf_open(new_config->pool, $1, "a");
 | 
			
		||||
     if (!this_log->rf) cf_error("Unable to open log file '%s': %m", $1);
 | 
			
		||||
     this_log->fh = rf_file(this_log->rf);
 | 
			
		||||
     this_log->pos = -1;
 | 
			
		||||
     this_log->filename = $1;
 | 
			
		||||
   }
 | 
			
		||||
 | SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; }
 | 
			
		||||
 | STDERR { $$ = stderr; }
 | 
			
		||||
 | SYSLOG syslog_name { this_log->fh = NULL; new_config->syslog_name = $2; }
 | 
			
		||||
 | STDERR { this_log->fh = stderr; }
 | 
			
		||||
 ;
 | 
			
		||||
 | 
			
		||||
log_mask:
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,8 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
@@ -86,6 +88,54 @@ static char *class_names[] = {
 | 
			
		||||
  "BUG"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline off_t
 | 
			
		||||
log_size(struct log_config *l)
 | 
			
		||||
{
 | 
			
		||||
  struct stat st;
 | 
			
		||||
  return (!fstat(rf_fileno(l->rf), &st) && S_ISREG(st.st_mode)) ? st.st_size : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
log_close(struct log_config *l)
 | 
			
		||||
{
 | 
			
		||||
  rfree(l->rf);
 | 
			
		||||
  l->rf = NULL;
 | 
			
		||||
  l->fh = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
log_open(struct log_config *l)
 | 
			
		||||
{
 | 
			
		||||
  l->rf = rf_open(config->pool, l->filename, "a");
 | 
			
		||||
  if (!l->rf)
 | 
			
		||||
  {
 | 
			
		||||
    /* Well, we cannot do much in case of error as log is closed */
 | 
			
		||||
    l->mask = 0;
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  l->fh = rf_file(l->rf);
 | 
			
		||||
  l->pos = log_size(l);
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
log_rotate(struct log_config *l)
 | 
			
		||||
{
 | 
			
		||||
  log_close(l);
 | 
			
		||||
 | 
			
		||||
  /* If we cannot rename the logfile, we at least try to delete it
 | 
			
		||||
     in order to continue logging and not exceeding logfile size */
 | 
			
		||||
  if ((rename(l->filename, l->backup) < 0) &&
 | 
			
		||||
      (unlink(l->filename) < 0))
 | 
			
		||||
  {
 | 
			
		||||
    l->mask = 0;
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return log_open(l);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * log_commit - commit a log message
 | 
			
		||||
@@ -121,6 +171,22 @@ log_commit(int class, buffer *buf)
 | 
			
		||||
	    {
 | 
			
		||||
	      byte tbuf[TM_DATETIME_BUFFER_SIZE];
 | 
			
		||||
	      tm_format_real_time(tbuf, config->tf_log.fmt1, current_real_time());
 | 
			
		||||
 | 
			
		||||
	      if (l->limit)
 | 
			
		||||
	      {
 | 
			
		||||
		off_t msg_len = strlen(tbuf) + strlen(class_names[class]) +
 | 
			
		||||
		  (buf->pos - buf->start) + 5;
 | 
			
		||||
 | 
			
		||||
		if (l->pos < 0)
 | 
			
		||||
		  l->pos = log_size(l);
 | 
			
		||||
 | 
			
		||||
		if (l->pos + msg_len > l->limit)
 | 
			
		||||
		  if (log_rotate(l) < 0)
 | 
			
		||||
		    continue;
 | 
			
		||||
 | 
			
		||||
		l->pos += msg_len;
 | 
			
		||||
	      }
 | 
			
		||||
 | 
			
		||||
	      fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]);
 | 
			
		||||
	    }
 | 
			
		||||
	  fputs(buf->start, l->fh);
 | 
			
		||||
@@ -279,12 +345,26 @@ default_log_list(int debug, int init, char **syslog_name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
log_switch(int debug, list *l, char *new_syslog_name)
 | 
			
		||||
log_switch(int debug, list *logs, char *new_syslog_name)
 | 
			
		||||
{
 | 
			
		||||
  if (!l || EMPTY_LIST(*l))
 | 
			
		||||
    l = default_log_list(debug, !l, &new_syslog_name);
 | 
			
		||||
  struct log_config *l;
 | 
			
		||||
 | 
			
		||||
  current_log_list = l;
 | 
			
		||||
  if (!logs || EMPTY_LIST(*logs))
 | 
			
		||||
    logs = default_log_list(debug, !logs, &new_syslog_name);
 | 
			
		||||
 | 
			
		||||
  /* Close the logs to avoid pinning them on disk when deleted */
 | 
			
		||||
  if (current_log_list)
 | 
			
		||||
    WALK_LIST(l, *current_log_list)
 | 
			
		||||
      if (l->rf)
 | 
			
		||||
	log_close(l);
 | 
			
		||||
 | 
			
		||||
  /* Reopen the logs, needed for 'configure undo' */
 | 
			
		||||
  if (logs)
 | 
			
		||||
    WALK_LIST(l, *logs)
 | 
			
		||||
      if (l->filename && !l->rf)
 | 
			
		||||
	log_open(l);
 | 
			
		||||
 | 
			
		||||
  current_log_list = logs;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SYSLOG_H
 | 
			
		||||
  if (current_syslog_name && new_syslog_name &&
 | 
			
		||||
 
 | 
			
		||||
@@ -122,6 +122,11 @@ struct log_config {
 | 
			
		||||
  node n;
 | 
			
		||||
  uint mask;				/* Classes to log */
 | 
			
		||||
  void *fh;				/* FILE to log to, NULL=syslog */
 | 
			
		||||
  struct rfile *rf;			/* Resource for log file */
 | 
			
		||||
  char *filename;			/* Log filename */
 | 
			
		||||
  char *backup;				/* Secondary filename (for log rotation) */
 | 
			
		||||
  off_t pos;				/* Position/size of current log */
 | 
			
		||||
  off_t limit;				/* Log size limit */
 | 
			
		||||
  int terminal_flag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user