alloc alloc_str realloc bigalloc mempool mempool-str mempool-fmt eltpool \
mmap partmap hashfunc \
slists simple-lists bitsig \
- log log-file logstream proctitle \
+ log log-stream log-file log-syslog proctitle \
conf-alloc conf-dump conf-input conf-intr conf-journal conf-parse conf-section \
ipaccess \
profile \
#error This program requires the GNU C compiler.
#endif
-#include "ucw/logstream.h"
-/* Logging */
-/*
-#define L_DEBUG 'D' * Debugging messages *
-#define L_INFO 'I' * Informational msgs, warnings and errors *
-#define L_WARN 'W'
-#define L_ERROR 'E'
-#define L_INFO_R 'i' * Errors caused by external events *
-#define L_WARN_R 'w'
-#define L_ERROR_R 'e'
-#define L_FATAL '!' * die() *
-*/
-#define L_SIGHANDLER 0x10000 /* Avoid operations that are unsafe in signal handlers */
+/* Logging (more in <ucw/log.h>) */
+
+enum log_levels
+{
+ L_DEBUG=0, // 'D' - Debugging
+ L_INFO, // 'I' - Informational
+ L_WARN, // 'W' - Warning
+ L_ERROR, // 'E' - Error, but non-critical
+ L_INFO_R, // 'i' - An alternative set of levels for messages caused by remote events
+ L_WARN_R, // 'w' (e.g., a packet received via network)
+ L_ERROR_R, // 'e'
+ L_FATAL, // '!' - Fatal error
+};
+
+#define L_SIGHANDLER 0x80000000 /* Avoid operations that are unsafe in signal handlers */
extern char *log_title; /* NULL - print no title, default is program name given to log_init() */
-extern char *log_filename; /* Expanded name of the current log file */
extern int log_pid; /* 0 if shouldn't be logged */
-extern int log_precise_timings; /* Include microsecond timestamps in log messages */
-extern void (*log_die_hook)(void);
-struct tm;
-extern void (*log_switch_hook)(struct tm *tm);
+extern void (*log_die_hook)(void); // FIXME
-void msg(uns cat, const char *fmt, ...) FORMAT_CHECK(printf,2,3);
-void vmsg(uns cat, const char *fmt, va_list args);
+void msg(uns flags, const char *fmt, ...) FORMAT_CHECK(printf,2,3);
+void vmsg(uns flags, const char *fmt, va_list args);
void die(const char *, ...) NONRET FORMAT_CHECK(printf,1,2);
+
void log_init(const char *argv0);
void log_file(const char *name);
void log_fork(void); /* Call after fork() to update log_pid */
/* If the log name contains metacharacters for date and time, we switch the logs
* automatically whenever the name changes. You can disable it and switch explicitly. */
+#if 0 // FIXME
int log_switch(void);
void log_switch_disable(void);
void log_switch_enable(void);
+#endif
void assert_failed(const char *assertion, const char *file, int line) NONRET;
void assert_failed_noinfo(void) NONRET;
/*
- * UCW Library -- Keeping of Log Files
+ * UCW Library -- Logging to Files
*
- * (c) 1997--2006 Martin Mares <mj@ucw.cz>
+ * (c) 1997--2009 Martin Mares <mj@ucw.cz>
+ * (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
*/
#include "ucw/lib.h"
+#include "ucw/log.h"
#include "ucw/lfs.h"
#include "ucw/threads.h"
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
+#include <errno.h>
+
+#if 0 // FIXME
static char *log_name_patt;
static int log_params;
log_switch_nest--;
}
+#endif
+
+/* destructor for standard files */
+static void ls_fdfile_close(struct log_stream *ls)
+{
+ ASSERT(ls);
+ close(ls->idata);
+ if(ls->name)
+ xfree(ls->name);
+}
+
+/* handler for standard files */
+static int ls_fdfile_handler(struct log_stream* ls, const char *m, u32 cat UNUSED)
+{
+ int len = strlen(m);
+ int r = write(ls->idata, m, len);
+ /* TODO: check the errors here? */
+ if (r!=len)
+ return errno;
+ return 0;
+}
+
+/* assign log to a file descriptor */
+/* initialize with the default formatting, does NOT close the descriptor */
+struct log_stream *ls_fdfile_new(int fd)
+{
+ struct log_stream *ls=ls_new();
+ ls->idata=fd;
+ ls->msgfmt=LSFMT_DEFAULT;
+ ls->handler=ls_fdfile_handler;
+ return ls;
+}
+
+/* open() a file (append mode) */
+/* initialize with the default formatting */
+struct log_stream *ls_file_new(const char *path)
+{
+ struct log_stream *ls;
+ int fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0666);
+ if (fd<0)
+ {
+ ls_msg(L_ERROR, "Opening logfile '%s' failed: %m.", path);
+ return NULL;
+ }
+ ls = ls_new();
+ ls->name = xstrdup(path);
+ ls->idata = fd;
+ ls->msgfmt = LSFMT_DEFAULT;
+ ls->handler = ls_fdfile_handler;
+ ls->close = ls_fdfile_close;
+ return ls;
+}
+
#ifdef TEST
int main(int argc, char **argv)
--- /dev/null
+/*
+ * UCW Library -- Logging: Management of Log Streams
+ *
+ * (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
+ * (c) 2009 Martin Mares <mj@ucw.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#include "ucw/lib.h"
+#include "ucw/clists.h"
+#include "ucw/simple-lists.h"
+#include "ucw/log.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <alloca.h>
+#include <fcntl.h>
+
+/* Flag indicating initialization of the module */
+static int ls_initialized = 0;
+
+/* The head of the list of freed log_streams indexes in ls_streams.ptr (-1 if none free).
+ * Freed positions in ls_streams.ptr are connected into a linked list in the following way:
+ * ls_streams.ptr[ls_streams_free].idata is the index of next freed position (or -1) */
+static int ls_streams_free = -1;
+
+/* Initialize the logstream module.
+ * It is not neccessary to call this explicitely as it is called by
+ * the first ls_new() (for backward compatibility and ease of use). */
+static void ls_init_module(void)
+{
+ if (ls_initialized) return;
+
+ /* create the grow array */
+ lsbuf_init(&log_streams);
+ lsbuf_set_size(&log_streams, LS_INIT_STREAMS);
+
+ bzero(log_streams.ptr, sizeof(struct log_stream*) * (log_streams.len));
+ ls_streams_free = -1;
+
+ ls_initialized = 1;
+
+ /* init the default stream (0) as forwarder to fd2 */
+ struct log_stream *ls = ls_new();
+ ASSERT(ls == log_streams.ptr[0]);
+ ASSERT(ls->regnum == 0);
+ ls->name = "default";
+ ls_add_substream(ls, (struct log_stream *) &ls_default_log);
+
+ /* log this */
+ ls_msg(L_DEBUG, "logstream module initialized.");
+}
+
+/* close all open streams, un-initialize the module, free all memory,
+ * use only ls_default_log */
+void ls_close_all(void)
+{
+ int i;
+
+ if (!ls_initialized) return;
+
+ for (i=0; i<log_streams_after; i++)
+ {
+ if (log_streams.ptr[i]->regnum>=0)
+ ls_close(log_streams.ptr[i]);
+ xfree(log_streams.ptr[i]);
+ }
+
+ /* set to the default state */
+ lsbuf_done(&log_streams);
+ log_streams_after=0;
+ ls_streams_free=-1;
+ ls_initialized = 0;
+}
+
+/* add a new substream, malloc()-ate a new simp_node */
+void ls_add_substream(struct log_stream *where, struct log_stream *what)
+{
+ ASSERT(where);
+ ASSERT(what);
+
+ simp_node *n = xmalloc(sizeof(simp_node));
+ n->p = what;
+ clist_add_tail(&(where->substreams), (cnode*)n);
+}
+
+/* remove all occurences of a substream, free() the simp_node */
+/* return number of deleted entries */
+int ls_rm_substream(struct log_stream *where, struct log_stream *what)
+{
+ void *tmp;
+ int cnt=0;
+ ASSERT(where);
+ ASSERT(what);
+
+ CLIST_FOR_EACH_DELSAFE(simp_node *, i, where->substreams, tmp)
+ if (i->p == what)
+ {
+ clist_remove((cnode*)i);
+ xfree(i);
+ cnt++;
+ }
+ return cnt;
+}
+
+/* Return a pointer to a new stream with no handler and an empty substream list. */
+struct log_stream *ls_new(void)
+{
+ struct log_stream *l;
+ int index;
+
+ /* initialize the array if not initialized already */
+ if (unlikely(ls_initialized==0))
+ ls_init_module();
+
+ /* there is no closed stream -- allocate a new one */
+ if (ls_streams_free==-1)
+ {
+ /* check the size of the pointer array */
+ lsbuf_grow(&log_streams, log_streams_after+1);
+ ls_streams_free = log_streams_after++;
+ log_streams.ptr[ls_streams_free] = xmalloc(sizeof(struct log_stream));
+ log_streams.ptr[ls_streams_free]->idata = -1;
+ log_streams.ptr[ls_streams_free]->regnum = -1;
+ }
+
+ ASSERT(ls_streams_free>=0);
+
+ /* initialize the stream */
+ index = ls_streams_free;
+ l = log_streams.ptr[index];
+ ls_streams_free = l->idata;
+ memset(l, 0, sizeof(struct log_stream));
+ l->levels = LS_ALL_LEVELS;
+ l->regnum = LS_SET_STRNUM(index);
+ l->substreams.head.next = &(l->substreams.head);
+ l->substreams.head.prev = &(l->substreams.head);
+ return l;
+}
+
+/* Close and remember given log_stream */
+/* does not affect substreams, but frees the .substreams list */
+void ls_close(struct log_stream *ls)
+{
+ void *tmp;
+ ASSERT(ls);
+
+ /* xfree() all the simp_nodes from substreams */
+ CLIST_FOR_EACH_DELSAFE(simp_node *, i, ls->substreams, tmp)
+ {
+ clist_remove((cnode*)i);
+ xfree(i);
+ }
+
+ /* close and remember the stream */
+ if (ls->close!=NULL)
+ ls->close(ls);
+ ls->idata = ls_streams_free;
+ ls_streams_free = LS_GET_STRNUM(ls->regnum);
+ ls->regnum = -1;
+}
--- /dev/null
+/*
+ * UCW Library -- Logging to Syslog
+ *
+ * (c) 2009 Martin Mares <mj@ucw.cz>
+ * (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#include "ucw/lib.h"
+#include "ucw/log.h"
+
+#include <syslog.h>
+
+/* destructor for syslog logs */
+static void ls_syslog_close(struct log_stream *ls)
+{
+ ASSERT(ls);
+ if(ls->name)
+ xfree(ls->name);
+}
+
+/* convert severity level to syslog constants */
+static int ls_syslog_convert_level(int level)
+{
+ switch(level)
+ {
+ case L_DEBUG: return LOG_DEBUG;
+ case L_INFO: return LOG_INFO;
+ case L_INFO_R: return LOG_INFO;
+ case L_WARN: return LOG_WARNING;
+ case L_WARN_R: return LOG_WARNING;
+ case L_ERROR: return LOG_ERR;
+ case L_ERROR_R: return LOG_ERR;
+ case L_FATAL: return LOG_CRIT;
+ default: return LOG_NOTICE;
+ }
+}
+
+/* simple syslog write handler */
+static int ls_syslog_handler(struct log_stream *ls, const char *m, u32 flags)
+{
+ int prio;
+ ASSERT(ls);
+ ASSERT(m);
+
+ prio = ls_syslog_convert_level(LS_GET_LEVEL(flags)) | (ls->idata);
+ if (ls->name)
+ syslog(prio | (ls->idata), "%s: %s", ls->name, m);
+ else
+ syslog(prio | (ls->idata), "%s", m);
+ return 0;
+}
+
+/* assign log to a syslog facility */
+/* initialize with no formatting (syslog adds these inforamtion) */
+/* name is optional prefix (NULL for none) */
+struct log_stream *ls_syslog_new(int facility, const char *name)
+{
+ struct log_stream *ls=ls_new();
+ if (name) ls->name = xstrdup(name);
+ ls->idata = facility;
+ ls->msgfmt = LSFMT_NONE;
+ ls->handler = ls_syslog_handler;
+ ls->close = ls_syslog_close;
+ return ls;
+}
/*
* UCW Library -- Logging
*
- * (c) 1997--2008 Martin Mares <mj@ucw.cz>
+ * (c) 1997--2009 Martin Mares <mj@ucw.cz>
+ * (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
*
* This software may be freely distributed and used according to the terms
* of the GNU Lesser General Public License.
*/
#include "ucw/lib.h"
+#include "ucw/log.h"
+#include "ucw/simple-lists.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <alloca.h>
+#include <errno.h>
static char log_progname[32];
-char *log_filename;
char *log_title;
int log_pid;
-int log_precise_timings;
void (*log_die_hook)(void);
-void (*log_switch_hook)(struct tm *tm);
-void
-vmsg(unsigned int cat, const char *fmt, va_list args)
+// FIXME: duplicate?
+static int ls_default_handler(struct log_stream* ls, const char *m, u32 cat UNUSED)
+{
+ int len = strlen(m);
+ int r = write(ls->idata, m, len);
+ /* TODO: check the errors here? */
+ if (r!=len)
+ return errno;
+ return 0;
+}
+
+/* the default logger */
+const struct log_stream ls_default_log={
+ .name = "fd2", .idata = 2, .pdata = NULL, .regnum = 0,
+ .handler = ls_default_handler,
+ .levels = LS_ALL_LEVELS,
+ .msgfmt = LSFMT_DEFAULT,
+ // empty clist
+ .substreams.head.next = (cnode *) &ls_default_log.substreams.head,
+ .substreams.head.prev = (cnode *) &ls_default_log.substreams.head,
+};
+
+/*** Registry of streams and their identifiers ***/
+
+/* The growing array of pointers to log_streams. */
+struct lsbuf_t log_streams;
+
+/* the first never-used index in ls_streams.ptr */
+int log_streams_after = 0;
+
+/* get a stream by its LS_SET_STRNUM() */
+/* returns NULL for free/invalid numbers */
+/* defaults to ls_default_stream when stream number 0 closed */
+struct log_stream *log_stream_by_flags(uns flags)
+{
+ /* get the real number */
+ int n = LS_GET_STRNUM(flags);
+ if ((n<0) || (n>=log_streams_after) || (log_streams.ptr[n]->regnum==-1) )
+ {
+ if (n==0)
+ return (struct log_stream *)&ls_default_log;
+ else
+ return NULL;
+ }
+ return log_streams.ptr[n];
+}
+
+/*** Logging ***/
+
+void vmsg(unsigned int cat, const char *fmt, va_list args)
{
struct timeval tv;
int have_tm = 0;
struct tm tm;
- byte *buf, *p;
- int buflen = 256;
- int l, l0, r;
va_list args2;
+ char stime[24];
+ char sutime[12];
+ char *buf,*p;
+ int len;
+ struct log_stream *ls=log_stream_by_flags(cat);
+
+ /* Check the stream existence */
+ if(!ls)
+ {
+ msg((LS_INTERNAL_MASK&cat)|L_WARN, "No log_stream with number %d! Logging to the default log.",
+ LS_GET_STRNUM(cat));
+ ls=(struct log_stream *)&ls_default_log;
+ }
- if (!(cat & L_SIGHANDLER))
+ /* get the time */
+ if (!(cat&LSFLAG_SIGHANDLER))
{
/* CAVEAT: These calls are not safe in signal handlers. */
gettimeofday(&tv, NULL);
if (localtime_r(&tv.tv_sec, &tm))
have_tm = 1;
- if (log_switch_hook)
- log_switch_hook(&tm);
}
- while (1)
+ /* generate time strings */
+ if (have_tm)
{
- p = buf = alloca(buflen);
- *p++ = cat & 0xff;
- if (have_tm)
+ strftime(stime, 24, "%Y-%m-%d %H:%M:%S", &tm);
+ snprintf(sutime, 12, ".%06d", (int)tv.tv_usec);
+ }
+ else
+ {
+ snprintf(stime, 24, "\?\?\?\?-\?\?-\?\? \?\?:\?\?:\?\?");
+ snprintf(sutime, 12, ".\?\?\?\?\?\?");
+ }
+
+ /* generate the message string */
+ va_copy(args2, args);
+ /* WARN: this may be C99 specefic */
+ len = vsnprintf(NULL, 0, fmt, args2);
+ va_end(args2);
+ buf = xmalloc(len+2);
+ vsnprintf(buf, len+1, fmt, args);
+
+ /* remove non-printable characters and newlines */
+ p=buf;
+ while (*p)
+ {
+ if (*p < 0x20 && *p != '\t')
+ *p = 0x7f;
+ p++;
+ }
+
+ /* pass the message to the log_stream */
+ if(ls_passmsg(0, ls, stime, sutime, buf, cat))
+ {
+ /* error (such as looping) occured */
+ ls_passmsg(0, (struct log_stream *)&ls_default_log, stime, sutime, buf, cat);
+ }
+
+ xfree(buf);
+}
+
+/* process a message (string) */
+/* depth prevents undetected looping */
+/* returns 1 in case of loop detection or other fatal error
+ * 0 otherwise */
+int ls_passmsg(int depth, struct log_stream *ls, const char *stime, const char *sutime, const char *m, u32 cat)
+{
+ ASSERT(ls);
+
+ /* Check recursion depth */
+ if( depth > LS_MAX_DEPTH )
+ {
+ ls_passmsg(0, (struct log_stream *)&ls_default_log, stime, sutime,
+ "Loop in the log_stream system detected.", L_ERROR | (cat&LS_INTERNAL_MASK) );
+ return 1;
+ }
+
+ /* Filter by level and filter hook */
+ if(!( (1<<LS_GET_LEVEL(cat)) & ls->levels )) return 0;
+ if( ls->filter )
+ if( ls->filter(ls, m, cat) != 0 ) return 0;
+
+ /* pass message to substreams */
+ CLIST_FOR_EACH(simp_node *, s, ls->substreams)
+ {
+ if (ls_passmsg(depth+1, (struct log_stream*)(s->p), stime, sutime, m, cat))
+ return 1;
+ }
+
+ /* Prepare for handler */
+ if(ls->handler)
+ {
+ int len = strlen(m) + strlen(stime) + strlen(sutime) + 32;
+ /* SHOULD be enough for all information, but beware */
+ if (log_title) len += strlen(log_title);
+ if (ls->name) len += strlen(ls->name);
+ char *buf=xmalloc(len);
+ char *p=buf;
+
+ /* Level (2 chars) */
+ if(ls->msgfmt & LSFMT_LEVEL)
{
- p += strftime(p, buflen, " %Y-%m-%d %H:%M:%S", &tm);
- if (log_precise_timings)
- p += sprintf(p, ".%06d", (int)tv.tv_usec);
+ *p++=LS_LEVEL_LETTER(LS_GET_LEVEL(cat));
+ *p++=' ';
}
- else
+
+ /* Time (|stime| + |sutime| + 1 chars) */
+ if(ls->msgfmt & LSFMT_TIME)
{
- p += sprintf(p, " \?\?\?\?-\?\?-\?\? \?\?:\?\?:\?\?");
- if (log_precise_timings)
- p += sprintf(p, ".\?\?\?\?\?\?");
+ char *q = (char *)stime;
+
+ while(*q)
+ *p++=*q++;
+ if(ls->msgfmt & LSFMT_USEC)
+ {
+ q = (char *)sutime;
+ while(*q)
+ *p++=*q++;
+ }
+ *p++=' ';
}
- *p++ = ' ';
- if (log_title)
+
+ /* process name, PID ( |log_title| + 6 + (|PID|<=10) chars ) */
+ if((ls->msgfmt & LSFMT_TITLE) && log_title)
{
- if (log_pid)
- p += sprintf(p, "[%s (%d)] ", log_title, log_pid);
+ if(ls->msgfmt & LSFMT_PID)
+ p += sprintf(p, "[%s (%d)] ", log_title, getpid());
else
p += sprintf(p, "[%s] ", log_title);
}
else
{
- if (log_pid)
- p += sprintf(p, "[%d] ", log_pid);
+ if(ls->msgfmt & LSFMT_PID)
+ p += sprintf(p, "[%d] ", getpid());
}
- l0 = p - buf + 1;
- r = buflen - l0;
- va_copy(args2, args);
- l = vsnprintf(p, r, fmt, args2);
- va_end(args2);
- if (l < 0)
- l = r;
- else if (l < r)
+
+ /* log_stream name ( |ls->name| + 4 chars ) */
+ if(ls->msgfmt & LSFMT_LOGNAME)
{
- while (*p)
- {
- if (*p < 0x20 && *p != '\t')
- *p = 0x7f;
- p++;
- }
- *p = '\n';
- write(2, buf, l + l0);
- return;
+ if(ls->name)
+ p += sprintf(p, "<%s> ", ls->name);
+ else
+ p += sprintf(p, "<?> ");
+ }
+
+ /* finish the string and call the handler ( |m| + 1 chars ) */
+ {
+ char *q = (char *)m;
+
+ while(*q)
+ *p++=*q++;
+ *p++ = '\n';
+ *p++ = '\0';
+ ls->handler(ls, buf, cat);
}
- buflen = l + l0 + 1;
+ xfree(buf);
}
+ return 0;
}
void
log_title = log_progname;
}
}
+
+#ifdef TEST
+
+int main(void)
+{
+ // ls_default_log.msgfmt |= LSFMT_USEC;
+ msg(L_INFO, "Brum!");
+ return 0;
+}
+
+#endif
--- /dev/null
+/*
+ * UCW Library -- Logging
+ *
+ * (c) 1997--2009 Martin Mares <mj@ucw.cz>
+ * (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
+#ifndef _UCW_LOG_H_
+#define _UCW_LOG_H_
+
+#include "ucw/clists.h"
+
+/* user de/allocated program/process name for use in the logsystem */
+extern char *ls_title;
+
+struct log_stream
+{
+ /* optional name, 0-term, de/allocated by constr./destr. or user */
+ char *name;
+ /* number for use with msg parameter (from LS_SET_STRNUM()), -1 for closed log_stream */
+ int regnum;
+ /* arbitrary data for filter/handler */
+ int idata;
+ void *pdata;
+ /* severity levels to accept - bitmask of (1<<LEVEL) */
+ int levels;
+ /* if filter returns nonzero, discard the message */
+ int (*filter)(struct log_stream* ls, const char *m, u32 cat);
+ /* pass the message to these streams (simple-list of pointers) */
+ struct clist substreams;
+ /* what kind of string to format to pass to the handler (bitmask of LSFMT_xxx ) */
+ int msgfmt;
+ /* what to do to commit the message (ret 0 on success, nonzero on error)
+ * msg is 0-term string, with desired info, one line, ending with "\n\0". */
+ int (*handler)(struct log_stream* ls, const char *m, u32 cat);
+ /* close the log_stream file/connection */
+ void (*close)(struct log_stream* ls);
+};
+
+/* the default logger */
+extern const struct log_stream ls_default_log;
+
+/* A message is processed as follows:
+ * 1. Discard if message level not in levels
+ * 2. Run filter (if any), discard if ret. nonzero
+ * 3. Pass the message to all log_streams in substreams
+ * 4. Format the message informaion acc. to msgfmt
+ * 5. Run the handler
+ */
+
+/* log header verbosity specifying message passed to handler */
+enum ls_fmt
+{
+ LSFMT_LEVEL=1, /* log severity level (one letter) */
+ LSFMT_TIME=2, /* log time (date-seconds) */
+ LSFMT_USEC=4, /* log also micro-seconds */
+ LSFMT_TITLE=8, /* log program title (global string) */
+ LSFMT_PID=16, /* log program PID */
+ LSFMT_LOGNAME=32, /* log log_stream name */
+ LSFMT_NONE=0,
+ LSFMT_FULL=LSFMT_LEVEL+LSFMT_TIME+LSFMT_USEC+LSFMT_TITLE+LSFMT_PID+LSFMT_LOGNAME,
+ LSFMT_DEFAULT=LSFMT_LEVEL+LSFMT_TIME
+};
+
+/* Mask of containing all existing levels. */
+#define LS_ALL_LEVELS 0xfff
+
+// return the letter associated with the severity level
+#define LS_LEVEL_LETTER(level) ("DIiWwEe!###"[( level )])
+
+///// Macros for extracting parts of the flags parameter
+// The division of the flags parameter is decided only here
+// The current division is (for 32 bit flags):
+// MSB <5 bits: any internal log flags> <8 bits: "user" flags> <10 bits: stream number>
+// <8 bits: severity level> LSB
+
+// Bits per section
+enum ls_flagbits {
+ LS_LEVEL_BITS = 8,
+ LS_STRNUM_BITS = 16,
+ LS_FLAGS_BITS = 5,
+ LS_INTERNAL_BITS = 4,
+};
+
+// Section shifts
+enum ls_flagpos {
+ LS_LEVEL_POS = 0,
+ LS_STRNUM_POS = LS_LEVEL_POS + LS_LEVEL_BITS,
+ LS_FLAGS_POS = LS_STRNUM_POS + LS_STRNUM_BITS,
+ LS_INTERNAL_POS = LS_FLAGS_POS + LS_FLAGS_BITS,
+};
+
+// Bitmasks
+enum ls_flagmasks {
+ LS_LEVEL_MASK = (( 1 << LS_LEVEL_BITS ) - 1 ) << LS_LEVEL_POS,
+ LS_STRNUM_MASK = (( 1 << LS_STRNUM_BITS ) - 1 ) << LS_STRNUM_POS,
+ LS_FLAGS_MASK = (( 1 << LS_FLAGS_BITS ) - 1 ) << LS_FLAGS_POS,
+ LS_INTERNAL_MASK = (( 1 << LS_INTERNAL_BITS ) - 1 ) << LS_INTERNAL_POS,
+};
+
+// "Get" macros (break flags to parts)
+#define LS_GET_LEVEL(flags) ((( flags ) & LS_LEVEL_MASK ) >> LS_LEVEL_POS )
+#define LS_GET_STRNUM(flags) ((( flags ) & LS_STRNUM_MASK ) >> LS_STRNUM_POS )
+#define LS_GET_FLAGS(flags) ((( flags ) & LS_FLAGS_MASK ) >> LS_FLAGS_POS )
+#define LS_GET_INTERNAL(flags) ((( flags ) & LS_INTERNAL_MASK ) >> LS_INTERNAL_POS )
+
+// "Set" macros (parts to flags)
+#define LS_SET_LEVEL(level) (( level ) << LS_LEVEL_POS )
+#define LS_SET_STRNUM(strnum) (( strnum ) << LS_STRNUM_POS )
+#define LS_SET_FLAGS(flags) (( flags ) << LS_FLAGS_POS )
+#define LS_SET_INTERNAL(intern) (( intern ) << LS_INTERNAL_POS )
+
+// Internal flags of the logsystem
+// Avoid operations that are unsafe in signal handlers
+#define LSFLAG_SIGHANDLER LS_SET_INTERNAL(0x001)
+
+// The module is initialized when a first stream is created.
+// Before that only the default stream exists.
+
+// Initial number of streams to allocate (must be >=2)
+#define LS_INIT_STREAMS 8
+
+/* Return pointer a new (xmalloc()-ated) stream with no handler and an empty substream list. */
+struct log_stream *ls_new(void);
+
+/* Close and xfree() given log_stream */
+/* Does not affect substreams */
+void ls_close(struct log_stream *ls);
+
+/* close all open streams, un-initialize the module, free all memory,
+ * use only ls_default_log */
+void ls_close_all(void);
+
+/* add a new substream, xmalloc()-ate a new simp_node */
+void ls_add_substream(struct log_stream *where, struct log_stream *what);
+
+/* remove all occurences of a substream, free() the simp_node */
+/* return number of deleted entries */
+int ls_rm_substream(struct log_stream *where, struct log_stream *what);
+
+/* get a stream by its number (regnum) */
+/* returns NULL for free numbers */
+/* defaults to ls_default_stream for 0 when stream number 0 not set */
+struct log_stream *log_stream_by_flags(uns flags);
+
+/* The proposed alternative to original vmsg() */
+void ls_vmsg(unsigned int cat, const char *fmt, va_list args);
+
+/* The proposed alternative to original msg() */
+void ls_msg(unsigned int cat, const char *fmt, ...);
+
+/* The proposed alternative to original die() */
+void ls_die(const char *fmt, ...);
+
+/* process a message (string) (INTERNAL) */
+/* depth prevents undetected looping */
+/* returns 1 in case of loop detection or other fatal error
+ * 0 otherwise */
+int ls_passmsg(int depth, struct log_stream *ls, const char *stime, const char *sutime,
+ const char *msg, u32 cat);
+
+/* Maximal depth of ls_passmsg recursion */
+#define LS_MAX_DEPTH 64
+
+/* Define an array (growing buffer) for pointers to log_streams. */
+#define GBUF_TYPE struct log_stream*
+#define GBUF_PREFIX(x) lsbuf_##x
+#include "ucw/gbuf.h"
+
+extern struct lsbuf_t log_streams;
+extern int log_streams_after;
+
+/********* Individual handler types (constructors, handlers, destructors) */
+
+/**** standard (filedes) files */
+
+// NOTE:
+// under unix, for ordinary files open in append mode, the writes
+// are atomic (unless you meet the quota or other bad things happen),
+// so using a single log_stream is thread-safe and the file can be shared
+// among multiple processes
+
+/* assign log to a file descriptor */
+/* initialize with the default formatting, does NOT close the descriptor */
+struct log_stream *ls_fdfile_new(int fd);
+
+/* open() a file (append mode) */
+/* initialize with the default formatting */
+struct log_stream *ls_file_new(const char *path);
+
+
+/**** syslog */
+
+// NOTE:
+// The syslog uses a bit different severity levels, for details, see
+// ls_syslog_convert_level().
+// syslog also prepends it's own time and severity info, so the default
+// messaging passes only clean message
+
+/* assign log to a syslog facility */
+/* initialize with no formatting (syslog adds these inforamtion) */
+/* name is optional prefix (NULL for none) */
+struct log_stream *ls_syslog_new(int facility, const char *name);
+
+#endif
+++ /dev/null
-/*
- * UCW Library -- Logging
- *
- * (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
- * (c) 2009 Martin Mares <mj@ucw.cz>
- *
- * This software may be freely distributed and used according to the terms
- * of the GNU Lesser General Public License.
- */
-
-#include "ucw/lib.h"
-#include "ucw/clists.h"
-#include "ucw/simple-lists.h"
-#include "ucw/logstream.h"
-
-#include <syslog.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <alloca.h>
-#include <fcntl.h>
-
-/* forward declaration */
-static int ls_fdfile_handler(struct log_stream* ls, const char *m, u32 cat);
-
-/* the deafult logger */
-const struct log_stream ls_default_log={
- .name = "fd2", .idata = 2, .pdata = NULL, .regnum = 0,
- .handler = ls_fdfile_handler,
- .levels = LS_ALL_LEVELS,
- .msgfmt = LSFMT_DEFAULT,
- // empty clist
- .substreams.head.next = (cnode *) &ls_default_log.substreams.head,
- .substreams.head.prev = (cnode *) &ls_default_log.substreams.head,
-};
-
-/* user de/allocated program/process name for use in the logsystem (for LSFMT_TITLE) */
-char *ls_title = NULL;
-
-/* Define an array (growing buffer) for pointers to log_streams. */
-#define GBUF_TYPE struct log_stream*
-#define GBUF_PREFIX(x) lsbuf_##x
-#include "ucw/gbuf.h"
-
-/* Flag indicating initialization of the module */
-static int ls_initialized = 0;
-
-/* The growing array of pointers to log_streams. */
-static struct lsbuf_t ls_streams;
-
-/* The head of the list of freed log_streams indexes in ls_streams.ptr (-1 if none free).
- * Freed positions in ls_streams.ptr are connected into a linked list in the following way:
- * ls_streams.ptr[ls_streams_free].idata is the index of next freed position (or -1) */
-int ls_streams_free = -1;
-
-/* the first never-used index in ls_streams.ptr */
-int ls_streams_after = 0;
-
-/* Initialize the logstream module.
- * It is not neccessary to call this explicitely as it is called by
- * the first ls_new() (for backward compatibility and ease of use). */
-static void ls_init_module(void)
-{
- if (ls_initialized) return;
-
- /* create the grow array */
- lsbuf_init(&ls_streams);
- lsbuf_set_size(&ls_streams, LS_INIT_STREAMS);
-
- bzero(ls_streams.ptr, sizeof(struct log_stream*) * (ls_streams.len));
- ls_streams_free = -1;
-
- ls_initialized = 1;
-
- /* init the default stream (0) as forwarder to fd2 */
- struct log_stream *ls = ls_new();
- ASSERT(ls == ls_streams.ptr[0]);
- ASSERT(ls->regnum == 0);
- ls->name = "default";
- ls_add_substream(ls, (struct log_stream *) &ls_default_log);
-
- /* log this */
- ls_msg(L_DEBUG, "logstream module initialized.");
-}
-
-/* close all open streams, un-initialize the module, free all memory,
- * use only ls_default_log */
-void ls_close_all(void)
-{
- int i;
-
- if (!ls_initialized) return;
-
- for (i=0; i<ls_streams_after; i++)
- {
- if (ls_streams.ptr[i]->regnum>=0)
- ls_close(ls_streams.ptr[i]);
- xfree(ls_streams.ptr[i]);
- }
-
- /* set to the default state */
- lsbuf_done(&ls_streams);
- ls_streams_after=0;
- ls_streams_free=-1;
- ls_initialized = 0;
-}
-
-/* add a new substream, malloc()-ate a new simp_node */
-void ls_add_substream(struct log_stream *where, struct log_stream *what)
-{
- ASSERT(where);
- ASSERT(what);
-
- simp_node *n = xmalloc(sizeof(simp_node));
- n->p = what;
- clist_add_tail(&(where->substreams), (cnode*)n);
-}
-
-/* remove all occurences of a substream, free() the simp_node */
-/* return number of deleted entries */
-int ls_rm_substream(struct log_stream *where, struct log_stream *what)
-{
- void *tmp;
- int cnt=0;
- ASSERT(where);
- ASSERT(what);
-
- CLIST_FOR_EACH_DELSAFE(simp_node *, i, where->substreams, tmp)
- if (i->p == what)
- {
- clist_remove((cnode*)i);
- xfree(i);
- cnt++;
- }
- return cnt;
-}
-
-/* Return a pointer to a new stream with no handler and an empty substream list. */
-struct log_stream *ls_new(void)
-{
- struct log_stream *l;
- int index;
-
- /* initialize the array if not initialized already */
- if (unlikely(ls_initialized==0))
- ls_init_module();
-
- /* there is no closed stream -- allocate a new one */
- if (ls_streams_free==-1)
- {
- /* check the size of the pointer array */
- lsbuf_grow(&ls_streams, ls_streams_after+1);
- ls_streams_free = ls_streams_after++;
- ls_streams.ptr[ls_streams_free] = xmalloc(sizeof(struct log_stream));
- ls_streams.ptr[ls_streams_free]->idata = -1;
- ls_streams.ptr[ls_streams_free]->regnum = -1;
- }
-
- ASSERT(ls_streams_free>=0);
-
- /* initialize the stream */
- index = ls_streams_free;
- l = ls_streams.ptr[index];
- ls_streams_free = l->idata;
- memset(l, 0, sizeof(struct log_stream));
- l->levels = LS_ALL_LEVELS;
- l->regnum = LS_SET_STRNUM(index);
- l->substreams.head.next = &(l->substreams.head);
- l->substreams.head.prev = &(l->substreams.head);
- return l;
-}
-
-/* Close and remember given log_stream */
-/* does not affect substreams, but frees the .substreams list */
-void ls_close(struct log_stream *ls)
-{
- void *tmp;
- ASSERT(ls);
-
- /* xfree() all the simp_nodes from substreams */
- CLIST_FOR_EACH_DELSAFE(simp_node *, i, ls->substreams, tmp)
- {
- clist_remove((cnode*)i);
- xfree(i);
- }
-
- /* close and remember the stream */
- if (ls->close!=NULL)
- ls->close(ls);
- ls->idata = ls_streams_free;
- ls_streams_free = LS_GET_STRNUM(ls->regnum);
- ls->regnum = -1;
-}
-
-/* get a stream by its LS_SET_STRNUM() */
-/* returns NULL for free/invalid numbers */
-/* defaults to ls_default_stream when stream number 0 closed */
-struct log_stream *ls_bynum(int num)
-{
- /* get the real number */
- int n = LS_GET_STRNUM(num);
- if ((n<0) || (n>=ls_streams_after) || (ls_streams.ptr[n]->regnum==-1) )
- {
- if (n==0)
- return (struct log_stream *)&ls_default_log;
- else
- return NULL;
- }
- return ls_streams.ptr[n];
-}
-
-/* The proposed alternative to original vmsg() */
-void ls_vmsg(unsigned int cat, const char *fmt, va_list args)
-{
- struct timeval tv;
- int have_tm = 0;
- struct tm tm;
- va_list args2;
- char stime[24];
- char sutime[12];
- char *buf,*p;
- int len;
- struct log_stream *ls=ls_bynum(cat);
-
- /* Check the stream existence */
- if(!ls)
- {
- ls_msg((LS_INTERNAL_MASK&cat)|L_WARN, "No log_stream with number %d! Logging to the default log.",
- LS_GET_STRNUM(cat));
- ls=(struct log_stream *)&ls_default_log;
- }
-
- /* get the time */
- if (!(cat&LSFLAG_SIGHANDLER))
- {
- /* CAVEAT: These calls are not safe in signal handlers. */
- gettimeofday(&tv, NULL);
- if (localtime_r(&tv.tv_sec, &tm))
- have_tm = 1;
- }
-
- /* generate time strings */
- if (have_tm)
- {
- strftime(stime, 24, "%Y-%m-%d %H:%M:%S", &tm);
- snprintf(sutime, 12, ".%06d", (int)tv.tv_usec);
- }
- else
- {
- snprintf(stime, 24, "\?\?\?\?-\?\?-\?\? \?\?:\?\?:\?\?");
- snprintf(sutime, 12, ".\?\?\?\?\?\?");
- }
-
- /* generate the message string */
- va_copy(args2, args);
- /* WARN: this may be C99 specefic */
- len = vsnprintf(NULL, 0, fmt, args2);
- va_end(args2);
- buf = xmalloc(len+2);
- vsnprintf(buf, len+1, fmt, args);
-
- /* remove non-printable characters and newlines */
- p=buf;
- while (*p)
- {
- if (*p < 0x20 && *p != '\t')
- *p = 0x7f;
- p++;
- }
-
- /* pass the message to the log_stream */
- if(ls_passmsg(0, ls, stime, sutime, buf, cat))
- {
- /* error (such as looping) occured */
- ls_passmsg(0, (struct log_stream *)&ls_default_log, stime, sutime, buf, cat);
- }
-
- xfree(buf);
-}
-
-/* The proposed alternative to original msg() */
-void ls_msg(unsigned int cat, const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- ls_vmsg(cat, fmt, args);
- va_end(args);
-}
-
-/* The proposed alternative to original die() */
-void ls_die(const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- ls_vmsg(L_FATAL, fmt, args);
- va_end(args);
-///// why this?
-// if (log_die_hook)
-// log_die_hook();
-#ifdef DEBUG_DIE_BY_ABORT
- abort();
-#else
- exit(1);
-#endif
-}
-
-/* process a message (string) */
-/* depth prevents undetected looping */
-/* returns 1 in case of loop detection or other fatal error
- * 0 otherwise */
-int ls_passmsg(int depth, struct log_stream *ls, const char *stime, const char *sutime, const char *m, u32 cat)
-{
- ASSERT(ls);
-
- /* Check recursion depth */
- if( depth > LS_MAX_DEPTH )
- {
- ls_passmsg(0, (struct log_stream *)&ls_default_log, stime, sutime,
- "Loop in the log_stream system detected.", L_ERROR | (cat&LS_INTERNAL_MASK) );
- return 1;
- }
-
- /* Filter by level and filter hook */
- if(!( (1<<LS_GET_LEVEL(cat)) & ls->levels )) return 0;
- if( ls->filter )
- if( ls->filter(ls, m, cat) != 0 ) return 0;
-
- /* pass message to substreams */
- CLIST_FOR_EACH(simp_node *, s, ls->substreams)
- {
- if (ls_passmsg(depth+1, (struct log_stream*)(s->p), stime, sutime, m, cat))
- return 1;
- }
-
- /* Prepare for handler */
- if(ls->handler)
- {
- int len = strlen(m) + strlen(stime) + strlen(sutime) + 32;
- /* SHOULD be enough for all information, but beware */
- if (ls_title) len += strlen(ls_title);
- if (ls->name) len += strlen(ls->name);
- char *buf=xmalloc(len);
- char *p=buf;
-
- /* Level (2 chars) */
- if(ls->msgfmt & LSFMT_LEVEL)
- {
- *p++=LS_LEVEL_LETTER(LS_GET_LEVEL(cat));
- *p++=' ';
- }
-
- /* Time (|stime| + |sutime| + 1 chars) */
- if(ls->msgfmt & LSFMT_TIME)
- {
- char *q = (char *)stime;
-
- while(*q)
- *p++=*q++;
- if(ls->msgfmt & LSFMT_USEC)
- {
- q = (char *)sutime;
- while(*q)
- *p++=*q++;
- }
- *p++=' ';
- }
-
- /* process name, PID ( |ls_title| + 6 + (|PID|<=10) chars ) */
- if((ls->msgfmt & LSFMT_TITLE) && ls_title)
- {
- if(ls->msgfmt & LSFMT_PID)
- p += sprintf(p, "[%s (%d)] ", ls_title, getpid());
- else
- p += sprintf(p, "[%s] ", ls_title);
- }
- else
- {
- if(ls->msgfmt & LSFMT_PID)
- p += sprintf(p, "[%d] ", getpid());
- }
-
- /* log_stream name ( |ls->name| + 4 chars ) */
- if(ls->msgfmt & LSFMT_LOGNAME)
- {
- if(ls->name)
- p += sprintf(p, "<%s> ", ls->name);
- else
- p += sprintf(p, "<?> ");
- }
-
- /* finish the string and call the handler ( |m| + 1 chars ) */
- {
- char *q = (char *)m;
-
- while(*q)
- *p++=*q++;
- *p++ = '\n';
- *p++ = '\0';
- ls->handler(ls, buf, cat);
- }
- xfree(buf);
- }
- return 0;
-}
-
-
-/********** log types */
-
-
-/**** standard (filedes) files */
-
-/* destructor for standard files */
-static void ls_fdfile_close(struct log_stream *ls)
-{
- ASSERT(ls);
- close(ls->idata);
- if(ls->name)
- xfree(ls->name);
-}
-
-/* handler for standard files */
-static int ls_fdfile_handler(struct log_stream* ls, const char *m, u32 cat UNUSED)
-{
- int len = strlen(m);
- int r = write(ls->idata, m, len);
- /* TODO: check the errors here? */
- if (r!=len)
- return errno;
- return 0;
-}
-
-/* assign log to a file descriptor */
-/* initialize with the default formatting, does NOT close the descriptor */
-struct log_stream *ls_fdfile_new(int fd)
-{
- struct log_stream *ls=ls_new();
- ls->idata=fd;
- ls->msgfmt=LSFMT_DEFAULT;
- ls->handler=ls_fdfile_handler;
- return ls;
-}
-
-/* open() a file (append mode) */
-/* initialize with the default formatting */
-struct log_stream *ls_file_new(const char *path)
-{
- struct log_stream *ls;
- int fd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0666);
- if (fd<0)
- {
- ls_msg(L_ERROR, "Opening logfile '%s' failed: %m.", path);
- return NULL;
- }
- ls = ls_new();
- ls->name = xstrdup(path);
- ls->idata = fd;
- ls->msgfmt = LSFMT_DEFAULT;
- ls->handler = ls_fdfile_handler;
- ls->close = ls_fdfile_close;
- return ls;
-}
-
-
-/**** syslog */
-
-/* destructor for syslog logs */
-static void ls_syslog_close(struct log_stream *ls)
-{
- ASSERT(ls);
- if(ls->name)
- xfree(ls->name);
-}
-
-/* convert severity level to syslog constants */
-static int ls_syslog_convert_level(int level)
-{
- switch(level)
- {
- case L_DEBUG: return LOG_DEBUG;
- case L_INFO: return LOG_INFO;
- case L_INFO_R: return LOG_INFO;
- case L_WARN: return LOG_WARNING;
- case L_WARN_R: return LOG_WARNING;
- case L_ERROR: return LOG_ERR;
- case L_ERROR_R: return LOG_ERR;
- case L_FATAL: return LOG_CRIT;
- default: return LOG_NOTICE;
- }
-}
-
-/* simple syslog write handler */
-static int ls_syslog_handler(struct log_stream *ls, const char *m, u32 flags)
-{
- int prio;
- ASSERT(ls);
- ASSERT(m);
-
- prio = ls_syslog_convert_level(LS_GET_LEVEL(flags)) | (ls->idata);
- if (ls->name)
- syslog(prio | (ls->idata), "%s: %s", ls->name, m);
- else
- syslog(prio | (ls->idata), "%s", m);
- return 0;
-}
-
-/* assign log to a syslog facility */
-/* initialize with no formatting (syslog adds these inforamtion) */
-/* name is optional prefix (NULL for none) */
-struct log_stream *ls_syslog_new(int facility, const char *name)
-{
- struct log_stream *ls=ls_new();
- if (name) ls->name = xstrdup(name);
- ls->idata = facility;
- ls->msgfmt = LSFMT_NONE;
- ls->handler = ls_syslog_handler;
- ls->close = ls_syslog_close;
- return ls;
-}
-
-#ifdef TEST
-
-int main(void)
-{
- ls_msg(L_INFO, "Brum!");
- return 0;
-}
-
-#endif
+++ /dev/null
-/*
- * UCW Library -- Logging
- *
- * (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
- * (c) 2009 Martin Mares <mj@ucw.cz>
- *
- * This software may be freely distributed and used according to the terms
- * of the GNU Lesser General Public License.
- */
-
-#ifndef _UCW_LOGSTREAM_H_
-#define _UCW_LOGSTREAM_H_
-
-#include "ucw/clists.h"
-
-/* user de/allocated program/process name for use in the logsystem */
-extern char *ls_title;
-
-struct log_stream
-{
- /* optional name, 0-term, de/allocated by constr./destr. or user */
- char *name;
- /* number for use with msg parameter (from LS_SET_STRNUM()), -1 for closed log_stream */
- int regnum;
- /* arbitrary data for filter/handler */
- int idata;
- void *pdata;
- /* severity levels to accept - bitmask of (1<<LEVEL) */
- int levels;
- /* if filter returns nonzero, discard the message */
- int (*filter)(struct log_stream* ls, const char *m, u32 cat);
- /* pass the message to these streams (simple-list of pointers) */
- struct clist substreams;
- /* what kind of string to format to pass to the handler (bitmask of LSFMT_xxx ) */
- int msgfmt;
- /* what to do to commit the message (ret 0 on success, nonzero on error)
- * msg is 0-term string, with desired info, one line, ending with "\n\0". */
- int (*handler)(struct log_stream* ls, const char *m, u32 cat);
- /* close the log_stream file/connection */
- void (*close)(struct log_stream* ls);
-};
-
-/* the default logger */
-extern const struct log_stream ls_default_log;
-
-/* A message is processed as follows:
- * 1. Discard if message level not in levels
- * 2. Run filter (if any), discard if ret. nonzero
- * 3. Pass the message to all log_streams in substreams
- * 4. Format the message informaion acc. to msgfmt
- * 5. Run the handler
- */
-
-/* log header verbosity specifying message passed to handler */
-enum ls_fmt
-{
- LSFMT_LEVEL=1, /* log severity level (one letter) */
- LSFMT_TIME=2, /* log time (date-seconds) */
- LSFMT_USEC=4, /* log also micro-seconds */
- LSFMT_TITLE=8, /* log program title (global string) */
- LSFMT_PID=16, /* log program PID */
- LSFMT_LOGNAME=32, /* log log_stream name */
- LSFMT_NONE=0,
- LSFMT_FULL=LSFMT_LEVEL+LSFMT_TIME+LSFMT_USEC+LSFMT_TITLE+LSFMT_PID+LSFMT_LOGNAME,
- LSFMT_DEFAULT=LSFMT_LEVEL+LSFMT_TIME
-};
-
-enum ls_levels
-{
- L_DEBUG=0, /* 'D' - Debugging messages */
- L_INFO, /* 'I' - Informational */
- L_INFO_R, /* 'i' - xxx_R are messages caused by external events */
- L_WARN, /* 'W' - Warning */
- L_WARN_R, /* 'w' */
- L_ERROR, /* 'E' - Error, but non-critical */
- L_ERROR_R, /* 'e' */
- L_FATAL, /* '!' - Error, from die() */
-};
-
-/* Mask of containing all existing levels. */
-#define LS_ALL_LEVELS 0xfff
-
-// return the letter associated with the severity level
-#define LS_LEVEL_LETTER(level) ("DIiWwEe!###"[( level )])
-
-///// Macros for extracting parts of the flags parameter
-// The division of the flags parameter is decided only here
-// The current division is (for 32 bit flags):
-// MSB <5 bits: any internal log flags> <8 bits: "user" flags> <10 bits: stream number>
-// <8 bits: severity level> LSB
-
-// Bits per section
-enum ls_flagbits {
- LS_LEVEL_BITS = 8,
- LS_STRNUM_BITS = 16,
- LS_FLAGS_BITS = 5,
- LS_INTERNAL_BITS = 4,
-};
-
-// Section shifts
-enum ls_flagpos {
- LS_LEVEL_POS = 0,
- LS_STRNUM_POS = LS_LEVEL_POS + LS_LEVEL_BITS,
- LS_FLAGS_POS = LS_STRNUM_POS + LS_STRNUM_BITS,
- LS_INTERNAL_POS = LS_FLAGS_POS + LS_FLAGS_BITS,
-};
-
-// Bitmasks
-enum ls_flagmasks {
- LS_LEVEL_MASK = (( 1 << LS_LEVEL_BITS ) - 1 ) << LS_LEVEL_POS,
- LS_STRNUM_MASK = (( 1 << LS_STRNUM_BITS ) - 1 ) << LS_STRNUM_POS,
- LS_FLAGS_MASK = (( 1 << LS_FLAGS_BITS ) - 1 ) << LS_FLAGS_POS,
- LS_INTERNAL_MASK = (( 1 << LS_INTERNAL_BITS ) - 1 ) << LS_INTERNAL_POS,
-};
-
-// "Get" macros (break flags to parts)
-#define LS_GET_LEVEL(flags) ((( flags ) & LS_LEVEL_MASK ) >> LS_LEVEL_POS )
-#define LS_GET_STRNUM(flags) ((( flags ) & LS_STRNUM_MASK ) >> LS_STRNUM_POS )
-#define LS_GET_FLAGS(flags) ((( flags ) & LS_FLAGS_MASK ) >> LS_FLAGS_POS )
-#define LS_GET_INTERNAL(flags) ((( flags ) & LS_INTERNAL_MASK ) >> LS_INTERNAL_POS )
-
-// "Set" macros (parts to flags)
-#define LS_SET_LEVEL(level) (( level ) << LS_LEVEL_POS )
-#define LS_SET_STRNUM(strnum) (( strnum ) << LS_STRNUM_POS )
-#define LS_SET_FLAGS(flags) (( flags ) << LS_FLAGS_POS )
-#define LS_SET_INTERNAL(intern) (( intern ) << LS_INTERNAL_POS )
-
-// Internal flags of the logsystem
-// Avoid operations that are unsafe in signal handlers
-#define LSFLAG_SIGHANDLER LS_SET_INTERNAL(0x001)
-
-// The module is initialized when a first stream is created.
-// Before that only the default stream exists.
-
-// Initial number of streams to allocate (must be >=2)
-#define LS_INIT_STREAMS 8
-
-/* Return pointer a new (xmalloc()-ated) stream with no handler and an empty substream list. */
-struct log_stream *ls_new(void);
-
-/* Close and xfree() given log_stream */
-/* Does not affect substreams */
-void ls_close(struct log_stream *ls);
-
-/* close all open streams, un-initialize the module, free all memory,
- * use only ls_default_log */
-void ls_close_all(void);
-
-/* add a new substream, xmalloc()-ate a new simp_node */
-void ls_add_substream(struct log_stream *where, struct log_stream *what);
-
-/* remove all occurences of a substream, free() the simp_node */
-/* return number of deleted entries */
-int ls_rm_substream(struct log_stream *where, struct log_stream *what);
-
-/* get a stream by its number (regnum) */
-/* returns NULL for free numbers */
-/* defaults to ls_default_stream for 0 when stream number 0 not set */
-struct log_stream *ls_bynum(int num);
-
-/* The proposed alternative to original vmsg() */
-void ls_vmsg(unsigned int cat, const char *fmt, va_list args);
-
-/* The proposed alternative to original msg() */
-void ls_msg(unsigned int cat, const char *fmt, ...);
-
-/* The proposed alternative to original die() */
-void ls_die(const char *fmt, ...);
-
-/* process a message (string) (INTERNAL) */
-/* depth prevents undetected looping */
-/* returns 1 in case of loop detection or other fatal error
- * 0 otherwise */
-int ls_passmsg(int depth, struct log_stream *ls, const char *stime, const char *sutime,
- const char *msg, u32 cat);
-
-/* Maximal depth of ls_passmsg recursion */
-#define LS_MAX_DEPTH 64
-
-/********* Individual handler types (constructors, handlers, destructors) */
-
-/**** standard (filedes) files */
-
-// NOTE:
-// under unix, for ordinary files open in append mode, the writes
-// are atomic (unless you meet the quota or other bad things happen),
-// so using a single log_stream is thread-safe and the file can be shared
-// among multiple processes
-
-/* assign log to a file descriptor */
-/* initialize with the default formatting, does NOT close the descriptor */
-struct log_stream *ls_fdfile_new(int fd);
-
-/* open() a file (append mode) */
-/* initialize with the default formatting */
-struct log_stream *ls_file_new(const char *path);
-
-
-/**** syslog */
-
-// NOTE:
-// The syslog uses a bit different severity levels, for details, see
-// ls_syslog_convert_level().
-// syslog also prepends it's own time and severity info, so the default
-// messaging passes only clean message
-
-/* assign log to a syslog facility */
-/* initialize with no formatting (syslog adds these inforamtion) */
-/* name is optional prefix (NULL for none) */
-struct log_stream *ls_syslog_new(int facility, const char *name);
-
-#endif