#include "ucw/simple-lists.h"
#include <string.h>
-#include <syslog.h> // FIXME
+#include <syslog.h>
struct stream_config {
cnode n;
if (c->file_name && c->syslog_facility)
return "Both FileName and SyslogFacility selected";
+ if (c->syslog_facility && !log_syslog_facility_exists(c->syslog_facility))
+ return cf_printf("SyslogFacility `%s' is not recognized", c->syslog_facility);
return NULL;
}
if (c->file_name)
ls = log_new_file(c->file_name);
else if (c->syslog_facility)
- ls = log_new_syslog(LOG_USER, NULL); // FIXME: Facility
+ ls = log_new_syslog(c->syslog_facility, 0); // FIXME: Logging of PID
else
ls = log_new_stream(sizeof(*ls));
struct log_stream *ls = log_new_configured("combined");
msg(L_INFO | ls->regnum, "Hello, universe!");
+ log_close_all();
return 0;
}
#include "ucw/lib.h"
#include "ucw/log.h"
+#include <string.h>
#include <syslog.h>
struct syslog_stream {
int facility;
};
+static int syslog_open_count;
+
static void
-syslog_close(struct log_stream *ls)
+syslog_close(struct log_stream *ls UNUSED)
+{
+ if (!--syslog_open_count)
+ closelog();
+}
+
+/* Convert syslog facility to its identifier. */
+static int
+syslog_facility(const char *name)
{
- if (ls->name)
- xfree(ls->name);
+ // Unfortunately, there is no standard way how to get at the list of facility names
+ static const struct {
+ const char *name;
+ int id;
+ } facilities[] = {
+ { "auth", LOG_AUTH },
+ { "authpriv", LOG_AUTHPRIV },
+ { "cron", LOG_CRON },
+ { "daemon", LOG_DAEMON },
+ { "ftp", LOG_FTP },
+ { "kern", LOG_KERN },
+ { "lpr", LOG_LPR },
+ { "mail", LOG_MAIL },
+ { "news", LOG_NEWS },
+ { "syslog", LOG_SYSLOG },
+ { "user", LOG_USER },
+ { "uucp", LOG_UUCP },
+ { "local0", LOG_LOCAL0 },
+ { "local1", LOG_LOCAL1 },
+ { "local2", LOG_LOCAL2 },
+ { "local3", LOG_LOCAL3 },
+ { "local4", LOG_LOCAL4 },
+ { "local5", LOG_LOCAL5 },
+ { "local6", LOG_LOCAL6 },
+ { "local7", LOG_LOCAL7 },
+ };
+
+ for (uns i=0; i < ARRAY_SIZE(facilities); i++)
+ if (!strcmp(facilities[i].name, name))
+ return facilities[i].id;
+ return -1;
}
/* Convert severity level to syslog constants */
ASSERT(ls);
ASSERT(m);
- // FIXME: Logging of PID
prio = syslog_level(LS_GET_LEVEL(m->flags)) | ss->facility;
- if (ls->name)
- syslog(prio, "%s: %s", ls->name, m->m);
- else
- syslog(prio, "%s", m->m);
+ syslog(prio, "%s", m->m);
return 0;
}
struct log_stream *
-log_new_syslog(int facility, const char *name)
+log_new_syslog(const char *facility, int options)
{
+ int fac = syslog_facility(facility);
+ if (fac < 0)
+ die("No such syslog facility: %s", facility);
+
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->name = "syslog";
ls->msgfmt = 0;
ls->handler = syslog_handler;
ls->close = syslog_close;
- ss->facility = facility;
+ ss->facility = fac;
+
+ if (!syslog_open_count++)
+ openlog(log_title, options, LOG_INFO);
return ls;
- // FIXME: L_SIGHANDLER?
+}
+
+int
+log_syslog_facility_exists(const char *facility)
+{
+ return (syslog_facility(facility) >= 0);
}
int main(void)
{
- struct log_stream *ls = log_new_syslog(LOG_USER, "syslog");
+ struct log_stream *ls = log_new_syslog("local3", 0);
msg(L_INFO | ls->regnum, "Brum <%300s>", ":-)");
log_set_format(log_default_stream(), ~0U, LSFMT_USEC);
msg(L_INFO, "Brum <%300s>", ":-)");
* === Logging to syslog
*
* This log stream uses the libc interface to the system logging daemon (`syslogd`).
- * As syslog serverities differ from our scheme, they are translated; if you
- * are interested in details, search for syslog_level().
+ * This interface has several limitations:
*
- * Syslog also provides its own timestamps, so we turn off all formatting
- * of the LibUCW logger.
+ * * Syslog are poorer than our scheme, so they are translated with a slight
+ * loss of information (most importantly, the distinction between local and
+ * remote messages is lost). If you are interested in details, search the
+ * source for syslog_level().
+ * * Syslog options (especially logging of PID with each message) must be fixed
+ * during initialization of the logger
+ * * Syslog provides its own formatting, so we turn off all formatting flags
+ * of the LibUCW logger. You can override this manually by setting the @msgfmt
+ * field of the log stream, but the result won't be nice.
+ * * Syslog does not support timestamps with sub-second precision.
***/
/**
* Create a log stream for logging to a selected syslog facility.
- * The @name is an optional prefix of the messages.
+ * The @options are passed to openlog(). (Beware, due to limitations of the
+ * syslog interface in libc, the @options are shared for all syslog streams
+ * and they are applied when the first stream is created.)
**/
-struct log_stream *log_new_syslog(int facility, const char *name);
+struct log_stream *log_new_syslog(const char *facility, int options);
+
+/**
+ * Verify that a facility of the given name exists. Return 1 if it does, 0 otherwise.
+ **/
+int log_syslog_facility_exists(const char *facility);
/***
* === Configuring log streams