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