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