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