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
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369001 $")
00035
00036
00037
00038 #include <syslog.h>
00039
00040 #include "asterisk/_private.h"
00041 #include "asterisk/paths.h"
00042 #include "asterisk/logger.h"
00043 #include "asterisk/lock.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/config.h"
00046 #include "asterisk/term.h"
00047 #include "asterisk/cli.h"
00048 #include "asterisk/utils.h"
00049 #include "asterisk/manager.h"
00050 #include "asterisk/threadstorage.h"
00051 #include "asterisk/strings.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/app.h"
00054 #include "asterisk/syslog.h"
00055
00056 #include <signal.h>
00057 #include <time.h>
00058 #include <sys/stat.h>
00059 #include <fcntl.h>
00060 #ifdef HAVE_BKTR
00061 #include <execinfo.h>
00062 #define MAX_BACKTRACE_FRAMES 20
00063 # if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
00064 # include <dlfcn.h>
00065 # include <bfd.h>
00066 # endif
00067 #endif
00068
00069 #if defined(__linux__) && !defined(__NR_gettid)
00070 #include <asm/unistd.h>
00071 #endif
00072
00073 #if defined(__linux__) && defined(__NR_gettid)
00074 #define GETTID() syscall(__NR_gettid)
00075 #else
00076 #define GETTID() getpid()
00077 #endif
00078 static char dateformat[256] = "%b %e %T";
00079
00080 static char queue_log_name[256] = QUEUELOG;
00081 static char exec_after_rotate[256] = "";
00082
00083 static int filesize_reload_needed;
00084 static unsigned int global_logmask = 0xFFFF;
00085 static int queuelog_init;
00086 static int logger_initialized;
00087
00088 static enum rotatestrategy {
00089 SEQUENTIAL = 1 << 0,
00090 ROTATE = 1 << 1,
00091 TIMESTAMP = 1 << 2,
00092 } rotatestrategy = SEQUENTIAL;
00093
00094 static struct {
00095 unsigned int queue_log:1;
00096 unsigned int queue_log_to_file:1;
00097 unsigned int queue_adaptive_realtime:1;
00098 } logfiles = { 1 };
00099
00100 static char hostname[MAXHOSTNAMELEN];
00101
00102 enum logtypes {
00103 LOGTYPE_SYSLOG,
00104 LOGTYPE_FILE,
00105 LOGTYPE_CONSOLE,
00106 };
00107
00108 struct logchannel {
00109
00110 unsigned int logmask;
00111
00112 int disabled;
00113
00114 int facility;
00115
00116 enum logtypes type;
00117
00118 FILE *fileptr;
00119
00120 char filename[PATH_MAX];
00121
00122 AST_LIST_ENTRY(logchannel) list;
00123
00124 int lineno;
00125
00126 char components[0];
00127 };
00128
00129 static AST_RWLIST_HEAD_STATIC(logchannels, logchannel);
00130
00131 enum logmsgtypes {
00132 LOGMSG_NORMAL = 0,
00133 LOGMSG_VERBOSE,
00134 };
00135
00136 struct logmsg {
00137 enum logmsgtypes type;
00138 int level;
00139 int line;
00140 long process_id;
00141 AST_DECLARE_STRING_FIELDS(
00142 AST_STRING_FIELD(date);
00143 AST_STRING_FIELD(file);
00144 AST_STRING_FIELD(function);
00145 AST_STRING_FIELD(message);
00146 AST_STRING_FIELD(level_name);
00147 );
00148 AST_LIST_ENTRY(logmsg) list;
00149 };
00150
00151 static AST_LIST_HEAD_STATIC(logmsgs, logmsg);
00152 static pthread_t logthread = AST_PTHREADT_NULL;
00153 static ast_cond_t logcond;
00154 static int close_logger_thread = 0;
00155
00156 static FILE *qlog;
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 static char *levels[NUMLOGLEVELS] = {
00170 "DEBUG",
00171 "---EVENT---",
00172 "NOTICE",
00173 "WARNING",
00174 "ERROR",
00175 "VERBOSE",
00176 "DTMF",
00177 };
00178
00179
00180 static const int colors[NUMLOGLEVELS] = {
00181 COLOR_BRGREEN,
00182 COLOR_BRBLUE,
00183 COLOR_YELLOW,
00184 COLOR_BRRED,
00185 COLOR_RED,
00186 COLOR_GREEN,
00187 COLOR_BRGREEN,
00188 0,
00189 0,
00190 0,
00191 0,
00192 0,
00193 0,
00194 0,
00195 0,
00196 0,
00197 COLOR_BRBLUE,
00198 COLOR_BRBLUE,
00199 COLOR_BRBLUE,
00200 COLOR_BRBLUE,
00201 COLOR_BRBLUE,
00202 COLOR_BRBLUE,
00203 COLOR_BRBLUE,
00204 COLOR_BRBLUE,
00205 COLOR_BRBLUE,
00206 COLOR_BRBLUE,
00207 COLOR_BRBLUE,
00208 COLOR_BRBLUE,
00209 COLOR_BRBLUE,
00210 COLOR_BRBLUE,
00211 COLOR_BRBLUE,
00212 COLOR_BRBLUE,
00213 };
00214
00215 AST_THREADSTORAGE(verbose_buf);
00216 #define VERBOSE_BUF_INIT_SIZE 256
00217
00218 AST_THREADSTORAGE(log_buf);
00219 #define LOG_BUF_INIT_SIZE 256
00220
00221 static void logger_queue_init(void);
00222
00223 static unsigned int make_components(const char *s, int lineno)
00224 {
00225 char *w;
00226 unsigned int res = 0;
00227 char *stringp = ast_strdupa(s);
00228 unsigned int x;
00229
00230 while ((w = strsep(&stringp, ","))) {
00231 w = ast_skip_blanks(w);
00232
00233 if (!strcmp(w, "*")) {
00234 res = 0xFFFFFFFF;
00235 break;
00236 } else for (x = 0; x < ARRAY_LEN(levels); x++) {
00237 if (levels[x] && !strcasecmp(w, levels[x])) {
00238 res |= (1 << x);
00239 break;
00240 }
00241 }
00242 }
00243
00244 return res;
00245 }
00246
00247 static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno)
00248 {
00249 struct logchannel *chan;
00250 char *facility;
00251
00252 if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan) + strlen(components) + 1)))
00253 return NULL;
00254
00255 strcpy(chan->components, components);
00256 chan->lineno = lineno;
00257
00258 if (!strcasecmp(channel, "console")) {
00259 chan->type = LOGTYPE_CONSOLE;
00260 } else if (!strncasecmp(channel, "syslog", 6)) {
00261
00262
00263
00264
00265 facility = strchr(channel, '.');
00266 if (!facility++ || !facility) {
00267 facility = "local0";
00268 }
00269
00270 chan->facility = ast_syslog_facility(facility);
00271
00272 if (chan->facility < 0) {
00273 fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
00274 ast_free(chan);
00275 return NULL;
00276 }
00277
00278 chan->type = LOGTYPE_SYSLOG;
00279 ast_copy_string(chan->filename, channel, sizeof(chan->filename));
00280 openlog("asterisk", LOG_PID, chan->facility);
00281 } else {
00282 if (!ast_strlen_zero(hostname)) {
00283 snprintf(chan->filename, sizeof(chan->filename), "%s/%s.%s",
00284 channel[0] != '/' ? ast_config_AST_LOG_DIR : "", channel, hostname);
00285 } else {
00286 snprintf(chan->filename, sizeof(chan->filename), "%s/%s",
00287 channel[0] != '/' ? ast_config_AST_LOG_DIR : "", channel);
00288 }
00289 if (!(chan->fileptr = fopen(chan->filename, "a"))) {
00290
00291
00292 ast_console_puts_mutable("ERROR: Unable to open log file '", __LOG_ERROR);
00293 ast_console_puts_mutable(chan->filename, __LOG_ERROR);
00294 ast_console_puts_mutable("': ", __LOG_ERROR);
00295 ast_console_puts_mutable(strerror(errno), __LOG_ERROR);
00296 ast_console_puts_mutable("'\n", __LOG_ERROR);
00297 ast_free(chan);
00298 return NULL;
00299 }
00300 chan->type = LOGTYPE_FILE;
00301 }
00302 chan->logmask = make_components(chan->components, lineno);
00303
00304 return chan;
00305 }
00306
00307 static void init_logger_chain(int locked)
00308 {
00309 struct logchannel *chan;
00310 struct ast_config *cfg;
00311 struct ast_variable *var;
00312 const char *s;
00313 struct ast_flags config_flags = { 0 };
00314
00315 if (!(cfg = ast_config_load2("logger.conf", "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00316 return;
00317 }
00318
00319
00320 if (!locked) {
00321 AST_RWLIST_WRLOCK(&logchannels);
00322 }
00323 while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list))) {
00324 ast_free(chan);
00325 }
00326 global_logmask = 0;
00327 if (!locked) {
00328 AST_RWLIST_UNLOCK(&logchannels);
00329 }
00330
00331 errno = 0;
00332
00333 closelog();
00334
00335
00336 if (!cfg) {
00337 if (errno) {
00338 fprintf(stderr, "Unable to open logger.conf: %s; default settings will be used.\n", strerror(errno));
00339 } else {
00340 fprintf(stderr, "Errors detected in logger.conf: see above; default settings will be used.\n");
00341 }
00342 if (!(chan = ast_calloc(1, sizeof(*chan)))) {
00343 return;
00344 }
00345 chan->type = LOGTYPE_CONSOLE;
00346 chan->logmask = __LOG_WARNING | __LOG_NOTICE | __LOG_ERROR;
00347 if (!locked) {
00348 AST_RWLIST_WRLOCK(&logchannels);
00349 }
00350 AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
00351 global_logmask |= chan->logmask;
00352 if (!locked) {
00353 AST_RWLIST_UNLOCK(&logchannels);
00354 }
00355 return;
00356 }
00357
00358 if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
00359 if (ast_true(s)) {
00360 if (gethostname(hostname, sizeof(hostname) - 1)) {
00361 ast_copy_string(hostname, "unknown", sizeof(hostname));
00362 fprintf(stderr, "What box has no hostname???\n");
00363 }
00364 } else
00365 hostname[0] = '\0';
00366 } else
00367 hostname[0] = '\0';
00368 if ((s = ast_variable_retrieve(cfg, "general", "dateformat")))
00369 ast_copy_string(dateformat, s, sizeof(dateformat));
00370 else
00371 ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
00372 if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
00373 logfiles.queue_log = ast_true(s);
00374 }
00375 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_to_file"))) {
00376 logfiles.queue_log_to_file = ast_true(s);
00377 }
00378 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name"))) {
00379 ast_copy_string(queue_log_name, s, sizeof(queue_log_name));
00380 }
00381 if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate"))) {
00382 ast_copy_string(exec_after_rotate, s, sizeof(exec_after_rotate));
00383 }
00384 if ((s = ast_variable_retrieve(cfg, "general", "rotatestrategy"))) {
00385 if (strcasecmp(s, "timestamp") == 0) {
00386 rotatestrategy = TIMESTAMP;
00387 } else if (strcasecmp(s, "rotate") == 0) {
00388 rotatestrategy = ROTATE;
00389 } else if (strcasecmp(s, "sequential") == 0) {
00390 rotatestrategy = SEQUENTIAL;
00391 } else {
00392 fprintf(stderr, "Unknown rotatestrategy: %s\n", s);
00393 }
00394 } else {
00395 if ((s = ast_variable_retrieve(cfg, "general", "rotatetimestamp"))) {
00396 rotatestrategy = ast_true(s) ? TIMESTAMP : SEQUENTIAL;
00397 fprintf(stderr, "rotatetimestamp option has been deprecated. Please use rotatestrategy instead.\n");
00398 }
00399 }
00400
00401 if (!locked) {
00402 AST_RWLIST_WRLOCK(&logchannels);
00403 }
00404 var = ast_variable_browse(cfg, "logfiles");
00405 for (; var; var = var->next) {
00406 if (!(chan = make_logchannel(var->name, var->value, var->lineno))) {
00407
00408
00409 ast_console_puts_mutable("ERROR: Unable to create log channel '", __LOG_ERROR);
00410 ast_console_puts_mutable(var->name, __LOG_ERROR);
00411 ast_console_puts_mutable("'\n", __LOG_ERROR);
00412 continue;
00413 }
00414 AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
00415 global_logmask |= chan->logmask;
00416 }
00417
00418 if (qlog) {
00419 fclose(qlog);
00420 qlog = NULL;
00421 }
00422
00423 if (!locked) {
00424 AST_RWLIST_UNLOCK(&logchannels);
00425 }
00426
00427 ast_config_destroy(cfg);
00428 }
00429
00430 void ast_child_verbose(int level, const char *fmt, ...)
00431 {
00432 char *msg = NULL, *emsg = NULL, *sptr, *eptr;
00433 va_list ap, aq;
00434 int size;
00435
00436
00437 if (option_verbose < level) {
00438 return;
00439 }
00440
00441 va_start(ap, fmt);
00442 va_copy(aq, ap);
00443 if ((size = vsnprintf(msg, 0, fmt, ap)) < 0) {
00444 va_end(ap);
00445 va_end(aq);
00446 return;
00447 }
00448 va_end(ap);
00449
00450 if (!(msg = ast_malloc(size + 1))) {
00451 va_end(aq);
00452 return;
00453 }
00454
00455 vsnprintf(msg, size + 1, fmt, aq);
00456 va_end(aq);
00457
00458 if (!(emsg = ast_malloc(size * 2 + 1))) {
00459 ast_free(msg);
00460 return;
00461 }
00462
00463 for (sptr = msg, eptr = emsg; ; sptr++) {
00464 if (*sptr == '"') {
00465 *eptr++ = '\\';
00466 }
00467 *eptr++ = *sptr;
00468 if (*sptr == '\0') {
00469 break;
00470 }
00471 }
00472 ast_free(msg);
00473
00474 fprintf(stdout, "verbose \"%s\" %d\n", emsg, level);
00475 fflush(stdout);
00476 ast_free(emsg);
00477 }
00478
00479 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
00480 {
00481 va_list ap;
00482 struct timeval tv;
00483 struct ast_tm tm;
00484 char qlog_msg[8192];
00485 int qlog_len;
00486 char time_str[30];
00487
00488 if (!logger_initialized) {
00489
00490 return;
00491 }
00492 if (!queuelog_init) {
00493 AST_RWLIST_WRLOCK(&logchannels);
00494 if (!queuelog_init) {
00495
00496
00497
00498
00499
00500 logger_queue_init();
00501 queuelog_init = 1;
00502 AST_RWLIST_UNLOCK(&logchannels);
00503 ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
00504 } else {
00505 AST_RWLIST_UNLOCK(&logchannels);
00506 }
00507 }
00508
00509 if (ast_check_realtime("queue_log")) {
00510 tv = ast_tvnow();
00511 ast_localtime(&tv, &tm, NULL);
00512 ast_strftime(time_str, sizeof(time_str), "%F %T.%6q", &tm);
00513 va_start(ap, fmt);
00514 vsnprintf(qlog_msg, sizeof(qlog_msg), fmt, ap);
00515 va_end(ap);
00516 if (logfiles.queue_adaptive_realtime) {
00517 AST_DECLARE_APP_ARGS(args,
00518 AST_APP_ARG(data)[5];
00519 );
00520 AST_NONSTANDARD_APP_ARGS(args, qlog_msg, '|');
00521
00522 ast_realtime_require_field("queue_log",
00523 "data1", RQ_CHAR, strlen(S_OR(args.data[0], "")),
00524 "data2", RQ_CHAR, strlen(S_OR(args.data[1], "")),
00525 "data3", RQ_CHAR, strlen(S_OR(args.data[2], "")),
00526 "data4", RQ_CHAR, strlen(S_OR(args.data[3], "")),
00527 "data5", RQ_CHAR, strlen(S_OR(args.data[4], "")),
00528 SENTINEL);
00529
00530
00531 ast_store_realtime("queue_log", "time", time_str,
00532 "callid", callid,
00533 "queuename", queuename,
00534 "agent", agent,
00535 "event", event,
00536 "data1", S_OR(args.data[0], ""),
00537 "data2", S_OR(args.data[1], ""),
00538 "data3", S_OR(args.data[2], ""),
00539 "data4", S_OR(args.data[3], ""),
00540 "data5", S_OR(args.data[4], ""),
00541 SENTINEL);
00542 } else {
00543 ast_store_realtime("queue_log", "time", time_str,
00544 "callid", callid,
00545 "queuename", queuename,
00546 "agent", agent,
00547 "event", event,
00548 "data", qlog_msg,
00549 SENTINEL);
00550 }
00551
00552 if (!logfiles.queue_log_to_file) {
00553 return;
00554 }
00555 }
00556
00557 if (qlog) {
00558 va_start(ap, fmt);
00559 qlog_len = snprintf(qlog_msg, sizeof(qlog_msg), "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
00560 vsnprintf(qlog_msg + qlog_len, sizeof(qlog_msg) - qlog_len, fmt, ap);
00561 va_end(ap);
00562 AST_RWLIST_RDLOCK(&logchannels);
00563 if (qlog) {
00564 fprintf(qlog, "%s\n", qlog_msg);
00565 fflush(qlog);
00566 }
00567 AST_RWLIST_UNLOCK(&logchannels);
00568 }
00569 }
00570
00571 static int rotate_file(const char *filename)
00572 {
00573 char old[PATH_MAX];
00574 char new[PATH_MAX];
00575 int x, y, which, found, res = 0, fd;
00576 char *suffixes[4] = { "", ".gz", ".bz2", ".Z" };
00577
00578 switch (rotatestrategy) {
00579 case SEQUENTIAL:
00580 for (x = 0; ; x++) {
00581 snprintf(new, sizeof(new), "%s.%d", filename, x);
00582 fd = open(new, O_RDONLY);
00583 if (fd > -1)
00584 close(fd);
00585 else
00586 break;
00587 }
00588 if (rename(filename, new)) {
00589 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
00590 res = -1;
00591 } else {
00592 filename = new;
00593 }
00594 break;
00595 case TIMESTAMP:
00596 snprintf(new, sizeof(new), "%s.%ld", filename, (long)time(NULL));
00597 if (rename(filename, new)) {
00598 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
00599 res = -1;
00600 } else {
00601 filename = new;
00602 }
00603 break;
00604 case ROTATE:
00605
00606 for (x = 0; ; x++) {
00607 found = 0;
00608 for (which = 0; which < ARRAY_LEN(suffixes); which++) {
00609 snprintf(new, sizeof(new), "%s.%d%s", filename, x, suffixes[which]);
00610 fd = open(new, O_RDONLY);
00611 if (fd > -1) {
00612 close(fd);
00613 found = 1;
00614 break;
00615 }
00616 }
00617 if (!found) {
00618 break;
00619 }
00620 }
00621
00622
00623 for (y = x; y > 0; y--) {
00624 for (which = 0; which < ARRAY_LEN(suffixes); which++) {
00625 snprintf(old, sizeof(old), "%s.%d%s", filename, y - 1, suffixes[which]);
00626 fd = open(old, O_RDONLY);
00627 if (fd > -1) {
00628
00629 close(fd);
00630 snprintf(new, sizeof(new), "%s.%d%s", filename, y, suffixes[which]);
00631 if (rename(old, new)) {
00632 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
00633 res = -1;
00634 }
00635 break;
00636 }
00637 }
00638 }
00639
00640
00641 snprintf(new, sizeof(new), "%s.0", filename);
00642 if (rename(filename, new)) {
00643 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
00644 res = -1;
00645 } else {
00646 filename = new;
00647 }
00648 }
00649
00650 if (!ast_strlen_zero(exec_after_rotate)) {
00651 struct ast_channel *c = ast_dummy_channel_alloc();
00652 char buf[512];
00653
00654 pbx_builtin_setvar_helper(c, "filename", filename);
00655 pbx_substitute_variables_helper(c, exec_after_rotate, buf, sizeof(buf));
00656 if (c) {
00657 c = ast_channel_unref(c);
00658 }
00659 if (ast_safe_system(buf) == -1) {
00660 ast_log(LOG_WARNING, "error executing '%s'\n", buf);
00661 }
00662 }
00663 return res;
00664 }
00665
00666
00667
00668
00669
00670
00671
00672 static int logger_queue_rt_start(void)
00673 {
00674 if (ast_check_realtime("queue_log")) {
00675 if (!ast_realtime_require_field("queue_log",
00676 "time", RQ_DATETIME, 26,
00677 "data1", RQ_CHAR, 20,
00678 "data2", RQ_CHAR, 20,
00679 "data3", RQ_CHAR, 20,
00680 "data4", RQ_CHAR, 20,
00681 "data5", RQ_CHAR, 20,
00682 SENTINEL)) {
00683 logfiles.queue_adaptive_realtime = 1;
00684 } else {
00685 logfiles.queue_adaptive_realtime = 0;
00686 }
00687
00688 if (!logfiles.queue_log_to_file) {
00689
00690 return 1;
00691 }
00692 }
00693 return 0;
00694 }
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707 static int logger_queue_restart(int queue_rotate)
00708 {
00709 int res = 0;
00710 char qfname[PATH_MAX];
00711
00712 if (logger_queue_rt_start()) {
00713 return res;
00714 }
00715
00716 snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
00717 if (qlog) {
00718
00719 fclose(qlog);
00720 qlog = NULL;
00721 }
00722 if (queue_rotate) {
00723 rotate_file(qfname);
00724 }
00725
00726
00727 qlog = fopen(qfname, "a");
00728 if (!qlog) {
00729 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
00730 res = -1;
00731 }
00732 return res;
00733 }
00734
00735 static int reload_logger(int rotate)
00736 {
00737 int queue_rotate = rotate;
00738 struct logchannel *f;
00739 int res = 0;
00740
00741 AST_RWLIST_WRLOCK(&logchannels);
00742
00743 if (qlog) {
00744 if (rotate < 0) {
00745
00746 if (ftello(qlog) > 0x40000000) {
00747 fclose(qlog);
00748 qlog = NULL;
00749 } else {
00750 queue_rotate = 0;
00751 }
00752 } else {
00753 fclose(qlog);
00754 qlog = NULL;
00755 }
00756 } else {
00757 queue_rotate = 0;
00758 }
00759
00760 ast_mkdir(ast_config_AST_LOG_DIR, 0777);
00761
00762 AST_RWLIST_TRAVERSE(&logchannels, f, list) {
00763 if (f->disabled) {
00764 f->disabled = 0;
00765 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
00766 }
00767 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00768 int rotate_this = 0;
00769 if (ftello(f->fileptr) > 0x40000000) {
00770
00771 rotate_this = 1;
00772 }
00773 fclose(f->fileptr);
00774 f->fileptr = NULL;
00775 if (rotate || rotate_this) {
00776 rotate_file(f->filename);
00777 }
00778 }
00779 }
00780
00781 filesize_reload_needed = 0;
00782
00783 init_logger_chain(1 );
00784
00785 ast_unload_realtime("queue_log");
00786 if (logfiles.queue_log) {
00787 res = logger_queue_restart(queue_rotate);
00788 AST_RWLIST_UNLOCK(&logchannels);
00789 ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
00790 ast_verb(1, "Asterisk Queue Logger restarted\n");
00791 } else {
00792 AST_RWLIST_UNLOCK(&logchannels);
00793 }
00794
00795 return res;
00796 }
00797
00798
00799
00800 int logger_reload(void)
00801 {
00802 if (reload_logger(0)) {
00803 return RESULT_FAILURE;
00804 }
00805 return RESULT_SUCCESS;
00806 }
00807
00808 static char *handle_logger_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00809 {
00810 switch (cmd) {
00811 case CLI_INIT:
00812 e->command = "logger reload";
00813 e->usage =
00814 "Usage: logger reload\n"
00815 " Reloads the logger subsystem state. Use after restarting syslogd(8) if you are using syslog logging.\n";
00816 return NULL;
00817 case CLI_GENERATE:
00818 return NULL;
00819 }
00820 if (reload_logger(0)) {
00821 ast_cli(a->fd, "Failed to reload the logger\n");
00822 return CLI_FAILURE;
00823 }
00824 return CLI_SUCCESS;
00825 }
00826
00827 static char *handle_logger_rotate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00828 {
00829 switch (cmd) {
00830 case CLI_INIT:
00831 e->command = "logger rotate";
00832 e->usage =
00833 "Usage: logger rotate\n"
00834 " Rotates and Reopens the log files.\n";
00835 return NULL;
00836 case CLI_GENERATE:
00837 return NULL;
00838 }
00839 if (reload_logger(1)) {
00840 ast_cli(a->fd, "Failed to reload the logger and rotate log files\n");
00841 return CLI_FAILURE;
00842 }
00843 return CLI_SUCCESS;
00844 }
00845
00846 static char *handle_logger_set_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00847 {
00848 int x;
00849 int state;
00850 int level = -1;
00851
00852 switch (cmd) {
00853 case CLI_INIT:
00854 e->command = "logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}";
00855 e->usage =
00856 "Usage: logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}\n"
00857 " Set a specific log level to enabled/disabled for this console.\n";
00858 return NULL;
00859 case CLI_GENERATE:
00860 return NULL;
00861 }
00862
00863 if (a->argc < 5)
00864 return CLI_SHOWUSAGE;
00865
00866 AST_RWLIST_WRLOCK(&logchannels);
00867
00868 for (x = 0; x < ARRAY_LEN(levels); x++) {
00869 if (levels[x] && !strcasecmp(a->argv[3], levels[x])) {
00870 level = x;
00871 break;
00872 }
00873 }
00874
00875 AST_RWLIST_UNLOCK(&logchannels);
00876
00877 state = ast_true(a->argv[4]) ? 1 : 0;
00878
00879 if (level != -1) {
00880 ast_console_toggle_loglevel(a->fd, level, state);
00881 ast_cli(a->fd, "Logger status for '%s' has been set to '%s'.\n", levels[level], state ? "on" : "off");
00882 } else
00883 return CLI_SHOWUSAGE;
00884
00885 return CLI_SUCCESS;
00886 }
00887
00888
00889 static char *handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00890 {
00891 #define FORMATL "%-35.35s %-8.8s %-9.9s "
00892 struct logchannel *chan;
00893 switch (cmd) {
00894 case CLI_INIT:
00895 e->command = "logger show channels";
00896 e->usage =
00897 "Usage: logger show channels\n"
00898 " List configured logger channels.\n";
00899 return NULL;
00900 case CLI_GENERATE:
00901 return NULL;
00902 }
00903 ast_cli(a->fd, FORMATL, "Channel", "Type", "Status");
00904 ast_cli(a->fd, "Configuration\n");
00905 ast_cli(a->fd, FORMATL, "-------", "----", "------");
00906 ast_cli(a->fd, "-------------\n");
00907 AST_RWLIST_RDLOCK(&logchannels);
00908 AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
00909 unsigned int level;
00910
00911 ast_cli(a->fd, FORMATL, chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" : (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"),
00912 chan->disabled ? "Disabled" : "Enabled");
00913 ast_cli(a->fd, " - ");
00914 for (level = 0; level < ARRAY_LEN(levels); level++) {
00915 if ((chan->logmask & (1 << level)) && levels[level]) {
00916 ast_cli(a->fd, "%s ", levels[level]);
00917 }
00918 }
00919 ast_cli(a->fd, "\n");
00920 }
00921 AST_RWLIST_UNLOCK(&logchannels);
00922 ast_cli(a->fd, "\n");
00923
00924 return CLI_SUCCESS;
00925 }
00926
00927 struct verb {
00928 void (*verboser)(const char *string);
00929 AST_LIST_ENTRY(verb) list;
00930 };
00931
00932 static AST_RWLIST_HEAD_STATIC(verbosers, verb);
00933
00934 static struct ast_cli_entry cli_logger[] = {
00935 AST_CLI_DEFINE(handle_logger_show_channels, "List configured log channels"),
00936 AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"),
00937 AST_CLI_DEFINE(handle_logger_rotate, "Rotates and reopens the log files"),
00938 AST_CLI_DEFINE(handle_logger_set_level, "Enables/Disables a specific logging level for this console")
00939 };
00940
00941 static void _handle_SIGXFSZ(int sig)
00942 {
00943
00944 filesize_reload_needed = 1;
00945 }
00946
00947 static struct sigaction handle_SIGXFSZ = {
00948 .sa_handler = _handle_SIGXFSZ,
00949 .sa_flags = SA_RESTART,
00950 };
00951
00952 static void ast_log_vsyslog(struct logmsg *msg)
00953 {
00954 char buf[BUFSIZ];
00955 int syslog_level = ast_syslog_priority_from_loglevel(msg->level);
00956
00957 if (syslog_level < 0) {
00958
00959 fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", msg->level);
00960 return;
00961 }
00962
00963 snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: %s",
00964 levels[msg->level], msg->process_id, msg->file, msg->line, msg->function, msg->message);
00965
00966 term_strip(buf, buf, strlen(buf) + 1);
00967 syslog(syslog_level, "%s", buf);
00968 }
00969
00970
00971 static void logger_print_normal(struct logmsg *logmsg)
00972 {
00973 struct logchannel *chan = NULL;
00974 char buf[BUFSIZ];
00975 struct verb *v = NULL;
00976
00977 if (logmsg->level == __LOG_VERBOSE) {
00978 char *tmpmsg = ast_strdupa(logmsg->message + 1);
00979
00980 AST_RWLIST_RDLOCK(&verbosers);
00981 AST_RWLIST_TRAVERSE(&verbosers, v, list)
00982 v->verboser(logmsg->message);
00983 AST_RWLIST_UNLOCK(&verbosers);
00984 ast_string_field_set(logmsg, message, tmpmsg);
00985 }
00986
00987 AST_RWLIST_RDLOCK(&logchannels);
00988
00989 if (!AST_RWLIST_EMPTY(&logchannels)) {
00990 AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
00991
00992 if (chan->disabled)
00993 continue;
00994
00995 if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << logmsg->level))) {
00996 ast_log_vsyslog(logmsg);
00997
00998 } else if (chan->type == LOGTYPE_CONSOLE && (chan->logmask & (1 << logmsg->level))) {
00999 char linestr[128];
01000 char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
01001
01002
01003 if (logmsg->level == __LOG_VERBOSE)
01004 continue;
01005
01006
01007 snprintf(linestr, sizeof(linestr), "%d", logmsg->line);
01008
01009 snprintf(buf, sizeof(buf), "[%s] %s[%ld]: %s:%s %s: %s",
01010 logmsg->date,
01011 term_color(tmp1, logmsg->level_name, colors[logmsg->level], 0, sizeof(tmp1)),
01012 logmsg->process_id,
01013 term_color(tmp2, logmsg->file, COLOR_BRWHITE, 0, sizeof(tmp2)),
01014 term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
01015 term_color(tmp4, logmsg->function, COLOR_BRWHITE, 0, sizeof(tmp4)),
01016 logmsg->message);
01017
01018 ast_console_puts_mutable(buf, logmsg->level);
01019
01020 } else if (chan->type == LOGTYPE_FILE && (chan->logmask & (1 << logmsg->level))) {
01021 int res = 0;
01022
01023
01024 if (!chan->fileptr) {
01025 continue;
01026 }
01027
01028
01029 res = fprintf(chan->fileptr, "[%s] %s[%ld] %s: %s",
01030 logmsg->date, logmsg->level_name, logmsg->process_id, logmsg->file, term_strip(buf, logmsg->message, BUFSIZ));
01031 if (res <= 0 && !ast_strlen_zero(logmsg->message)) {
01032 fprintf(stderr, "**** Asterisk Logging Error: ***********\n");
01033 if (errno == ENOMEM || errno == ENOSPC)
01034 fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
01035 else
01036 fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
01037 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
01038 chan->disabled = 1;
01039 } else if (res > 0) {
01040 fflush(chan->fileptr);
01041 }
01042 }
01043 }
01044 } else if (logmsg->level != __LOG_VERBOSE) {
01045 fputs(logmsg->message, stdout);
01046 }
01047
01048 AST_RWLIST_UNLOCK(&logchannels);
01049
01050
01051 if (filesize_reload_needed) {
01052 reload_logger(-1);
01053 ast_verb(1, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
01054 }
01055
01056 return;
01057 }
01058
01059
01060 static void *logger_thread(void *data)
01061 {
01062 struct logmsg *next = NULL, *msg = NULL;
01063
01064 for (;;) {
01065
01066 AST_LIST_LOCK(&logmsgs);
01067 if (AST_LIST_EMPTY(&logmsgs)) {
01068 if (close_logger_thread) {
01069 AST_LIST_UNLOCK(&logmsgs);
01070 break;
01071 } else {
01072 ast_cond_wait(&logcond, &logmsgs.lock);
01073 }
01074 }
01075 next = AST_LIST_FIRST(&logmsgs);
01076 AST_LIST_HEAD_INIT_NOLOCK(&logmsgs);
01077 AST_LIST_UNLOCK(&logmsgs);
01078
01079
01080 while ((msg = next)) {
01081
01082 next = AST_LIST_NEXT(msg, list);
01083
01084
01085 logger_print_normal(msg);
01086
01087
01088 ast_free(msg);
01089 }
01090
01091
01092 if (close_logger_thread)
01093 break;
01094 }
01095
01096 return NULL;
01097 }
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107 static void logger_queue_init(void)
01108 {
01109 ast_unload_realtime("queue_log");
01110 if (logfiles.queue_log) {
01111 char qfname[PATH_MAX];
01112
01113 if (logger_queue_rt_start()) {
01114 return;
01115 }
01116
01117
01118 snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR,
01119 queue_log_name);
01120 if (qlog) {
01121
01122 fclose(qlog);
01123 }
01124 qlog = fopen(qfname, "a");
01125 if (!qlog) {
01126 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
01127 }
01128 }
01129 }
01130
01131 int init_logger(void)
01132 {
01133
01134 sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
01135
01136
01137 ast_cond_init(&logcond, NULL);
01138 if (ast_pthread_create(&logthread, NULL, logger_thread, NULL) < 0) {
01139 ast_cond_destroy(&logcond);
01140 return -1;
01141 }
01142
01143
01144 ast_cli_register_multiple(cli_logger, ARRAY_LEN(cli_logger));
01145
01146 ast_mkdir(ast_config_AST_LOG_DIR, 0777);
01147
01148
01149 init_logger_chain(0 );
01150 logger_initialized = 1;
01151
01152 return 0;
01153 }
01154
01155 void close_logger(void)
01156 {
01157 struct logchannel *f = NULL;
01158
01159 logger_initialized = 0;
01160
01161
01162 AST_LIST_LOCK(&logmsgs);
01163 close_logger_thread = 1;
01164 ast_cond_signal(&logcond);
01165 AST_LIST_UNLOCK(&logmsgs);
01166
01167 if (logthread != AST_PTHREADT_NULL)
01168 pthread_join(logthread, NULL);
01169
01170 AST_RWLIST_WRLOCK(&logchannels);
01171
01172 if (qlog) {
01173 fclose(qlog);
01174 qlog = NULL;
01175 }
01176
01177 AST_RWLIST_TRAVERSE(&logchannels, f, list) {
01178 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
01179 fclose(f->fileptr);
01180 f->fileptr = NULL;
01181 }
01182 }
01183
01184 closelog();
01185
01186 AST_RWLIST_UNLOCK(&logchannels);
01187 }
01188
01189
01190
01191
01192 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
01193 {
01194 struct logmsg *logmsg = NULL;
01195 struct ast_str *buf = NULL;
01196 struct ast_tm tm;
01197 struct timeval now = ast_tvnow();
01198 int res = 0;
01199 va_list ap;
01200 char datestring[256];
01201
01202 if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE)))
01203 return;
01204
01205 if (level != __LOG_VERBOSE && AST_RWLIST_EMPTY(&logchannels)) {
01206
01207
01208
01209
01210 int result;
01211 va_start(ap, fmt);
01212 result = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
01213 va_end(ap);
01214 if (result != AST_DYNSTR_BUILD_FAILED) {
01215 term_filter_escapes(ast_str_buffer(buf));
01216 fputs(ast_str_buffer(buf), stdout);
01217 }
01218 return;
01219 }
01220
01221
01222
01223
01224
01225
01226
01227 if (!option_verbose && !option_debug && (level == __LOG_DEBUG))
01228 return;
01229
01230
01231 if (level != __LOG_VERBOSE && !(global_logmask & (1 << level)))
01232 return;
01233
01234
01235 va_start(ap, fmt);
01236 res = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
01237 va_end(ap);
01238
01239
01240 if (res == AST_DYNSTR_BUILD_FAILED)
01241 return;
01242
01243
01244 if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128)))
01245 return;
01246
01247
01248 ast_string_field_set(logmsg, message, ast_str_buffer(buf));
01249
01250
01251 if (level == __LOG_VERBOSE) {
01252 logmsg->type = LOGMSG_VERBOSE;
01253 } else {
01254 logmsg->type = LOGMSG_NORMAL;
01255 }
01256
01257
01258 ast_localtime(&now, &tm, NULL);
01259 ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
01260 ast_string_field_set(logmsg, date, datestring);
01261
01262
01263 logmsg->level = level;
01264 logmsg->line = line;
01265 ast_string_field_set(logmsg, level_name, levels[level]);
01266 ast_string_field_set(logmsg, file, file);
01267 ast_string_field_set(logmsg, function, function);
01268 logmsg->process_id = (long) GETTID();
01269
01270
01271 if (logthread != AST_PTHREADT_NULL) {
01272 AST_LIST_LOCK(&logmsgs);
01273 if (close_logger_thread) {
01274
01275 ast_free(logmsg);
01276 } else {
01277 AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list);
01278 ast_cond_signal(&logcond);
01279 }
01280 AST_LIST_UNLOCK(&logmsgs);
01281 } else {
01282 logger_print_normal(logmsg);
01283 ast_free(logmsg);
01284 }
01285 }
01286
01287 #ifdef HAVE_BKTR
01288
01289 struct ast_bt *ast_bt_create(void)
01290 {
01291 struct ast_bt *bt = ast_calloc(1, sizeof(*bt));
01292 if (!bt) {
01293 ast_log(LOG_ERROR, "Unable to allocate memory for backtrace structure!\n");
01294 return NULL;
01295 }
01296
01297 bt->alloced = 1;
01298
01299 ast_bt_get_addresses(bt);
01300
01301 return bt;
01302 }
01303
01304 int ast_bt_get_addresses(struct ast_bt *bt)
01305 {
01306 bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES);
01307
01308 return 0;
01309 }
01310
01311 void *ast_bt_destroy(struct ast_bt *bt)
01312 {
01313 if (bt->alloced) {
01314 ast_free(bt);
01315 }
01316
01317 return NULL;
01318 }
01319
01320 char **ast_bt_get_symbols(void **addresses, size_t num_frames)
01321 {
01322 char **strings = NULL;
01323 #if defined(BETTER_BACKTRACES)
01324 int stackfr;
01325 bfd *bfdobj;
01326 Dl_info dli;
01327 long allocsize;
01328 asymbol **syms = NULL;
01329 bfd_vma offset;
01330 const char *lastslash;
01331 asection *section;
01332 const char *file, *func;
01333 unsigned int line;
01334 char address_str[128];
01335 char msg[1024];
01336 size_t strings_size;
01337 size_t *eachlen;
01338 #endif
01339
01340 #if defined(BETTER_BACKTRACES)
01341 strings_size = num_frames * sizeof(*strings);
01342 eachlen = ast_calloc(num_frames, sizeof(*eachlen));
01343
01344 if (!(strings = ast_calloc(num_frames, sizeof(*strings)))) {
01345 return NULL;
01346 }
01347
01348 for (stackfr = 0; stackfr < num_frames; stackfr++) {
01349 int found = 0, symbolcount;
01350
01351 msg[0] = '\0';
01352
01353 if (!dladdr(addresses[stackfr], &dli)) {
01354 continue;
01355 }
01356
01357 if (strcmp(dli.dli_fname, "asterisk") == 0) {
01358 char asteriskpath[256];
01359 if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) {
01360
01361 ast_log(LOG_DEBUG, "Failed to find asterisk binary for debug symbols.\n");
01362 dli.dli_fname = "asterisk";
01363 }
01364 }
01365
01366 lastslash = strrchr(dli.dli_fname, '/');
01367 if ( (bfdobj = bfd_openr(dli.dli_fname, NULL)) &&
01368 bfd_check_format(bfdobj, bfd_object) &&
01369 (allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 &&
01370 (syms = ast_malloc(allocsize)) &&
01371 (symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) {
01372
01373 if (bfdobj->flags & DYNAMIC) {
01374 offset = addresses[stackfr] - dli.dli_fbase;
01375 } else {
01376 offset = addresses[stackfr] - (void *) 0;
01377 }
01378
01379 for (section = bfdobj->sections; section; section = section->next) {
01380 if ( !bfd_get_section_flags(bfdobj, section) & SEC_ALLOC ||
01381 section->vma > offset ||
01382 section->size + section->vma < offset) {
01383 continue;
01384 }
01385
01386 if (!bfd_find_nearest_line(bfdobj, section, syms, offset - section->vma, &file, &func, &line)) {
01387 continue;
01388 }
01389
01390
01391 file = file ? file : "";
01392
01393
01394 found++;
01395 if ((lastslash = strrchr(file, '/'))) {
01396 const char *prevslash;
01397 for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--);
01398 if (prevslash >= file) {
01399 lastslash = prevslash;
01400 }
01401 }
01402 if (dli.dli_saddr == NULL) {
01403 address_str[0] = '\0';
01404 } else {
01405 snprintf(address_str, sizeof(address_str), " (%p+%lX)",
01406 dli.dli_saddr,
01407 (unsigned long) (addresses[stackfr] - dli.dli_saddr));
01408 }
01409 snprintf(msg, sizeof(msg), "%s:%u %s()%s",
01410 lastslash ? lastslash + 1 : file, line,
01411 S_OR(func, "???"),
01412 address_str);
01413
01414 break;
01415 }
01416 }
01417 if (bfdobj) {
01418 bfd_close(bfdobj);
01419 if (syms) {
01420 ast_free(syms);
01421 }
01422 }
01423
01424
01425 if (!found) {
01426 if (dli.dli_saddr == NULL) {
01427 address_str[0] = '\0';
01428 } else {
01429 snprintf(address_str, sizeof(address_str), " (%p+%lX)",
01430 dli.dli_saddr,
01431 (unsigned long) (addresses[stackfr] - dli.dli_saddr));
01432 }
01433 snprintf(msg, sizeof(msg), "%s %s()%s",
01434 lastslash ? lastslash + 1 : dli.dli_fname,
01435 S_OR(dli.dli_sname, "<unknown>"),
01436 address_str);
01437 }
01438
01439 if (!ast_strlen_zero(msg)) {
01440 char **tmp;
01441 eachlen[stackfr] = strlen(msg);
01442 if (!(tmp = ast_realloc(strings, strings_size + eachlen[stackfr] + 1))) {
01443 ast_free(strings);
01444 strings = NULL;
01445 break;
01446 }
01447 strings = tmp;
01448 strings[stackfr] = (char *) strings + strings_size;
01449 ast_copy_string(strings[stackfr], msg, eachlen[stackfr] + 1);
01450 strings_size += eachlen[stackfr] + 1;
01451 }
01452 }
01453
01454 if (strings) {
01455
01456 strings[0] = (char *) strings + num_frames * sizeof(*strings);
01457 for (stackfr = 1; stackfr < num_frames; stackfr++) {
01458 strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1] + 1;
01459 }
01460 }
01461 #else
01462 strings = backtrace_symbols(addresses, num_frames);
01463 #endif
01464 return strings;
01465 }
01466
01467 #endif
01468
01469 void ast_backtrace(void)
01470 {
01471 #ifdef HAVE_BKTR
01472 struct ast_bt *bt;
01473 int i = 0;
01474 char **strings;
01475
01476 if (!(bt = ast_bt_create())) {
01477 ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
01478 return;
01479 }
01480
01481 if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
01482 ast_debug(1, "Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
01483 for (i = 3; i < bt->num_frames - 2; i++) {
01484 ast_log(LOG_DEBUG, "#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
01485 }
01486
01487
01488 #undef free
01489 free(strings);
01490 } else {
01491 ast_debug(1, "Could not allocate memory for backtrace\n");
01492 }
01493 ast_bt_destroy(bt);
01494 #else
01495 ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
01496 #endif
01497 }
01498
01499 void __ast_verbose_ap(const char *file, int line, const char *func, const char *fmt, va_list ap)
01500 {
01501 struct ast_str *buf = NULL;
01502 int res = 0;
01503
01504 if (!(buf = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)))
01505 return;
01506
01507 if (ast_opt_timestamp) {
01508 struct timeval now;
01509 struct ast_tm tm;
01510 char date[40];
01511 char *datefmt;
01512
01513 now = ast_tvnow();
01514 ast_localtime(&now, &tm, NULL);
01515 ast_strftime(date, sizeof(date), dateformat, &tm);
01516 datefmt = alloca(strlen(date) + 3 + strlen(fmt) + 1);
01517 sprintf(datefmt, "%c[%s] %s", 127, date, fmt);
01518 fmt = datefmt;
01519 } else {
01520 char *tmp = alloca(strlen(fmt) + 2);
01521 sprintf(tmp, "%c%s", 127, fmt);
01522 fmt = tmp;
01523 }
01524
01525
01526 res = ast_str_set_va(&buf, 0, fmt, ap);
01527
01528
01529 if (res == AST_DYNSTR_BUILD_FAILED)
01530 return;
01531
01532 ast_log(__LOG_VERBOSE, file, line, func, "%s", ast_str_buffer(buf));
01533 }
01534
01535 void __ast_verbose(const char *file, int line, const char *func, const char *fmt, ...)
01536 {
01537 va_list ap;
01538
01539 va_start(ap, fmt);
01540 __ast_verbose_ap(file, line, func, fmt, ap);
01541 va_end(ap);
01542 }
01543
01544
01545 #undef ast_verbose
01546 void __attribute__((format(printf, 1,2))) ast_verbose(const char *fmt, ...);
01547 void ast_verbose(const char *fmt, ...)
01548 {
01549 va_list ap;
01550
01551 va_start(ap, fmt);
01552 __ast_verbose_ap("", 0, "", fmt, ap);
01553 va_end(ap);
01554 }
01555
01556 int ast_register_verbose(void (*v)(const char *string))
01557 {
01558 struct verb *verb;
01559
01560 if (!(verb = ast_malloc(sizeof(*verb))))
01561 return -1;
01562
01563 verb->verboser = v;
01564
01565 AST_RWLIST_WRLOCK(&verbosers);
01566 AST_RWLIST_INSERT_HEAD(&verbosers, verb, list);
01567 AST_RWLIST_UNLOCK(&verbosers);
01568
01569 return 0;
01570 }
01571
01572 int ast_unregister_verbose(void (*v)(const char *string))
01573 {
01574 struct verb *cur;
01575
01576 AST_RWLIST_WRLOCK(&verbosers);
01577 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) {
01578 if (cur->verboser == v) {
01579 AST_RWLIST_REMOVE_CURRENT(list);
01580 ast_free(cur);
01581 break;
01582 }
01583 }
01584 AST_RWLIST_TRAVERSE_SAFE_END;
01585 AST_RWLIST_UNLOCK(&verbosers);
01586
01587 return cur ? 0 : -1;
01588 }
01589
01590 static void update_logchannels(void)
01591 {
01592 struct logchannel *cur;
01593
01594 AST_RWLIST_WRLOCK(&logchannels);
01595
01596 global_logmask = 0;
01597
01598 AST_RWLIST_TRAVERSE(&logchannels, cur, list) {
01599 cur->logmask = make_components(cur->components, cur->lineno);
01600 global_logmask |= cur->logmask;
01601 }
01602
01603 AST_RWLIST_UNLOCK(&logchannels);
01604 }
01605
01606 int ast_logger_register_level(const char *name)
01607 {
01608 unsigned int level;
01609 unsigned int available = 0;
01610
01611 AST_RWLIST_WRLOCK(&logchannels);
01612
01613 for (level = 0; level < ARRAY_LEN(levels); level++) {
01614 if ((level >= 16) && !available && !levels[level]) {
01615 available = level;
01616 continue;
01617 }
01618
01619 if (levels[level] && !strcasecmp(levels[level], name)) {
01620 ast_log(LOG_WARNING,
01621 "Unable to register dynamic logger level '%s': a standard logger level uses that name.\n",
01622 name);
01623 AST_RWLIST_UNLOCK(&logchannels);
01624
01625 return -1;
01626 }
01627 }
01628
01629 if (!available) {
01630 ast_log(LOG_WARNING,
01631 "Unable to register dynamic logger level '%s'; maximum number of levels registered.\n",
01632 name);
01633 AST_RWLIST_UNLOCK(&logchannels);
01634
01635 return -1;
01636 }
01637
01638 levels[available] = ast_strdup(name);
01639
01640 AST_RWLIST_UNLOCK(&logchannels);
01641
01642 ast_debug(1, "Registered dynamic logger level '%s' with index %d.\n", name, available);
01643
01644 update_logchannels();
01645
01646 return available;
01647 }
01648
01649 void ast_logger_unregister_level(const char *name)
01650 {
01651 unsigned int found = 0;
01652 unsigned int x;
01653
01654 AST_RWLIST_WRLOCK(&logchannels);
01655
01656 for (x = 16; x < ARRAY_LEN(levels); x++) {
01657 if (!levels[x]) {
01658 continue;
01659 }
01660
01661 if (strcasecmp(levels[x], name)) {
01662 continue;
01663 }
01664
01665 found = 1;
01666 break;
01667 }
01668
01669 if (found) {
01670
01671
01672
01673
01674 global_logmask &= ~(1 << x);
01675
01676 ast_free(levels[x]);
01677 levels[x] = NULL;
01678 AST_RWLIST_UNLOCK(&logchannels);
01679
01680 ast_debug(1, "Unregistered dynamic logger level '%s' with index %d.\n", name, x);
01681
01682 update_logchannels();
01683 } else {
01684 AST_RWLIST_UNLOCK(&logchannels);
01685 }
01686 }
01687