Sun Aug 6 15:02:42 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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: 30033 $")
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    /* close syslog */
00309    closelog();
00310    
00311    cfg = ast_config_load("logger.conf");
00312    
00313    /* If no config file, we're fine, set default options. */
00314    if (!cfg) {
00315       fprintf(stderr, "Unable to open logger.conf: %s\n", strerror(errno));
00316       chan = malloc(sizeof(struct logchannel));
00317       memset(chan, 0, sizeof(struct logchannel));
00318       chan->type = LOGTYPE_CONSOLE;
00319       chan->logmask = 28; /*warning,notice,error */
00320       chan->next = logchannels;
00321       logchannels = chan;
00322       global_logmask |= chan->logmask;
00323       return;
00324    }
00325    
00326    ast_mutex_lock(&loglock);
00327    if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
00328       if(ast_true(s)) {
00329          if(gethostname(hostname, sizeof(hostname)-1)) {
00330             ast_copy_string(hostname, "unknown", sizeof(hostname));
00331             ast_log(LOG_WARNING, "What box has no hostname???\n");
00332          }
00333       } else
00334          hostname[0] = '\0';
00335    } else
00336       hostname[0] = '\0';
00337    if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
00338       ast_copy_string(dateformat, s, sizeof(dateformat));
00339    } else
00340       ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
00341    if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
00342       logfiles.queue_log = ast_true(s);
00343    }
00344    if ((s = ast_variable_retrieve(cfg, "general", "event_log"))) {
00345       logfiles.event_log = ast_true(s);
00346    }
00347 
00348    var = ast_variable_browse(cfg, "logfiles");
00349    while(var) {
00350       chan = make_logchannel(var->name, var->value, var->lineno);
00351       if (chan) {
00352          chan->next = logchannels;
00353          logchannels = chan;
00354          global_logmask |= chan->logmask;
00355       }
00356       var = var->next;
00357    }
00358 
00359    ast_config_destroy(cfg);
00360    ast_mutex_unlock(&loglock);
00361 }
00362 
00363 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
00364 {
00365    va_list ap;
00366    ast_mutex_lock(&loglock);
00367    if (qlog) {
00368       va_start(ap, fmt);
00369       fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
00370       vfprintf(qlog, fmt, ap);
00371       fprintf(qlog, "\n");
00372       va_end(ap);
00373       fflush(qlog);
00374    }
00375    ast_mutex_unlock(&loglock);
00376 }
00377 
00378 int reload_logger(int rotate)
00379 {
00380    char old[AST_CONFIG_MAX_PATH] = "";
00381    char new[AST_CONFIG_MAX_PATH];
00382    int event_rotate = rotate, queue_rotate = rotate;
00383    struct logchannel *f;
00384    FILE *myf;
00385    int x, res = 0;
00386 
00387    ast_mutex_lock(&msglist_lock);   /* to avoid deadlock */
00388    ast_mutex_lock(&loglock);
00389    if (eventlog) 
00390       fclose(eventlog);
00391    else 
00392       event_rotate = 0;
00393    eventlog = NULL;
00394 
00395    if (qlog) 
00396       fclose(qlog);
00397    else 
00398       queue_rotate = 0;
00399    qlog = NULL;
00400 
00401    mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00402 
00403    f = logchannels;
00404    while(f) {
00405       if (f->disabled) {
00406          f->disabled = 0;  /* Re-enable logging at reload */
00407          manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
00408       }
00409       if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00410          fclose(f->fileptr);  /* Close file */
00411          f->fileptr = NULL;
00412          if(rotate) {
00413             ast_copy_string(old, f->filename, sizeof(old));
00414    
00415             for(x=0;;x++) {
00416                snprintf(new, sizeof(new), "%s.%d", f->filename, x);
00417                myf = fopen((char *)new, "r");
00418                if (myf) {
00419                   fclose(myf);
00420                } else {
00421                   break;
00422                }
00423             }
00424        
00425             /* do it */
00426             if (rename(old,new))
00427                fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
00428          }
00429       }
00430       f = f->next;
00431    }
00432 
00433    filesize_reload_needed = 0;
00434 
00435    init_logger_chain();
00436 
00437    if (logfiles.event_log) {
00438       snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00439       if (event_rotate) {
00440          for (x=0;;x++) {
00441             snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x);
00442             myf = fopen((char *)new, "r");
00443             if (myf)    /* File exists */
00444                fclose(myf);
00445             else
00446                break;
00447          }
00448    
00449          /* do it */
00450          if (rename(old,new))
00451             ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
00452       }
00453 
00454       eventlog = fopen(old, "a");
00455       if (eventlog) {
00456          ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
00457          if (option_verbose)
00458             ast_verbose("Asterisk Event Logger restarted\n");
00459       } else {
00460          ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00461          res = -1;
00462       }
00463    }
00464 
00465    if (logfiles.queue_log) {
00466       snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
00467       if (queue_rotate) {
00468          for (x = 0; ; x++) {
00469             snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, QUEUELOG, x);
00470             myf = fopen((char *)new, "r");
00471             if (myf)    /* File exists */
00472                fclose(myf);
00473             else
00474                break;
00475          }
00476    
00477          /* do it */
00478          if (rename(old, new))
00479             ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
00480       }
00481 
00482       qlog = fopen(old, "a");
00483       if (qlog) {
00484          ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
00485          ast_log(LOG_EVENT, "Restarted Asterisk Queue Logger\n");
00486          if (option_verbose)
00487             ast_verbose("Asterisk Queue Logger restarted\n");
00488       } else {
00489          ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
00490          res = -1;
00491       }
00492    }
00493    ast_mutex_unlock(&loglock);
00494    ast_mutex_unlock(&msglist_lock);
00495 
00496    return res;
00497 }
00498 
00499 static int handle_logger_reload(int fd, int argc, char *argv[])
00500 {
00501    if(reload_logger(0)) {
00502       ast_cli(fd, "Failed to reload the logger\n");
00503       return RESULT_FAILURE;
00504    } else
00505       return RESULT_SUCCESS;
00506 }
00507 
00508 static int handle_logger_rotate(int fd, int argc, char *argv[])
00509 {
00510    if(reload_logger(1)) {
00511       ast_cli(fd, "Failed to reload the logger and rotate log files\n");
00512       return RESULT_FAILURE;
00513    } else
00514       return RESULT_SUCCESS;
00515 }
00516 
00517 /*--- handle_logger_show_channels: CLI command to show logging system 
00518    configuration */
00519 static int handle_logger_show_channels(int fd, int argc, char *argv[])
00520 {
00521 #define FORMATL   "%-35.35s %-8.8s %-9.9s "
00522    struct logchannel *chan;
00523 
00524    ast_mutex_lock(&loglock);
00525 
00526    chan = logchannels;
00527    ast_cli(fd,FORMATL, "Channel", "Type", "Status");
00528    ast_cli(fd, "Configuration\n");
00529    ast_cli(fd,FORMATL, "-------", "----", "------");
00530    ast_cli(fd, "-------------\n");
00531    while (chan) {
00532       ast_cli(fd, FORMATL, chan->filename, chan->type==LOGTYPE_CONSOLE ? "Console" : (chan->type==LOGTYPE_SYSLOG ? "Syslog" : "File"),
00533          chan->disabled ? "Disabled" : "Enabled");
00534       ast_cli(fd, " - ");
00535       if (chan->logmask & (1 << __LOG_DEBUG)) 
00536          ast_cli(fd, "Debug ");
00537       if (chan->logmask & (1 << __LOG_DTMF)) 
00538          ast_cli(fd, "DTMF ");
00539       if (chan->logmask & (1 << __LOG_VERBOSE)) 
00540          ast_cli(fd, "Verbose ");
00541       if (chan->logmask & (1 << __LOG_WARNING)) 
00542          ast_cli(fd, "Warning ");
00543       if (chan->logmask & (1 << __LOG_NOTICE)) 
00544          ast_cli(fd, "Notice ");
00545       if (chan->logmask & (1 << __LOG_ERROR)) 
00546          ast_cli(fd, "Error ");
00547       if (chan->logmask & (1 << __LOG_EVENT)) 
00548          ast_cli(fd, "Event ");
00549       ast_cli(fd, "\n");
00550       chan = chan->next;
00551    }
00552    ast_cli(fd, "\n");
00553 
00554    ast_mutex_unlock(&loglock);
00555       
00556    return RESULT_SUCCESS;
00557 }
00558 
00559 static struct verb {
00560    void (*verboser)(const char *string, int opos, int replacelast, int complete);
00561    struct verb *next;
00562 } *verboser = NULL;
00563 
00564 
00565 static char logger_reload_help[] =
00566 "Usage: logger reload\n"
00567 "       Reloads the logger subsystem state.  Use after restarting syslogd(8) if you are using syslog logging.\n";
00568 
00569 static char logger_rotate_help[] =
00570 "Usage: logger rotate\n"
00571 "       Rotates and Reopens the log files.\n";
00572 
00573 static char logger_show_channels_help[] =
00574 "Usage: logger show channels\n"
00575 "       Show configured logger channels.\n";
00576 
00577 static struct ast_cli_entry logger_show_channels_cli = 
00578    { { "logger", "show", "channels", NULL }, 
00579    handle_logger_show_channels, "List configured log channels",
00580    logger_show_channels_help };
00581 
00582 static struct ast_cli_entry reload_logger_cli = 
00583    { { "logger", "reload", NULL }, 
00584    handle_logger_reload, "Reopens the log files",
00585    logger_reload_help };
00586 
00587 static struct ast_cli_entry rotate_logger_cli = 
00588    { { "logger", "rotate", NULL }, 
00589    handle_logger_rotate, "Rotates and reopens the log files",
00590    logger_rotate_help };
00591 
00592 static int handle_SIGXFSZ(int sig) 
00593 {
00594    /* Indicate need to reload */
00595    filesize_reload_needed = 1;
00596    return 0;
00597 }
00598 
00599 int init_logger(void)
00600 {
00601    char tmp[256];
00602    int res = 0;
00603 
00604    /* auto rotate if sig SIGXFSZ comes a-knockin */
00605    (void) signal(SIGXFSZ,(void *) handle_SIGXFSZ);
00606 
00607    /* register the relaod logger cli command */
00608    ast_cli_register(&reload_logger_cli);
00609    ast_cli_register(&rotate_logger_cli);
00610    ast_cli_register(&logger_show_channels_cli);
00611 
00612    mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00613   
00614    /* create log channels */
00615    init_logger_chain();
00616 
00617    /* create the eventlog */
00618    if (logfiles.event_log) {
00619       mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00620       snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00621       eventlog = fopen((char *)tmp, "a");
00622       if (eventlog) {
00623          ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
00624          if (option_verbose)
00625             ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp);
00626       } else {
00627          ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00628          res = -1;
00629       }
00630    }
00631 
00632    if (logfiles.queue_log) {
00633       snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
00634       qlog = fopen(tmp, "a");
00635       ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
00636    }
00637    return res;
00638 }
00639 
00640 void close_logger(void)
00641 {
00642    struct msglist *m, *tmp;
00643 
00644    ast_mutex_lock(&msglist_lock);
00645    m = list;
00646    while(m) {
00647       if (m->msg) {
00648          free(m->msg);
00649       }
00650       tmp = m->next;
00651       free(m);
00652       m = tmp;
00653    }
00654    list = last = NULL;
00655    msgcnt = 0;
00656    ast_mutex_unlock(&msglist_lock);
00657    return;
00658 }
00659 
00660 static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args) 
00661 {
00662    char buf[BUFSIZ];
00663    char *s;
00664 
00665    if (level >= SYSLOG_NLEVELS) {
00666       /* we are locked here, so cannot ast_log() */
00667       fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
00668       return;
00669    }
00670    if (level == __LOG_VERBOSE) {
00671       snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)GETTID());
00672       level = __LOG_DEBUG;
00673    } else if (level == __LOG_DTMF) {
00674       snprintf(buf, sizeof(buf), "DTMF[%ld]: ", (long)GETTID());
00675       level = __LOG_DEBUG;
00676    } else {
00677       snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
00678           levels[level], (long)GETTID(), file, line, function);
00679    }
00680    s = buf + strlen(buf);
00681    vsnprintf(s, sizeof(buf) - strlen(buf), fmt, args);
00682    term_strip(s, s, strlen(s) + 1);
00683    syslog(syslog_level_map[level], "%s", buf);
00684 }
00685 
00686 /*
00687  * send log messages to syslog and/or the console
00688  */
00689 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
00690 {
00691    struct logchannel *chan;
00692    char buf[BUFSIZ];
00693    time_t t;
00694    struct tm tm;
00695    char date[256];
00696 
00697    va_list ap;
00698    
00699    /* don't display LOG_DEBUG messages unless option_verbose _or_ option_debug
00700       are non-zero; LOG_DEBUG messages can still be displayed if option_debug
00701       is zero, if option_verbose is non-zero (this allows for 'level zero'
00702       LOG_DEBUG messages to be displayed, if the logmask on any channel
00703       allows it)
00704    */
00705    if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
00706       return;
00707    }
00708 
00709    /* Ignore anything that never gets logged anywhere */
00710    if (!(global_logmask & (1 << level)))
00711       return;
00712    
00713    /* Ignore anything other than the currently debugged file if there is one */
00714    if ((level == __LOG_DEBUG) && !ast_strlen_zero(debug_filename) && strcasecmp(debug_filename, file))
00715       return;
00716 
00717    /* begin critical section */
00718    ast_mutex_lock(&loglock);
00719 
00720    time(&t);
00721    localtime_r(&t, &tm);
00722    strftime(date, sizeof(date), dateformat, &tm);
00723 
00724    if (logfiles.event_log && level == __LOG_EVENT) {
00725       va_start(ap, fmt);
00726 
00727       fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
00728       vfprintf(eventlog, fmt, ap);
00729       fflush(eventlog);
00730 
00731       va_end(ap);
00732       ast_mutex_unlock(&loglock);
00733       return;
00734    }
00735 
00736    if (logchannels) {
00737       chan = logchannels;
00738       while(chan && !chan->disabled) {
00739          /* Check syslog channels */
00740          if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << level))) {
00741             va_start(ap, fmt);
00742             ast_log_vsyslog(level, file, line, function, fmt, ap);
00743             va_end(ap);
00744          /* Console channels */
00745          } else if ((chan->logmask & (1 << level)) && (chan->type == LOGTYPE_CONSOLE)) {
00746             char linestr[128];
00747             char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
00748 
00749             if (level != __LOG_VERBOSE) {
00750                sprintf(linestr, "%d", line);
00751                snprintf(buf, sizeof(buf), option_timestamp ? "[%s] %s[%ld]: %s:%s %s: " : "%s %s[%ld]: %s:%s %s: ",
00752                   date,
00753                   term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
00754                   (long)GETTID(),
00755                   term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
00756                   term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
00757                   term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
00758                
00759                ast_console_puts(buf);
00760                va_start(ap, fmt);
00761                vsnprintf(buf, sizeof(buf), fmt, ap);
00762                va_end(ap);
00763                ast_console_puts(buf);
00764             }
00765          /* File channels */
00766          } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
00767             int res;
00768             snprintf(buf, sizeof(buf), option_timestamp ? "[%s] %s[%ld]: " : "%s %s[%ld] %s: ", date,
00769                levels[level], (long)GETTID(), file);
00770             res = fprintf(chan->fileptr, buf);
00771             if (res <= 0 && buf[0] != '\0') {   /* Error, no characters printed */
00772                fprintf(stderr,"**** Asterisk Logging Error: ***********\n");
00773                if (errno == ENOMEM || errno == ENOSPC) {
00774                   fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
00775                } else
00776                   fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
00777                manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
00778                chan->disabled = 1;  
00779             } else {
00780                /* No error message, continue printing */
00781                va_start(ap, fmt);
00782                vsnprintf(buf, sizeof(buf), fmt, ap);
00783                va_end(ap);
00784                term_strip(buf, buf, sizeof(buf));
00785                fputs(buf, chan->fileptr);
00786                fflush(chan->fileptr);
00787             }
00788          }
00789          chan = chan->next;
00790       }
00791    } else {
00792       /* 
00793        * we don't have the logger chain configured yet,
00794        * so just log to stdout 
00795       */
00796       if (level != __LOG_VERBOSE) {
00797          va_start(ap, fmt);
00798          vsnprintf(buf, sizeof(buf), fmt, ap);
00799          va_end(ap);
00800          fputs(buf, stdout);
00801       }
00802    }
00803 
00804    ast_mutex_unlock(&loglock);
00805    /* end critical section */
00806    if (filesize_reload_needed) {
00807       reload_logger(1);
00808       ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00809       if (option_verbose)
00810          ast_verbose("Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00811    }
00812 }
00813 
00814 void ast_verbose(const char *fmt, ...)
00815 {
00816    static char stuff[4096];
00817    static int len = 0;
00818    static int replacelast = 0;
00819 
00820    int complete;
00821    int olen;
00822    struct msglist *m;
00823    struct verb *v;
00824    
00825    va_list ap;
00826    va_start(ap, fmt);
00827 
00828    if (option_timestamp) {
00829       time_t t;
00830       struct tm tm;
00831       char date[40];
00832       char *datefmt;
00833 
00834       time(&t);
00835       localtime_r(&t, &tm);
00836       strftime(date, sizeof(date), dateformat, &tm);
00837       datefmt = alloca(strlen(date) + 3 + strlen(fmt) + 1);
00838       if (datefmt) {
00839          sprintf(datefmt, "[%s] %s", date, fmt);
00840          fmt = datefmt;
00841       }
00842    }
00843 
00844    /* this lock is also protecting against multiple threads
00845       being in this function at the same time, so it must be
00846       held before any of the static variables are accessed
00847    */
00848    ast_mutex_lock(&msglist_lock);
00849 
00850    /* there is a potential security problem here: if formatting
00851       the current date using 'dateformat' results in a string
00852       containing '%', then the vsnprintf() call below will
00853       probably try to access random memory
00854    */
00855    vsnprintf(stuff + len, sizeof(stuff) - len, fmt, ap);
00856    va_end(ap);
00857 
00858    olen = len;
00859    len = strlen(stuff);
00860 
00861    complete = (stuff[len - 1] == '\n') ? 1 : 0;
00862 
00863    /* If we filled up the stuff completely, then log it even without the '\n' */
00864    if (len >= sizeof(stuff) - 1) {
00865       complete = 1;
00866       len = 0;
00867    }
00868 
00869    if (complete) {
00870       if (msgcnt < MAX_MSG_QUEUE) {
00871          /* Allocate new structure */
00872          if ((m = malloc(sizeof(*m))))
00873             msgcnt++;
00874       } else {
00875          /* Recycle the oldest entry */
00876          m = list;
00877          list = list->next;
00878          free(m->msg);
00879       }
00880       if (m) {
00881          m->msg = strdup(stuff);
00882          if (m->msg) {
00883             if (last)
00884                last->next = m;
00885             else
00886                list = m;
00887             m->next = NULL;
00888             last = m;
00889          } else {
00890             msgcnt--;
00891             ast_log(LOG_ERROR, "Out of memory\n");
00892             free(m);
00893          }
00894       }
00895    }
00896 
00897    for (v = verboser; v; v = v->next)
00898       v->verboser(stuff, olen, replacelast, complete);
00899 
00900    ast_log(LOG_VERBOSE, "%s", stuff);
00901 
00902    if (len) {
00903       if (!complete)
00904          replacelast = 1;
00905       else 
00906          replacelast = len = 0;
00907    }
00908 
00909    ast_mutex_unlock(&msglist_lock);
00910 }
00911 
00912 int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
00913 {
00914    struct msglist *m;
00915    ast_mutex_lock(&msglist_lock);
00916    m = list;
00917    while(m) {
00918       /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
00919       v(m->msg, 0, 0, 1);
00920       m = m->next;
00921    }
00922    ast_mutex_unlock(&msglist_lock);
00923    return 0;
00924 }
00925 
00926 int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete)) 
00927 {
00928    struct msglist *m;
00929    struct verb *tmp;
00930    /* XXX Should be more flexible here, taking > 1 verboser XXX */
00931    if ((tmp = malloc(sizeof (struct verb)))) {
00932       tmp->verboser = v;
00933       ast_mutex_lock(&msglist_lock);
00934       tmp->next = verboser;
00935       verboser = tmp;
00936       m = list;
00937       while(m) {
00938          /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
00939          v(m->msg, 0, 0, 1);
00940          m = m->next;
00941       }
00942       ast_mutex_unlock(&msglist_lock);
00943       return 0;
00944    }
00945    return -1;
00946 }
00947 
00948 int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
00949 {
00950    int res = -1;
00951    struct verb *tmp, *tmpl=NULL;
00952    ast_mutex_lock(&msglist_lock);
00953    tmp = verboser;
00954    while(tmp) {
00955       if (tmp->verboser == v) {
00956          if (tmpl)
00957             tmpl->next = tmp->next;
00958          else
00959             verboser = tmp->next;
00960          free(tmp);
00961          break;
00962       }
00963       tmpl = tmp;
00964       tmp = tmp->next;
00965    }
00966    if (tmp)
00967       res = 0;
00968    ast_mutex_unlock(&msglist_lock);
00969    return res;
00970 }

Generated on Sun Aug 6 15:02:42 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2