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: 407456 $")
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/astobj2.h"
00051 #include "asterisk/threadstorage.h"
00052 #include "asterisk/strings.h"
00053 #include "asterisk/pbx.h"
00054 #include "asterisk/app.h"
00055 #include "asterisk/syslog.h"
00056 #include "asterisk/buildinfo.h"
00057 #include "asterisk/ast_version.h"
00058
00059 #include <signal.h>
00060 #include <time.h>
00061 #include <sys/stat.h>
00062 #include <fcntl.h>
00063 #ifdef HAVE_BKTR
00064 #include <execinfo.h>
00065 #define MAX_BACKTRACE_FRAMES 20
00066 # if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
00067 # include <dlfcn.h>
00068 # include <bfd.h>
00069 # endif
00070 #endif
00071
00072
00073
00074
00075 static char dateformat[256] = "%b %e %T";
00076
00077 static char queue_log_name[256] = QUEUELOG;
00078 static char exec_after_rotate[256] = "";
00079
00080 static int filesize_reload_needed;
00081 static unsigned int global_logmask = 0xFFFF;
00082 static int queuelog_init;
00083 static int logger_initialized;
00084 static volatile int next_unique_callid;
00085 static int display_callids;
00086 static void unique_callid_cleanup(void *data);
00087
00088 struct ast_callid {
00089 int call_identifier;
00090 };
00091
00092 AST_THREADSTORAGE_CUSTOM(unique_callid, NULL, unique_callid_cleanup);
00093
00094 static enum rotatestrategy {
00095 SEQUENTIAL = 1 << 0,
00096 ROTATE = 1 << 1,
00097 TIMESTAMP = 1 << 2,
00098 } rotatestrategy = SEQUENTIAL;
00099
00100 static struct {
00101 unsigned int queue_log:1;
00102 unsigned int queue_log_to_file:1;
00103 unsigned int queue_adaptive_realtime:1;
00104 } logfiles = { 1 };
00105
00106 static char hostname[MAXHOSTNAMELEN];
00107
00108 enum logtypes {
00109 LOGTYPE_SYSLOG,
00110 LOGTYPE_FILE,
00111 LOGTYPE_CONSOLE,
00112 };
00113
00114 struct logchannel {
00115
00116 unsigned int logmask;
00117
00118 int disabled;
00119
00120 int facility;
00121
00122 int verbosity;
00123
00124 enum logtypes type;
00125
00126 FILE *fileptr;
00127
00128 char filename[PATH_MAX];
00129
00130 AST_LIST_ENTRY(logchannel) list;
00131
00132 int lineno;
00133
00134 char components[0];
00135 };
00136
00137 static AST_RWLIST_HEAD_STATIC(logchannels, logchannel);
00138
00139 enum logmsgtypes {
00140 LOGMSG_NORMAL = 0,
00141 LOGMSG_VERBOSE,
00142 };
00143
00144 struct logmsg {
00145 enum logmsgtypes type;
00146 int level;
00147 int line;
00148 int lwp;
00149 struct ast_callid *callid;
00150 AST_DECLARE_STRING_FIELDS(
00151 AST_STRING_FIELD(date);
00152 AST_STRING_FIELD(file);
00153 AST_STRING_FIELD(function);
00154 AST_STRING_FIELD(message);
00155 AST_STRING_FIELD(level_name);
00156 );
00157 AST_LIST_ENTRY(logmsg) list;
00158 };
00159
00160 static void logmsg_free(struct logmsg *msg)
00161 {
00162 if (msg->callid) {
00163 ast_callid_unref(msg->callid);
00164 }
00165 ast_free(msg);
00166 }
00167
00168 static AST_LIST_HEAD_STATIC(logmsgs, logmsg);
00169 static pthread_t logthread = AST_PTHREADT_NULL;
00170 static ast_cond_t logcond;
00171 static int close_logger_thread = 0;
00172
00173 static FILE *qlog;
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 static char *levels[NUMLOGLEVELS] = {
00187 "DEBUG",
00188 "---EVENT---",
00189 "NOTICE",
00190 "WARNING",
00191 "ERROR",
00192 "VERBOSE",
00193 "DTMF",
00194 };
00195
00196
00197 static const int colors[NUMLOGLEVELS] = {
00198 COLOR_BRGREEN,
00199 COLOR_BRBLUE,
00200 COLOR_YELLOW,
00201 COLOR_BRRED,
00202 COLOR_RED,
00203 COLOR_GREEN,
00204 COLOR_BRGREEN,
00205 0,
00206 0,
00207 0,
00208 0,
00209 0,
00210 0,
00211 0,
00212 0,
00213 0,
00214 COLOR_BRBLUE,
00215 COLOR_BRBLUE,
00216 COLOR_BRBLUE,
00217 COLOR_BRBLUE,
00218 COLOR_BRBLUE,
00219 COLOR_BRBLUE,
00220 COLOR_BRBLUE,
00221 COLOR_BRBLUE,
00222 COLOR_BRBLUE,
00223 COLOR_BRBLUE,
00224 COLOR_BRBLUE,
00225 COLOR_BRBLUE,
00226 COLOR_BRBLUE,
00227 COLOR_BRBLUE,
00228 COLOR_BRBLUE,
00229 COLOR_BRBLUE,
00230 };
00231
00232 AST_THREADSTORAGE(verbose_buf);
00233 #define VERBOSE_BUF_INIT_SIZE 256
00234
00235 AST_THREADSTORAGE(log_buf);
00236 #define LOG_BUF_INIT_SIZE 256
00237
00238 static void logger_queue_init(void);
00239
00240 static void make_components(struct logchannel *chan)
00241 {
00242 char *w;
00243 unsigned int logmask = 0;
00244 char *stringp = ast_strdupa(chan->components);
00245 unsigned int x;
00246 int verb_level;
00247
00248
00249 verb_level = -1;
00250
00251 while ((w = strsep(&stringp, ","))) {
00252 w = ast_strip(w);
00253 if (ast_strlen_zero(w)) {
00254 continue;
00255 }
00256 if (!strcmp(w, "*")) {
00257 logmask = 0xFFFFFFFF;
00258 } else if (!strncasecmp(w, "verbose(", 8)) {
00259 if (levels[__LOG_VERBOSE] && sscanf(w + 8, "%30u)", &verb_level) == 1) {
00260 logmask |= (1 << __LOG_VERBOSE);
00261 }
00262 } else {
00263 for (x = 0; x < ARRAY_LEN(levels); ++x) {
00264 if (levels[x] && !strcasecmp(w, levels[x])) {
00265 logmask |= (1 << x);
00266 break;
00267 }
00268 }
00269 }
00270 }
00271 if (chan->type == LOGTYPE_CONSOLE) {
00272
00273
00274
00275
00276
00277 chan->verbosity = -1;
00278 } else {
00279 chan->verbosity = verb_level;
00280 }
00281 chan->logmask = logmask;
00282 }
00283
00284 static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno)
00285 {
00286 struct logchannel *chan;
00287 char *facility;
00288 struct ast_tm tm;
00289 struct timeval now = ast_tvnow();
00290 char datestring[256];
00291
00292 if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan) + strlen(components) + 1)))
00293 return NULL;
00294
00295 strcpy(chan->components, components);
00296 chan->lineno = lineno;
00297
00298 if (!strcasecmp(channel, "console")) {
00299 chan->type = LOGTYPE_CONSOLE;
00300 } else if (!strncasecmp(channel, "syslog", 6)) {
00301
00302
00303
00304
00305 facility = strchr(channel, '.');
00306 if (!facility++ || !facility) {
00307 facility = "local0";
00308 }
00309
00310 chan->facility = ast_syslog_facility(facility);
00311
00312 if (chan->facility < 0) {
00313 fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
00314 ast_free(chan);
00315 return NULL;
00316 }
00317
00318 chan->type = LOGTYPE_SYSLOG;
00319 ast_copy_string(chan->filename, channel, sizeof(chan->filename));
00320 openlog("asterisk", LOG_PID, chan->facility);
00321 } else {
00322 const char *log_dir_prefix = "";
00323 const char *log_dir_separator = "";
00324
00325 if (channel[0] != '/') {
00326 log_dir_prefix = ast_config_AST_LOG_DIR;
00327 log_dir_separator = "/";
00328 }
00329
00330 if (!ast_strlen_zero(hostname)) {
00331 snprintf(chan->filename, sizeof(chan->filename), "%s%s%s.%s",
00332 log_dir_prefix, log_dir_separator, channel, hostname);
00333 } else {
00334 snprintf(chan->filename, sizeof(chan->filename), "%s%s%s",
00335 log_dir_prefix, log_dir_separator, channel);
00336 }
00337
00338 if (!(chan->fileptr = fopen(chan->filename, "a"))) {
00339
00340
00341 ast_console_puts_mutable("ERROR: Unable to open log file '", __LOG_ERROR);
00342 ast_console_puts_mutable(chan->filename, __LOG_ERROR);
00343 ast_console_puts_mutable("': ", __LOG_ERROR);
00344 ast_console_puts_mutable(strerror(errno), __LOG_ERROR);
00345 ast_console_puts_mutable("'\n", __LOG_ERROR);
00346 ast_free(chan);
00347 return NULL;
00348 } else {
00349
00350 ast_localtime(&now, &tm, NULL);
00351 ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
00352
00353 fprintf(chan->fileptr, "[%s] Asterisk %s built by %s @ %s on a %s running %s on %s\n",
00354 datestring, ast_get_version(), ast_build_user, ast_build_hostname,
00355 ast_build_machine, ast_build_os, ast_build_date);
00356 fflush(chan->fileptr);
00357 }
00358 chan->type = LOGTYPE_FILE;
00359 }
00360 make_components(chan);
00361
00362 return chan;
00363 }
00364
00365 static void init_logger_chain(int locked, const char *altconf)
00366 {
00367 struct logchannel *chan;
00368 struct ast_config *cfg;
00369 struct ast_variable *var;
00370 const char *s;
00371 struct ast_flags config_flags = { 0 };
00372
00373 display_callids = 1;
00374
00375 if (!(cfg = ast_config_load2(S_OR(altconf, "logger.conf"), "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
00376 return;
00377 }
00378
00379
00380 if (!locked) {
00381 AST_RWLIST_WRLOCK(&logchannels);
00382 }
00383 while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list))) {
00384 ast_free(chan);
00385 }
00386 global_logmask = 0;
00387 if (!locked) {
00388 AST_RWLIST_UNLOCK(&logchannels);
00389 }
00390
00391 errno = 0;
00392
00393 closelog();
00394
00395
00396 if (!cfg) {
00397 if (errno) {
00398 fprintf(stderr, "Unable to open logger.conf: %s; default settings will be used.\n", strerror(errno));
00399 } else {
00400 fprintf(stderr, "Errors detected in logger.conf: see above; default settings will be used.\n");
00401 }
00402 if (!(chan = ast_calloc(1, sizeof(*chan)))) {
00403 return;
00404 }
00405 chan->type = LOGTYPE_CONSOLE;
00406 chan->logmask = __LOG_WARNING | __LOG_NOTICE | __LOG_ERROR;
00407 if (!locked) {
00408 AST_RWLIST_WRLOCK(&logchannels);
00409 }
00410 AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
00411 global_logmask |= chan->logmask;
00412 if (!locked) {
00413 AST_RWLIST_UNLOCK(&logchannels);
00414 }
00415 return;
00416 }
00417
00418 if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
00419 if (ast_true(s)) {
00420 if (gethostname(hostname, sizeof(hostname) - 1)) {
00421 ast_copy_string(hostname, "unknown", sizeof(hostname));
00422 fprintf(stderr, "What box has no hostname???\n");
00423 }
00424 } else
00425 hostname[0] = '\0';
00426 } else
00427 hostname[0] = '\0';
00428 if ((s = ast_variable_retrieve(cfg, "general", "display_callids"))) {
00429 display_callids = ast_true(s);
00430 }
00431 if ((s = ast_variable_retrieve(cfg, "general", "dateformat")))
00432 ast_copy_string(dateformat, s, sizeof(dateformat));
00433 else
00434 ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
00435 if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
00436 logfiles.queue_log = ast_true(s);
00437 }
00438 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_to_file"))) {
00439 logfiles.queue_log_to_file = ast_true(s);
00440 }
00441 if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name"))) {
00442 ast_copy_string(queue_log_name, s, sizeof(queue_log_name));
00443 }
00444 if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate"))) {
00445 ast_copy_string(exec_after_rotate, s, sizeof(exec_after_rotate));
00446 }
00447 if ((s = ast_variable_retrieve(cfg, "general", "rotatestrategy"))) {
00448 if (strcasecmp(s, "timestamp") == 0) {
00449 rotatestrategy = TIMESTAMP;
00450 } else if (strcasecmp(s, "rotate") == 0) {
00451 rotatestrategy = ROTATE;
00452 } else if (strcasecmp(s, "sequential") == 0) {
00453 rotatestrategy = SEQUENTIAL;
00454 } else {
00455 fprintf(stderr, "Unknown rotatestrategy: %s\n", s);
00456 }
00457 } else {
00458 if ((s = ast_variable_retrieve(cfg, "general", "rotatetimestamp"))) {
00459 rotatestrategy = ast_true(s) ? TIMESTAMP : SEQUENTIAL;
00460 fprintf(stderr, "rotatetimestamp option has been deprecated. Please use rotatestrategy instead.\n");
00461 }
00462 }
00463
00464 if (!locked) {
00465 AST_RWLIST_WRLOCK(&logchannels);
00466 }
00467 var = ast_variable_browse(cfg, "logfiles");
00468 for (; var; var = var->next) {
00469 if (!(chan = make_logchannel(var->name, var->value, var->lineno))) {
00470
00471
00472 ast_console_puts_mutable("ERROR: Unable to create log channel '", __LOG_ERROR);
00473 ast_console_puts_mutable(var->name, __LOG_ERROR);
00474 ast_console_puts_mutable("'\n", __LOG_ERROR);
00475 continue;
00476 }
00477 AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
00478 global_logmask |= chan->logmask;
00479 }
00480
00481 if (qlog) {
00482 fclose(qlog);
00483 qlog = NULL;
00484 }
00485
00486 if (!locked) {
00487 AST_RWLIST_UNLOCK(&logchannels);
00488 }
00489
00490 ast_config_destroy(cfg);
00491 }
00492
00493 void ast_child_verbose(int level, const char *fmt, ...)
00494 {
00495 char *msg = NULL, *emsg = NULL, *sptr, *eptr;
00496 va_list ap, aq;
00497 int size;
00498
00499 va_start(ap, fmt);
00500 va_copy(aq, ap);
00501 if ((size = vsnprintf(msg, 0, fmt, ap)) < 0) {
00502 va_end(ap);
00503 va_end(aq);
00504 return;
00505 }
00506 va_end(ap);
00507
00508 if (!(msg = ast_malloc(size + 1))) {
00509 va_end(aq);
00510 return;
00511 }
00512
00513 vsnprintf(msg, size + 1, fmt, aq);
00514 va_end(aq);
00515
00516 if (!(emsg = ast_malloc(size * 2 + 1))) {
00517 ast_free(msg);
00518 return;
00519 }
00520
00521 for (sptr = msg, eptr = emsg; ; sptr++) {
00522 if (*sptr == '"') {
00523 *eptr++ = '\\';
00524 }
00525 *eptr++ = *sptr;
00526 if (*sptr == '\0') {
00527 break;
00528 }
00529 }
00530 ast_free(msg);
00531
00532 fprintf(stdout, "verbose \"%s\" %d\n", emsg, level);
00533 fflush(stdout);
00534 ast_free(emsg);
00535 }
00536
00537 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
00538 {
00539 va_list ap;
00540 struct timeval tv;
00541 struct ast_tm tm;
00542 char qlog_msg[8192];
00543 int qlog_len;
00544 char time_str[30];
00545
00546 if (!logger_initialized) {
00547
00548 return;
00549 }
00550 if (!queuelog_init) {
00551 AST_RWLIST_WRLOCK(&logchannels);
00552 if (!queuelog_init) {
00553
00554
00555
00556
00557
00558 logger_queue_init();
00559 queuelog_init = 1;
00560 AST_RWLIST_UNLOCK(&logchannels);
00561 ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
00562 } else {
00563 AST_RWLIST_UNLOCK(&logchannels);
00564 }
00565 }
00566
00567 if (ast_check_realtime("queue_log")) {
00568 tv = ast_tvnow();
00569 ast_localtime(&tv, &tm, NULL);
00570 ast_strftime(time_str, sizeof(time_str), "%F %T.%6q", &tm);
00571 va_start(ap, fmt);
00572 vsnprintf(qlog_msg, sizeof(qlog_msg), fmt, ap);
00573 va_end(ap);
00574 if (logfiles.queue_adaptive_realtime) {
00575 AST_DECLARE_APP_ARGS(args,
00576 AST_APP_ARG(data)[5];
00577 );
00578 AST_NONSTANDARD_APP_ARGS(args, qlog_msg, '|');
00579
00580 ast_realtime_require_field("queue_log",
00581 "data1", RQ_CHAR, strlen(S_OR(args.data[0], "")),
00582 "data2", RQ_CHAR, strlen(S_OR(args.data[1], "")),
00583 "data3", RQ_CHAR, strlen(S_OR(args.data[2], "")),
00584 "data4", RQ_CHAR, strlen(S_OR(args.data[3], "")),
00585 "data5", RQ_CHAR, strlen(S_OR(args.data[4], "")),
00586 SENTINEL);
00587
00588
00589 ast_store_realtime("queue_log", "time", time_str,
00590 "callid", callid,
00591 "queuename", queuename,
00592 "agent", agent,
00593 "event", event,
00594 "data1", S_OR(args.data[0], ""),
00595 "data2", S_OR(args.data[1], ""),
00596 "data3", S_OR(args.data[2], ""),
00597 "data4", S_OR(args.data[3], ""),
00598 "data5", S_OR(args.data[4], ""),
00599 SENTINEL);
00600 } else {
00601 ast_store_realtime("queue_log", "time", time_str,
00602 "callid", callid,
00603 "queuename", queuename,
00604 "agent", agent,
00605 "event", event,
00606 "data", qlog_msg,
00607 SENTINEL);
00608 }
00609
00610 if (!logfiles.queue_log_to_file) {
00611 return;
00612 }
00613 }
00614
00615 if (qlog) {
00616 va_start(ap, fmt);
00617 qlog_len = snprintf(qlog_msg, sizeof(qlog_msg), "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
00618 vsnprintf(qlog_msg + qlog_len, sizeof(qlog_msg) - qlog_len, fmt, ap);
00619 va_end(ap);
00620 AST_RWLIST_RDLOCK(&logchannels);
00621 if (qlog) {
00622 fprintf(qlog, "%s\n", qlog_msg);
00623 fflush(qlog);
00624 }
00625 AST_RWLIST_UNLOCK(&logchannels);
00626 }
00627 }
00628
00629 static int rotate_file(const char *filename)
00630 {
00631 char old[PATH_MAX];
00632 char new[PATH_MAX];
00633 int x, y, which, found, res = 0, fd;
00634 char *suffixes[4] = { "", ".gz", ".bz2", ".Z" };
00635
00636 switch (rotatestrategy) {
00637 case SEQUENTIAL:
00638 for (x = 0; ; x++) {
00639 snprintf(new, sizeof(new), "%s.%d", filename, x);
00640 fd = open(new, O_RDONLY);
00641 if (fd > -1)
00642 close(fd);
00643 else
00644 break;
00645 }
00646 if (rename(filename, new)) {
00647 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
00648 res = -1;
00649 } else {
00650 filename = new;
00651 }
00652 break;
00653 case TIMESTAMP:
00654 snprintf(new, sizeof(new), "%s.%ld", filename, (long)time(NULL));
00655 if (rename(filename, new)) {
00656 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
00657 res = -1;
00658 } else {
00659 filename = new;
00660 }
00661 break;
00662 case ROTATE:
00663
00664 for (x = 0; ; x++) {
00665 found = 0;
00666 for (which = 0; which < ARRAY_LEN(suffixes); which++) {
00667 snprintf(new, sizeof(new), "%s.%d%s", filename, x, suffixes[which]);
00668 fd = open(new, O_RDONLY);
00669 if (fd > -1) {
00670 close(fd);
00671 found = 1;
00672 break;
00673 }
00674 }
00675 if (!found) {
00676 break;
00677 }
00678 }
00679
00680
00681 for (y = x; y > 0; y--) {
00682 for (which = 0; which < ARRAY_LEN(suffixes); which++) {
00683 snprintf(old, sizeof(old), "%s.%d%s", filename, y - 1, suffixes[which]);
00684 fd = open(old, O_RDONLY);
00685 if (fd > -1) {
00686
00687 close(fd);
00688 snprintf(new, sizeof(new), "%s.%d%s", filename, y, suffixes[which]);
00689 if (rename(old, new)) {
00690 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
00691 res = -1;
00692 }
00693 break;
00694 }
00695 }
00696 }
00697
00698
00699 snprintf(new, sizeof(new), "%s.0", filename);
00700 if (rename(filename, new)) {
00701 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
00702 res = -1;
00703 } else {
00704 filename = new;
00705 }
00706 }
00707
00708 if (!ast_strlen_zero(exec_after_rotate)) {
00709 struct ast_channel *c = ast_dummy_channel_alloc();
00710 char buf[512];
00711
00712 pbx_builtin_setvar_helper(c, "filename", filename);
00713 pbx_substitute_variables_helper(c, exec_after_rotate, buf, sizeof(buf));
00714 if (c) {
00715 c = ast_channel_unref(c);
00716 }
00717 if (ast_safe_system(buf) == -1) {
00718 ast_log(LOG_WARNING, "error executing '%s'\n", buf);
00719 }
00720 }
00721 return res;
00722 }
00723
00724
00725
00726
00727
00728
00729
00730 static int logger_queue_rt_start(void)
00731 {
00732 if (ast_check_realtime("queue_log")) {
00733 if (!ast_realtime_require_field("queue_log",
00734 "time", RQ_DATETIME, 26,
00735 "data1", RQ_CHAR, 20,
00736 "data2", RQ_CHAR, 20,
00737 "data3", RQ_CHAR, 20,
00738 "data4", RQ_CHAR, 20,
00739 "data5", RQ_CHAR, 20,
00740 SENTINEL)) {
00741 logfiles.queue_adaptive_realtime = 1;
00742 } else {
00743 logfiles.queue_adaptive_realtime = 0;
00744 }
00745
00746 if (!logfiles.queue_log_to_file) {
00747
00748 return 1;
00749 }
00750 }
00751 return 0;
00752 }
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765 static int logger_queue_restart(int queue_rotate)
00766 {
00767 int res = 0;
00768 char qfname[PATH_MAX];
00769
00770 if (logger_queue_rt_start()) {
00771 return res;
00772 }
00773
00774 snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
00775 if (qlog) {
00776
00777 fclose(qlog);
00778 qlog = NULL;
00779 }
00780 if (queue_rotate) {
00781 rotate_file(qfname);
00782 }
00783
00784
00785 qlog = fopen(qfname, "a");
00786 if (!qlog) {
00787 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
00788 res = -1;
00789 }
00790 return res;
00791 }
00792
00793 static int reload_logger(int rotate, const char *altconf)
00794 {
00795 int queue_rotate = rotate;
00796 struct logchannel *f;
00797 int res = 0;
00798
00799 AST_RWLIST_WRLOCK(&logchannels);
00800
00801 if (qlog) {
00802 if (rotate < 0) {
00803
00804 if (ftello(qlog) > 0x40000000) {
00805 fclose(qlog);
00806 qlog = NULL;
00807 } else {
00808 queue_rotate = 0;
00809 }
00810 } else {
00811 fclose(qlog);
00812 qlog = NULL;
00813 }
00814 } else {
00815 queue_rotate = 0;
00816 }
00817
00818 ast_mkdir(ast_config_AST_LOG_DIR, 0777);
00819
00820 AST_RWLIST_TRAVERSE(&logchannels, f, list) {
00821 if (f->disabled) {
00822 f->disabled = 0;
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
00834 }
00835 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00836 int rotate_this = 0;
00837 if (ftello(f->fileptr) > 0x40000000) {
00838
00839 rotate_this = 1;
00840 }
00841 fclose(f->fileptr);
00842 f->fileptr = NULL;
00843 if (rotate || rotate_this) {
00844 rotate_file(f->filename);
00845 }
00846 }
00847 }
00848
00849 filesize_reload_needed = 0;
00850
00851 init_logger_chain(1 , altconf);
00852
00853 ast_unload_realtime("queue_log");
00854 if (logfiles.queue_log) {
00855 res = logger_queue_restart(queue_rotate);
00856 AST_RWLIST_UNLOCK(&logchannels);
00857 ast_verb_update();
00858 ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
00859 ast_verb(1, "Asterisk Queue Logger restarted\n");
00860 } else {
00861 AST_RWLIST_UNLOCK(&logchannels);
00862 ast_verb_update();
00863 }
00864
00865 return res;
00866 }
00867
00868
00869
00870 int logger_reload(void)
00871 {
00872 if (reload_logger(0, NULL)) {
00873 return RESULT_FAILURE;
00874 }
00875 return RESULT_SUCCESS;
00876 }
00877
00878 static char *handle_logger_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00879 {
00880 switch (cmd) {
00881 case CLI_INIT:
00882 e->command = "logger reload";
00883 e->usage =
00884 "Usage: logger reload [<alt-conf>]\n"
00885 " Reloads the logger subsystem state. Use after restarting syslogd(8) if you are using syslog logging.\n";
00886 return NULL;
00887 case CLI_GENERATE:
00888 return NULL;
00889 }
00890 if (reload_logger(0, a->argc == 3 ? a->argv[2] : NULL)) {
00891 ast_cli(a->fd, "Failed to reload the logger\n");
00892 return CLI_FAILURE;
00893 }
00894 return CLI_SUCCESS;
00895 }
00896
00897 static char *handle_logger_rotate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00898 {
00899 switch (cmd) {
00900 case CLI_INIT:
00901 e->command = "logger rotate";
00902 e->usage =
00903 "Usage: logger rotate\n"
00904 " Rotates and Reopens the log files.\n";
00905 return NULL;
00906 case CLI_GENERATE:
00907 return NULL;
00908 }
00909 if (reload_logger(1, NULL)) {
00910 ast_cli(a->fd, "Failed to reload the logger and rotate log files\n");
00911 return CLI_FAILURE;
00912 }
00913 return CLI_SUCCESS;
00914 }
00915
00916 static char *handle_logger_set_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00917 {
00918 int x;
00919 int state;
00920 int level = -1;
00921
00922 switch (cmd) {
00923 case CLI_INIT:
00924 e->command = "logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}";
00925 e->usage =
00926 "Usage: logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}\n"
00927 " Set a specific log level to enabled/disabled for this console.\n";
00928 return NULL;
00929 case CLI_GENERATE:
00930 return NULL;
00931 }
00932
00933 if (a->argc < 5)
00934 return CLI_SHOWUSAGE;
00935
00936 AST_RWLIST_WRLOCK(&logchannels);
00937
00938 for (x = 0; x < ARRAY_LEN(levels); x++) {
00939 if (levels[x] && !strcasecmp(a->argv[3], levels[x])) {
00940 level = x;
00941 break;
00942 }
00943 }
00944
00945 AST_RWLIST_UNLOCK(&logchannels);
00946
00947 state = ast_true(a->argv[4]) ? 1 : 0;
00948
00949 if (level != -1) {
00950 ast_console_toggle_loglevel(a->fd, level, state);
00951 ast_cli(a->fd, "Logger status for '%s' has been set to '%s'.\n", levels[level], state ? "on" : "off");
00952 } else
00953 return CLI_SHOWUSAGE;
00954
00955 return CLI_SUCCESS;
00956 }
00957
00958
00959 static char *handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00960 {
00961 #define FORMATL "%-35.35s %-8.8s %-9.9s "
00962 struct logchannel *chan;
00963 switch (cmd) {
00964 case CLI_INIT:
00965 e->command = "logger show channels";
00966 e->usage =
00967 "Usage: logger show channels\n"
00968 " List configured logger channels.\n";
00969 return NULL;
00970 case CLI_GENERATE:
00971 return NULL;
00972 }
00973 ast_cli(a->fd, FORMATL, "Channel", "Type", "Status");
00974 ast_cli(a->fd, "Configuration\n");
00975 ast_cli(a->fd, FORMATL, "-------", "----", "------");
00976 ast_cli(a->fd, "-------------\n");
00977 AST_RWLIST_RDLOCK(&logchannels);
00978 AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
00979 unsigned int level;
00980
00981 ast_cli(a->fd, FORMATL, chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" : (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"),
00982 chan->disabled ? "Disabled" : "Enabled");
00983 ast_cli(a->fd, " - ");
00984 for (level = 0; level < ARRAY_LEN(levels); level++) {
00985 if ((chan->logmask & (1 << level)) && levels[level]) {
00986 ast_cli(a->fd, "%s ", levels[level]);
00987 }
00988 }
00989 ast_cli(a->fd, "\n");
00990 }
00991 AST_RWLIST_UNLOCK(&logchannels);
00992 ast_cli(a->fd, "\n");
00993
00994 return CLI_SUCCESS;
00995 }
00996
00997 struct verb {
00998 void (*verboser)(const char *string);
00999 AST_LIST_ENTRY(verb) list;
01000 };
01001
01002 static AST_RWLIST_HEAD_STATIC(verbosers, verb);
01003
01004 static struct ast_cli_entry cli_logger[] = {
01005 AST_CLI_DEFINE(handle_logger_show_channels, "List configured log channels"),
01006 AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"),
01007 AST_CLI_DEFINE(handle_logger_rotate, "Rotates and reopens the log files"),
01008 AST_CLI_DEFINE(handle_logger_set_level, "Enables/Disables a specific logging level for this console"),
01009 };
01010
01011 static void _handle_SIGXFSZ(int sig)
01012 {
01013
01014 filesize_reload_needed = 1;
01015 }
01016
01017 static struct sigaction handle_SIGXFSZ = {
01018 .sa_handler = _handle_SIGXFSZ,
01019 .sa_flags = SA_RESTART,
01020 };
01021
01022 static void ast_log_vsyslog(struct logmsg *msg)
01023 {
01024 char buf[BUFSIZ];
01025 int syslog_level = ast_syslog_priority_from_loglevel(msg->level);
01026 char call_identifier_str[13];
01027
01028 if (msg->callid) {
01029 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", msg->callid->call_identifier);
01030 } else {
01031 call_identifier_str[0] = '\0';
01032 }
01033
01034 if (syslog_level < 0) {
01035
01036 fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", msg->level);
01037 return;
01038 }
01039
01040 snprintf(buf, sizeof(buf), "%s[%d]%s: %s:%d in %s: %s",
01041 levels[msg->level], msg->lwp, call_identifier_str, msg->file, msg->line, msg->function, msg->message);
01042
01043 term_strip(buf, buf, strlen(buf) + 1);
01044 syslog(syslog_level, "%s", buf);
01045 }
01046
01047
01048 static void logger_print_normal(struct logmsg *logmsg)
01049 {
01050 struct logchannel *chan = NULL;
01051 char buf[BUFSIZ];
01052 struct verb *v = NULL;
01053 int level = 0;
01054
01055 if (logmsg->level == __LOG_VERBOSE) {
01056 char *tmpmsg = ast_strdupa(logmsg->message + 1);
01057
01058 level = VERBOSE_MAGIC2LEVEL(logmsg->message);
01059
01060
01061 AST_RWLIST_RDLOCK(&verbosers);
01062 AST_RWLIST_TRAVERSE(&verbosers, v, list)
01063 v->verboser(logmsg->message);
01064 AST_RWLIST_UNLOCK(&verbosers);
01065 ast_string_field_set(logmsg, message, tmpmsg);
01066 }
01067
01068 AST_RWLIST_RDLOCK(&logchannels);
01069
01070 if (!AST_RWLIST_EMPTY(&logchannels)) {
01071 AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
01072 char call_identifier_str[13];
01073
01074 if (logmsg->callid) {
01075 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", logmsg->callid->call_identifier);
01076 } else {
01077 call_identifier_str[0] = '\0';
01078 }
01079
01080
01081
01082 if (chan->disabled) {
01083 continue;
01084 }
01085 if (logmsg->level == __LOG_VERBOSE
01086 && (((chan->verbosity < 0) ? option_verbose : chan->verbosity)) < level) {
01087 continue;
01088 }
01089
01090
01091 if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << logmsg->level))) {
01092 ast_log_vsyslog(logmsg);
01093
01094 } else if (chan->type == LOGTYPE_CONSOLE && (chan->logmask & (1 << logmsg->level))) {
01095 char linestr[128];
01096 char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
01097
01098
01099 if (logmsg->level == __LOG_VERBOSE)
01100 continue;
01101
01102
01103 snprintf(linestr, sizeof(linestr), "%d", logmsg->line);
01104
01105 snprintf(buf, sizeof(buf), "[%s] %s[%d]%s: %s:%s %s: %s",
01106 logmsg->date,
01107 term_color(tmp1, logmsg->level_name, colors[logmsg->level], 0, sizeof(tmp1)),
01108 logmsg->lwp,
01109 call_identifier_str,
01110 term_color(tmp2, logmsg->file, COLOR_BRWHITE, 0, sizeof(tmp2)),
01111 term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
01112 term_color(tmp4, logmsg->function, COLOR_BRWHITE, 0, sizeof(tmp4)),
01113 logmsg->message);
01114
01115 ast_console_puts_mutable(buf, logmsg->level);
01116
01117 } else if (chan->type == LOGTYPE_FILE && (chan->logmask & (1 << logmsg->level))) {
01118 int res = 0;
01119
01120
01121 if (!chan->fileptr) {
01122 continue;
01123 }
01124
01125
01126 res = fprintf(chan->fileptr, "[%s] %s[%d]%s %s: %s",
01127 logmsg->date, logmsg->level_name, logmsg->lwp, call_identifier_str,
01128 logmsg->file, term_strip(buf, logmsg->message, BUFSIZ));
01129 if (res <= 0 && !ast_strlen_zero(logmsg->message)) {
01130 fprintf(stderr, "**** Asterisk Logging Error: ***********\n");
01131 if (errno == ENOMEM || errno == ENOSPC)
01132 fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
01133 else
01134 fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
01146 chan->disabled = 1;
01147 } else if (res > 0) {
01148 fflush(chan->fileptr);
01149 }
01150 }
01151 }
01152 } else if (logmsg->level != __LOG_VERBOSE) {
01153 fputs(logmsg->message, stdout);
01154 }
01155
01156 AST_RWLIST_UNLOCK(&logchannels);
01157
01158
01159 if (filesize_reload_needed) {
01160 reload_logger(-1, NULL);
01161 ast_verb(1, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
01162 }
01163
01164 return;
01165 }
01166
01167
01168 static void *logger_thread(void *data)
01169 {
01170 struct logmsg *next = NULL, *msg = NULL;
01171
01172 for (;;) {
01173
01174 AST_LIST_LOCK(&logmsgs);
01175 if (AST_LIST_EMPTY(&logmsgs)) {
01176 if (close_logger_thread) {
01177 AST_LIST_UNLOCK(&logmsgs);
01178 break;
01179 } else {
01180 ast_cond_wait(&logcond, &logmsgs.lock);
01181 }
01182 }
01183 next = AST_LIST_FIRST(&logmsgs);
01184 AST_LIST_HEAD_INIT_NOLOCK(&logmsgs);
01185 AST_LIST_UNLOCK(&logmsgs);
01186
01187
01188 while ((msg = next)) {
01189
01190 next = AST_LIST_NEXT(msg, list);
01191
01192
01193 logger_print_normal(msg);
01194
01195
01196 logmsg_free(msg);
01197 }
01198 }
01199
01200 return NULL;
01201 }
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211 static void logger_queue_init(void)
01212 {
01213 ast_unload_realtime("queue_log");
01214 if (logfiles.queue_log) {
01215 char qfname[PATH_MAX];
01216
01217 if (logger_queue_rt_start()) {
01218 return;
01219 }
01220
01221
01222 snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR,
01223 queue_log_name);
01224 if (qlog) {
01225
01226 fclose(qlog);
01227 }
01228 qlog = fopen(qfname, "a");
01229 if (!qlog) {
01230 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
01231 }
01232 }
01233 }
01234
01235 int init_logger(void)
01236 {
01237
01238 sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
01239
01240
01241
01242
01243
01244
01245
01246 ast_mutex_destroy(&logmsgs.lock);
01247 ast_mutex_init(&logmsgs.lock);
01248 ast_cond_init(&logcond, NULL);
01249
01250
01251 if (ast_pthread_create(&logthread, NULL, logger_thread, NULL) < 0) {
01252 ast_cond_destroy(&logcond);
01253 return -1;
01254 }
01255
01256
01257 ast_cli_register_multiple(cli_logger, ARRAY_LEN(cli_logger));
01258
01259 ast_mkdir(ast_config_AST_LOG_DIR, 0777);
01260
01261
01262 init_logger_chain(0 , NULL);
01263 ast_verb_update();
01264 logger_initialized = 1;
01265
01266 return 0;
01267 }
01268
01269 void close_logger(void)
01270 {
01271 struct logchannel *f = NULL;
01272 struct verb *cur = NULL;
01273
01274 ast_cli_unregister_multiple(cli_logger, ARRAY_LEN(cli_logger));
01275
01276 logger_initialized = 0;
01277
01278
01279 AST_LIST_LOCK(&logmsgs);
01280 close_logger_thread = 1;
01281 ast_cond_signal(&logcond);
01282 AST_LIST_UNLOCK(&logmsgs);
01283
01284 if (logthread != AST_PTHREADT_NULL)
01285 pthread_join(logthread, NULL);
01286
01287 AST_RWLIST_WRLOCK(&verbosers);
01288 while ((cur = AST_LIST_REMOVE_HEAD(&verbosers, list))) {
01289 ast_free(cur);
01290 }
01291 AST_RWLIST_UNLOCK(&verbosers);
01292
01293 AST_RWLIST_WRLOCK(&logchannels);
01294
01295 if (qlog) {
01296 fclose(qlog);
01297 qlog = NULL;
01298 }
01299
01300 while ((f = AST_LIST_REMOVE_HEAD(&logchannels, list))) {
01301 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
01302 fclose(f->fileptr);
01303 f->fileptr = NULL;
01304 }
01305 ast_free(f);
01306 }
01307
01308 closelog();
01309
01310 AST_RWLIST_UNLOCK(&logchannels);
01311 }
01312
01313 void ast_callid_strnprint(char *buffer, size_t buffer_size, struct ast_callid *callid)
01314 {
01315 snprintf(buffer, buffer_size, "[C-%08x]", callid->call_identifier);
01316 }
01317
01318 struct ast_callid *ast_create_callid(void)
01319 {
01320 struct ast_callid *call;
01321
01322 call = ao2_alloc_options(sizeof(*call), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
01323 if (!call) {
01324 ast_log(LOG_ERROR, "Could not allocate callid struct.\n");
01325 return NULL;
01326 }
01327
01328 call->call_identifier = ast_atomic_fetchadd_int(&next_unique_callid, +1);
01329 #ifdef TEST_FRAMEWORK
01330 ast_debug(3, "CALL_ID [C-%08x] created by thread.\n", call->call_identifier);
01331 #endif
01332 return call;
01333 }
01334
01335 struct ast_callid *ast_read_threadstorage_callid(void)
01336 {
01337 struct ast_callid **callid;
01338
01339 callid = ast_threadstorage_get(&unique_callid, sizeof(*callid));
01340 if (callid && *callid) {
01341 ast_callid_ref(*callid);
01342 return *callid;
01343 }
01344
01345 return NULL;
01346
01347 }
01348
01349 int ast_callid_threadassoc_change(struct ast_callid *callid)
01350 {
01351 struct ast_callid **id = ast_threadstorage_get(&unique_callid, sizeof(*id));
01352
01353 if (!id) {
01354 ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
01355 return -1;
01356 }
01357
01358 if (*id && (*id != callid)) {
01359 #ifdef TEST_FRAMEWORK
01360 ast_debug(3, "CALL_ID [C-%08x] being removed from thread.\n", (*id)->call_identifier);
01361 #endif
01362 *id = ast_callid_unref(*id);
01363 *id = NULL;
01364 }
01365
01366 if (!(*id) && callid) {
01367
01368 ast_callid_ref(callid);
01369 *id = callid;
01370 #ifdef TEST_FRAMEWORK
01371 ast_debug(3, "CALL_ID [C-%08x] bound to thread.\n", callid->call_identifier);
01372 #endif
01373 }
01374
01375 return 0;
01376 }
01377
01378 int ast_callid_threadassoc_add(struct ast_callid *callid)
01379 {
01380 struct ast_callid **pointing;
01381
01382 pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
01383 if (!(pointing)) {
01384 ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
01385 return -1;
01386 }
01387
01388 if (!(*pointing)) {
01389
01390 ast_callid_ref(callid);
01391 *pointing = callid;
01392 #ifdef TEST_FRAMEWORK
01393 ast_debug(3, "CALL_ID [C-%08x] bound to thread.\n", callid->call_identifier);
01394 #endif
01395 } else {
01396 ast_log(LOG_WARNING, "Attempted to ast_callid_threadassoc_add on thread already associated with a callid.\n");
01397 return 1;
01398 }
01399
01400 return 0;
01401 }
01402
01403 int ast_callid_threadassoc_remove(void)
01404 {
01405 struct ast_callid **pointing;
01406
01407 pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
01408 if (!(pointing)) {
01409 ast_log(LOG_ERROR, "Failed to allocate thread storage.\n");
01410 return -1;
01411 }
01412
01413 if (!(*pointing)) {
01414 ast_log(LOG_ERROR, "Tried to clean callid thread storage with no callid in thread storage.\n");
01415 return -1;
01416 } else {
01417 #ifdef TEST_FRAMEWORK
01418 ast_debug(3, "Call_ID [C-%08x] being removed from thread.\n", (*pointing)->call_identifier);
01419 #endif
01420 *pointing = ast_callid_unref(*pointing);
01421 return 0;
01422 }
01423 }
01424
01425 int ast_callid_threadstorage_auto(struct ast_callid **callid)
01426 {
01427 struct ast_callid *tmp;
01428
01429
01430 tmp = ast_read_threadstorage_callid();
01431 if (tmp) {
01432 *callid = tmp;
01433 return 0;
01434 }
01435
01436
01437 tmp = ast_create_callid();
01438 if (tmp) {
01439 ast_callid_threadassoc_add(tmp);
01440 *callid = tmp;
01441 return 1;
01442 }
01443
01444
01445 return -1;
01446 }
01447
01448 void ast_callid_threadstorage_auto_clean(struct ast_callid *callid, int callid_created)
01449 {
01450 if (callid) {
01451
01452 if (callid_created == 1) {
01453 ast_callid_threadassoc_remove();
01454 }
01455 callid = ast_callid_unref(callid);
01456 }
01457 }
01458
01459
01460
01461
01462
01463 static void unique_callid_cleanup(void *data)
01464 {
01465 struct ast_callid **callid = data;
01466
01467 if (*callid) {
01468 ast_callid_unref(*callid);
01469 }
01470
01471 ast_free(data);
01472 }
01473
01474
01475
01476
01477 static void __attribute__((format(printf, 6, 0))) ast_log_full(int level, const char *file, int line, const char *function, struct ast_callid *callid, const char *fmt, va_list ap)
01478 {
01479 struct logmsg *logmsg = NULL;
01480 struct ast_str *buf = NULL;
01481 struct ast_tm tm;
01482 struct timeval now = ast_tvnow();
01483 int res = 0;
01484 char datestring[256];
01485
01486 if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE)))
01487 return;
01488
01489 if (level != __LOG_VERBOSE && AST_RWLIST_EMPTY(&logchannels)) {
01490
01491
01492
01493
01494 int result;
01495 result = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
01496 if (result != AST_DYNSTR_BUILD_FAILED) {
01497 term_filter_escapes(ast_str_buffer(buf));
01498 fputs(ast_str_buffer(buf), stdout);
01499 }
01500 return;
01501 }
01502
01503
01504 if (level != __LOG_VERBOSE && !(global_logmask & (1 << level)))
01505 return;
01506
01507
01508 res = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
01509
01510
01511 if (res == AST_DYNSTR_BUILD_FAILED)
01512 return;
01513
01514
01515 if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128)))
01516 return;
01517
01518
01519 ast_string_field_set(logmsg, message, ast_str_buffer(buf));
01520
01521
01522 if (level == __LOG_VERBOSE) {
01523 logmsg->type = LOGMSG_VERBOSE;
01524 } else {
01525 logmsg->type = LOGMSG_NORMAL;
01526 }
01527
01528 if (display_callids && callid) {
01529 logmsg->callid = ast_callid_ref(callid);
01530
01531 }
01532
01533
01534 ast_localtime(&now, &tm, NULL);
01535 ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
01536 ast_string_field_set(logmsg, date, datestring);
01537
01538
01539 logmsg->level = level;
01540 logmsg->line = line;
01541 ast_string_field_set(logmsg, level_name, levels[level]);
01542 ast_string_field_set(logmsg, file, file);
01543 ast_string_field_set(logmsg, function, function);
01544 logmsg->lwp = ast_get_tid();
01545
01546
01547 if (logthread != AST_PTHREADT_NULL) {
01548 AST_LIST_LOCK(&logmsgs);
01549 if (close_logger_thread) {
01550
01551 logmsg_free(logmsg);
01552 } else {
01553 AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list);
01554 ast_cond_signal(&logcond);
01555 }
01556 AST_LIST_UNLOCK(&logmsgs);
01557 } else {
01558 logger_print_normal(logmsg);
01559 logmsg_free(logmsg);
01560 }
01561 }
01562
01563 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
01564 {
01565 struct ast_callid *callid;
01566 va_list ap;
01567
01568 callid = ast_read_threadstorage_callid();
01569
01570 va_start(ap, fmt);
01571 if (level == __LOG_VERBOSE) {
01572 __ast_verbose_ap(file, line, function, 0, callid, fmt, ap);
01573 } else {
01574 ast_log_full(level, file, line, function, callid, fmt, ap);
01575 }
01576 va_end(ap);
01577
01578 if (callid) {
01579 ast_callid_unref(callid);
01580 }
01581 }
01582
01583 void ast_log_callid(int level, const char *file, int line, const char *function, struct ast_callid *callid, const char *fmt, ...)
01584 {
01585 va_list ap;
01586 va_start(ap, fmt);
01587 ast_log_full(level, file, line, function, callid, fmt, ap);
01588 va_end(ap);
01589 }
01590
01591 #ifdef HAVE_BKTR
01592
01593 struct ast_bt *ast_bt_create(void)
01594 {
01595 struct ast_bt *bt = ast_calloc(1, sizeof(*bt));
01596 if (!bt) {
01597 ast_log(LOG_ERROR, "Unable to allocate memory for backtrace structure!\n");
01598 return NULL;
01599 }
01600
01601 bt->alloced = 1;
01602
01603 ast_bt_get_addresses(bt);
01604
01605 return bt;
01606 }
01607
01608 int ast_bt_get_addresses(struct ast_bt *bt)
01609 {
01610 bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES);
01611
01612 return 0;
01613 }
01614
01615 void *ast_bt_destroy(struct ast_bt *bt)
01616 {
01617 if (bt->alloced) {
01618 ast_free(bt);
01619 }
01620
01621 return NULL;
01622 }
01623
01624 char **ast_bt_get_symbols(void **addresses, size_t num_frames)
01625 {
01626 char **strings;
01627 #if defined(BETTER_BACKTRACES)
01628 int stackfr;
01629 bfd *bfdobj;
01630 Dl_info dli;
01631 long allocsize;
01632 asymbol **syms = NULL;
01633 bfd_vma offset;
01634 const char *lastslash;
01635 asection *section;
01636 const char *file, *func;
01637 unsigned int line;
01638 char address_str[128];
01639 char msg[1024];
01640 size_t strings_size;
01641 size_t *eachlen;
01642 #endif
01643
01644 #if defined(BETTER_BACKTRACES)
01645 strings_size = num_frames * sizeof(*strings);
01646
01647 eachlen = ast_calloc(num_frames, sizeof(*eachlen));
01648 strings = ast_std_calloc(num_frames, sizeof(*strings));
01649 if (!eachlen || !strings) {
01650 ast_free(eachlen);
01651 ast_std_free(strings);
01652 return NULL;
01653 }
01654
01655 for (stackfr = 0; stackfr < num_frames; stackfr++) {
01656 int found = 0, symbolcount;
01657
01658 msg[0] = '\0';
01659
01660 if (!dladdr(addresses[stackfr], &dli)) {
01661 continue;
01662 }
01663
01664 if (strcmp(dli.dli_fname, "asterisk") == 0) {
01665 char asteriskpath[256];
01666
01667 if (!(dli.dli_fname = ast_utils_which("asterisk", asteriskpath, sizeof(asteriskpath)))) {
01668
01669 ast_debug(1, "Failed to find asterisk binary for debug symbols.\n");
01670 dli.dli_fname = "asterisk";
01671 }
01672 }
01673
01674 lastslash = strrchr(dli.dli_fname, '/');
01675 if ((bfdobj = bfd_openr(dli.dli_fname, NULL)) &&
01676 bfd_check_format(bfdobj, bfd_object) &&
01677 (allocsize = bfd_get_symtab_upper_bound(bfdobj)) > 0 &&
01678 (syms = ast_malloc(allocsize)) &&
01679 (symbolcount = bfd_canonicalize_symtab(bfdobj, syms))) {
01680
01681 if (bfdobj->flags & DYNAMIC) {
01682 offset = addresses[stackfr] - dli.dli_fbase;
01683 } else {
01684 offset = addresses[stackfr] - (void *) 0;
01685 }
01686
01687 for (section = bfdobj->sections; section; section = section->next) {
01688 if (!bfd_get_section_flags(bfdobj, section) & SEC_ALLOC ||
01689 section->vma > offset ||
01690 section->size + section->vma < offset) {
01691 continue;
01692 }
01693
01694 if (!bfd_find_nearest_line(bfdobj, section, syms, offset - section->vma, &file, &func, &line)) {
01695 continue;
01696 }
01697
01698
01699 file = file ? file : "";
01700
01701
01702 found++;
01703 if ((lastslash = strrchr(file, '/'))) {
01704 const char *prevslash;
01705
01706 for (prevslash = lastslash - 1; *prevslash != '/' && prevslash >= file; prevslash--) {
01707 }
01708 if (prevslash >= file) {
01709 lastslash = prevslash;
01710 }
01711 }
01712 if (dli.dli_saddr == NULL) {
01713 address_str[0] = '\0';
01714 } else {
01715 snprintf(address_str, sizeof(address_str), " (%p+%lX)",
01716 dli.dli_saddr,
01717 (unsigned long) (addresses[stackfr] - dli.dli_saddr));
01718 }
01719 snprintf(msg, sizeof(msg), "%s:%u %s()%s",
01720 lastslash ? lastslash + 1 : file, line,
01721 S_OR(func, "???"),
01722 address_str);
01723
01724 break;
01725 }
01726 }
01727 if (bfdobj) {
01728 bfd_close(bfdobj);
01729 ast_free(syms);
01730 }
01731
01732
01733 if (!found) {
01734 if (dli.dli_saddr == NULL) {
01735 address_str[0] = '\0';
01736 } else {
01737 snprintf(address_str, sizeof(address_str), " (%p+%lX)",
01738 dli.dli_saddr,
01739 (unsigned long) (addresses[stackfr] - dli.dli_saddr));
01740 }
01741 snprintf(msg, sizeof(msg), "%s %s()%s",
01742 lastslash ? lastslash + 1 : dli.dli_fname,
01743 S_OR(dli.dli_sname, "<unknown>"),
01744 address_str);
01745 }
01746
01747 if (!ast_strlen_zero(msg)) {
01748 char **tmp;
01749
01750 eachlen[stackfr] = strlen(msg) + 1;
01751 if (!(tmp = ast_std_realloc(strings, strings_size + eachlen[stackfr]))) {
01752 ast_std_free(strings);
01753 strings = NULL;
01754 break;
01755 }
01756 strings = tmp;
01757 strings[stackfr] = (char *) strings + strings_size;
01758 strcpy(strings[stackfr], msg);
01759 strings_size += eachlen[stackfr];
01760 }
01761 }
01762
01763 if (strings) {
01764
01765 strings[0] = (char *) strings + num_frames * sizeof(*strings);
01766 for (stackfr = 1; stackfr < num_frames; stackfr++) {
01767 strings[stackfr] = strings[stackfr - 1] + eachlen[stackfr - 1];
01768 }
01769 }
01770 ast_free(eachlen);
01771
01772 #else
01773
01774 strings = backtrace_symbols(addresses, num_frames);
01775 #endif
01776 return strings;
01777 }
01778
01779 #endif
01780
01781 void ast_backtrace(void)
01782 {
01783 #ifdef HAVE_BKTR
01784 struct ast_bt *bt;
01785 int i = 0;
01786 char **strings;
01787
01788 if (!(bt = ast_bt_create())) {
01789 ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
01790 return;
01791 }
01792
01793 if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
01794 ast_debug(1, "Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
01795 for (i = 3; i < bt->num_frames - 2; i++) {
01796 ast_debug(1, "#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
01797 }
01798
01799 ast_std_free(strings);
01800 } else {
01801 ast_debug(1, "Could not allocate memory for backtrace\n");
01802 }
01803 ast_bt_destroy(bt);
01804 #else
01805 ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
01806 #endif
01807 }
01808
01809 void __ast_verbose_ap(const char *file, int line, const char *func, int level, struct ast_callid *callid, const char *fmt, va_list ap)
01810 {
01811 const char *p;
01812 struct ast_str *prefixed, *buf = NULL;
01813 int res = 0;
01814 const char *prefix = level >= 4 ? VERBOSE_PREFIX_4 : level == 3 ? VERBOSE_PREFIX_3 : level == 2 ? VERBOSE_PREFIX_2 : level == 1 ? VERBOSE_PREFIX_1 : "";
01815 signed char magic = level > 9 ? -10 : -level - 1;
01816
01817
01818 if (level < 0) {
01819 if (!strncmp(fmt, VERBOSE_PREFIX_4, strlen(VERBOSE_PREFIX_4))) {
01820 magic = -5;
01821 } else if (!strncmp(fmt, VERBOSE_PREFIX_3, strlen(VERBOSE_PREFIX_3))) {
01822 magic = -4;
01823 } else if (!strncmp(fmt, VERBOSE_PREFIX_2, strlen(VERBOSE_PREFIX_2))) {
01824 magic = -3;
01825 } else if (!strncmp(fmt, VERBOSE_PREFIX_1, strlen(VERBOSE_PREFIX_1))) {
01826 magic = -2;
01827 } else {
01828 magic = -1;
01829 }
01830 }
01831
01832 if (!(prefixed = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)) ||
01833 !(buf = ast_str_create(VERBOSE_BUF_INIT_SIZE))) {
01834 return;
01835 }
01836
01837 res = ast_str_set_va(&buf, 0, fmt, ap);
01838
01839 if (res == AST_DYNSTR_BUILD_FAILED) {
01840 ast_free(buf);
01841 return;
01842 }
01843
01844 ast_str_reset(prefixed);
01845
01846 fmt = ast_str_buffer(buf);
01847 do {
01848 if (!(p = strchr(fmt, '\n'))) {
01849 p = strchr(fmt, '\0') - 1;
01850 }
01851 ++p;
01852
01853 if (ast_opt_timestamp) {
01854 struct ast_tm tm;
01855 char date[40];
01856 struct timeval now = ast_tvnow();
01857 ast_localtime(&now, &tm, NULL);
01858 ast_strftime(date, sizeof(date), dateformat, &tm);
01859 ast_str_append(&prefixed, 0, "%c[%s] %s", (char) magic, date, prefix);
01860 } else {
01861 ast_str_append(&prefixed, 0, "%c%s", (char) magic, prefix);
01862 }
01863 ast_str_append_substr(&prefixed, 0, fmt, p - fmt);
01864 fmt = p;
01865 } while (p && *p);
01866
01867 ast_log_callid(__LOG_VERBOSE, file, line, func, callid, "%s", ast_str_buffer(prefixed));
01868 ast_free(buf);
01869 }
01870
01871 void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...)
01872 {
01873 struct ast_callid *callid;
01874 va_list ap;
01875
01876 callid = ast_read_threadstorage_callid();
01877
01878 va_start(ap, fmt);
01879 __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
01880 va_end(ap);
01881
01882 if (callid) {
01883 ast_callid_unref(callid);
01884 }
01885 }
01886
01887 void __ast_verbose_callid(const char *file, int line, const char *func, int level, struct ast_callid *callid, const char *fmt, ...)
01888 {
01889 va_list ap;
01890 va_start(ap, fmt);
01891 __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
01892 va_end(ap);
01893 }
01894
01895
01896 #undef ast_verbose
01897 void __attribute__((format(printf, 1,2))) ast_verbose(const char *fmt, ...);
01898 void ast_verbose(const char *fmt, ...)
01899 {
01900 struct ast_callid *callid;
01901 va_list ap;
01902
01903 callid = ast_read_threadstorage_callid();
01904
01905 va_start(ap, fmt);
01906 __ast_verbose_ap("", 0, "", 0, callid, fmt, ap);
01907 va_end(ap);
01908
01909 if (callid) {
01910 ast_callid_unref(callid);
01911 }
01912 }
01913
01914
01915 struct verb_console {
01916
01917 AST_LIST_ENTRY(verb_console) node;
01918
01919 int *level;
01920 };
01921
01922
01923 static AST_RWLIST_HEAD_STATIC(verb_consoles, verb_console);
01924
01925
01926 AST_MUTEX_DEFINE_STATIC(verb_update_lock);
01927
01928 void ast_verb_update(void)
01929 {
01930 struct logchannel *log;
01931 struct verb_console *console;
01932 int verb_level;
01933
01934 ast_mutex_lock(&verb_update_lock);
01935
01936 AST_RWLIST_RDLOCK(&verb_consoles);
01937
01938
01939 verb_level = option_verbose;
01940
01941
01942 AST_LIST_TRAVERSE(&verb_consoles, console, node) {
01943 if (verb_level < *console->level) {
01944 verb_level = *console->level;
01945 }
01946 }
01947 AST_RWLIST_UNLOCK(&verb_consoles);
01948
01949
01950 AST_RWLIST_RDLOCK(&logchannels);
01951 AST_RWLIST_TRAVERSE(&logchannels, log, list) {
01952 if (verb_level < log->verbosity) {
01953 verb_level = log->verbosity;
01954 }
01955 }
01956 AST_RWLIST_UNLOCK(&logchannels);
01957
01958 ast_verb_sys_level = verb_level;
01959
01960 ast_mutex_unlock(&verb_update_lock);
01961 }
01962
01963
01964
01965
01966
01967
01968
01969
01970
01971 static void verb_console_unregister(struct verb_console *console)
01972 {
01973 AST_RWLIST_WRLOCK(&verb_consoles);
01974 console = AST_RWLIST_REMOVE(&verb_consoles, console, node);
01975 AST_RWLIST_UNLOCK(&verb_consoles);
01976 if (console) {
01977 ast_verb_update();
01978 }
01979 }
01980
01981 static void verb_console_free(void *v_console)
01982 {
01983 struct verb_console *console = v_console;
01984
01985 verb_console_unregister(console);
01986 ast_free(console);
01987 }
01988
01989
01990 AST_THREADSTORAGE_CUSTOM(my_verb_console, NULL, verb_console_free);
01991
01992 void ast_verb_console_register(int *level)
01993 {
01994 struct verb_console *console;
01995
01996 console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
01997 if (!console || !level) {
01998 return;
01999 }
02000 console->level = level;
02001
02002 AST_RWLIST_WRLOCK(&verb_consoles);
02003 AST_RWLIST_INSERT_HEAD(&verb_consoles, console, node);
02004 AST_RWLIST_UNLOCK(&verb_consoles);
02005 ast_verb_update();
02006 }
02007
02008 void ast_verb_console_unregister(void)
02009 {
02010 struct verb_console *console;
02011
02012 console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
02013 if (!console) {
02014 return;
02015 }
02016 verb_console_unregister(console);
02017 }
02018
02019 int ast_verb_console_get(void)
02020 {
02021 struct verb_console *console;
02022 int verb_level;
02023
02024 console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
02025 AST_RWLIST_RDLOCK(&verb_consoles);
02026 if (!console) {
02027 verb_level = 0;
02028 } else if (console->level) {
02029 verb_level = *console->level;
02030 } else {
02031 verb_level = option_verbose;
02032 }
02033 AST_RWLIST_UNLOCK(&verb_consoles);
02034 return verb_level;
02035 }
02036
02037 void ast_verb_console_set(int verb_level)
02038 {
02039 struct verb_console *console;
02040
02041 console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
02042 if (!console) {
02043 return;
02044 }
02045
02046 AST_RWLIST_WRLOCK(&verb_consoles);
02047 if (console->level) {
02048 *console->level = verb_level;
02049 } else {
02050 option_verbose = verb_level;
02051 }
02052 AST_RWLIST_UNLOCK(&verb_consoles);
02053 ast_verb_update();
02054 }
02055
02056 int ast_register_verbose(void (*v)(const char *string))
02057 {
02058 struct verb *verb;
02059
02060 if (!(verb = ast_malloc(sizeof(*verb))))
02061 return -1;
02062
02063 verb->verboser = v;
02064
02065 AST_RWLIST_WRLOCK(&verbosers);
02066 AST_RWLIST_INSERT_HEAD(&verbosers, verb, list);
02067 AST_RWLIST_UNLOCK(&verbosers);
02068
02069 return 0;
02070 }
02071
02072 int ast_unregister_verbose(void (*v)(const char *string))
02073 {
02074 struct verb *cur;
02075
02076 AST_RWLIST_WRLOCK(&verbosers);
02077 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) {
02078 if (cur->verboser == v) {
02079 AST_RWLIST_REMOVE_CURRENT(list);
02080 ast_free(cur);
02081 break;
02082 }
02083 }
02084 AST_RWLIST_TRAVERSE_SAFE_END;
02085 AST_RWLIST_UNLOCK(&verbosers);
02086
02087 return cur ? 0 : -1;
02088 }
02089
02090 static void update_logchannels(void)
02091 {
02092 struct logchannel *cur;
02093
02094 AST_RWLIST_WRLOCK(&logchannels);
02095
02096 global_logmask = 0;
02097
02098 AST_RWLIST_TRAVERSE(&logchannels, cur, list) {
02099 make_components(cur);
02100 global_logmask |= cur->logmask;
02101 }
02102
02103 AST_RWLIST_UNLOCK(&logchannels);
02104 }
02105
02106 int ast_logger_register_level(const char *name)
02107 {
02108 unsigned int level;
02109 unsigned int available = 0;
02110
02111 AST_RWLIST_WRLOCK(&logchannels);
02112
02113 for (level = 0; level < ARRAY_LEN(levels); level++) {
02114 if ((level >= 16) && !available && !levels[level]) {
02115 available = level;
02116 continue;
02117 }
02118
02119 if (levels[level] && !strcasecmp(levels[level], name)) {
02120 ast_log(LOG_WARNING,
02121 "Unable to register dynamic logger level '%s': a standard logger level uses that name.\n",
02122 name);
02123 AST_RWLIST_UNLOCK(&logchannels);
02124
02125 return -1;
02126 }
02127 }
02128
02129 if (!available) {
02130 ast_log(LOG_WARNING,
02131 "Unable to register dynamic logger level '%s'; maximum number of levels registered.\n",
02132 name);
02133 AST_RWLIST_UNLOCK(&logchannels);
02134
02135 return -1;
02136 }
02137
02138 levels[available] = ast_strdup(name);
02139
02140 AST_RWLIST_UNLOCK(&logchannels);
02141
02142 ast_debug(1, "Registered dynamic logger level '%s' with index %d.\n", name, available);
02143
02144 update_logchannels();
02145
02146 return available;
02147 }
02148
02149 void ast_logger_unregister_level(const char *name)
02150 {
02151 unsigned int found = 0;
02152 unsigned int x;
02153
02154 AST_RWLIST_WRLOCK(&logchannels);
02155
02156 for (x = 16; x < ARRAY_LEN(levels); x++) {
02157 if (!levels[x]) {
02158 continue;
02159 }
02160
02161 if (strcasecmp(levels[x], name)) {
02162 continue;
02163 }
02164
02165 found = 1;
02166 break;
02167 }
02168
02169 if (found) {
02170
02171
02172
02173
02174 global_logmask &= ~(1 << x);
02175
02176 ast_free(levels[x]);
02177 levels[x] = NULL;
02178 AST_RWLIST_UNLOCK(&logchannels);
02179
02180 ast_debug(1, "Unregistered dynamic logger level '%s' with index %d.\n", name, x);
02181
02182 update_logchannels();
02183 } else {
02184 AST_RWLIST_UNLOCK(&logchannels);
02185 }
02186 }