Author: Kev <klmitch@mit.edu>
authorKevin L. Mitchell <klmitch@mit.edu>
Tue, 28 Nov 2000 22:28:20 +0000 (22:28 +0000)
committerKevin L. Mitchell <klmitch@mit.edu>
Tue, 28 Nov 2000 22:28:20 +0000 (22:28 +0000)
Log message:

Started working on a new logging API that can log to files and/or to
syslog; the intent will be to eventually make this flexible enough that
log files for subsystems can be set from the .conf.

Status: Stable
Testing done:

Compiles.  No run-time checking done because nothing calls these functions
yet.

Future directions:

An API for setting log files needs to be added.  It would also be nice to
have support for sending the log messages through the server notices
mechanism.

git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@316 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
include/ircd_log.h
ircd/ircd_log.c

index dc1ad39979ec344a7cefe7d000f1a86eec3ea39a..59d946a533cf2a2fe5cb2c0d24566902e98daa04 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2000-11-28  Kevin L. Mitchell  <klmitch@mit.edu>
 
+       * ircd/ircd_log.c: make sure the various LOG_* constants are
+       defined (probably not needed, since #include <syslog.h> isn't
+       conditional); various static data needed for the new logging
+       functions; definitions of new logging functions
+
+       * include/ircd_log.h: new LogSys enum, declarations for part of
+       new logging API
+
        * ircd/motd.c: we were setting type to MOTD_CLASS unconditionally,
        which was of course stupid; switched to using switch/case in
        initialization in motd_create(); zero the MotdList.other pointer
index 64294b2ba60c738424a5430ea88a38dfa63003a3..4ffb8d25cf37c5c82d26666fdd49b4d6a258984d 100644 (file)
@@ -34,6 +34,14 @@ enum LogLevel {
   L_LAST_LEVEL
 };
 
+/* WARNING WARNING WARNING -- Order is important; these are
+ * used as indexes into an array of LogDesc structures.
+ */
+enum LogSys {
+  LS_GLINE,
+  LS_LAST_SYSTEM
+};
+
 extern void open_log(const char* process_name);
 extern void close_log(void);
 extern void set_log_level(int level);
@@ -45,4 +53,11 @@ extern void ircd_log_kill(const struct Client* victim,
                           const char*          inpath,
                           const char*          path);
 
+extern void log_init(const char *process_name);
+extern void log_reopen(void);
+extern void log_close(void);
+
+extern void log_write(enum LogSys subsys, enum LogLevel severity,
+                     const char *fmt, ...);
+
 #endif /* INCLUDED_ircd_log_h */
index c0c2f9d6f705d2afc94e3af5e2e41f97616aa88b..8970077aefe756a2991d794129bbee626828d8a4 100644 (file)
 #include "ircd_log.h"
 #include "client.h"
 #include "config.h"
+#include "ircd_snprintf.h"
 #include "ircd_string.h"
+#include "ircd.h"
 #include "s_debug.h"
 #include "struct.h"
 
 #include <assert.h>
+#include <fcntl.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/uio.h>
 #include <syslog.h>
+#include <time.h>
 #include <unistd.h>
 
 #define LOG_BUFSIZE 2048 
 
+/* These constants are present even if we don't use syslog */
+#ifndef LOG_CRIT
+# define LOG_CRIT 0
+#endif
+#ifndef LOG_ERR
+# define LOG_ERR 0
+#endif
+#ifndef LOG_WARNING
+# define LOG_WARNING 0
+#endif
+#ifndef LOG_NOTICE
+# define LOG_NOTICE 0
+#endif
+#ifndef LOG_INFO
+# define LOG_INFO 0
+#endif
+
+/* Map severity levels to strings and syslog levels */
+static struct LevelData {
+  enum LogLevel level;
+  char        *string;
+  int          syslog;
+} levelData[] = {
+#define L(level, syslog)   { L_ ## level, #level, (syslog) }
+  L(CRIT, LOG_CRIT),
+  L(ERROR, LOG_ERR),
+  L(WARNING, LOG_WARNING),
+  L(NOTICE, LOG_NOTICE),
+  L(TRACE, LOG_INFO),
+  L(INFO, LOG_INFO),
+  L(DEBUG, LOG_INFO),
+#undef L
+  { L_LAST_LEVEL, 0 }
+};
+
+/* Descriptions of all logging subsystems */
+static struct LogDesc {
+  enum LogSys    subsys;   /* number for subsystem */
+  char          *name;     /* subsystem name */
+  struct LogFile *file;            /* file descriptor for subsystem */
+  int            facility; /* -1 means don't use syslog */
+} logDesc[] = {
+#define S(system, defprio) { LS_ ## system, #system, 0, (defprio) }
+  S(GLINE, -1),
+#undef S
+  { LS_LAST_SYSTEM, 0, 0, -1 }
+};
+
+struct LogFile {
+  struct LogFile *next;        /* next log file descriptor */
+  int            fd;   /* file's descriptor-- -1 if not open */
+  char          *file; /* file name */
+};
+
+static struct LogFile *logFileList = 0; /* list of log files */
+
+static const char *procname = "ircd"; /* process's name */
+
 static int logLevel = L_INFO;
 
 #ifdef USE_SYSLOG
