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: 377771 $")
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
01138
01139
01140
01141
01142 ast_mutex_destroy(&logmsgs.lock);
01143 ast_mutex_init(&logmsgs.lock);
01144 ast_cond_init(&logcond, NULL);
01145
01146
01147 if (ast_pthread_create(&logthread, NULL, logger_thread, NULL) < 0) {
01148 ast_cond_destroy(&logcond);
01149 return -1;
01150 }
01151
01152
01153 ast_cli_register_multiple(cli_logger, ARRAY_LEN(cli_logger));
01154
01155 ast_mkdir(ast_config_AST_LOG_DIR, 0777);
01156
01157
01158 init_logger_chain(0 );
01159 logger_initialized = 1;
01160
01161 return 0;
01162 }
01163
01164 void close_logger(void)
01165 {
01166 struct logchannel *f = NULL;
01167 struct verb *cur = NULL;
01168
01169 ast_cli_unregister_multiple(cli_logger, ARRAY_LEN(cli_logger));
01170
01171 logger_initialized = 0;
01172
01173
01174 AST_LIST_LOCK(&logmsgs);
01175 close_logger_thread = 1;
01176 ast_cond_signal(&logcond);
01177 AST_LIST_UNLOCK(&logmsgs);
01178
01179 if (logthread != AST_PTHREADT_NULL)
01180 pthread_join(logthread, NULL);
01181
01182 AST_RWLIST_WRLOCK(&verbosers);
01183 while ((cur = AST_LIST_REMOVE_HEAD(&verbosers, list))) {
01184 ast_free(cur);
01185 }
01186 AST_RWLIST_UNLOCK(&verbosers);
01187
01188 AST_RWLIST_WRLOCK(&logchannels);
01189
01190 if (qlog) {
01191 fclose(qlog);
01192 qlog = NULL;
01193 }
01194
01195 while ((f = AST_LIST_REMOVE_HEAD(&logchannels, list))) {
01196 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
01197 fclose(f->fileptr);
01198 f->fileptr = NULL;
01199 }
01200 ast_free(f);
01201 }
01202
01203 closelog();
01204
01205 AST_RWLIST_UNLOCK(&logchannels);
01206 }
01207
01208
01209
01210
01211 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
01212 {
01213 struct logmsg *logmsg = NULL;
01214 struct ast_str *buf = NULL;
01215 struct ast_tm tm;
01216 struct timeval now = ast_tvnow();
01217 int res = 0;
01218 va_list ap;
01219 char datestring[256];
01220
01221 if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE)))
01222 return;
01223
01224 if (level != __LOG_VERBOSE && AST_RWLIST_EMPTY(&logchannels)) {
01225
01226
01227
01228
01229 int result;
01230 va_start(ap, fmt);
01231 result = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
01232 va_end(ap);
01233 if (result != AST_DYNSTR_BUILD_FAILED) {
01234 term_filter_escapes(ast_str_buffer(buf));
01235 fputs(ast_str_buffer(buf), stdout);
01236 }
01237 return;
01238 }
01239
01240
01241
01242
01243
01244
01245
01246 if (!option_verbose && !option_debug && (level == __LOG_DEBUG))
01247 return;
01248
01249
01250 if (level != __LOG_VERBOSE && !(global_logmask & (1 << level)))
01251 return;
01252
01253
01254 va_start(ap, fmt);
01255 res = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
01256 va_end(ap);
01257
01258
01259 if (res == AST_DYNSTR_BUILD_FAILED)
01260 return;
01261
01262
01263 if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128)))
01264 return;
01265
01266
01267 ast_string_field_set(logmsg, message, ast_str_buffer(buf));
01268
01269
01270 if (level == __LOG_VERBOSE) {
01271 logmsg->type = LOGMSG_VERBOSE;
01272 } else {
01273 logmsg->type = LOGMSG_NORMAL;
01274 }
01275
01276
01277 ast_localtime(&now, &tm, NULL);
01278 ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
01279 ast_string_field_set(logmsg, date, datestring);
01280
01281
01282 logmsg->level = level;
01283 logmsg->line = line;
01284 ast_string_field_set(logmsg, level_name, levels[level]);
01285 ast_string_field_set(logmsg, file, file);
01286 ast_string_field_set(logmsg, function, function);
01287 logmsg->process_id = (long) GETTID();
01288
01289
01290 if (logthread != AST_PTHREADT_NULL) {
01291 AST_LIST_LOCK(&logmsgs);
01292 if (close_logger_thread) {
01293
01294 ast_free(logmsg);
01295 } else {
01296 AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list);
01297 ast_cond_signal(&logcond);
01298 }
01299 AST_LIST_UNLOCK(&logmsgs);
01300 } else {
01301 logger_print_normal(logmsg);
01302 ast_free(logmsg);
01303 }
01304 }
01305
01306 #ifdef HAVE_BKTR
01307
01308 struct ast_bt *ast_bt_create(void)
01309 {
01310 struct ast_bt *bt = ast_calloc(1, sizeof(*bt));
01311 if (!bt) {
01312 ast_log(LOG_ERROR, "Unable to allocate memory for backtrace structure!\n");
01313 return NULL;
01314 }
01315
01316 bt->alloced = 1;
01317
01318 ast_bt_get_addresses(bt);
01319
01320 return bt;
01321 }
01322
01323 int ast_bt_get_addresses(struct ast_bt *bt)
01324 {
01325 bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES);
01326
01327 return 0;
01328 }
01329
01330 void *ast_bt_destroy(struct ast_bt *bt)
01331 {
01332 if (bt->alloced) {
01333 ast_free(bt);
01334 }
01335
01336 return NULL;
01337 }
01338
01339 char **ast_bt_get_symbols(void **addresses, size_t num_frames)
01340 {
01341 char **strings = NULL;
01342 #if defined(BETTER_BACKTRACES)
01343 int stackfr;
01344 bfd *bfdobj;
01345 Dl_info dli;
01346 long allocsize;
01347 asymbol **syms = NULL;
01348 bfd_vma offset;
01349 const char *lastslash;
01350 asection *section;
01351 const char *file, *func;
01352 unsigned int line;
01353 char address_str[128];
01354 char msg[1024];
01355 size_t strings_size;
01356 size_t *eachlen;
01357 #endif
01358
01359 #if defined(BETTER_BACKTRACES)
01360 strings_size = num_frames * sizeof(*strings);
01361 eachlen = ast_calloc(num_frames, sizeof(*eachlen));
01362
01363 if (!(strings = ast_calloc(num_frames, sizeof(*strings)))) {
01364 return NULL;
01365 }
01366
01367 for (stackfr = 0; stackfr < num_frames; stackfr++) {
01368 int found = 0, symbolcount;
01369
01370 msg[0] = '\0';
01371
01372 if (!dladdr(addresses[stackfr], &dli)) {
01373 continue;
01374 }
01375
01376 if (strcmp(dli.dli_fname, "asterisk") == 0) {
01377 char asteriskpath[256];
01378 if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) {
01379
01380 ast_log(LOG_DEBUG, "Failed to find asterisk binary for debug symbols.\n");
01381 dli.dli_fname = "asterisk";
01382 }
01383 }
01384
01385 lastslash = strrchr(dli.dli_fname, '/');
01386 if ( (bfdobj = bfd_openr(dli.dli_fname, NULL)) &&
01387 bfd_check_format(bfdobj, bfd_object) &&
01388 (allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 &&
01389 (syms = ast_malloc(allocsize)) &&
01390 (symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) {
01391
01392 if (bfdobj->flags & DYNAMIC) {
01393 offset = addresses[stackfr] - dli.dli_fbase;
01394 } else {
01395 offset = addresses[stackfr] - (void *) 0;
01396 }
01397
01398 for (section = bfdobj->sections; section; section = section->next) {
01399 if ( !bfd_get_section_flags(bfdobj, section) & SEC_ALLOC ||
01400 section->vma > offset ||
01401 section->size + section->vma < offset) {
01402 continue;
01403 }
01404
01405 if (!bfd_find_nearest_line(bfdobj, section, syms, offset - section->vma, &file, &func, &line)) {
01406 continue;
01407 }
01408
01409
01410 file = file ? file : "";
01411
01412
01413 found++;
01414 if ((lastslash = strrchr(file, '/'))) {
01415 const char *prevslash;
01416 for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--);
01417 if (prevslash >= file) {
01418 lastslash = prevslash;
01419 }
01420 }
01421 if (dli.dli_saddr == NULL) {
01422 address_str[0] = '\0';
01423 } else {
01424 snprintf(address_str, sizeof(address_str), " (%p+%lX)",
01425 dli.dli_saddr,
01426 (unsigned long) (addresses[stackfr] - dli.dli_saddr));
01427 }
01428 snprintf(msg, sizeof(msg), "%s:%u %s()%s",
01429 lastslash ? lastslash + 1 : file, line,
01430 S_OR(func, "???"),
01431 address_str);
01432
01433 break;
01434 }
01435 }
01436 if (bfdobj) {
01437 bfd_close(bfdobj);
01438 if (syms) {
01439 ast_free(syms);
01440 }
01441 }
01442
01443
01444 if (!found) {
01445 if (dli.dli_saddr == NULL) {
01446 address_str[0] = '\0';
01447 } else {
01448 snprintf(address_str, sizeof(address_str), " (%p+%lX)",
01449 dli.dli_saddr,
01450 (unsigned long) (addresses[stackfr] - dli.dli_saddr));
01451 }
01452 snprintf(msg, sizeof(msg), "%s %s()%s",
01453 lastslash ? lastslash + 1 : dli.dli_fname,
01454 S_OR(dli.dli_sname, "<unknown>"),
01455 address_str);
01456 }
01457
01458 if (!ast_strlen_zero(msg)) {
01459 char **tmp;
01460 eachlen[stackfr] = strlen(msg);
01461 if (!(tmp = ast_realloc(strings, strings_size + eachlen[stackfr] + 1))) {
01462 ast_free(strings);
01463 strings = NULL;
01464 break;
01465 }
01466 strings = tmp;
01467 strings[stackfr] = (char *) strings + strings_size;
01468 ast_copy_string(strings[stackfr], msg, eachlen[stackfr] + 1);
01469 strings_size += eachlen[stackfr] + 1;
01470 }
01471 }
01472
01473 if (strings) {
01474
01475 strings[0] = (char *) strings + num_frames * sizeof(*strings);
01476 for (stackfr = 1; stackfr < num_frames; stackfr++) {
01477 strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1] + 1;
01478 }
01479 }
01480 #else
01481 strings = backtrace_symbols(addresses, num_frames);
01482 #endif
01483 return strings;
01484 }
01485
01486 #endif
01487
01488 void ast_backtrace(void)
01489 {
01490 #ifdef HAVE_BKTR
01491 struct ast_bt *bt;
01492 int i = 0;
01493 char **strings;
01494
01495 if (!(bt = ast_bt_create())) {
01496 ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
01497 return;
01498 }
01499
01500 if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
01501 ast_debug(1, "Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
01502 for (i = 3; i < bt->num_frames - 2; i++) {
01503 ast_log(LOG_DEBUG, "#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
01504 }
01505
01506
01507 #undef free
01508 free(strings);
01509 } else {
01510 ast_debug(1, "Could not allocate memory for backtrace\n");
01511 }
01512 ast_bt_destroy(bt);
01513 #else
01514 ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
01515 #endif
01516 }
01517
01518 void __ast_verbose_ap(const char *file, int line, const char *func, const char *fmt, va_list ap)
01519 {
01520 struct ast_str *buf = NULL;
01521 int res = 0;
01522
01523 if (!(buf = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)))
01524 return;
01525
01526 if (ast_opt_timestamp) {
01527 struct timeval now;
01528 struct ast_tm tm;
01529 char date[40];
01530 char *datefmt;
01531
01532 now = ast_tvnow();
01533 ast_localtime(&now, &tm, NULL);
01534 ast_strftime(date, sizeof(date), dateformat, &tm);
01535 datefmt = ast_alloca(strlen(date) + 3 + strlen(fmt) + 1);
01536 sprintf(datefmt, "%c[%s] %s", 127, date, fmt);
01537 fmt = datefmt;
01538 } else {
01539 char *tmp = ast_alloca(strlen(fmt) + 2);
01540 sprintf(tmp, "%c%s", 127, fmt);
01541 fmt = tmp;
01542 }
01543
01544
01545 res = ast_str_set_va(&buf, 0, fmt, ap);
01546
01547
01548 if (res == AST_DYNSTR_BUILD_FAILED)
01549 return;
01550
01551 ast_log(__LOG_VERBOSE, file, line, func, "%s", ast_str_buffer(buf));
01552 }
01553
01554 void __ast_verbose(const char *file, int line, const char *func, const char *fmt, ...)
01555 {
01556 va_list ap;
01557
01558 va_start(ap, fmt);
01559 __ast_verbose_ap(file, line, func, fmt, ap);
01560 va_end(ap);
01561 }
01562
01563
01564 #undef ast_verbose
01565 void __attribute__((format(printf, 1,2))) ast_verbose(const char *fmt, ...);
01566 void ast_verbose(const char *fmt, ...)
01567 {
01568 va_list ap;
01569
01570 va_start(ap, fmt);
01571 __ast_verbose_ap("", 0, "", fmt, ap);
01572 va_end(ap);
01573 }
01574
01575 int ast_register_verbose(void (*v)(const char *string))
01576 {
01577 struct verb *verb;
01578
01579 if (!(verb = ast_malloc(sizeof(*verb))))
01580 return -1;
01581
01582 verb->verboser = v;
01583
01584 AST_RWLIST_WRLOCK(&verbosers);
01585 AST_RWLIST_INSERT_HEAD(&verbosers, verb, list);
01586 AST_RWLIST_UNLOCK(&verbosers);
01587
01588 return 0;
01589 }
01590
01591 int ast_unregister_verbose(void (*v)(const char *string))
01592 {
01593 struct verb *cur;
01594
01595 AST_RWLIST_WRLOCK(&verbosers);
01596 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) {
01597 if (cur->verboser == v) {
01598 AST_RWLIST_REMOVE_CURRENT(list);
01599 ast_free(cur);
01600 break;
01601 }
01602 }
01603 AST_RWLIST_TRAVERSE_SAFE_END;
01604 AST_RWLIST_UNLOCK(&verbosers);
01605
01606 return cur ? 0 : -1;
01607 }
01608
01609 static void update_logchannels(void)
01610 {
01611 struct logchannel *cur;
01612
01613 AST_RWLIST_WRLOCK(&logchannels);
01614
01615 global_logmask = 0;
01616
01617 AST_RWLIST_TRAVERSE(&logchannels, cur, list) {
01618 cur->logmask = make_components(cur->components, cur->lineno);
01619 global_logmask |= cur->logmask;
01620 }
01621
01622 AST_RWLIST_UNLOCK(&logchannels);
01623 }
01624
01625 int ast_logger_register_level(const char *name)
01626 {
01627 unsigned int level;
01628 unsigned int available = 0;
01629
01630 AST_RWLIST_WRLOCK(&logchannels);
01631
01632 for (level = 0; level < ARRAY_LEN(levels); level++) {
01633 if ((level >= 16) && !available && !levels[level]) {
01634 available = level;
01635 continue;
01636 }
01637
01638 if (levels[level] && !strcasecmp(levels[level], name)) {
01639 ast_log(LOG_WARNING,
01640 "Unable to register dynamic logger level '%s': a standard logger level uses that name.\n",
01641 name);
01642 AST_RWLIST_UNLOCK(&logchannels);
01643
01644 return -1;
01645 }
01646 }
01647
01648 if (!available) {
01649 ast_log(LOG_WARNING,
01650 "Unable to register dynamic logger level '%s'; maximum number of levels registered.\n",
01651 name);
01652 AST_RWLIST_UNLOCK(&logchannels);
01653
01654 return -1;
01655 }
01656
01657 levels[available] = ast_strdup(name);
01658
01659 AST_RWLIST_UNLOCK(&logchannels);
01660
01661 ast_debug(1, "Registered dynamic logger level '%s' with index %d.\n", name, available);
01662
01663 update_logchannels();
01664
01665 return available;
01666 }
01667
01668 void ast_logger_unregister_level(const char *name)
01669 {
01670 unsigned int found = 0;
01671 unsigned int x;
01672
01673 AST_RWLIST_WRLOCK(&logchannels);
01674
01675 for (x = 16; x < ARRAY_LEN(levels); x++) {
01676 if (!levels[x]) {
01677 continue;
01678 }
01679
01680 if (strcasecmp(levels[x], name)) {
01681 continue;
01682 }
01683
01684 found = 1;
01685 break;
01686 }
01687
01688 if (found) {
01689
01690
01691
01692
01693 global_logmask &= ~(1 << x);
01694
01695 ast_free(levels[x]);
01696 levels[x] = NULL;
01697 AST_RWLIST_UNLOCK(&logchannels);
01698
01699 ast_debug(1, "Unregistered dynamic logger level '%s' with index %d.\n", name, x);
01700
01701 update_logchannels();
01702 } else {
01703 AST_RWLIST_UNLOCK(&logchannels);
01704 }
01705 }
01706