The outbreak of various private fields (idata, pdata, udata) in struct log_stream
has gotten somewhat ugly, so I have replaced them by real private data allocated
after the standard portion of the log_stream structure.
log_new_stream() has gained a parameter telling it the size of the structure
to allocate. I have kept the recycler for the time being -- while saving allocations
is not worth the effort, it still nicely keeps the list of free stream ID's.
As idata are gone, the list of free items is now chained by log_stream->levels.
The default log stream no longer stores the fd explicitly, both log-file and
log-syslog keep private data in their own data structure extending log_stream.
#include <unistd.h>
#include <time.h>
-/*
- * Use of the private fields of struct log_stream:
- *
- * idata file descriptor
- * udata various flags (FF_xxx)
- * pdata original name with strftime escapes
- * name current name of the log file
- * (a dynamically allocated buffer)
- */
+struct file_stream {
+ struct log_stream ls; // ls.name is the current name of the log file
+ int fd;
+ uns flags; // FF_xxx
+ char *orig_name; // Original name with strftime escapes
+};
enum log_file_flag {
FF_FORMAT_NAME = 1, // Name contains strftime escapes
static int log_switch_nest;
static void
-do_log_reopen(struct log_stream *ls, const char *name)
+do_log_reopen(struct file_stream *fs, const char *name)
{
int fd = ucw_open(name, O_WRONLY | O_CREAT | O_APPEND, 0666);
if (fd < 0)
die("Unable to open log file %s: %m", name);
- if (ls->idata < 0)
- ls->idata = fd;
+ if (fs->fd < 0)
+ fs->fd = fd;
else
{
- dup2(fd, ls->idata);
+ dup2(fd, fs->fd);
close(fd);
}
- if (ls->name)
+ if (fs->ls.name)
{
- xfree(ls->name);
- ls->name = NULL; // We have to keep this consistent, die() below can invoke logging
+ xfree(fs->ls.name);
+ fs->ls.name = NULL; // We have to keep this consistent, die() below can invoke logging
}
- ls->name = xstrdup(name);
+ fs->ls.name = xstrdup(name);
}
static int
-do_log_switch(struct log_stream *ls, struct tm *tm)
+do_log_switch(struct file_stream *fs, struct tm *tm)
{
- if (!(ls->udata & FF_FORMAT_NAME))
+ if (!(fs->flags & FF_FORMAT_NAME))
{
- if (ls->idata >= 0)
+ if (fs->fd >= 0)
return 1;
else
{
- do_log_reopen(ls, ls->pdata);
+ do_log_reopen(fs, fs->orig_name);
return 1;
}
}
- int buflen = strlen(ls->pdata) + MAX_EXPAND;
+ int buflen = strlen(fs->orig_name) + MAX_EXPAND;
char name[buflen];
int switched = 0;
if (!log_switch_nest) // Avoid infinite loops if we die when switching logs
{
log_switch_nest++;
- int l = strftime(name, buflen, ls->pdata, tm);
+ int l = strftime(name, buflen, fs->orig_name, tm);
if (l < 0 || l >= buflen)
die("Error formatting log file name: %m");
- if (!ls->name || strcmp(name, ls->name))
+ if (!fs->ls.name || strcmp(name, fs->ls.name))
{
- do_log_reopen(ls, name);
+ do_log_reopen(fs, name);
switched = 1;
}
log_switch_nest--;
struct log_stream *def = log_stream_by_flags(0);
log_rm_substream(def, NULL);
log_add_substream(def, ls);
- dup2(ls->idata, 2); // Let fd2 be an alias for the log file
+ dup2(((struct file_stream *)ls)->fd, 2); // Let fd2 be an alias for the log file
}
/* destructor for standard files */
static void
file_close(struct log_stream *ls)
{
- if ((ls->udata & FF_CLOSE_FD) && ls->idata >= 0)
- close(ls->idata);
- xfree(ls->name);
- xfree(ls->pdata);
+ struct file_stream *fs = (struct file_stream *) ls;
+ if ((fs->flags & FF_CLOSE_FD) && fs->fd >= 0)
+ close(fs->fd);
+ xfree(fs->ls.name);
+ xfree(fs->orig_name);
}
/* handler for standard files */
static int
file_handler(struct log_stream *ls, struct log_msg *m)
{
- if ((ls->udata & FF_FORMAT_NAME) && m->tm)
- do_log_switch(ls, m->tm);
+ struct file_stream *fs = (struct file_stream *) ls;
+ if ((fs->flags & FF_FORMAT_NAME) && m->tm)
+ do_log_switch(fs, m->tm);
- int r = write(ls->idata, m->m, m->m_len);
+ int r = write(fs->fd, m->m, m->m_len);
/* FIXME: check for errors here? */
return 0;
}
struct log_stream *
log_new_fd(int fd)
{
- struct log_stream *ls = log_new_stream();
- ls->idata = fd;
+ struct log_stream *ls = log_new_stream(sizeof(struct file_stream));
+ struct file_stream *fs = (struct file_stream *) ls;
+ fs->fd = fd;
ls->msgfmt = LSFMT_DEFAULT;
ls->handler = file_handler;
ls->close = file_close;
struct log_stream *
log_new_file(const char *path)
{
- struct log_stream *ls = log_new_stream();
- ls->idata = -1;
- ls->pdata = xstrdup(path);
+ struct log_stream *ls = log_new_stream(sizeof(struct file_stream));
+ struct file_stream *fs = (struct file_stream *) ls;
+ fs->fd = -1;
+ fs->orig_name = xstrdup(path);
if (strchr(path, '%'))
- ls->udata = FF_FORMAT_NAME;
- ls->udata |= FF_CLOSE_FD;
+ fs->flags = FF_FORMAT_NAME;
+ fs->flags |= FF_CLOSE_FD;
ls->msgfmt = LSFMT_DEFAULT;
ls->handler = file_handler;
ls->close = file_close;
time_t now = time(NULL);
struct tm *tm = localtime(&now);
ASSERT(tm);
- do_log_switch(ls, tm); // die()'s on errors
+ do_log_switch(fs, tm); // die()'s on errors
return ls;
}
int switched = 0;
for (int i=0; i < log_streams_after; i++)
if (log_streams.ptr[i]->handler == file_handler)
- switched |= do_log_switch(log_streams.ptr[i], tm);
+ switched |= do_log_switch((struct file_stream *) log_streams.ptr[i], tm);
return switched;
}
/* Flag indicating initialization of the module */
static int log_initialized = 0;
-/* The head of the list of freed log_streams indexes in log_streams.ptr (-1 if none free).
+/* The head of the list of freed log_streams indexes in log_streams.ptr (~0U if none free).
* Freed positions in log_streams.ptr are connected into a linked list in the following way:
- * log_streams.ptr[log_streams_free].idata is the index of next freed position (or -1) */
-static int log_streams_free = -1;
+ * log_streams.ptr[log_streams_free].levels is the index of next freed position (or ~0U) */
+static uns log_streams_free = ~0U;
/* Initialize the logstream module.
* It is not neccessary to call this explicitely as it is called by
lsbuf_set_size(&log_streams, LS_INIT_STREAMS);
bzero(log_streams.ptr, sizeof(struct log_stream*) * (log_streams.len));
- log_streams_free = -1;
+ log_streams_free = ~0U;
log_initialized = 1;
/* init the default stream (0) as forwarder to fd2 */
- struct log_stream *ls = log_new_stream();
+ struct log_stream *ls = log_new_stream(sizeof(*ls));
ASSERT(ls == log_streams.ptr[0]);
ASSERT(ls->regnum == 0);
ls->name = "default";
/* Back to the default state */
lsbuf_done(&log_streams);
log_streams_after = 0;
- log_streams_free = -1;
+ log_streams_free = ~0U;
log_initialized = 0;
}
clist_add_tail(&where->substreams, &n->n);
}
-/* Remove all occurences of a substream together with the references they
+/* Remove all occurrences of a substream together with the references they
* keep. If a substream becomes unreferenced, it is closed. If what is NULL,
* all substreams are removed. Returns the number of deleted entries. */
int
/* Return a pointer to a new stream with no handler and an empty substream list. */
struct log_stream *
-log_new_stream(void)
+log_new_stream(size_t size)
{
struct log_stream *l;
int index;
log_init_module();
/* Get a free stream, possibly recycling a closed one */
- if (log_streams_free < 0)
+ if (log_streams_free == ~0U)
{
lsbuf_grow(&log_streams, log_streams_after+1);
index = log_streams_after++;
- l = log_streams.ptr[index] = xmalloc(sizeof(struct log_stream));
+ l = log_streams.ptr[index] = xmalloc(size);
}
else
{
index = log_streams_free;
- l = log_streams.ptr[index];
- log_streams_free = l->idata;
+ l = xrealloc(log_streams.ptr[index], size);
+ log_streams.ptr[index] = l;
+ log_streams_free = l->levels;
}
/* Initialize the stream */
/* Close the stream and add it to the free-list */
if (ls->close)
ls->close(ls);
- ls->idata = log_streams_free;
+ ls->levels = log_streams_free;
log_streams_free = LS_GET_STRNUM(ls->regnum);
ls->regnum = -1;
return 1;
#include <syslog.h>
+struct syslog_stream {
+ struct log_stream ls;
+ int facility;
+};
+
/* Destructor */
static void
syslog_close(struct log_stream *ls)
static int
syslog_handler(struct log_stream *ls, struct log_msg *m)
{
+ struct syslog_stream *ss = (struct syslog_stream *) ls;
int prio;
ASSERT(ls);
ASSERT(m);
// FIXME: Logging of PID
- prio = syslog_level(LS_GET_LEVEL(m->flags)) | (ls->idata);
+ prio = syslog_level(LS_GET_LEVEL(m->flags)) | ss->facility;
if (ls->name)
- syslog(prio | (ls->idata), "%s: %s", ls->name, m->m);
+ syslog(prio, "%s: %s", ls->name, m->m);
else
- syslog(prio | (ls->idata), "%s", m->m);
+ syslog(prio, "%s", m->m);
return 0;
}
struct log_stream *
log_new_syslog(int facility, const char *name)
{
- struct log_stream *ls = log_new_stream();
+ struct log_stream *ls = log_new_stream(sizeof(struct syslog_stream));
+ struct syslog_stream *ss = (struct syslog_stream *) ls;
if (name)
ls->name = xstrdup(name);
- ls->idata = facility;
ls->msgfmt = LSFMT_NONE;
ls->handler = syslog_handler;
ls->close = syslog_close;
+ ss->facility = facility;
return ls;
}
/*** The default log stream, which logs to stderr ***/
-static int default_log_handler(struct log_stream *ls, struct log_msg *m)
+static int default_log_handler(struct log_stream *ls UNUSED, struct log_msg *m)
{
// This is a completely bare version of the log-file module. Errors are ignored.
- write(ls->idata, m->m, m->m_len);
+ write(2, m->m, m->m_len);
return 0;
}
struct log_stream log_stream_default = {
.name = "stderr",
- .idata = 2,
.use_count = 1000000,
.handler = default_log_handler,
.levels = LS_ALL_LEVELS,
struct clist substreams; // Pass the message to these streams (simple_list of pointers)
int (*handler)(struct log_stream *ls, struct log_msg *m); // Called to commit the message
void (*close)(struct log_stream* ls); // Called upon log_close_stream()
- int idata; // Private data of the handler
- void *pdata;
- uns udata;
+ // Private data of the handler follow
};
/* the default logger */
// The module is initialized when a first stream is created.
// Before that only the default stream exists.
-/* Return pointer a new (xmalloc()-ated) stream with no handler and an empty substream list. */
-struct log_stream *log_new_stream(void);
+/* Return pointer a new (xmalloc()-ated) stream with no handler and an empty substream list.
+ * Since struct log_stream is followed by private data, @size bytes of memory are allocated
+ * for the whole structure. */
+struct log_stream *log_new_stream(size_t size);
/* Close and xfree() given log_stream */
/* Does not affect substreams */