Add features (incomplete, highly experimental), fix DundiLookup app, debug improvemen...
[asterisk/asterisk.git] / logger.c
index 8b30d53..7f32b70 100755 (executable)
--- a/logger.c
+++ b/logger.c
 #include <asterisk/config.h>
 #include <asterisk/term.h>
 #include <asterisk/cli.h>
+#include <asterisk/utils.h>
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
-#include <pthread.h>
 #include <sys/stat.h>
 #include "asterisk.h"
 #include "astconf.h"
@@ -38,30 +38,44 @@ static int syslog_level_map[] = {
        LOG_INFO,    /* arbitrary equivalent of LOG_EVENT */
        LOG_NOTICE,
        LOG_WARNING,
-       LOG_ERR
+       LOG_ERR,
+       LOG_DEBUG
 };
-#define SYSLOG_NLEVELS 5
+
+#define SYSLOG_NLEVELS 6
 
 #include <asterisk/logger.h>
 
 #define MAX_MSG_QUEUE 200
 
-static ast_mutex_t msglist_lock = AST_MUTEX_INITIALIZER;
-static ast_mutex_t loglock = AST_MUTEX_INITIALIZER;
+#ifdef __linux__
+#include <asm/unistd.h>
+#define GETTID() syscall(__NR_gettid)
+#else
+#define GETTID() getpid()
+#endif
+
+static char dateformat[256] = "%b %e %T";              /* Original Asterisk Format */
+AST_MUTEX_DEFINE_STATIC(msglist_lock);
+AST_MUTEX_DEFINE_STATIC(loglock);
+static int pending_logger_reload = 0;
+static int global_logmask = -1;
 
 static struct msglist {
        char *msg;
        struct msglist *next;
 } *list = NULL, *last = NULL;
 
+static char hostname[256];
+
 struct logchannel {
-        int logmask;
-        int facility; /* syslog */
+       int logmask;
+       int facility; /* syslog */
        int syslog; /* syslog flag */
-        int console;  /* console logging */
+       int console;  /* console logging */
        FILE *fileptr; /* logfile logging */
        char filename[256];
-        struct logchannel *next;
+       struct logchannel *next;
 };
 
 static struct logchannel *logchannels = NULL;
@@ -71,19 +85,21 @@ static int msgcnt = 0;
 static FILE *eventlog = NULL;
 
 static char *levels[] = {
-       "DEBUG",
-       "EVENT",
-       "NOTICE",
-       "WARNING",
-       "ERROR"
+       "DEBUG",
+       "EVENT",
+       "NOTICE",
+       "WARNING",
+       "ERROR",
+       "VERBOSE"
 };
 
 static int colors[] = {
-       COLOR_BRGREEN,
-       COLOR_BRBLUE,
-       COLOR_YELLOW,
-       COLOR_BRRED,
-       COLOR_RED
+       COLOR_BRGREEN,
+       COLOR_BRBLUE,
+       COLOR_YELLOW,
+       COLOR_BRRED,
+       COLOR_RED,
+       COLOR_GREEN
 };
 
 static int make_components(char *s, int lineno)
@@ -106,6 +122,8 @@ static int make_components(char *s, int lineno)
                res |= (1 << __LOG_EVENT);
            else if (!strcasecmp(w, "debug"))
                res |= (1 << __LOG_DEBUG);
+           else if (!strcasecmp(w, "verbose"))
+               res |= (1 << __LOG_VERBOSE);
            else {
                fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
            }
