0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-09-16 18:35:19 +00:00

Logging: fixed size logfiles behaving as mmapped ringbuffers

This variant of logging avoids calling write() for every log line,
allowing for waitless logging. This makes heavy logging less heavy
and more useful for race condition debugging.
This commit is contained in:
Maria Matejka 2023-08-24 17:00:54 +02:00
parent 3ab857f1d0
commit 2dbbc4c36f
4 changed files with 57 additions and 6 deletions

View File

@ -471,7 +471,7 @@ ipv6 table
include "tablename.conf";;
</code>
<tag><label id="opt-log">log "<m/filename/" [<m/limit/ "<m/backup/"] | syslog [name <m/name/] | stderr all|{ <m/list of classes/ }</tag>
<tag><label id="opt-log">log "<m/filename/" [<m/limit/ "<m/backup/"] | fixed "<m/filename/" <m/size/ | syslog [name <m/name/] | stderr all|{ <m/list of classes/ }</tag>
Set logging of messages having the given class (either <cf/all/ or <cf>{
error|trace [, <m/.../] }</cf> etc.) into selected destination - a file
specified as a filename string (with optional log rotation information),
@ -488,7 +488,8 @@ include "tablename.conf";;
Logging directly to file supports basic log rotation -- there is an
optional log file limit and a backup filename, when log file reaches the
limit, the current log file is renamed to the backup filename and a new
log file is created.
log file is created. It's also possible to log to a single file behaving
as a ring buffer with a fixed size.
You may specify more than one <cf/log/ line to establish logging to
multiple destinations. Default: log everything to the system log, or

View File

@ -19,7 +19,7 @@ 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, STATUS)
CF_KEYWORDS(GRACEFUL, RESTART)
CF_KEYWORDS(GRACEFUL, RESTART, FIXED)
%type <i> log_mask log_mask_list log_cat cfg_timeout
%type <t> cfg_name
@ -57,6 +57,14 @@ log_file:
}
this_log->filename = $1;
}
| FIXED text expr {
if (!parse_and_exit)
{
this_log->rf = rf_open(new_config->pool, $2, RF_FIXED, this_log->limit = $3);
if (!this_log->rf) cf_error("Unable to open log file '%s': %m", $2);
}
this_log->filename = $2;
}
| SYSLOG syslog_name { this_log->rf = NULL; new_config->syslog_name = $2; }
| STDERR { this_log->rf = &rf_stderr; }
;

View File

@ -16,6 +16,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -69,6 +70,7 @@ struct rfile {
int fd;
off_t limit;
_Atomic off_t pos;
void *mapping;
};
struct rfile rf_stderr = {
@ -80,6 +82,9 @@ rf_free(resource *r)
{
struct rfile *a = (struct rfile *) r;
if (a->mapping)
munmap(a->mapping, a->limit);
close(a->fd);
}
@ -112,6 +117,10 @@ rf_open_get_fd(const char *name, enum rf_mode mode)
flags = O_WRONLY | O_CREAT | O_APPEND;
break;
case RF_FIXED:
flags = O_RDWR | O_CREAT;
break;
default:
bug("rf_open() must have the mode set");
}
@ -145,6 +154,19 @@ rf_open(pool *p, const char *name, enum rf_mode mode, off_t limit)
r->pos = S_ISREG(r->stat.st_mode) ? r->stat.st_size : 0;
break;
case RF_FIXED:
if ((ftruncate(fd, limit) < 0)
|| ((r->mapping = mmap(NULL, limit, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED))
{
bug("Failed: %m");
int erf = errno;
r->mapping = NULL;
rfree(r);
errno = erf;
return NULL;
}
break;
default:
bug("rf_open() must have the mode set");
}
@ -165,15 +187,34 @@ rf_same(struct rfile *a, struct rfile *b)
rf_stat(b);
return
(a->limit == b->limit) &&
(a->stat.st_mode == b->stat.st_mode) &&
(a->stat.st_dev == b->stat.st_dev) &&
(a->stat.st_ino == b->stat.st_ino);
}
int
rf_write(struct rfile *r, const void *buf, size_t count)
rf_write(struct rfile *r, const void *buf, size_t _count)
{
if (r->limit && (atomic_fetch_add_explicit(&r->pos, count, memory_order_relaxed) + (off_t) count > r->limit))
off_t count = _count;
if (r->mapping)
{
/* Update the pointer */
off_t target = atomic_fetch_add_explicit(&r->pos, count, memory_order_relaxed) % r->limit;
/* Take care of wrapping */
if (target + count > r->limit)
{
memcpy(r->mapping, buf + (r->limit - target), target + count - r->limit);
count = r->limit - target;
}
/* Write the line */
memcpy(r->mapping + target, buf, count);
return 1;
}
else if (r->limit && (atomic_fetch_add_explicit(&r->pos, count, memory_order_relaxed) + count > r->limit))
{
atomic_fetch_sub_explicit(&r->pos, count, memory_order_relaxed);
return 0;

View File

@ -116,7 +116,8 @@ void io_log_dump(void);
int sk_open_unix(struct birdsock *s, struct birdloop *, char *name);
enum rf_mode {
RF_APPEND,
RF_APPEND = 1,
RF_FIXED,
};
struct rfile *rf_open(struct pool *, const char *name, enum rf_mode mode, off_t limit);