Sat Aug 6 00:39:30 2011

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 - 2006, 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  *
00021  * \brief Asterisk Logger
00022  * 
00023  * Logging routines
00024  *
00025  * \author Mark Spencer <markster@digium.com>
00026  */
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 298905 $")
00031 
00032 #include <signal.h>
00033 #include <stdarg.h>
00034 #include <stdio.h>
00035 #include <unistd.h>
00036 #include <time.h>
00037 #include <string.h>
00038 #include <stdlib.h>
00039 #include <errno.h>
00040 #include <sys/stat.h>
00041 #if ((defined(AST_DEVMODE)) && (defined(linux)))
00042 #  include <execinfo.h>
00043 #  define MAX_BACKTRACE_FRAMES 20
00044 #  if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
00045 #    include <dlfcn.h>
00046 #    include <bfd.h>
00047 #  endif
00048 #endif
00049 
00050 #define SYSLOG_NAMES /* so we can map syslog facilities names to their numeric values,
00051               from <syslog.h> which is included by logger.h */
00052 #include <syslog.h>
00053 
00054 static int syslog_level_map[] = {
00055    LOG_DEBUG,
00056    LOG_INFO,    /* arbitrary equivalent of LOG_EVENT */
00057    LOG_NOTICE,
00058    LOG_WARNING,
00059    LOG_ERR,
00060    LOG_DEBUG,
00061    LOG_DEBUG
00062 };
00063 
00064 #define SYSLOG_NLEVELS sizeof(syslog_level_map) / sizeof(int)
00065 
00066 #include "asterisk/logger.h"
00067 #include "asterisk/lock.h"
00068 #include "asterisk/options.h"
00069 #include "asterisk/channel.h"
00070 #include "asterisk/config.h"
00071 #include "asterisk/term.h"
00072 #include "asterisk/cli.h"
00073 #include "asterisk/utils.h"
00074 #include "asterisk/manager.h"
00075 #include "asterisk/threadstorage.h"
00076 
00077 #if defined(__linux__) && !defined(__NR_gettid)
00078 #include <asm/unistd.h>
00079 #endif
00080 
00081 #if defined(__linux__) && defined(__NR_gettid)
00082 #define GETTID() syscall(__NR_gettid)
00083 #else
00084 #define GETTID() getpid()
00085 #endif
00086 
00087 
00088 static char dateformat[256] = "%b %e %T";    /* Original Asterisk Format */
00089 
00090 static int filesize_reload_needed;
00091 static int global_logmask = -1;
00092 
00093 static struct {
00094    unsigned int queue_log:1;
00095    unsigned int event_log:1;
00096 } logfiles = { 1, 1 };
00097 
00098 static char hostname[MAXHOSTNAMELEN];
00099 
00100 enum logtypes {
00101    LOGTYPE_SYSLOG,
00102    LOGTYPE_FILE,
00103    LOGTYPE_CONSOLE,
00104 };
00105 
00106 struct logchannel {
00107    int logmask;         /* What to log to this channel */
00108    int disabled;        /* If this channel is disabled or not */
00109    int facility;        /* syslog facility */
00110    enum logtypes type;     /* Type of log channel */
00111    FILE *fileptr;       /* logfile logging file pointer */
00112    char filename[256];     /* Filename */
00113    AST_LIST_ENTRY(logchannel) list;
00114 };
00115 
00116 static AST_LIST_HEAD_STATIC(logchannels, logchannel);
00117 
00118 static FILE *eventlog;
00119 static FILE *qlog;
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 AST_THREADSTORAGE(verbose_buf, verbose_buf_init);
00142 #define VERBOSE_BUF_INIT_SIZE   128
00143 
00144 AST_THREADSTORAGE(log_buf, log_buf_init);
00145 #define LOG_BUF_INIT_SIZE       128
00146 
00147 static int make_components(char *s, int lineno)
00148 {
00149    char *w;
00150    int res = 0;
00151    char *stringp = s;
00152 
00153    while ((w = strsep(&stringp, ","))) {
00154       w = ast_strip(w);
00155       if (ast_strlen_zero(w)) {
00156          continue;
00157       }
00158       if (!strcasecmp(w, "error")) 
00159          res |= (1 << __LOG_ERROR);
00160       else if (!strcasecmp(w, "warning"))
00161          res |= (1 << __LOG_WARNING);
00162       else if (!strcasecmp(w, "notice"))
00163          res |= (1 << __LOG_NOTICE);
00164       else if (!strcasecmp(w, "event"))
00165          res |= (1 << __LOG_EVENT);
00166       else if (!strcasecmp(w, "debug"))
00167          res |= (1 << __LOG_DEBUG);
00168       else if (!strcasecmp(w, "verbose"))
00169          res |= (1 << __LOG_VERBOSE);
00170       else if (!strcasecmp(w, "dtmf"))
00171          res |= (1 << __LOG_DTMF);
00172       else {
00173          fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
00174       }
00175    }
00176 
00177    return res;
00178 }
00179 
00180 static struct logchannel *make_logchannel(char *channel, char *components, int lineno)
00181 {
00182    struct logchannel *chan;
00183    char *facility;
00184 #ifndef SOLARIS
00185    CODE *cptr;
00186 #endif
00187 
00188    if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan))))
00189       return NULL;
00190 
00191    if (!strcasecmp(channel, "console")) {
00192       chan->type = LOGTYPE_CONSOLE;
00193    } else if (!strncasecmp(channel, "syslog", 6)) {
00194       /*
00195       * syntax is:
00196       *  syslog.facility => level,level,level
00197       */
00198       facility = strchr(channel, '.');
00199       if(!facility++ || !facility) {
00200          facility = "local0";
00201       }
00202 
00203 #ifndef SOLARIS
00204       /*
00205       * Walk through the list of facilitynames (defined in sys/syslog.h)
00206       * to see if we can find the one we have been given
00207       */
00208       chan->facility = -1;
00209       cptr = facilitynames;
00210       while (cptr->c_name) {
00211          if (!strcasecmp(facility, cptr->c_name)) {
00212             chan->facility = cptr->c_val;
00213             break;
00214          }
00215          cptr++;
00216       }
00217 #else
00218       chan->facility = -1;
00219       if (!strcasecmp(facility, "kern")) 
00220          chan->facility = LOG_KERN;
00221       else if (!strcasecmp(facility, "USER")) 
00222          chan->facility = LOG_USER;
00223       else if (!strcasecmp(facility, "MAIL")) 
00224          chan->facility = LOG_MAIL;
00225       else if (!strcasecmp(facility, "DAEMON")) 
00226          chan->facility = LOG_DAEMON;
00227       else if (!strcasecmp(facility, "AUTH")) 
00228          chan->facility = LOG_AUTH;
00229       else if (!strcasecmp(facility, "SYSLOG")) 
00230          chan->facility = LOG_SYSLOG;
00231       else if (!strcasecmp(facility, "LPR")) 
00232          chan->facility = LOG_LPR;
00233       else if (!strcasecmp(facility, "NEWS")) 
00234          chan->facility = LOG_NEWS;
00235       else if (!strcasecmp(facility, "UUCP")) 
00236          chan->facility = LOG_UUCP;
00237       else if (!strcasecmp(facility, "CRON")) 
00238          chan->facility = LOG_CRON;
00239       else if (!strcasecmp(facility, "LOCAL0")) 
00240          chan->facility = LOG_LOCAL0;
00241       else if (!strcasecmp(facility, "LOCAL1")) 
00242          chan->facility = LOG_LOCAL1;
00243       else if (!strcasecmp(facility, "LOCAL2")) 
00244          chan->facility = LOG_LOCAL2;
00245       else if (!strcasecmp(facility, "LOCAL3")) 
00246          chan->facility = LOG_LOCAL3;
00247       else if (!strcasecmp(facility, "LOCAL4")) 
00248          chan->facility = LOG_LOCAL4;
00249       else if (!strcasecmp(facility, "LOCAL5")) 
00250          chan->facility = LOG_LOCAL5;
00251       else if (!strcasecmp(facility, "LOCAL6")) 
00252          chan->facility = LOG_LOCAL6;
00253       else if (!strcasecmp(facility, "LOCAL7")) 
00254          chan->facility = LOG_LOCAL7;
00255 #endif /* Solaris */
00256 
00257       if (0 > chan->facility) {
00258          fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
00259          free(chan);
00260          return NULL;
00261       }
00262 
00263       chan->type = LOGTYPE_SYSLOG;
00264       snprintf(chan->filename, sizeof(chan->filename), "%s", channel);
00265       openlog("asterisk", LOG_PID, chan->facility);
00266    } else {
00267       if (!ast_strlen_zero(hostname)) {
00268          snprintf(chan->filename, sizeof(chan->filename), "%s/%s.%s",
00269              channel[0] != '/' ? ast_config_AST_LOG_DIR : "", channel, hostname);
00270       } else {
00271          snprintf(chan->filename, sizeof(chan->filename), "%s/%s",
00272              channel[0] != '/' ? ast_config_AST_LOG_DIR : "", channel);
00273       }
00274       chan->fileptr = fopen(chan->filename, "a");
00275       if (!chan->fileptr) {
00276          /* Can't log here, since we're called with a lock */
00277          fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
00278       } 
00279       chan->type = LOGTYPE_FILE;
00280    }
00281    chan->logmask = make_components(components, lineno);
00282    return chan;
00283 }
00284 
00285 static void init_logger_chain(void)
00286 {
00287    struct logchannel *chan;
00288    struct ast_config *cfg;
00289    struct ast_variable *var;
00290    const char *s;
00291 
00292    /* delete our list of log channels */
00293    AST_LIST_LOCK(&logchannels);
00294    while ((chan = AST_LIST_REMOVE_HEAD(&logchannels, list)))
00295       free(chan);
00296    AST_LIST_UNLOCK(&logchannels);
00297    
00298    global_logmask = 0;
00299    errno = 0;
00300    /* close syslog */
00301    closelog();
00302    
00303    cfg = ast_config_load("logger.conf");
00304    
00305    /* If no config file, we're fine, set default options. */
00306    if (!cfg) {
00307       if (errno)
00308          fprintf(stderr, "Unable to open logger.conf: %s; default settings will be used.\n", strerror(errno));
00309       else
00310          fprintf(stderr, "Errors detected in logger.conf: see above; default settings will be used.\n");
00311       if (!(chan = ast_calloc(1, sizeof(*chan))))
00312          return;
00313       chan->type = LOGTYPE_CONSOLE;
00314       chan->logmask = 28; /*warning,notice,error */
00315       AST_LIST_LOCK(&logchannels);
00316       AST_LIST_INSERT_HEAD(&logchannels, chan, list);
00317       AST_LIST_UNLOCK(&logchannels);
00318       global_logmask |= chan->logmask;
00319       return;
00320    }
00321    
00322    if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
00323       if (ast_true(s)) {
00324          if (gethostname(hostname, sizeof(hostname) - 1)) {
00325             ast_copy_string(hostname, "unknown", sizeof(hostname));
00326             ast_log(LOG_WARNING, "What box has no hostname???\n");
00327          }
00328       } else
00329          hostname[0] = '\0';
00330    } else
00331       hostname[0] = '\0';
00332    if ((s = ast_variable_retrieve(cfg, "general", "dateformat")))
00333       ast_copy_string(dateformat, s, sizeof(dateformat));
00334    else
00335       ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
00336    if ((s = ast_variable_retrieve(cfg, "general", "queue_log")))
00337       logfiles.queue_log = ast_true(s);
00338    if ((s = ast_variable_retrieve(cfg, "general", "event_log")))
00339       logfiles.event_log = ast_true(s);
00340 
00341    AST_LIST_LOCK(&logchannels);
00342    var = ast_variable_browse(cfg, "logfiles");
00343    for (; var; var = var->next) {
00344       if (!(chan = make_logchannel(var->name, var->value, var->lineno)))
00345          continue;
00346       AST_LIST_INSERT_HEAD(&logchannels, chan, list);
00347       global_logmask |= chan->logmask;
00348    }
00349    AST_LIST_UNLOCK(&logchannels);
00350 
00351    ast_config_destroy(cfg);
00352 }
00353 
00354 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
00355 {
00356    va_list ap;
00357    AST_LIST_LOCK(&logchannels);
00358    if (qlog) {
00359       va_start(ap, fmt);
00360       fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
00361       vfprintf(qlog, fmt, ap);
00362       fprintf(qlog, "\n");
00363       va_end(ap);
00364       fflush(qlog);
00365    }
00366    AST_LIST_UNLOCK(&logchannels);
00367 }
00368 
00369 int reload_logger(int rotate)
00370 {
00371    char old[PATH_MAX] = "";
00372    char new[PATH_MAX];
00373    int event_rotate = rotate, queue_rotate = rotate;
00374    struct logchannel *f;
00375    FILE *myf;
00376    int x, res = 0;
00377 
00378    AST_LIST_LOCK(&logchannels);
00379 
00380    if (eventlog) 
00381       fclose(eventlog);
00382    else 
00383       event_rotate = 0;
00384    eventlog = NULL;
00385 
00386    if (qlog) 
00387       fclose(qlog);
00388    else 
00389       queue_rotate = 0;
00390    qlog = NULL;
00391 
00392    mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00393 
00394    AST_LIST_TRAVERSE(&logchannels, f, list) {
00395       if (f->disabled) {
00396          f->disabled = 0;  /* Re-enable logging at reload */
00397          manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
00398       }
00399       if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00400          fclose(f->fileptr);  /* Close file */
00401          f->fileptr = NULL;
00402          if (rotate) {
00403             ast_copy_string(old, f->filename, sizeof(old));
00404    
00405             for (x = 0; ; x++) {
00406                snprintf(new, sizeof(new), "%s.%d", f->filename, x);
00407                myf = fopen((char *)new, "r");
00408                if (myf)
00409                   fclose(myf);
00410                else
00411                   break;
00412             }
00413        
00414             /* do it */
00415             if (rename(old,new))
00416                fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
00417          }
00418       }
00419    }
00420 
00421    filesize_reload_needed = 0;
00422    
00423    init_logger_chain();
00424 
00425    if (logfiles.event_log) {
00426       snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00427       if (event_rotate) {
00428          for (x=0;;x++) {
00429             snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x);
00430             myf = fopen((char *)new, "r");
00431             if (myf)    /* File exists */
00432                fclose(myf);
00433             else
00434                break;
00435          }
00436    
00437          /* do it */
00438          if (rename(old,new))
00439             ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
00440       }
00441 
00442       eventlog = fopen(old, "a");
00443       if (eventlog) {
00444          ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
00445          if (option_verbose)
00446             ast_verbose("Asterisk Event Logger restarted\n");
00447       } else {
00448          ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00449          res = -1;
00450       }
00451    }
00452 
00453    if (logfiles.queue_log) {
00454       snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
00455       if (queue_rotate) {
00456          for (x = 0; ; x++) {
00457             snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, QUEUELOG, x);
00458             myf = fopen((char *)new, "r");
00459             if (myf)    /* File exists */
00460                fclose(myf);
00461             else
00462                break;
00463          }
00464    
00465          /* do it */
00466          if (rename(old, new))
00467             ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
00468       }
00469 
00470       qlog = fopen(old, "a");
00471       if (qlog) {
00472          ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
00473          ast_log(LOG_EVENT, "Restarted Asterisk Queue Logger\n");
00474          if (option_verbose)
00475             ast_verbose("Asterisk Queue Logger restarted\n");
00476       } else {
00477          ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
00478          res = -1;
00479       }
00480    }
00481 
00482    AST_LIST_UNLOCK(&logchannels);
00483 
00484    return res;
00485 }
00486 
00487 /*! \brief Reload the logger module without rotating log files (also used from loader.c during
00488    a full Asterisk reload) */
00489 int logger_reload(void)
00490 {
00491    if(reload_logger(0))
00492       return RESULT_FAILURE;
00493    return RESULT_SUCCESS;
00494 }
00495 
00496 static int handle_logger_reload(int fd, int argc, char *argv[])
00497 {
00498    int result = logger_reload();
00499    if (result == RESULT_FAILURE)
00500       ast_cli(fd, "Failed to reload the logger\n");
00501    return result;
00502 }
00503 
00504 static int handle_logger_rotate(int fd, int argc, char *argv[])
00505 {
00506    if(reload_logger(1)) {
00507       ast_cli(fd, "Failed to reload the logger and rotate log files\n");
00508       return RESULT_FAILURE;
00509    }
00510    return RESULT_SUCCESS;
00511 }
00512 
00513 /*! \brief CLI command to show logging system configuration */
00514 static int handle_logger_show_channels(int fd, int argc, char *argv[])
00515 {
00516 #define FORMATL   "%-35.35s %-8.8s %-9.9s "
00517    struct logchannel *chan;
00518 
00519    ast_cli(fd,FORMATL, "Channel", "Type", "Status");
00520    ast_cli(fd, "Configuration\n");
00521    ast_cli(fd,FORMATL, "-------", "----", "------");
00522    ast_cli(fd, "-------------\n");
00523    AST_LIST_LOCK(&logchannels);
00524    AST_LIST_TRAVERSE(&logchannels, chan, list) {
00525       ast_cli(fd, FORMATL, chan->filename, chan->type==LOGTYPE_CONSOLE ? "Console" : (chan->type==LOGTYPE_SYSLOG ? "Syslog" : "File"),
00526          chan->disabled ? "Disabled" : "Enabled");
00527       ast_cli(fd, " - ");
00528       if (chan->logmask & (1 << __LOG_DEBUG)) 
00529          ast_cli(fd, "Debug ");
00530       if (chan->logmask & (1 << __LOG_DTMF)) 
00531          ast_cli(fd, "DTMF ");
00532       if (chan->logmask & (1 << __LOG_VERBOSE)) 
00533          ast_cli(fd, "Verbose ");
00534       if (chan->logmask & (1 << __LOG_WARNING)) 
00535          ast_cli(fd, "Warning ");
00536       if (chan->logmask & (1 << __LOG_NOTICE)) 
00537          ast_cli(fd, "Notice ");
00538       if (chan->logmask & (1 << __LOG_ERROR)) 
00539          ast_cli(fd, "Error ");
00540       if (chan->logmask & (1 << __LOG_EVENT)) 
00541          ast_cli(fd, "Event ");
00542       ast_cli(fd, "\n");
00543    }
00544    AST_LIST_UNLOCK(&logchannels);
00545    ast_cli(fd, "\n");
00546       
00547    return RESULT_SUCCESS;
00548 }
00549 
00550 struct verb {
00551    void (*verboser)(const char *string);
00552    AST_LIST_ENTRY(verb) list;
00553 };
00554 
00555 static AST_LIST_HEAD_STATIC(verbosers, verb);
00556 
00557 static char logger_reload_help[] =
00558 "Usage: logger reload\n"
00559 "       Reloads the logger subsystem state.  Use after restarting syslogd(8) if you are using syslog logging.\n";
00560 
00561 static char logger_rotate_help[] =
00562 "Usage: logger rotate\n"
00563 "       Rotates and Reopens the log files.\n";
00564 
00565 static char logger_show_channels_help[] =
00566 "Usage: logger show channels\n"
00567 "       List configured logger channels.\n";
00568 
00569 static struct ast_cli_entry cli_logger[] = {
00570    { { "logger", "show", "channels", NULL }, 
00571    handle_logger_show_channels, "List configured log channels",
00572    logger_show_channels_help },
00573 
00574    { { "logger", "reload", NULL }, 
00575    handle_logger_reload, "Reopens the log files",
00576    logger_reload_help },
00577 
00578    { { "logger", "rotate", NULL }, 
00579    handle_logger_rotate, "Rotates and reopens the log files",
00580    logger_rotate_help },
00581 };
00582 
00583 static void _handle_SIGXFSZ(int sig)
00584 {
00585    /* Indicate need to reload */
00586    filesize_reload_needed = 1;
00587 }
00588 
00589 static struct sigaction handle_SIGXFSZ = {
00590    .sa_handler = _handle_SIGXFSZ,
00591    .sa_flags = SA_RESTART,
00592 };
00593 
00594 int init_logger(void)
00595 {
00596    char tmp[256];
00597    int res = 0;
00598 
00599    /* auto rotate if sig SIGXFSZ comes a-knockin */
00600    sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
00601 
00602    /* register the logger cli commands */
00603    ast_cli_register_multiple(cli_logger, sizeof(cli_logger) / sizeof(struct ast_cli_entry));
00604 
00605    mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00606 
00607    /* create log channels */
00608    init_logger_chain();
00609 
00610    /* create the eventlog */
00611    if (logfiles.event_log) {
00612       mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00613       snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00614       eventlog = fopen((char *)tmp, "a");
00615       if (eventlog) {
00616          ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
00617          if (option_verbose)
00618             ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp);
00619       } else {
00620          ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00621          res = -1;
00622       }
00623    }
00624 
00625    if (logfiles.queue_log) {
00626       snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
00627       qlog = fopen(tmp, "a");
00628       ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
00629    }
00630    return res;
00631 }
00632 
00633 void close_logger(void)
00634 {
00635    struct logchannel *f;
00636 
00637    AST_LIST_LOCK(&logchannels);
00638 
00639    if (eventlog) {
00640       fclose(eventlog);
00641       eventlog = NULL;
00642    }
00643 
00644    if (qlog) {
00645       fclose(qlog);
00646       qlog = NULL;
00647    }
00648 
00649    AST_LIST_TRAVERSE(&logchannels, f, list) {
00650       if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00651          fclose(f->fileptr);
00652          f->fileptr = NULL;
00653       }
00654    }
00655 
00656    closelog(); /* syslog */
00657 
00658    AST_LIST_UNLOCK(&logchannels);
00659 
00660    return;
00661 }
00662 
00663 static void __attribute__((format(printf, 5, 0))) ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args) 
00664 {
00665    char buf[BUFSIZ];
00666    char *s;
00667 
00668    if (level >= SYSLOG_NLEVELS) {
00669       /* we are locked here, so cannot ast_log() */
00670       fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
00671       return;
00672    }
00673    if (level == __LOG_VERBOSE) {
00674       snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)GETTID());
00675       level = __LOG_DEBUG;
00676    } else if (level == __LOG_DTMF) {
00677       snprintf(buf, sizeof(buf), "DTMF[%ld]: ", (long)GETTID());
00678       level = __LOG_DEBUG;
00679    } else {
00680       snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
00681           levels[level], (long)GETTID(), file, line, function);
00682    }
00683    s = buf + strlen(buf);
00684    vsnprintf(s, sizeof(buf) - strlen(buf), fmt, args);
00685    term_strip(s, s, strlen(s) + 1);
00686    syslog(syslog_level_map[level], "%s", buf);
00687 }
00688 
00689 /*!
00690  * \brief send log messages to syslog and/or the console
00691  */
00692 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
00693 {
00694    struct logchannel *chan;
00695    struct ast_dynamic_str *buf;
00696    time_t t;
00697    struct tm tm;
00698    char date[256];
00699 
00700    va_list ap;
00701 
00702    if (!(buf = ast_dynamic_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE)))
00703       return;
00704 
00705    if (AST_LIST_EMPTY(&logchannels))
00706    {
00707       /*
00708        * we don't have the logger chain configured yet,
00709        * so just log to stdout
00710       */
00711       if (level != __LOG_VERBOSE) {
00712          int res;
00713          va_start(ap, fmt);
00714          res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap);
00715          va_end(ap);
00716          if (res != AST_DYNSTR_BUILD_FAILED) {
00717             term_filter_escapes(buf->str);
00718             fputs(buf->str, stdout);
00719          }
00720       }
00721       return;
00722    }
00723 
00724    /* don't display LOG_DEBUG messages unless option_verbose _or_ option_debug
00725       are non-zero; LOG_DEBUG messages can still be displayed if option_debug
00726       is zero, if option_verbose is non-zero (this allows for 'level zero'
00727       LOG_DEBUG messages to be displayed, if the logmask on any channel
00728       allows it)
00729    */
00730    if (!option_verbose && !option_debug && (level == __LOG_DEBUG))
00731       return;
00732 
00733    /* Ignore anything that never gets logged anywhere */
00734    if (!(global_logmask & (1 << level)))
00735       return;
00736    
00737    /* Ignore anything other than the currently debugged file if there is one */
00738    if ((level == __LOG_DEBUG) && !ast_strlen_zero(debug_filename) && strcasecmp(debug_filename, file))
00739       return;
00740 
00741    time(&t);
00742    ast_localtime(&t, &tm, NULL);
00743    strftime(date, sizeof(date), dateformat, &tm);
00744 
00745    AST_LIST_LOCK(&logchannels);
00746 
00747    if (logfiles.event_log && level == __LOG_EVENT) {
00748       va_start(ap, fmt);
00749 
00750       fprintf(eventlog, "%s asterisk[%ld]: ", date, (long)getpid());
00751       vfprintf(eventlog, fmt, ap);
00752       fflush(eventlog);
00753 
00754       va_end(ap);
00755       AST_LIST_UNLOCK(&logchannels);
00756       return;
00757    }
00758 
00759    AST_LIST_TRAVERSE(&logchannels, chan, list) {
00760       if (chan->disabled)
00761          break;
00762       /* Check syslog channels */
00763       if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << level))) {
00764          va_start(ap, fmt);
00765          ast_log_vsyslog(level, file, line, function, fmt, ap);
00766          va_end(ap);
00767       /* Console channels */
00768       } else if ((chan->logmask & (1 << level)) && (chan->type == LOGTYPE_CONSOLE)) {
00769          char linestr[128];
00770          char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
00771 
00772          if (level != __LOG_VERBOSE) {
00773             int res;
00774             sprintf(linestr, "%d", line);
00775             ast_dynamic_str_thread_set(&buf, BUFSIZ, &log_buf,
00776                "[%s] %s[%ld]: %s:%s %s: ",
00777                date,
00778                term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
00779                (long)GETTID(),
00780                term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
00781                term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
00782                term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
00783             /*filter to the console!*/
00784             term_filter_escapes(buf->str);
00785             ast_console_puts_mutable(buf->str);
00786             
00787             va_start(ap, fmt);
00788             res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap);
00789             va_end(ap);
00790             if (res != AST_DYNSTR_BUILD_FAILED)
00791                ast_console_puts_mutable(buf->str);
00792          }
00793       /* File channels */
00794       } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
00795          int res;
00796          ast_dynamic_str_thread_set(&buf, BUFSIZ, &log_buf, 
00797             "[%s] %s[%ld] %s: ",
00798             date, levels[level], (long)GETTID(), file);
00799          res = fprintf(chan->fileptr, "%s", term_strip(buf->str, buf->str, strlen(buf->str) + 1));
00800          if (res <= 0 && !ast_strlen_zero(buf->str)) {   /* Error, no characters printed */
00801             fprintf(stderr,"**** Asterisk Logging Error: ***********\n");
00802             if (errno == ENOMEM || errno == ENOSPC) {
00803                fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
00804             } else
00805                fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
00806             manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
00807             chan->disabled = 1;  
00808          } else {
00809             int res;
00810             /* No error message, continue printing */
00811             va_start(ap, fmt);
00812             res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap);
00813             va_end(ap);
00814             if (res != AST_DYNSTR_BUILD_FAILED) {
00815                term_strip(buf->str, buf->str, buf->len);
00816                fputs(buf->str, chan->fileptr);
00817                fflush(chan->fileptr);
00818             }
00819          }
00820       }
00821    }
00822 
00823    AST_LIST_UNLOCK(&logchannels);
00824 
00825    if (filesize_reload_needed) {
00826       reload_logger(1);
00827       ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00828       if (option_verbose)
00829          ast_verbose("Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00830    }
00831 }
00832 
00833 void ast_backtrace(void)
00834 {
00835 #ifdef linux
00836 #  ifdef AST_DEVMODE
00837    int stackcount = 0, stackfr;
00838    void **addresses;
00839 #    if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
00840    bfd *bfdobj;           /* bfd.h */
00841    Dl_info dli;           /* dlfcn.h */
00842    long allocsize;
00843    asymbol **syms = NULL; /* bfd.h */
00844    bfd_vma offset;        /* bfd.h */
00845    const char *lastslash;
00846    asection *section;
00847    const char *file, *func;
00848    unsigned int line;
00849    char address_str[128];
00850 #    else
00851    char **strings;
00852 #    endif
00853 
00854    if ((addresses = ast_calloc(MAX_BACKTRACE_FRAMES, sizeof(*addresses)))) {
00855       stackcount = backtrace(addresses, MAX_BACKTRACE_FRAMES);
00856 #    if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
00857       ast_log(LOG_DEBUG, "Got %d backtrace record%c\n", stackcount, stackcount != 1 ? 's' : ' ');
00858       for (stackfr = 0; stackfr < stackcount; stackfr++) {
00859          int found = 0, symbolcount;
00860 
00861          if (!dladdr(addresses[stackfr], &dli)) {
00862             continue;
00863          }
00864 
00865          if (strcmp(dli.dli_fname, "asterisk") == 0) {
00866             char asteriskpath[256];
00867             if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) {
00868                /* This will fail to find symbols */
00869                ast_log(LOG_DEBUG, "Failed to find asterisk binary for debug symbols.\n");
00870                dli.dli_fname = "asterisk";
00871             }
00872          }
00873 
00874          lastslash = strrchr(dli.dli_fname, '/');
00875          if (  (bfdobj = bfd_openr(dli.dli_fname, NULL)) &&
00876                bfd_check_format(bfdobj, bfd_object) &&
00877                (allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 &&
00878                (syms = ast_malloc(allocsize)) &&
00879                (symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) {
00880 
00881             if (bfdobj->flags & DYNAMIC) {
00882                offset = addresses[stackfr] - dli.dli_fbase;
00883             } else {
00884                offset = addresses[stackfr] - (void *) 0;
00885             }
00886 
00887             for (section = bfdobj->sections; section; section = section->next) {
00888                if (  !bfd_get_section_flags(bfdobj, section) & SEC_ALLOC ||
00889                      section->vma > offset ||
00890                      section->size + section->vma < offset) {
00891                   continue;
00892                }
00893 
00894                if (!bfd_find_nearest_line(bfdobj, section, syms, offset - section->vma, &file, &func, &line)) {
00895                   continue;
00896                }
00897 
00898                /* Stack trace output */
00899                found++;
00900                lastslash = strrchr(file, '/');
00901 #      if __WORDSIZE == 32
00902                if (dli.dli_saddr == NULL) {
00903                   address_str[0] = '\0';
00904                } else {
00905                   snprintf(address_str, sizeof(address_str), " (%08lX+%lX)",
00906                      (unsigned long) dli.dli_saddr,
00907                      (unsigned long) (addresses[stackfr] - dli.dli_saddr));
00908                }
00909                ast_log(LOG_DEBUG, "#%d: [%08lX] %s:%u %s()%s\n", stackfr,
00910                   (unsigned long) addresses[stackfr],
00911                   lastslash ? lastslash + 1 : file, line,
00912                   S_OR(func, "???"),
00913                   address_str);
00914 #      elif __WORDSIZE == 64
00915                if (dli.dli_saddr == NULL) {
00916                   address_str[0] = '\0';
00917                } else {
00918                   snprintf(address_str, sizeof(address_str), " (%016lX+%lX)",
00919                      (unsigned long) dli.dli_saddr,
00920                      (unsigned long) (addresses[stackfr] - dli.dli_saddr));
00921                }
00922                ast_log(LOG_DEBUG, "#%d: [%016lX] %s:%u %s()%s\n", stackfr,
00923                   (unsigned long) addresses[stackfr],
00924                   lastslash ? lastslash + 1 : file, line,
00925                   S_OR(func, "???"),
00926                   address_str);
00927 #      endif
00928 
00929                break;
00930             }
00931          }
00932          if (bfdobj) {
00933             bfd_close(bfdobj);
00934             if (syms) {
00935                ast_free(syms);
00936             }
00937          }
00938 
00939          /* Default output, if we cannot find the information within BFD */
00940          if (!found) {
00941 #      if __WORDSIZE == 32
00942             if (dli.dli_saddr == NULL) {
00943                address_str[0] = '\0';
00944             } else {
00945                snprintf(address_str, sizeof(address_str), " (%08lX+%lX)",
00946                   (unsigned long) dli.dli_saddr,
00947                   (unsigned long) (addresses[stackfr] - dli.dli_saddr));
00948             }
00949             ast_log(LOG_DEBUG, "#%d: [%08lX] %s %s()%s\n", stackfr,
00950                (unsigned long) addresses[stackfr],
00951                lastslash ? lastslash + 1 : dli.dli_fname,
00952                S_OR(dli.dli_sname, "<unknown>"),
00953                address_str);
00954 #      elif __WORDSIZE == 64
00955             if (dli.dli_saddr == NULL) {
00956                address_str[0] = '\0';
00957             } else {
00958                snprintf(address_str, sizeof(address_str), " (%016lX+%lX)",
00959                   (unsigned long) dli.dli_saddr,
00960                   (unsigned long) (addresses[stackfr] - dli.dli_saddr));
00961             }
00962             ast_log(LOG_DEBUG, "#%d: [%016lX] %s %s()%s\n", stackfr,
00963                (unsigned long) addresses[stackfr],
00964                lastslash ? lastslash + 1 : dli.dli_fname,
00965                S_OR(dli.dli_sname, "<unknown>"),
00966                address_str);
00967 #      endif
00968          }
00969       }
00970 #    else /* !defined(HAVE_DLADDR) || !defined(HAVE_BFD) || !defined(BETTER_BACKTRACES) */
00971       if ((strings = backtrace_symbols(addresses, stackcount))) {
00972          ast_log(LOG_DEBUG, "Got %d backtrace record%c\n", stackcount, stackcount != 1 ? 's' : ' ');
00973          for (stackfr = 0; stackfr < stackcount ; stackfr++) {
00974 #      if __WORDSIZE == 32
00975             ast_log(LOG_DEBUG, "#%d: [%08X] %s\n", stackfr, (unsigned int)addresses[stackfr], strings[stackfr]);
00976 #      elif __WORDSIZE == 64
00977             ast_log(LOG_DEBUG, "#%d: [%016lX] %s\n", stackfr, (unsigned long)addresses[stackfr], strings[stackfr]);
00978 #      endif
00979          }
00980          free(strings);
00981       } else {
00982          ast_log(LOG_DEBUG, "Could not allocate memory for backtrace\n");
00983       }
00984 #    endif /* defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES) */
00985       free(addresses);
00986    }
00987 #  else /* !defined(AST_DEVMODE) */
00988    ast_log(LOG_WARNING, "Must run configure with '--enable-dev-mode' for stack backtraces.\n");
00989 #  endif /* defined(AST_DEVMODE) */
00990 #else /* ndef linux */
00991    ast_log(LOG_WARNING, "Inline stack backtraces are only available on the Linux platform.\n");
00992 #endif
00993 }
00994 
00995 void ast_verbose(const char *fmt, ...)
00996 {
00997    struct verb *v;
00998    struct ast_dynamic_str *buf;
00999    int res;
01000    va_list ap;
01001 
01002    if (ast_opt_timestamp) {
01003       time_t t;
01004       struct tm tm;
01005       char date[40];
01006       char *datefmt;
01007 
01008       time(&t);
01009       ast_localtime(&t, &tm, NULL);
01010       strftime(date, sizeof(date), dateformat, &tm);
01011       datefmt = alloca(strlen(date) + 3 + strlen(fmt) + 1);
01012       sprintf(datefmt, "%c[%s] %s", 127, date, fmt);
01013       fmt = datefmt;
01014    } else {
01015       char *tmp = alloca(strlen(fmt) + 2);
01016       sprintf(tmp, "%c%s", 127, fmt);
01017       fmt = tmp;
01018    }
01019 
01020    if (!(buf = ast_dynamic_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)))
01021       return;
01022 
01023    va_start(ap, fmt);
01024    res = ast_dynamic_str_thread_set_va(&buf, 0, &verbose_buf, fmt, ap);
01025    va_end(ap);
01026 
01027    if (res == AST_DYNSTR_BUILD_FAILED)
01028       return;
01029    
01030    /* filter out possibly hazardous escape sequences */
01031    term_filter_escapes(buf->str);
01032 
01033    AST_LIST_LOCK(&verbosers);
01034    AST_LIST_TRAVERSE(&verbosers, v, list)
01035       v->verboser(buf->str);
01036    AST_LIST_UNLOCK(&verbosers);
01037 
01038    ast_log(LOG_VERBOSE, "%s", buf->str + 1);
01039 }
01040 
01041 int ast_register_verbose(void (*v)(const char *string)) 
01042 {
01043    struct verb *verb;
01044 
01045    if (!(verb = ast_malloc(sizeof(*verb))))
01046       return -1;
01047 
01048    verb->verboser = v;
01049 
01050    AST_LIST_LOCK(&verbosers);
01051    AST_LIST_INSERT_HEAD(&verbosers, verb, list);
01052    AST_LIST_UNLOCK(&verbosers);
01053    
01054    return 0;
01055 }
01056 
01057 int ast_unregister_verbose(void (*v)(const char *string))
01058 {
01059    struct verb *cur;
01060 
01061    AST_LIST_LOCK(&verbosers);
01062    AST_LIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) {
01063       if (cur->verboser == v) {
01064          AST_LIST_REMOVE_CURRENT(&verbosers, list);
01065          free(cur);
01066          break;
01067       }
01068    }
01069    AST_LIST_TRAVERSE_SAFE_END
01070    AST_LIST_UNLOCK(&verbosers);
01071    
01072    return cur ? 0 : -1;
01073 }

Generated on Sat Aug 6 00:39:30 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7