mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +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:
parent
3ab857f1d0
commit
2dbbc4c36f
@ -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
|
||||
|
@ -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; }
|
||||
;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user