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