00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
00051
00052 #include <syslog.h>
00053
00054 static int syslog_level_map[] = {
00055 LOG_DEBUG,
00056 LOG_INFO,
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";
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;
00108 int disabled;
00109 int facility;
00110 enum logtypes type;
00111 FILE *fileptr;
00112 char filename[256];
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
00196
00197
00198 facility = strchr(channel, '.');
00199 if(!facility++ || !facility) {
00200 facility = "local0";
00201 }
00202
00203 #ifndef SOLARIS
00204
00205
00206
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
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
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
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
00301 closelog();
00302
00303 cfg = ast_config_load("logger.conf");
00304
00305
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;
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;
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);
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
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)
00432 fclose(myf);
00433 else
00434 break;
00435 }
00436
00437
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)
00460 fclose(myf);
00461 else
00462 break;
00463 }
00464
00465
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
00488
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
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
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
00600 sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
00601
00602
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
00608 init_logger_chain();
00609
00610
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();
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
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
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
00709
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
00725
00726
00727
00728
00729
00730 if (!option_verbose && !option_debug && (level == __LOG_DEBUG))
00731 return;
00732
00733
00734 if (!(global_logmask & (1 << level)))
00735 return;
00736
00737
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
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
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
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
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)) {
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
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;
00841 Dl_info dli;
00842 long allocsize;
00843 asymbol **syms = NULL;
00844 bfd_vma offset;
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
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
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
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
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
00985 free(addresses);
00986 }
00987 # else
00988 ast_log(LOG_WARNING, "Must run configure with '--enable-dev-mode' for stack backtraces.\n");
00989 # endif
00990 #else
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
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 }