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