@@ -120,12 +138,12 @@ static struct logchannel *make_logchannel(char *channel, char *components, int l
        char *facility;
        CODE *cptr;
 
-       if (!strlen(channel))
+       if (ast_strlen_zero(channel))
                return NULL;
        chan = malloc(sizeof(struct logchannel));
 
        if (chan) {
-               memset(chan, 0, sizeof(chan));
+               memset(chan, 0, sizeof(struct logchannel));
                if (!strcasecmp(channel, "console")) {
                    chan->console = 1;
                } else if (!strncasecmp(channel, "syslog", 6)) {
@@ -159,10 +177,19 @@ static struct logchannel *make_logchannel(char *channel, char *components, int l
                    chan->syslog = 1;
                    openlog("asterisk", LOG_PID, chan->facility);
                } else {
-                       if (channel[0] == '/') 
-                               strncpy(chan->filename, channel, sizeof(chan->filename) - 1);
-                       else
+                       if (channel[0] == '/') {
+                               if(!ast_strlen_zero(hostname)) { 
+                                       snprintf(chan->filename, sizeof(chan->filename) - 1,"%s.%s", channel, hostname);
+                               } else {
+                                       strncpy(chan->filename, channel, sizeof(chan->filename) - 1);
+                               }
+                       }                 
+                       
+                       if(!ast_strlen_zero(hostname)) {
+                               snprintf(chan->filename, sizeof(chan->filename), "%s/%s.%s",(char *)ast_config_AST_LOG_DIR, channel, hostname);
+                       } else {
                                snprintf(chan->filename, sizeof(chan->filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, channel);
+                       }
                        chan->fileptr = fopen(chan->filename, "a");
                        if (!chan->fileptr) {
                                /* Can't log here, since we're called with a lock */
@@ -179,6 +206,7 @@ static void init_logger_chain(void)
        struct logchannel *chan, *cur;
        struct ast_config *cfg;
        struct ast_variable *var;
+       char *s;
 
        /* delete our list of log channels */
        ast_mutex_lock(&loglock);
@@ -190,23 +218,39 @@ static void init_logger_chain(void)
        }
        logchannels = NULL;
        ast_mutex_unlock(&loglock);
-
+       
+       global_logmask = 0;
        /* close syslog */
        closelog();
-
+       
        cfg = ast_load("logger.conf");
        
        /* If no config file, we're fine */
        if (!cfg)
            return;
-
+       
        ast_mutex_lock(&loglock);
+       if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
+               if(ast_true(s)) {
+                       if(gethostname(hostname, sizeof(hostname))) {
+                               strncpy(hostname, "unknown", sizeof(hostname)-1);
+                               ast_log(LOG_WARNING, "What box has no hostname???\n");
+                       }
+               } else
+                       hostname[0] = '\0';
+       } else
+               hostname[0] = '\0';
+       if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
+               strncpy(dateformat, s, sizeof(dateformat) - 1);
+       } else
+               strncpy(dateformat, "%b %e %T", sizeof(dateformat) - 1);
        var = ast_variable_browse(cfg, "logfiles");
        while(var) {
                chan = make_logchannel(var->name, var->value, var->lineno);
                if (chan) {
                        chan->next = logchannels;
                        logchannels = chan;
+                       global_logmask |= chan->logmask;
                }
                var = var->next;
        }
@@ -215,15 +259,51 @@ static void init_logger_chain(void)
        ast_mutex_unlock(&loglock);
 }
 
+static FILE *qlog = NULL;
+AST_MUTEX_DEFINE_STATIC(qloglock);
+
+void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
+{
+       va_list ap;
+       ast_mutex_lock(&qloglock);
+       if (qlog) {
+               va_start(ap, fmt);
+               fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
+               vfprintf(qlog, fmt, ap);
+               fprintf(qlog, "\n");
+               va_end(ap);
+               fflush(qlog);
+       }
+       ast_mutex_unlock(&qloglock);
+}
+
+static void queue_log_init(void)
+{
+       char filename[256];
+       int reloaded = 0;
+       ast_mutex_lock(&qloglock);
+       if (qlog) {
+               reloaded = 1;
+               fclose(qlog);
+               qlog = NULL;
+       }
+       snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, "queue_log");
+       qlog = fopen(filename, "a");
+       ast_mutex_unlock(&qloglock);
+       if (reloaded) 
+               ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
+       else
+               ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
+}
+
 int reload_logger(int rotate)
 {
-       char old[AST_CONFIG_MAX_PATH];
+       char old[AST_CONFIG_MAX_PATH] = "";
        char new[AST_CONFIG_MAX_PATH];
        struct logchannel *f;
        FILE *myf;
 
        int x;
-
        ast_mutex_lock(&loglock);
        if (eventlog) 
                fclose(eventlog);
@@ -259,7 +339,7 @@ int reload_logger(int rotate)
                        fclose(f->fileptr);
                        f->fileptr = NULL;
                        if(rotate) {
-                               strncpy(old, f->filename, sizeof(old));
+                               strncpy(old, f->filename, sizeof(old) - 1);
        
                                for(x=0;;x++) {
                                        snprintf(new, sizeof(new), "%s.%d", f->filename, x);
@@ -281,6 +361,8 @@ int reload_logger(int rotate)
 
        ast_mutex_unlock(&loglock);
 
+       queue_log_init();
+
        if (eventlog) {
                init_logger_chain();
                ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
@@ -290,6 +372,7 @@ int reload_logger(int rotate)
        } else 
                ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
        init_logger_chain();
+       pending_logger_reload = 0;
        return -1;
 }
 
@@ -326,7 +409,7 @@ static char logger_reload_help[] =
 "       Reloads the logger subsystem state.  Use after restarting syslogd(8)\n";
 
 static char logger_rotate_help[] =
-"Usage: logger reload\n"
+"Usage: logger rotate\n"
 "       Rotates and Reopens the log files.\n";
 
 static struct ast_cli_entry reload_logger_cli = 
@@ -336,15 +419,14 @@ static struct ast_cli_entry reload_logger_cli =
 
 static struct ast_cli_entry rotate_logger_cli = 
        { { "logger", "rotate", NULL }, 
-       handle_logger_rotate, "Reopens the log files",
+       handle_logger_rotate, "Rotates and reopens the log files",
        logger_rotate_help };
 
-static int handle_SIGXFSZ(int sig) {
-    reload_logger(1);
-    ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ\n");
-    if (option_verbose)
-           ast_verbose("Rotated Logs Per SIGXFSZ\n");
-    return 0;
+static int handle_SIGXFSZ(int sig) 
+{
+       /* Indicate need to reload */
+       pending_logger_reload = 1;
+       return 0;
 }
 
 int init_logger(void)
@@ -358,6 +440,9 @@ int init_logger(void)
        ast_cli_register(&reload_logger_cli);
        ast_cli_register(&rotate_logger_cli);
 
+       /* initialize queue logger */
+       queue_log_init();
+
        /* create the eventlog */
        mkdir((char *)ast_config_AST_LOG_DIR, 0755);
        snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
@@ -371,30 +456,49 @@ int init_logger(void)
        } else 
                ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
 
-       init_logger_chain();
-
        /* create log channels */
        init_logger_chain();
        return -1;
 }
 
-static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args) {
-    char buf[BUFSIZ];
+void close_logger(void)
+{
+       struct msglist *m, *tmp;
 
-    if(level >= SYSLOG_NLEVELS) {
-           /* we are locked here, so cannot ast_log() */
-           fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
-           return;
-    }
-    if(file && line && function) {
-       snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
-                levels[level], (long)pthread_self(), file, line, function);
-    } else {
-       snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)pthread_self());
-       level = __LOG_DEBUG;
-    }
-    vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, args);
-    syslog(syslog_level_map[level], buf);
+       ast_mutex_lock(&msglist_lock);
+       m = list;
+       while(m) {
+               if (m->msg) {
+                       free(m->msg);
+               }
+               tmp = m->next;
+               free(m);
+               m = tmp;
+       }
+       list = last = NULL;
+       msgcnt = 0;
+       ast_mutex_unlock(&msglist_lock);
+       return;
+}
+
+static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args) 
+{
+       char buf[BUFSIZ];
+
+       if (level >= SYSLOG_NLEVELS) {
+               /* we are locked here, so cannot ast_log() */
+               fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
+               return;
+       }
+       if (level == __LOG_VERBOSE) {
+               snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)GETTID());
+               level = __LOG_DEBUG;
+       } else {
+               snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
+                       levels[level], (long)GETTID(), file, line, function);
+       }
+       vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, args);
+       syslog(syslog_level_map[level], "%s", buf);
 }
 
 /*
@@ -402,81 +506,100 @@ static void ast_log_vsyslog(int level, const char *file, int line, const char *f
  */
 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
 {
-    struct logchannel *chan;
-    char buf[BUFSIZ];
-    time_t t;
-    struct tm tm;
-    char date[256];
+       struct logchannel *chan;
+       char buf[BUFSIZ];
+       time_t t;
+       struct tm tm;
+       char date[256];
 
-    va_list ap;
+       va_list ap;
        
-    if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
-       return;
-    }
+       if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
+               return;
+       }
+       /* Ignore anything that never gets logged anywhere */
+       if (!(global_logmask & (1 << level)))
+               return;
 
