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