Thu May 24 14:21:11 2007

Asterisk developer's documentation


logger.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  * \brief Asterisk Logger
00021  * 
00022  * Logging routines
00023  *
00024  */
00025 
00026 #include <signal.h>
00027 #include <stdarg.h>
00028 #include <stdio.h>
00029 #include <unistd.h>
00030 #include <time.h>
00031 #include <string.h>
00032 #include <stdlib.h>
00033 #include <errno.h>
00034 #include <sys/stat.h>
00035 
00036 #define SYSLOG_NAMES /* so we can map syslog facilities names to their numeric values,
00037               from <syslog.h> which is included by logger.h */
00038 #include <syslog.h>
00039 
00040 #include "asterisk.h"
00041 
00042 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 42200 $")
00043 
00044 static int syslog_level_map[] = {
00045    LOG_DEBUG,
00046    LOG_INFO,    /* arbitrary equivalent of LOG_EVENT */
00047    LOG_NOTICE,
00048    LOG_WARNING,
00049    LOG_ERR,
00050    LOG_DEBUG,
00051    LOG_DEBUG
00052 };
00053 
00054 #define SYSLOG_NLEVELS sizeof(syslog_level_map) / sizeof(int)
00055 
00056 #include "asterisk/logger.h"
00057 #include "asterisk/lock.h"
00058 #include "asterisk/options.h"
00059 #include "asterisk/channel.h"
00060 #include "asterisk/config.h"
00061 #include "asterisk/term.h"
00062 #include "asterisk/cli.h"
00063 #include "asterisk/utils.h"
00064 #include "asterisk/manager.h"
00065 
00066 #define MAX_MSG_QUEUE 200
00067 
00068 #if defined(__linux__) && !defined(__NR_gettid)
00069 #include <asm/unistd.h>
00070 #endif
00071 
00072 #if defined(__linux__) && defined(__NR_gettid)
00073 #define GETTID() syscall(__NR_gettid)
00074 #else
00075 #define GETTID() getpid()
00076 #endif
00077 
00078 
00079 static char dateformat[256] = "%b %e %T";    /* Original Asterisk Format */
00080 
00081 AST_MUTEX_DEFINE_STATIC(msglist_lock);
00082 AST_MUTEX_DEFINE_STATIC(loglock);
00083 static int filesize_reload_needed = 0;
00084 static int global_logmask = -1;
00085 
00086 static struct {
00087    unsigned int queue_log:1;
00088    unsigned int event_log:1;
00089 } logfiles = { 1, 1 };
00090 
00091 static struct msglist {
00092    char *msg;
00093    struct msglist *next;
00094 } *list = NULL, *last = NULL;
00095 
00096 static char hostname[MAXHOSTNAMELEN];
00097 
00098 enum logtypes {
00099    LOGTYPE_SYSLOG,
00100    LOGTYPE_FILE,
00101    LOGTYPE_CONSOLE,
00102 };
00103 
00104 struct logchannel {
00105    int logmask;         /* What to log to this channel */
00106    int disabled;        /* If this channel is disabled or not */
00107    int facility;        /* syslog facility */
00108    enum logtypes type;     /* Type of log channel */
00109    FILE *fileptr;       /* logfile logging file pointer */
00110    char filename[256];     /* Filename */
00111    struct logchannel *next;   /* Next channel in chain */
00112 };
00113 
00114 static struct logchannel *logchannels = NULL;
00115 
00116 static int msgcnt = 0;
00117 
00118 static FILE *eventlog = NULL;
00119 static FILE *qlog = NULL;
00120 
00121 static char *levels[] = {
00122    "DEBUG",
00123    "EVENT",
00124    "NOTICE",
00125    "WARNING",
00126    "ERROR",
00127    "VERBOSE",
00128    "DTMF"
00129 };
00130 
00131 static int colors[] = {
00132    COLOR_BRGREEN,
00133    COLOR_BRBLUE,
00134    COLOR_YELLOW,
00135    COLOR_BRRED,
00136    COLOR_RED,
00137    COLOR_GREEN,
00138    COLOR_BRGREEN
00139 };
00140 
00141 static int make_components(char *s, int lineno)
00142 {
00143    char *w;
00144    int res = 0;
00145    char *stringp=NULL;
00146    stringp=s;
00147    w = strsep(&stringp, ",");
00148    while(w) {
00149       while(*w && (*w < 33))
00150          w++;
00151       if (!strcasecmp(w, "error")) 
00152          res |= (1 << __LOG_ERROR);
00153       else if (!strcasecmp(w, "warning"))
00154          res |= (1 << __LOG_WARNING);
00155       else if (!strcasecmp(w, "notice"))
00156          res |= (1 << __LOG_NOTICE);
00157       else if (!strcasecmp(w, "event"))
00158          res |= (1 << __LOG_EVENT);
00159       else if (!strcasecmp(w, "debug"))
00160          res |= (1 << __LOG_DEBUG);
00161       else if (!strcasecmp(w, "verbose"))
00162          res |= (1 << __LOG_VERBOSE);
00163       else if (!strcasecmp(w, "dtmf"))
00164          res |= (1 << __LOG_DTMF);
00165       else {
00166          fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
00167       }
00168       w = strsep(&stringp, ",");
00169    }
00170    return res;
00171 }
00172 
00173 static struct logchannel *make_logchannel(char *channel, char *components, int lineno)
00174 {
00175    struct logchannel *chan;
00176    char *facility;
00177 #ifndef SOLARIS
00178    CODE *cptr;
00179 #endif
00180 
00181    if (ast_strlen_zero(channel))
00182       return NULL;
00183    chan = malloc(sizeof(struct logchannel));
00184 
00185    if (!chan)  /* Can't allocate memory */
00186       return NULL;
00187 
00188    memset(chan, 0, sizeof(struct logchannel));
00189    if (!strcasecmp(channel, "console")) {
00190       chan->type = LOGTYPE_CONSOLE;
00191    } else if (!strncasecmp(channel, "syslog", 6)) {
00192       /*
00193       * syntax is:
00194       *  syslog.facility => level,level,level
00195       */
00196       facility = strchr(channel, '.');
00197       if(!facility++ || !facility) {
00198          facility = "local0";
00199       }
00200 
00201 #ifndef SOLARIS
00202       /*
00203       * Walk through the list of facilitynames (defined in sys/syslog.h)
00204       * to see if we can find the one we have been given
00205       */
00206       chan->facility = -1;
00207       cptr = facilitynames;
00208       while (cptr->c_name) {
00209          if (!strcasecmp(facility, cptr->c_name)) {
00210             chan->facility = cptr->c_val;
00211             break;
00212          }
00213          cptr++;
00214       }
00215 #else
00216       chan->facility = -1;
00217       if (!strcasecmp(facility, "kern")) 
00218          chan->facility = LOG_KERN;
00219       else if (!strcasecmp(facility, "USER")) 
00220          chan->facility = LOG_USER;
00221       else if (!strcasecmp(facility, "MAIL")) 
00222          chan->facility = LOG_MAIL;
00223       else if (!strcasecmp(facility, "DAEMON")) 
00224          chan->facility = LOG_DAEMON;
00225       else if (!strcasecmp(facility, "AUTH")) 
00226          chan->facility = LOG_AUTH;
00227       else if (!strcasecmp(facility, "SYSLOG")) 
00228          chan->facility = LOG_SYSLOG;
00229       else if (!strcasecmp(facility, "LPR")) 
00230          chan->facility = LOG_LPR;
00231       else if (!strcasecmp(facility, "NEWS")) 
00232          chan->facility = LOG_NEWS;
00233       else if (!strcasecmp(facility, "UUCP")) 
00234          chan->facility = LOG_UUCP;
00235       else if (!strcasecmp(facility, "CRON")) 
00236          chan->facility = LOG_CRON;
00237       else if (!strcasecmp(facility, "LOCAL0")) 
00238          chan->facility = LOG_LOCAL0;
00239       else if (!strcasecmp(facility, "LOCAL1")) 
00240          chan->facility = LOG_LOCAL1;
00241       else if (!strcasecmp(facility, "LOCAL2")) 
00242          chan->facility = LOG_LOCAL2;
00243       else if (!strcasecmp(facility, "LOCAL3")) 
00244          chan->facility = LOG_LOCAL3;
00245       else if (!strcasecmp(facility, "LOCAL4")) 
00246          chan->facility = LOG_LOCAL4;
00247       else if (!strcasecmp(facility, "LOCAL5")) 
00248          chan->facility = LOG_LOCAL5;
00249       else if (!strcasecmp(facility, "LOCAL6")) 
00250          chan->facility = LOG_LOCAL6;
00251       else if (!strcasecmp(facility, "LOCAL7")) 
00252          chan->facility = LOG_LOCAL7;
00253 #endif /* Solaris */
00254 
00255       if (0 > chan->facility) {
00256          fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
00257          free(chan);
00258          return NULL;
00259       }
00260 
00261       chan->type = LOGTYPE_SYSLOG;
00262       snprintf(chan->filename, sizeof(chan->filename), "%s", channel);
00263       openlog("asterisk", LOG_PID, chan->facility);
00264    } else {
00265       if (channel[0] == '/') {
00266          if(!ast_strlen_zero(hostname)) { 
00267             snprintf(chan->filename, sizeof(chan->filename) - 1,"%s.%s", channel, hostname);
00268          } else {
00269             ast_copy_string(chan->filename, channel, sizeof(chan->filename));
00270          }
00271       }       
00272       
00273       if(!ast_strlen_zero(hostname)) {
00274          snprintf(chan->filename, sizeof(chan->filename), "%s/%s.%s",(char *)ast_config_AST_LOG_DIR, channel, hostname);
00275       } else {
00276          snprintf(chan->filename, sizeof(chan->filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, channel);
00277       }
00278       chan->fileptr = fopen(chan->filename, "a");
00279       if (!chan->fileptr) {
00280          /* Can't log here, since we're called with a lock */
00281          fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
00282       } 
00283       chan->type = LOGTYPE_FILE;
00284    }
00285    chan->logmask = make_components(components, lineno);
00286    return chan;
00287 }
00288 
00289 static void init_logger_chain(void)
00290 {
00291    struct logchannel *chan, *cur;
00292    struct ast_config *cfg;
00293    struct ast_variable *var;
00294    char *s;
00295 
00296    /* delete our list of log channels */
00297    ast_mutex_lock(&loglock);
00298    chan = logchannels;
00299    while (chan) {
00300       cur = chan->next;
00301       free(chan);
00302       chan = cur;
00303    }
00304    logchannels = NULL;
00305    ast_mutex_unlock(&loglock);
00306    
00307    global_logmask = 0;
00308    errno = 0;
00309    /* close syslog */
00310    closelog();
00311    
00312    cfg = ast_config_load("logger.conf");
00313    
00314    /* If no config file, we're fine, set default options. */
00315    if (!cfg) {
00316       if (errno)
00317          fprintf(stderr, "Unable to open logger.conf: %s; default settings will be used.\n", strerror(errno));
00318       else
00319          fprintf(stderr, "Errors detected in logger.conf: see above; default settings will be used.\n");
00320       chan = malloc(sizeof(struct logchannel));
00321       memset(chan, 0, sizeof(struct logchannel));
00322       chan->type = LOGTYPE_CONSOLE;
00323       chan->logmask = 28; /*warning,notice,error */
00324       chan->next = logchannels;
00325       logchannels = chan;
00326       global_logmask |= chan->logmask;
00327       return;
00328    }
00329    
00330    ast_mutex_lock(&loglock);
00331    if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
00332       if(ast_true(s)) {
00333          if(gethostname(hostname, sizeof(hostname)-1)) {
00334             ast_copy_string(hostname, "unknown", sizeof(hostname));
00335             ast_log(LOG_WARNING, "What box has no hostname???\n");
00336          }
00337       } else
00338          hostname[0] = '\0';
00339    } else
00340       hostname[0] = '\0';
00341    if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
00342       ast_copy_string(dateformat, s, sizeof(dateformat));
00343    } else
00344       ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
00345    if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
00346       logfiles.queue_log = ast_true(s);
00347    }
00348    if ((s = ast_variable_retrieve(cfg, "general", "event_log"))) {
00349       logfiles.event_log = ast_true(s);
00350    }
00351 
00352    var = ast_variable_browse(cfg, "logfiles");
00353    while(var) {
00354       chan = make_logchannel(var->name, var->value, var->lineno);
00355       if (chan) {
00356          chan->next = logchannels;
00357          logchannels = chan;
00358          global_logmask |= chan->logmask;
00359       }
00360       var = var->next;
00361    }
00362 
00363    ast_config_destroy(cfg);
00364    ast_mutex_unlock(&loglock);
00365 }
00366 
00367 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
00368 {
00369    va_list ap;
00370    ast_mutex_lock(&loglock);
00371    if (qlog) {
00372       va_start(ap, fmt);
00373       fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
00374       vfprintf(qlog, fmt, ap);
00375       fprintf(qlog, "\n");
00376       va_end(ap);
00377       fflush(qlog);
00378    }
00379    ast_mutex_unlock(&loglock);
00380 }
00381 
00382 int reload_logger(int rotate)
00383 {
00384    char old[AST_CONFIG_MAX_PATH] = "";
00385    char new[AST_CONFIG_MAX_PATH];
00386    int event_rotate = rotate, queue_rotate = rotate;
00387    struct logchannel *f;
00388    FILE *myf;
00389    int x, res = 0;
00390 
00391    ast_mutex_lock(&msglist_lock);   /* to avoid deadlock */
00392    ast_mutex_lock(&loglock);
00393    if (eventlog) 
00394       fclose(eventlog);
00395    else 
00396       event_rotate = 0;
00397    eventlog = NULL;
00398 
00399    if (qlog) 
00400       fclose(qlog);
00401    else 
00402       queue_rotate = 0;
00403    qlog = NULL;
00404 
00405    mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00406 
00407    f = logchannels;
00408    while(f) {
00409       if (f->disabled) {
00410          f->disabled = 0;  /* Re-enable logging at reload */
00411          manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
00412       }
00413       if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00414          fclose(f->fileptr);  /* Close file */
00415          f->fileptr = NULL;
00416          if(rotate) {
00417             ast_copy_string(old, f->filename, sizeof(old));
00418    
00419             for(x=0;;x++) {
00420                snprintf(new, sizeof(new), "%s.%d", f->filename, x);
00421                myf = fopen((char *)new, "r");
00422                if (myf) {
00423                   fclose(myf);
00424                } else {
00425                   break;
00426                }
00427             }
00428        
00429             /* do it */
00430             if (rename(old,new))
00431                fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
00432          }
00433       }
00434       f = f->next;
00435    }
00436 
00437    filesize_reload_needed = 0;
00438 
00439    init_logger_chain();
00440 
00441    if (logfiles.event_log) {
00442       snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00443       if (event_rotate) {
00444          for (x=0;;x++) {
00445             snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x);
00446             myf = fopen((char *)new, "r");
00447             if (myf)    /* File exists */
00448                fclose(myf);
00449             else
00450                break;
00451          }
00452    
00453          /* do it */
00454          if (rename(old,new))
00455             ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
00456       }
00457 
00458       eventlog = fopen(old, "a");
00459       if (eventlog) {
00460          ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
00461          if (option_verbose)
00462             ast_verbose("Asterisk Event Logger restarted\n");
00463       } else {
00464          ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00465          res = -1;
00466       }
00467    }
00468 
00469    if (logfiles.queue_log) {
00470       snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
00471       if (queue_rotate) {
00472          for (x = 0; ; x++) {
00473             snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, QUEUELOG, x);
00474             myf = fopen((char *)new, "r");
00475             if (myf)    /* File exists */
00476                fclose(myf);
00477             else
00478                break;
00479          }
00480    
00481          /* do it */
00482          if (rename(old, new))
00483             ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
00484       }
00485 
00486       qlog = fopen(old, "a");
00487       if (qlog) {
00488          ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
00489          ast_log(LOG_EVENT, "Restarted Asterisk Queue Logger\n");
00490          if (option_verbose)
00491             ast_verbose("Asterisk Queue Logger restarted\n");
00492       } else {
00493          ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
00494          res = -1;
00495       }
00496    }
00497    ast_mutex_unlock(&loglock);
00498    ast_mutex_unlock(&msglist_lock);
00499 
00500    return res;
00501 }
00502 
00503 static int handle_logger_reload(int fd, int argc, char *argv[])
00504 {
00505    if(reload_logger(0)) {
00506       ast_cli(fd, "Failed to reload the logger\n");
00507       return RESULT_FAILURE;
00508    } else
00509       return RESULT_SUCCESS;
00510 }
00511 
00512 static int handle_logger_rotate(int fd, int argc, char *argv[])
00513 {
00514    if(reload_logger(1)) {
00515       ast_cli(fd, "Failed to reload the logger and rotate log files\n");
00516       return RESULT_FAILURE;
00517    } else
00518       return RESULT_SUCCESS;
00519 }
00520 
00521 /*--- handle_logger_show_channels: CLI command to show logging system 
00522    configuration */
00523 static int handle_logger_show_channels(int fd, int argc, char *argv[])
00524 {
00525 #define FORMATL   "%-35.35s %-8.8s %-9.9s "
00526    struct logchannel *chan;
00527 
00528    ast_mutex_lock(&loglock);
00529 
00530    chan = logchannels;
00531    ast_cli(fd,FORMATL, "Channel", "Type", "Status");
00532    ast_cli(fd, "Configuration\n");
00533    ast_cli(fd,FORMATL, "-------", "----", "------");
00534    ast_cli(fd, "-------------\n");
00535    while (chan) {
00536       ast_cli(fd, FORMATL, chan->filename, chan->type==LOGTYPE_CONSOLE ? "Console" : (chan->type==LOGTYPE_SYSLOG ? "Syslog" : "File"),
00537          chan->disabled ? "Disabled" : "Enabled");
00538       ast_cli(fd, " - ");
00539       if (chan->logmask & (1 << __LOG_DEBUG)) 
00540          ast_cli(fd, "Debug ");
00541       if (chan->logmask & (1 << __LOG_DTMF)) 
00542          ast_cli(fd, "DTMF ");
00543       if (chan->logmask & (1 << __LOG_VERBOSE)) 
00544          ast_cli(fd, "Verbose ");
00545       if (chan->logmask & (1 << __LOG_WARNING)) 
00546          ast_cli(fd, "Warning ");
00547       if (chan->logmask & (1 << __LOG_NOTICE)) 
00548          ast_cli(fd, "Notice ");
00549       if (chan->logmask & (1 << __LOG_ERROR)) 
00550          ast_cli(fd, "Error ");
00551       if (chan->logmask & (1 << __LOG_EVENT)) 
00552          ast_cli(fd, "Event ");
00553       ast_cli(fd, "\n");
00554       chan = chan->next;
00555    }
00556    ast_cli(fd, "\n");
00557 
00558    ast_mutex_unlock(&loglock);
00559       
00560    return RESULT_SUCCESS;
00561 }
00562 
00563 static struct verb {
00564    void (*verboser)(const char *string, int opos, int replacelast, int complete);
00565    struct verb *next;
00566 } *verboser = NULL;
00567 
00568 
00569 static char logger_reload_help[] =
00570 "Usage: logger reload\n"
00571 "       Reloads the logger subsystem state.  Use after restarting syslogd(8) if you are using syslog logging.\n";
00572 
00573 static char logger_rotate_help[] =
00574 "Usage: logger rotate\n"
00575 "       Rotates and Reopens the log files.\n";
00576 
00577 static char logger_show_channels_help[] =
00578 "Usage: logger show channels\n"
00579 "       Show configured logger channels.\n";
00580 
00581 static struct ast_cli_entry logger_show_channels_cli = 
00582    { { "logger", "show", "channels", NULL }, 
00583    handle_logger_show_channels, "List configured log channels",
00584    logger_show_channels_help };
00585 
00586 static struct ast_cli_entry reload_logger_cli = 
00587    { { "logger", "reload", NULL }, 
00588    handle_logger_reload, "Reopens the log files",
00589    logger_reload_help };
00590 
00591 static struct ast_cli_entry rotate_logger_cli = 
00592    { { "logger", "rotate", NULL }, 
00593    handle_logger_rotate, "Rotates and reopens the log files",
00594    logger_rotate_help };
00595 
00596 static int handle_SIGXFSZ(int sig) 
00597 {
00598    /* Indicate need to reload */
00599    filesize_reload_needed = 1;
00600    return 0;
00601 }
00602 
00603 int init_logger(void)
00604 {
00605    char tmp[256];
00606    int res = 0;
00607 
00608    /* auto rotate if sig SIGXFSZ comes a-knockin */
00609    (void) signal(SIGXFSZ,(void *) handle_SIGXFSZ);
00610 
00611    /* register the relaod logger cli command */
00612    ast_cli_register(&reload_logger_cli);
00613    ast_cli_register(&rotate_logger_cli);
00614    ast_cli_register(&logger_show_channels_cli);
00615 
00616    mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00617   
00618    /* create log channels */
00619    init_logger_chain();
00620 
00621    /* create the eventlog */
00622    if (logfiles.event_log) {
00623       mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00624       snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00625       eventlog = fopen((char *)tmp, "a");
00626       if (eventlog) {
00627          ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
00628          if (option_verbose)
00629             ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp);
00630       } else {
00631          ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00632          res = -1;
00633       }
00634    }
00635 
00636    if (logfiles.queue_log) {
00637       snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
00638       qlog = fopen(tmp, "a");
00639       ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
00640    }
00641    return res;
00642 }
00643 
00644 void close_logger(void)
00645 {
00646    struct msglist *m, *tmp;
00647 
00648    ast_mutex_lock(&msglist_lock);
00649    m = list;
00650    while(m) {
00651       if (m->msg) {
00652          free(m->msg);
00653       }
00654       tmp = m->next;
00655       free(m);
00656       m = tmp;
00657    }
00658    list = last = NULL;
00659    msgcnt = 0;
00660    ast_mutex_unlock(&msglist_lock);
00661    return;
00662 }
00663 
00664 static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args) 
00665 {
00666    char buf[BUFSIZ];
00667    char *s;
00668 
00669    if (level >= SYSLOG_NLEVELS) {
00670       /* we are locked here, so cannot ast_log() */
00671       fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
00672       return;
00673    }
00674    if (level == __LOG_VERBOSE) {
00675       snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)GETTID());
00676       level = __LOG_DEBUG;
00677    } else if (level == __LOG_DTMF) {
00678       snprintf(buf, sizeof(buf), "DTMF[%ld]: ", (long)GETTID());
00679       level = __LOG_DEBUG;
00680    } else {
00681       snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
00682           levels[level], (long)GETTID(), file, line, function);
00683    }
00684    s = buf + strlen(buf);
00685    vsnprintf(s, sizeof(buf) - strlen(buf), fmt, args);
00686    term_strip(s, s, strlen(s) + 1);
00687    syslog(syslog_level_map[level], "%s", buf);
00688 }
00689 
00690 /*
00691  * send log messages to syslog and/or the console
00692  */
00693 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
00694 {
00695    struct logchannel *chan;
00696    char buf[BUFSIZ];
00697    time_t t;
00698    struct tm tm;
00699    char date[256];
00700 
00701    va_list ap;
00702    
00703    if (!logchannels)
00704    {
00705       /* 
00706        * we don't have the logger chain configured yet,
00707        * so just log to stdout 
00708       */
00709       if (level != __LOG_VERBOSE) {
00710          va_start(ap, fmt);
00711          vsnprintf(buf, sizeof(buf), fmt, ap);
00712          va_end(ap);
00713          fputs(buf, stdout);
00714       }
00715       return;
00716    }
00717 
00718    /* don't display LOG_DEBUG messages unless option_verbose _or_ option_debug
00719       are non-zero; LOG_DEBUG messages can still be displayed if option_debug
00720       is zero, if option_verbose is non-zero (this allows for 'level zero'
00721       LOG_DEBUG messages to be displayed, if the logmask on any channel
00722       allows it)
00723    */
00724    if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
00725       return;
00726    }
00727 
00728    /* Ignore anything that never gets logged anywhere */
00729    if (!(global_logmask & (1 << level)))
00730       return;
00731    
00732    /* Ignore anything other than the currently debugged file if there is one */
00733    if ((level == __LOG_DEBUG) && !ast_strlen_zero(debug_filename) && strcasecmp(debug_filename, file))
00734       return;
00735 
00736    /* begin critical section */
00737    ast_mutex_lock(&loglock);
00738 
00739    time(&t);
00740    localtime_r(&t, &tm);
00741    strftime(date, sizeof(date), dateformat, &tm);
00742 
00743    if (logfiles.event_log && level == __LOG_EVENT) {
00744       va_start(ap, fmt);
00745 
00746       fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
00747       vfprintf(eventlog, fmt, ap);
00748       fflush(eventlog);
00749 
00750       va_end(ap);
00751       ast_mutex_unlock(&loglock);
00752       return;
00753    }
00754 
00755    chan = logchannels;
00756    while(chan && !chan->disabled) {
00757       /* Check syslog channels */
00758       if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << level))) {
00759          va_start(ap, fmt);
00760          ast_log_vsyslog(level, file, line, function, fmt, ap);
00761          va_end(ap);
00762       /* Console channels */
00763       } else if ((chan->logmask & (1 << level)) && (chan->type == LOGTYPE_CONSOLE)) {
00764          char linestr[128];
00765          char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
00766 
00767          if (level != __LOG_VERBOSE) {
00768             sprintf(linestr, "%d", line);
00769             snprintf(buf, sizeof(buf), option_timestamp ? "[%s] %s[%ld]: %s:%s %s: " : "%s %s[%ld]: %s:%s %s: ",
00770                date,
00771                term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
00772                (long)GETTID(),
00773                term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
00774                term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
00775                term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
00776             
00777             ast_console_puts(buf);
00778             va_start(ap, fmt);
00779             vsnprintf(buf, sizeof(buf), fmt, ap);
00780             va_end(ap);
00781             ast_console_puts(buf);
00782          }
00783       /* File channels */
00784       } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
00785          int res;
00786          snprintf(buf, sizeof(buf), option_timestamp ? "[%s] %s[%ld]: " : "%s %s[%ld] %s: ", date,
00787             levels[level], (long)GETTID(), file);
00788          res = fprintf(chan->fileptr, buf);
00789          if (res <= 0 && buf[0] != '\0') {   /* Error, no characters printed */
00790             fprintf(stderr,"**** Asterisk Logging Error: ***********\n");
00791             if (errno == ENOMEM || errno == ENOSPC) {
00792                fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
00793             } else
00794                fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
00795             manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
00796             chan->disabled = 1;  
00797          } else {
00798             /* No error message, continue printing */
00799             va_start(ap, fmt);
00800             vsnprintf(buf, sizeof(buf), fmt, ap);
00801             va_end(ap);
00802             term_strip(buf, buf, sizeof(buf));
00803             fputs(buf, chan->fileptr);
00804             fflush(chan->fileptr);
00805          }
00806       }
00807       chan = chan->next;
00808    }
00809 
00810    ast_mutex_unlock(&loglock);
00811    /* end critical section */
00812    if (filesize_reload_needed) {
00813       reload_logger(1);
00814       ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00815       if (option_verbose)
00816          ast_verbose("Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00817    }
00818 }
00819 
00820 void ast_verbose(const char *fmt, ...)
00821 {
00822    static char stuff[4096];
00823    static int len = 0;
00824    static int replacelast = 0;
00825 
00826    int complete;
00827    int olen;
00828    struct msglist *m;
00829    struct verb *v;
00830    
00831    va_list ap;
00832    va_start(ap, fmt);
00833 
00834    if (option_timestamp) {
00835       time_t t;
00836       struct tm tm;
00837       char date[40];
00838       char *datefmt;
00839 
00840       time(&t);
00841       localtime_r(&t, &tm);
00842       strftime(date, sizeof(date), dateformat, &tm);
00843       datefmt = alloca(strlen(date) + 3 + strlen(fmt) + 1);
00844       if (datefmt) {
00845          sprintf(datefmt, "[%s] %s", date, fmt);
00846          fmt = datefmt;
00847       }
00848    }
00849 
00850    /* this lock is also protecting against multiple threads
00851       being in this function at the same time, so it must be
00852       held before any of the static variables are accessed
00853    */
00854    ast_mutex_lock(&msglist_lock);
00855 
00856    /* there is a potential security problem here: if formatting
00857       the current date using 'dateformat' results in a string
00858       containing '%', then the vsnprintf() call below will
00859       probably try to access random memory
00860    */
00861    vsnprintf(stuff + len, sizeof(stuff) - len, fmt, ap);
00862    va_end(ap);
00863 
00864    olen = len;
00865    len = strlen(stuff);
00866 
00867    complete = (stuff[len - 1] == '\n') ? 1 : 0;
00868 
00869    /* If we filled up the stuff completely, then log it even without the '\n' */
00870    if (len >= sizeof(stuff) - 1) {
00871       complete = 1;
00872       len = 0;
00873    }
00874 
00875    if (complete) {
00876       if (msgcnt < MAX_MSG_QUEUE) {
00877          /* Allocate new structure */
00878          if ((m = malloc(sizeof(*m))))
00879             msgcnt++;
00880       } else {
00881          /* Recycle the oldest entry */
00882          m = list;
00883          list = list->next;
00884          free(m->msg);
00885       }
00886       if (m) {
00887          m->msg = strdup(stuff);
00888          if (m->msg) {
00889             if (last)
00890                last->next = m;
00891             else
00892                list = m;
00893             m->next = NULL;
00894             last = m;
00895          } else {
00896             msgcnt--;
00897             ast_log(LOG_ERROR, "Out of memory\n");
00898             free(m);
00899          }
00900       }
00901    }
00902 
00903    for (v = verboser; v; v = v->next)
00904       v->verboser(stuff, olen, replacelast, complete);
00905 
00906    ast_log(LOG_VERBOSE, "%s", stuff);
00907 
00908    if (len) {
00909       if (!complete)
00910          replacelast = 1;
00911       else 
00912          replacelast = len = 0;
00913    }
00914 
00915    ast_mutex_unlock(&msglist_lock);
00916 }
00917 
00918 int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
00919 {
00920    struct msglist *m;
00921    ast_mutex_lock(&msglist_lock);
00922    m = list;
00923    while(m) {
00924       /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
00925       v(m->msg, 0, 0, 1);
00926       m = m->next;
00927    }
00928    ast_mutex_unlock(&msglist_lock);
00929    return 0;
00930 }
00931 
00932 int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete)) 
00933 {
00934    struct msglist *m;
00935    struct verb *tmp;
00936    /* XXX Should be more flexible here, taking > 1 verboser XXX */
00937    if ((tmp = malloc(sizeof (struct verb)))) {
00938       tmp->verboser = v;
00939       ast_mutex_lock(&msglist_lock);
00940       tmp->next = verboser;
00941       verboser = tmp;
00942       m = list;
00943       while(m) {
00944          /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
00945          v(m->msg, 0, 0, 1);
00946          m = m->next;
00947       }
00948       ast_mutex_unlock(&msglist_lock);
00949       return 0;
00950    }
00951    return -1;
00952 }
00953 
00954 int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
00955 {
00956    int res = -1;
00957    struct verb *tmp, *tmpl=NULL;
00958    ast_mutex_lock(&msglist_lock);
00959    tmp = verboser;
00960    while(tmp) {
00961       if (tmp->verboser == v) {
00962          if (tmpl)
00963             tmpl->next = tmp->next;
00964          else
00965             verboser = tmp->next;
00966          free(tmp);
00967          break;
00968       }
00969       tmpl = tmp;
00970       tmp = tmp->next;
00971    }
00972    if (tmp)
00973       res = 0;
00974    ast_mutex_unlock(&msglist_lock);
00975    return res;
00976 }

Generated on Thu May 24 14:21:11 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.7