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: 221922 $")
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 res = fprintf(chan->fileptr, "[%s] %s[%ld] %s: %s",
00913 logmsg->date, levels[logmsg->level], logmsg->process_id, logmsg->file, logmsg->str);
00914 if (res <= 0 && !ast_strlen_zero(logmsg->str)) {
00915 fprintf(stderr, "**** Asterisk Logging Error: ***********\n");
00916 if (errno == ENOMEM || errno == ENOSPC)
00917 fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
00918 else
00919 fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
00920 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
00921 chan->disabled = 1;
00922 } else if (res > 0) {
00923 fflush(chan->fileptr);
00924 }
00925 }
00926 }
00927 } else if (logmsg->level != __LOG_VERBOSE) {
00928 fputs(logmsg->str, stdout);
00929 }
00930
00931 AST_RWLIST_UNLOCK(&logchannels);
00932
00933
00934 if (filesize_reload_needed) {
00935 reload_logger(-1);
00936 ast_log(LOG_EVENT, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00937 ast_verb(1, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00938 }
00939
00940 return;
00941 }
00942
00943
00944 static void logger_print_verbose(struct logmsg *logmsg)
00945 {
00946 struct verb *v = NULL;
00947
00948
00949 AST_RWLIST_RDLOCK(&verbosers);
00950 AST_RWLIST_TRAVERSE(&verbosers, v, list)
00951 v->verboser(logmsg->str);
00952 AST_RWLIST_UNLOCK(&verbosers);
00953
00954 return;
00955 }
00956
00957
00958 static void *logger_thread(void *data)
00959 {
00960 struct logmsg *next = NULL, *msg = NULL;
00961
00962 for (;;) {
00963
00964 AST_LIST_LOCK(&logmsgs);
00965 if (AST_LIST_EMPTY(&logmsgs)) {
00966 if (close_logger_thread) {
00967 break;
00968 } else {
00969 ast_cond_wait(&logcond, &logmsgs.lock);
00970 }
00971 }
00972 next = AST_LIST_FIRST(&logmsgs);
00973 AST_LIST_HEAD_INIT_NOLOCK(&logmsgs);
00974 AST_LIST_UNLOCK(&logmsgs);
00975
00976
00977 while ((msg = next)) {
00978
00979 next = AST_LIST_NEXT(msg, list);
00980
00981
00982 if (msg->type == LOGMSG_NORMAL)
00983 logger_print_normal(msg);
00984 else if (msg->type == LOGMSG_VERBOSE)
00985 logger_print_verbose(msg);
00986
00987
00988 ast_free(msg);
00989 }
00990
00991
00992 if (close_logger_thread)
00993 break;
00994 }
00995
00996 return NULL;
00997 }
00998
00999 int init_logger(void)
01000 {
01001 char tmp[256];
01002 int res = 0;
01003
01004
01005 (void) signal(SIGXFSZ, (void *) handle_SIGXFSZ);
01006
01007
01008 ast_cond_init(&logcond, NULL);
01009 if (ast_pthread_create(&logthread, NULL, logger_thread, NULL) < 0) {
01010 ast_cond_destroy(&logcond);
01011 return -1;
01012 }
01013
01014
01015 ast_cli_register_multiple(cli_logger, sizeof(cli_logger) / sizeof(struct ast_cli_entry));
01016
01017 ast_mkdir(ast_config_AST_LOG_DIR, 0777);
01018
01019
01020 init_logger_chain(0 );
01021
01022
01023 if (logfiles.event_log) {
01024 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, EVENTLOG);
01025 eventlog = fopen(tmp, "a");
01026 if (eventlog) {
01027 ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
01028 ast_verb(1, "Asterisk Event Logger Started %s\n", tmp);
01029 } else {
01030 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
01031 res = -1;
01032 }
01033 }
01034
01035 if (logfiles.queue_log) {
01036 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
01037 qlog = fopen(tmp, "a");
01038 ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
01039 }
01040 return res;
01041 }
01042
01043 void close_logger(void)
01044 {
01045 struct logchannel *f = NULL;
01046
01047
01048 AST_LIST_LOCK(&logmsgs);
01049 close_logger_thread = 1;
01050 ast_cond_signal(&logcond);
01051 AST_LIST_UNLOCK(&logmsgs);
01052
01053 if (logthread != AST_PTHREADT_NULL)
01054 pthread_join(logthread, NULL);
01055
01056 AST_RWLIST_WRLOCK(&logchannels);
01057
01058 if (eventlog) {
01059 fclose(eventlog);
01060 eventlog = NULL;
01061 }
01062
01063 if (qlog) {
01064 fclose(qlog);
01065 qlog = NULL;
01066 }
01067
01068 AST_RWLIST_TRAVERSE(&logchannels, f, list) {
01069 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
01070 fclose(f->fileptr);
01071 f->fileptr = NULL;
01072 }
01073 }
01074
01075 closelog();
01076
01077 AST_RWLIST_UNLOCK(&logchannels);
01078
01079 return;
01080 }
01081
01082
01083
01084
01085 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
01086 {
01087 struct logmsg *logmsg = NULL;
01088 struct ast_str *buf = NULL;
01089 struct ast_tm tm;
01090 struct timeval now = ast_tvnow();
01091 int res = 0;
01092 va_list ap;
01093
01094 if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE)))
01095 return;
01096
01097 if (AST_RWLIST_EMPTY(&logchannels)) {
01098
01099
01100
01101
01102 if (level != __LOG_VERBOSE) {
01103 int result;
01104 va_start(ap, fmt);
01105 result = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
01106 va_end(ap);
01107 if (result != AST_DYNSTR_BUILD_FAILED) {
01108 term_filter_escapes(buf->str);
01109 fputs(buf->str, stdout);
01110 }
01111 }
01112 return;
01113 }
01114
01115
01116
01117
01118
01119
01120
01121 if (!option_verbose && !option_debug && (level == __LOG_DEBUG))
01122 return;
01123
01124
01125 if (!(global_logmask & (1 << level)))
01126 return;
01127
01128
01129 va_start(ap, fmt);
01130 res = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
01131 va_end(ap);
01132
01133
01134 if (res == AST_DYNSTR_BUILD_FAILED)
01135 return;
01136
01137
01138 if (!(logmsg = ast_calloc(1, sizeof(*logmsg) + res + 1)))
01139 return;
01140
01141
01142 strcpy(logmsg->str, buf->str);
01143
01144
01145 logmsg->type = LOGMSG_NORMAL;
01146
01147
01148 ast_localtime(&now, &tm, NULL);
01149 ast_strftime(logmsg->date, sizeof(logmsg->date), dateformat, &tm);
01150
01151
01152 logmsg->level = level;
01153 logmsg->line = line;
01154 ast_copy_string(logmsg->file, file, sizeof(logmsg->file));
01155 ast_copy_string(logmsg->function, function, sizeof(logmsg->function));
01156 logmsg->process_id = (long) GETTID();
01157
01158
01159 if (logthread != AST_PTHREADT_NULL) {
01160 AST_LIST_LOCK(&logmsgs);
01161 AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list);
01162 ast_cond_signal(&logcond);
01163 AST_LIST_UNLOCK(&logmsgs);
01164 } else {
01165 logger_print_normal(logmsg);
01166 ast_free(logmsg);
01167 }
01168
01169 return;
01170 }
01171
01172 #ifdef HAVE_BKTR
01173
01174 struct ast_bt *ast_bt_create(void)
01175 {
01176 struct ast_bt *bt = ast_calloc(1, sizeof(*bt));
01177 if (!bt) {
01178 ast_log(LOG_ERROR, "Unable to allocate memory for backtrace structure!\n");
01179 return NULL;
01180 }
01181
01182 bt->alloced = 1;
01183
01184 ast_bt_get_addresses(bt);
01185
01186 return bt;
01187 }
01188
01189 int ast_bt_get_addresses(struct ast_bt *bt)
01190 {
01191 bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES);
01192
01193 return 0;
01194 }
01195
01196 void *ast_bt_destroy(struct ast_bt *bt)
01197 {
01198 if (bt->alloced) {
01199 ast_free(bt);
01200 }
01201
01202 return NULL;
01203 }
01204
01205 #endif
01206
01207 void ast_backtrace(void)
01208 {
01209 #ifdef HAVE_BKTR
01210 struct ast_bt *bt;
01211 int i = 0;
01212 char **strings;
01213
01214 if (!(bt = ast_bt_create())) {
01215 ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
01216 return;
01217 }
01218
01219 if ((strings = backtrace_symbols(bt->addresses, bt->num_frames))) {
01220 ast_debug(1, "Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
01221 for (i = 0; i < bt->num_frames; i++) {
01222 ast_log(LOG_DEBUG, "#%d: [%p] %s\n", i, bt->addresses[i], strings[i]);
01223 }
01224 free(strings);
01225 } else {
01226 ast_debug(1, "Could not allocate memory for backtrace\n");
01227 }
01228 ast_bt_destroy(bt);
01229 #else
01230 ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
01231 #endif
01232 }
01233
01234 void __ast_verbose_ap(const char *file, int line, const char *func, const char *fmt, va_list ap)
01235 {
01236 struct logmsg *logmsg = NULL;
01237 struct ast_str *buf = NULL;
01238 int res = 0;
01239
01240 if (!(buf = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)))
01241 return;
01242
01243 if (ast_opt_timestamp) {
01244 struct timeval now;
01245 struct ast_tm tm;
01246 char date[40];
01247 char *datefmt;
01248
01249 now = ast_tvnow();
01250 ast_localtime(&now, &tm, NULL);
01251 ast_strftime(date, sizeof(date), dateformat, &tm);
01252 datefmt = alloca(strlen(date) + 3 + strlen(fmt) + 1);
01253 sprintf(datefmt, "%c[%s] %s", 127, date, fmt);
01254 fmt = datefmt;
01255 } else {
01256 char *tmp = alloca(strlen(fmt) + 2);
01257 sprintf(tmp, "%c%s", 127, fmt);
01258 fmt = tmp;
01259 }
01260
01261
01262 res = ast_str_set_va(&buf, 0, fmt, ap);
01263
01264
01265 if (res == AST_DYNSTR_BUILD_FAILED)
01266 return;
01267
01268 if (!(logmsg = ast_calloc(1, sizeof(*logmsg) + res + 1)))
01269 return;
01270
01271 strcpy(logmsg->str, buf->str);
01272
01273 ast_log(__LOG_VERBOSE, file, line, func, "%s", logmsg->str + 1);
01274
01275
01276 logmsg->type = LOGMSG_VERBOSE;
01277
01278
01279 if (logthread != AST_PTHREADT_NULL) {
01280 AST_LIST_LOCK(&logmsgs);
01281 AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list);
01282 ast_cond_signal(&logcond);
01283 AST_LIST_UNLOCK(&logmsgs);
01284 } else {
01285 logger_print_verbose(logmsg);
01286 ast_free(logmsg);
01287 }
01288 }
01289
01290 void __ast_verbose(const char *file, int line, const char *func, const char *fmt, ...)
01291 {
01292 va_list ap;
01293 va_start(ap, fmt);
01294 __ast_verbose_ap(file, line, func, fmt, ap);
01295 va_end(ap);
01296 }
01297
01298
01299 #undef ast_verbose
01300 void __attribute__((format(printf, 1,2))) ast_verbose(const char *fmt, ...);
01301 void ast_verbose(const char *fmt, ...)
01302 {
01303 va_list ap;
01304 va_start(ap, fmt);
01305 __ast_verbose_ap("", 0, "", fmt, ap);
01306 va_end(ap);
01307 }
01308
01309 int ast_register_verbose(void (*v)(const char *string))
01310 {
01311 struct verb *verb;
01312
01313 if (!(verb = ast_malloc(sizeof(*verb))))
01314 return -1;
01315
01316 verb->verboser = v;
01317
01318 AST_RWLIST_WRLOCK(&verbosers);
01319 AST_RWLIST_INSERT_HEAD(&verbosers, verb, list);
01320 AST_RWLIST_UNLOCK(&verbosers);
01321
01322 return 0;
01323 }
01324
01325 int ast_unregister_verbose(void (*v)(const char *string))
01326 {
01327 struct verb *cur;
01328
01329 AST_RWLIST_WRLOCK(&verbosers);
01330 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) {
01331 if (cur->verboser == v) {
01332 AST_RWLIST_REMOVE_CURRENT(list);
01333 ast_free(cur);
01334 break;
01335 }
01336 }
01337 AST_RWLIST_TRAVERSE_SAFE_END;
01338 AST_RWLIST_UNLOCK(&verbosers);
01339
01340 return cur ? 0 : -1;
01341 }