-    /* begin critical section */
-    ast_mutex_lock(&loglock);
+       /* begin critical section */
+       ast_mutex_lock(&loglock);
 
-    if (level == __LOG_EVENT) {
-           time(&t);
-           localtime_r(&t,&tm);
-           /* Log events into the event log file, with a different format */
-           strftime(date, sizeof(date), "%b %e %T", &tm);
-           va_start(ap, fmt);
+       time(&t);
+       localtime_r(&t, &tm);
+       strftime(date, sizeof(date), dateformat, &tm);
 
-           fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
-           vfprintf(eventlog, fmt, ap);
-           fflush(eventlog);
+       if (level == __LOG_EVENT) {
+               va_start(ap, fmt);
 
-           va_end(ap);
-           ast_mutex_unlock(&loglock);
-           return;
-    }
+               fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
+               vfprintf(eventlog, fmt, ap);
+               fflush(eventlog);
 
-    if (logchannels) {
-       chan = logchannels;
-       while(chan) {
-           if (chan->syslog && (chan->logmask & (1 << level))) {
-               va_start(ap, fmt);
-               ast_log_vsyslog(level, file, line, function, fmt, ap);
                va_end(ap);
-           } else if ((chan->logmask & (1 << level)) && (chan->console || chan->fileptr)) {
-               char linestr[128];
-               char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
-
-               time(&t);
-               localtime_r(&t, &tm);
-
-               strftime(date, sizeof(date), "%b %e %T", &tm);
-
-               sprintf(linestr, "%d", line);
-               snprintf(buf, sizeof(buf), "%s %s[%ld]: %s:%s %s: ",
-                        date,
-                        term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
-                        (long)pthread_self(),
-                        term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
-                        term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
-                        term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
-
-               if (chan->console)
-                       ast_console_puts(buf);
-               else
-                       fprintf(chan->fileptr, buf);
-               va_start(ap, fmt);
-               vsnprintf(buf, sizeof(buf), fmt, ap);
-               va_end(ap);
-               if (chan->console)
-                       ast_console_puts(buf);
-               else
-                       fprintf(chan->fileptr, buf);
+               ast_mutex_unlock(&loglock);
+               return;
+       }
 
-           }
-           chan = chan->next;
+       if (logchannels) {
+               chan = logchannels;
+               while(chan) {
+                       if (chan->syslog && (chan->logmask & (1 << level))) {
+                               va_start(ap, fmt);
+                               ast_log_vsyslog(level, file, line, function, fmt, ap);
+                               va_end(ap);
+                       } else if ((chan->logmask & (1 << level)) && (chan->console)) {
+                               char linestr[128];
+                               char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
+
+                               if (level != __LOG_VERBOSE) {
+                                       sprintf(linestr, "%d", line);
+                                       snprintf(buf, sizeof(buf), "%s %s[%ld]: %s:%s %s: ",
+                                               date,
+                                               term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
+                                               (long)GETTID(),
+                                               term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
+                                               term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
+                                               term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
+                   
+                                       ast_console_puts(buf);
+                                       va_start(ap, fmt);
+                                       vsnprintf(buf, sizeof(buf), fmt, ap);
+                                       va_end(ap);
+                                       ast_console_puts(buf);
+                               }
+                       } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
+                               snprintf(buf, sizeof(buf), "%s %s[%ld]: ", date,
+                                       levels[level], (long)GETTID());
+                               fprintf(chan->fileptr, buf);
+                               va_start(ap, fmt);
+                               vsnprintf(buf, sizeof(buf), fmt, ap);
+                               va_end(ap);
+                               fputs(buf, chan->fileptr);
+                               fflush(chan->fileptr);
+                       }
+                       chan = chan->next;
+               }
+       } else {
+               /* 
+                * we don't have the logger chain configured yet,
+                * so just log to stdout 
+               */
+               if (level != __LOG_VERBOSE) {
+                       va_start(ap, fmt);
+                       vsnprintf(buf, sizeof(buf), fmt, ap);
+                       va_end(ap);
+                       fputs(buf, stdout);
+               }
        }
-    }
 
-    ast_mutex_unlock(&loglock);
-    /* end critical section */
+       ast_mutex_unlock(&loglock);
+       /* end critical section */
+       if (pending_logger_reload) {
+               reload_logger(1);
+               ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ\n");
+               if (option_verbose)
+                       ast_verbose("Rotated Logs Per SIGXFSZ\n");
+       }
 }
 
 extern void ast_verbose(const char *fmt, ...)
@@ -532,26 +655,22 @@ extern void ast_verbose(const char *fmt, ...)
        } /* else
                fprintf(stdout, stuff + opos); */
 
+       ast_log(LOG_VERBOSE, stuff);
+
        if (fmt[strlen(fmt)-1] != '\n') 
                replacelast = 1;
        else 
                replacelast = pos = 0;
        va_end(ap);
 
-       va_start(ap, fmt);
-       if(stuff[strlen(stuff)-1] == '\n')
-           stuff[strlen(stuff)-1] = '\0';
-       ast_log_vsyslog(0, NULL, 0, NULL, fmt, ap);
-       va_end(ap);
-
        ast_mutex_unlock(&msglist_lock);
 }
 
 int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
 {
        struct msglist *m;
-       m = list;
        ast_mutex_lock(&msglist_lock);
+       m = list;
        while(m) {
                /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
                v(m->msg, 0, 0, 1);