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