@@ -129,3 +194,137 @@ void ircd_log_kill(const struct Client* victim, const struct Client* killer,
 }
 
 
+void
+log_init(const char *process_name)
+{
+  /* store the process name; probably belongs in ircd.c, but oh well... */
+  if (!EmptyString(process_name))
+    procname = process_name;
+
+#ifdef USE_SYSLOG
+  /* ok, open syslog; default facility: LOG_USER */
+  openlog(procname, LOG_PID | LOG_NDELAY, LOG_USER);
+#endif
+}
+
+void
+log_reopen(void)
+{
+  log_close(); /* close everything...we reopen on demand */
+
+#ifdef USE_SYSLOG
+  /* reopen syslog, if needed; default facility: LOG_USER */
+  openlog(procname, LOG_PID | LOG_NDELAY, LOG_USER);
+#endif
+}
+
+/* close the log files */
+void
+log_close(void)
+{
+  struct LogFile *ptr;
+
+#ifdef USE_SYSLOG
+  closelog(); /* close syslog */
+#endif
+
+  for (ptr = logFileList; ptr; ptr = ptr->next) {
+    if (ptr->fd >= 0)
+      close(ptr->fd);
+
+    ptr->fd = -1;
+  }
+}
+
+static void
+log_open(struct LogFile *lf)
+{
+  /* only open the file if we haven't already */
+  if (lf && lf->fd < 0) {
+    alarm(3);
+    lf->fd = open(lf->file, O_WRONLY | O_CREAT | O_APPEND,
+                    S_IREAD | S_IWRITE);
+    alarm(0);
+  }
+}
+
+/* This writes an entry to a log file */
+void
+log_write(enum LogSys subsys, enum LogLevel severity, const char *fmt, ...)
+{
+  struct VarData vd;
+  struct LogDesc *desc;
+  struct LevelData *ldata;
+  struct tm *tstamp;
+  struct iovec vector[3];
+  time_t curtime;
+  char buf[LOG_BUFSIZE];
+  /* 1234567890123456789012 3 */
+  /* [2000-11-28 16:11:20] \0 */
+  char timebuf[23];
+
+  /* check basic assumptions */
+  assert(-1 < subsys);
+  assert(subsys < LS_LAST_SYSTEM);
+  assert(-1 < severity);
+  assert(severity < L_LAST_LEVEL);
+  assert(0 != fmt);
+
+  /* find the log data and the severity data */
+  desc = &logDesc[subsys];
+  ldata = &levelData[severity];
+
+  /* check the set of ordering assumptions */
+  assert(desc->subsys == subsys);
+  assert(ldata->level == severity);
+
+  /* if we don't have anything to log to, short-circuit */
+  if (!desc->file
+#ifdef USE_SYSLOG
+      && desc->facility < 0
+#endif
+      )
+    return;
+
+  /* Build the basic log string */
+  vd.vd_format = fmt;
+  va_start(vd.vd_args, fmt);
+
+  /* save the length for writev */
+  /* Log format: "SYSTEM [SEVERITY] log message */
+  vector[1].iov_len =
+    ircd_snprintf(0, buf, sizeof(buf), "%s [%s] %v", desc->name,
+                 ldata->string, &vd) - 1;
+
+  va_end(vd.vd_args);
+
+  /* open the log file if we haven't already */
+  log_open(desc->file);
+  /* if we have something to write to... */
+  if (desc->file && desc->file->fd >= 0) {
+    curtime = TStime();
+    tstamp = localtime(&curtime); /* build the timestamp */
+
+    vector[0].iov_len =
+      ircd_snprintf(0, timebuf, sizeof(timebuf), "[%d-%d-%d %d:%02d:%02d] ",
+                   tstamp->tm_year + 1900, tstamp->tm_mon + 1,
+                   tstamp->tm_mday, tstamp->tm_hour, tstamp->tm_min,
+                   tstamp->tm_sec) - 1;
+
+    /* set up the remaining parts of the writev vector... */
+    vector[0].iov_base = timebuf;
+    vector[1].iov_base = buf;
+
+    vector[2].iov_base = "\n"; /* terminate lines with a \n */
+    vector[2].iov_len = 1;
+
+    /* write it out to the log file */
+    writev(desc->file->fd, vector, 3);
+  }
+
+#ifdef USE_SYSLOG
+  /* oh yeah, syslog it too... */
+  if (desc->facility >= 0)
+    syslog(ldata->syslog | desc->facility, "%s", buf);
+#endif
+}