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