Skip to content

Commit

Permalink
Unix: Implement log file size limit / log rotation
Browse files Browse the repository at this point in the history
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'.
  • Loading branch information
Ondrej Zajicek (work) committed Nov 18, 2018
1 parent c68ba7d commit 6712e77
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 16 deletions.
34 changes: 22 additions & 12 deletions sysdep/unix/config.Y
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}
;

Expand All @@ -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:
Expand Down
88 changes: 84 additions & 4 deletions sysdep/unix/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;

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 = l;
current_log_list = logs;

#ifdef HAVE_SYSLOG_H
if (current_syslog_name && new_syslog_name &&
Expand Down
5 changes: 5 additions & 0 deletions sysdep/unix/unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down

0 comments on commit 6712e77

Please sign in to comment.