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