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 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00031
00032 #include <signal.h>
00033 #include <stdarg.h>
00034 #include <stdio.h>
00035 #include <unistd.h>
00036 #include <time.h>
00037 #include <string.h>
00038 #include <stdlib.h>
00039 #include <errno.h>
00040 #include <sys/stat.h>
00041 #if ((defined(AST_DEVMODE)) && (defined(linux)))
00042 #include <execinfo.h>
00043 #define MAX_BACKTRACE_FRAMES 20
00044 #endif
00045
00046 #define SYSLOG_NAMES
00047
00048 #include <syslog.h>
00049
00050 static int syslog_level_map[] = {
00051 LOG_DEBUG,
00052 LOG_INFO,
00053 LOG_NOTICE,
00054 LOG_WARNING,
00055 LOG_ERR,
00056 LOG_DEBUG,
00057 LOG_DEBUG
00058 };
00059
00060 #define SYSLOG_NLEVELS sizeof(syslog_level_map) / sizeof(int)
00061
00062 #include "asterisk/logger.h"
00063 #include "asterisk/lock.h"
00064 #include "asterisk/options.h"
00065 #include "asterisk/channel.h"
00066 #include "asterisk/config.h"
00067 #include "asterisk/term.h"
00068 #include "asterisk/cli.h"
00069 #include "asterisk/utils.h"
00070 #include "asterisk/manager.h"
00071 #include "asterisk/threadstorage.h"
00072
00073 #if defined(__linux__) && !defined(__NR_gettid)
00074 #include <asm/unistd.h>
00075 #endif
00076
00077 #if defined(__linux__) && defined(__NR_gettid)
00078 #define GETTID() syscall(__NR_gettid)
00079 #else
00080 #define GETTID() getpid()
00081 #endif
00082
00083
00084 static char dateformat[256] = "%b %e %T";
00085
00086 static int filesize_reload_needed;
00087 static int global_logmask = -1;
00088
00089 static struct {
00090 unsigned int queue_log:1;
00091 unsigned int event_log:1;
00092 } logfiles = { 1, 1 };
00093
00094 static char hostname[MAXHOSTNAMELEN];
00095
00096 enum logtypes {
00097 LOGTYPE_SYSLOG,
00098 LOGTYPE_FILE,
00099 LOGTYPE_CONSOLE,
00100 };
00101
00102 struct logchannel {
00103 int logmask;
00104 int disabled;
00105 int facility;
00106 enum logtypes type;
00107 FILE *fileptr;
00108 char filename[256];
00109 AST_LIST_ENTRY(logchannel) list;
00110 };
00111
00112 static AST_LIST_HEAD_STATIC(logchannels, logchannel);
00113
00114 static FILE *eventlog;
00115 static FILE *qlog;
00116
00117 static char *levels[] = {
00118 "DEBUG",
00119 "EVENT",
00120 "NOTICE",
00121 "WARNING",
00122 "ERROR",
00123 "VERBOSE",
00124 "DTMF"
00125 };
00126
00127 static int colors[] = {
00128 COLOR_BRGREEN,
00129 COLOR_BRBLUE,
00130 COLOR_YELLOW,
00131 COLOR_BRRED,
00132 COLOR_RED,
00133 COLOR_GREEN,
00134 COLOR_BRGREEN
00135 };
00136
00137 AST_THREADSTORAGE(verbose_buf, verbose_buf_init);
00138 #define VERBOSE_BUF_INIT_SIZE 128
00139
00140 AST_THREADSTORAGE(log_buf, log_buf_init);
00141 #define LOG_BUF_INIT_SIZE 128
00142
00143 static int make_components(char *s, int lineno)
00144 {
00145 char *w;
00146 int res = 0;
00147 char *stringp = s;
00148
00149 while ((w = strsep(&stringp, ","))) {
00150 w = ast_skip_blanks(w);
00151 if (!strcasecmp(w, "error"))
00152 res |= (1 << __LOG_ERROR);
00153 else if (!strcasecmp(w, "warning"))
00154 res |= (1 << __LOG_WARNING);
00155 else if (!strcasecmp(w, "notice"))
00156 res |= (1 << __LOG_NOTICE);
00157 else if (!strcasecmp(w, "event"))
00158 res |= (1 << __LOG_EVENT);
00159 else if (!strcasecmp(w, "debug"))
00160 res |= (1 << __LOG_DEBUG);
00161 else if (!strcasecmp(w, "verbose"))
00162 res |= (1 << __LOG_VERBOSE);
00163 else if (!strcasecmp(w, "dtmf"))
00164 res |= (1 << __LOG_DTMF);
00165 else {
00166 fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
00167 }
00168 }
00169
00170 return res;
00171 }
00172
00173 static struct logchannel *make_logchannel(char *channel, char *components, int lineno)
00174 {
00175 struct logchannel *chan;
00176 char *facility;
00177 #ifndef SOLARIS
00178 CODE *cptr;
00179 #endif
00180
00181 if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan))))
00182 return NULL;
00183
00184 if (!strcasecmp(channel, "console")) {
00185 chan->type = LOGTYPE_CONSOLE;
00186 } else if (!strncasecmp(channel, "syslog", 6)) {
00187
00188
00189
00190
00191 facility = strchr(channel, '.');
00192 if(!facility++ || !facility) {
00193 facility = "local0";
00194 }
00195
00196 #ifndef SOLARIS
00197
00198
00199
00200
00201 chan->facility = -1;
00202 cptr = facilitynames;
00203 while (cptr->c_name) {
00204 if (!strcasecmp(facility, cptr->c_name)) {
00205 chan->facility = cptr->c_val;
00206 break;
00207 }
00208 cptr++;
00209 }
00210 #else
00211 chan->facility = -1;
00212 if (!strcasecmp(facility, "kern"))
00213 chan->facility = LOG_KERN;
00214 else if (!strcasecmp(facility, "USER"))
00215 chan->facility = LOG_USER;
00216 else if (!strcasecmp(facility, "MAIL"))
00217 chan->facility = LOG_MAIL;
00218 else if (!strcasecmp(facility, "DAEMON"))
00219 chan->facility = LOG_DAEMON;
00220 else if (!strcasecmp(facility, "AUTH"))
00221 chan->facility = LOG_AUTH;
00222 else if (!strcasecmp(facility, "SYSLOG"))
00223 chan->facility = LOG_SYSLOG;
00224 else if (!strcasecmp(facility, "LPR"))
00225 chan->facility = LOG_LPR;
00226 else if (!strcasecmp(facility, "NEWS"))
00227 chan->facility = LOG_NEWS;
00228 else if (!strcasecmp(facility, "UUCP"))
00229 chan->facility = LOG_UUCP;
00230 else if (!strcasecmp(facility, "CRON"))
00231 chan->facility = LOG_CRON;
00232 else if (!strcasecmp(facility, "LOCAL0"))
00233 chan->facility = LOG_LOCAL0;
00234 else if (!strcasecmp(facility, "LOCAL1"))
00235 chan->facility = LOG_LOCAL1;
00236 else if (!strcasecmp(facility, "LOCAL2"))
00237 chan->facility = LOG_LOCAL2;
00238 else if (!strcasecmp(facility, "LOCAL3"))
00239 chan->facility = LOG_LOCAL3;
00240 else if (!strcasecmp(facility, "LOCAL4"))
00241 chan->facility = LOG_LOCAL4;
00242 else if (!strcasecmp(facility, "LOCAL5"))
00243 chan->facility = LOG_LOCAL5;
00244 else if (!strcasecmp(facility, "LOCAL6"))
00245 chan->facility = LOG_LOCAL6;
00246 else if (!strcasecmp(facility, "LOCAL7"))
00247 chan->facility = LOG_LOCAL7;
00248 #endif
00249
00250 if (0 > chan->facility) {
00251 fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
00252 free(chan);
00253 return NULL;
00254 }
00255
00256 chan->type = LOGTYPE_SYSLOG;
00257 snprintf(chan->filename, sizeof(chan->filename), "%s", channel);
00258 openlog("asterisk", LOG_PID, chan->facility);
00259 } else {
00260 if (channel[0] == '/') {
00261 if(!ast_strlen_zero(hostname)) {
00262 snprintf(chan->filename, sizeof(chan->filename) - 1,"%s.%s", channel, hostname);
00263 } else {
00264 ast_copy_string(chan->filename, channel, sizeof(chan->filename));
00265 }
00266 }
00267
00268 if(!ast_strlen_zero(hostname)) {
00269 snprintf(chan->filename, sizeof(chan->filename), "%s/%s.%s",(char *)ast_config_AST_LOG_DIR, channel, hostname);
00270 } else {
00271 snprintf(chan->filename, sizeof(chan->filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, channel);
00272 }
00273 chan->fileptr = fopen(chan->filename, "a");
00274 if (!chan->fileptr) {
00275
00276 fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
00277 }
00278 chan->type = LOGTYPE_FILE;
00279 }
00280 chan->logmask = make_components(components, lineno);
00281 return chan;
00282 }
00283
00284 static void init_logger_chain(void)
00285 {
00286 struct logchannel *chan;
00287 struct ast_config *cfg;
00288 struct ast_variable *var;
00289 const char *s;
00290
00291
00292 AST_LIST_LOCK(&logchannels);
00293 while ((chan = AST_LIST_REMOVE_HEAD(&logchannels, list)))
00294 free(chan);
00295 AST_LIST_UNLOCK(&logchannels);
00296
00297 global_logmask = 0;
00298 errno = 0;
00299
00300 closelog();
00301
00302 cfg = ast_config_load("logger.conf");
00303
00304
00305 if (!cfg) {
00306 if (errno)
00307 fprintf(stderr, "Unable to open logger.conf: %s; default settings will be used.\n", strerror(errno));
00308 else
00309 fprintf(stderr, "Errors detected in logger.conf: see above; default settings will be used.\n");
00310 if (!(chan = ast_calloc(1, sizeof(*chan))))
00311 return;
00312 chan->type = LOGTYPE_CONSOLE;
00313 chan->logmask = 28;
00314 AST_LIST_LOCK(&logchannels);
00315 AST_LIST_INSERT_HEAD(&logchannels, chan, list);
00316 AST_LIST_UNLOCK(&logchannels);
00317 global_logmask |= chan->logmask;
00318 return;
00319 }
00320
00321 if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
00322 if (ast_true(s)) {
00323 if (gethostname(hostname, sizeof(hostname) - 1)) {
00324 ast_copy_string(hostname, "unknown", sizeof(hostname));
00325 ast_log(LOG_WARNING, "What box has no hostname???\n");
00326 }
00327 } else
00328 hostname[0] = '\0';
00329 } else
00330 hostname[0] = '\0';
00331 if ((s = ast_variable_retrieve(cfg, "general", "dateformat")))
00332 ast_copy_string(dateformat, s, sizeof(dateformat));
00333 else
00334 ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
00335 if ((s = ast_variable_retrieve(cfg, "general", "queue_log")))
00336 logfiles.queue_log = ast_true(s);
00337 if ((s = ast_variable_retrieve(cfg, "general", "event_log")))
00338 logfiles.event_log = ast_true(s);
00339
00340 AST_LIST_LOCK(&logchannels);
00341 var = ast_variable_browse(cfg, "logfiles");
00342 for (; var; var = var->next) {
00343 if (!(chan = make_logchannel(var->name, var->value, var->lineno)))
00344 continue;
00345 AST_LIST_INSERT_HEAD(&logchannels, chan, list);
00346 global_logmask |= chan->logmask;
00347 }
00348 AST_LIST_UNLOCK(&logchannels);
00349
00350 ast_config_destroy(cfg);
00351 }
00352
00353 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
00354 {
00355 va_list ap;
00356 AST_LIST_LOCK(&logchannels);
00357 if (qlog) {
00358 va_start(ap, fmt);
00359 fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
00360 vfprintf(qlog, fmt, ap);
00361 fprintf(qlog, "\n");
00362 va_end(ap);
00363 fflush(qlog);
00364 }
00365 AST_LIST_UNLOCK(&logchannels);
00366 }
00367
00368 int reload_logger(int rotate)
00369 {
00370 char old[PATH_MAX] = "";
00371 char new[PATH_MAX];
00372 int event_rotate = rotate, queue_rotate = rotate;
00373 struct logchannel *f;
00374 FILE *myf;
00375 int x, res = 0;
00376
00377 AST_LIST_LOCK(&logchannels);
00378
00379 if (eventlog)
00380 fclose(eventlog);
00381 else
00382 event_rotate = 0;
00383 eventlog = NULL;
00384
00385 if (qlog)
00386 fclose(qlog);
00387 else
00388 queue_rotate = 0;
00389 qlog = NULL;
00390
00391 mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00392
00393 AST_LIST_TRAVERSE(&logchannels, f, list) {
00394 if (f->disabled) {
00395 f->disabled = 0;
00396 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
00397 }
00398 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00399 fclose(f->fileptr);
00400 f->fileptr = NULL;
00401 if (rotate) {
00402 ast_copy_string(old, f->filename, sizeof(old));
00403
00404 for (x = 0; ; x++) {
00405 snprintf(new, sizeof(new), "%s.%d", f->filename, x);
00406 myf = fopen((char *)new, "r");
00407 if (myf)
00408 fclose(myf);
00409 else
00410 break;
00411 }
00412
00413
00414 if (rename(old,new))
00415 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
00416 }
00417 }
00418 }
00419
00420 filesize_reload_needed = 0;
00421
00422 init_logger_chain();
00423
00424 if (logfiles.event_log) {
00425 snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00426 if (event_rotate) {
00427 for (x=0;;x++) {
00428 snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x);
00429 myf = fopen((char *)new, "r");
00430 if (myf)
00431 fclose(myf);
00432 else
00433 break;
00434 }
00435
00436
00437 if (rename(old,new))
00438 ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
00439 }
00440
00441 eventlog = fopen(old, "a");
00442 if (eventlog) {
00443 ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
00444 if (option_verbose)
00445 ast_verbose("Asterisk Event Logger restarted\n");
00446 } else {
00447 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00448 res = -1;
00449 }
00450 }
00451
00452 if (logfiles.queue_log) {
00453 snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
00454 if (queue_rotate) {
00455 for (x = 0; ; x++) {
00456 snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, QUEUELOG, x);
00457 myf = fopen((char *)new, "r");
00458 if (myf)
00459 fclose(myf);
00460 else
00461 break;
00462 }
00463
00464
00465 if (rename(old, new))
00466 ast_log(LOG_ERROR, "Unable to rename file '%s' to '%s'\n", old, new);
00467 }
00468
00469 qlog = fopen(old, "a");
00470 if (qlog) {
00471 ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
00472 ast_log(LOG_EVENT, "Restarted Asterisk Queue Logger\n");
00473 if (option_verbose)
00474 ast_verbose("Asterisk Queue Logger restarted\n");
00475 } else {
00476 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
00477 res = -1;
00478 }
00479 }
00480
00481 AST_LIST_UNLOCK(&logchannels);
00482
00483 return res;
00484 }
00485
00486
00487
00488 int logger_reload(void)
00489 {
00490 if(reload_logger(0))
00491 return RESULT_FAILURE;
00492 return RESULT_SUCCESS;
00493 }
00494
00495 static int handle_logger_reload(int fd, int argc, char *argv[])
00496 {
00497 int result = logger_reload();
00498 if (result == RESULT_FAILURE)
00499 ast_cli(fd, "Failed to reload the logger\n");
00500 return result;
00501 }
00502
00503 static int handle_logger_rotate(int fd, int argc, char *argv[])
00504 {
00505 if(reload_logger(1)) {
00506 ast_cli(fd, "Failed to reload the logger and rotate log files\n");
00507 return RESULT_FAILURE;
00508 }
00509 return RESULT_SUCCESS;
00510 }
00511
00512
00513 static int handle_logger_show_channels(int fd, int argc, char *argv[])
00514 {
00515 #define FORMATL "%-35.35s %-8.8s %-9.9s "
00516 struct logchannel *chan;
00517
00518 ast_cli(fd,FORMATL, "Channel", "Type", "Status");
00519 ast_cli(fd, "Configuration\n");
00520 ast_cli(fd,FORMATL, "-------", "----", "------");
00521 ast_cli(fd, "-------------\n");
00522 AST_LIST_LOCK(&logchannels);
00523 AST_LIST_TRAVERSE(&logchannels, chan, list) {
00524 ast_cli(fd, FORMATL, chan->filename, chan->type==LOGTYPE_CONSOLE ? "Console" : (chan->type==LOGTYPE_SYSLOG ? "Syslog" : "File"),
00525 chan->disabled ? "Disabled" : "Enabled");
00526 ast_cli(fd, " - ");
00527 if (chan->logmask & (1 << __LOG_DEBUG))
00528 ast_cli(fd, "Debug ");
00529 if (chan->logmask & (1 << __LOG_DTMF))
00530 ast_cli(fd, "DTMF ");
00531 if (chan->logmask & (1 << __LOG_VERBOSE))
00532 ast_cli(fd, "Verbose ");
00533 if (chan->logmask & (1 << __LOG_WARNING))
00534 ast_cli(fd, "Warning ");
00535 if (chan->logmask & (1 << __LOG_NOTICE))
00536 ast_cli(fd, "Notice ");
00537 if (chan->logmask & (1 << __LOG_ERROR))
00538 ast_cli(fd, "Error ");
00539 if (chan->logmask & (1 << __LOG_EVENT))
00540 ast_cli(fd, "Event ");
00541 ast_cli(fd, "\n");
00542 }
00543 AST_LIST_UNLOCK(&logchannels);
00544 ast_cli(fd, "\n");
00545
00546 return RESULT_SUCCESS;
00547 }
00548
00549 struct verb {
00550 void (*verboser)(const char *string);
00551 AST_LIST_ENTRY(verb) list;
00552 };
00553
00554 static AST_LIST_HEAD_STATIC(verbosers, verb);
00555
00556 static char logger_reload_help[] =
00557 "Usage: logger reload\n"
00558 " Reloads the logger subsystem state. Use after restarting syslogd(8) if you are using syslog logging.\n";
00559
00560 static char logger_rotate_help[] =
00561 "Usage: logger rotate\n"
00562 " Rotates and Reopens the log files.\n";
00563
00564 static char logger_show_channels_help[] =
00565 "Usage: logger show channels\n"
00566 " List configured logger channels.\n";
00567
00568 static struct ast_cli_entry cli_logger[] = {
00569 { { "logger", "show", "channels", NULL },
00570 handle_logger_show_channels, "List configured log channels",
00571 logger_show_channels_help },
00572
00573 { { "logger", "reload", NULL },
00574 handle_logger_reload, "Reopens the log files",
00575 logger_reload_help },
00576
00577 { { "logger", "rotate", NULL },
00578 handle_logger_rotate, "Rotates and reopens the log files",
00579 logger_rotate_help },
00580 };
00581
00582 static int handle_SIGXFSZ(int sig)
00583 {
00584
00585 filesize_reload_needed = 1;
00586 return 0;
00587 }
00588
00589 int init_logger(void)
00590 {
00591 char tmp[256];
00592 int res = 0;
00593
00594
00595 (void) signal(SIGXFSZ,(void *) handle_SIGXFSZ);
00596
00597
00598 ast_cli_register_multiple(cli_logger, sizeof(cli_logger) / sizeof(struct ast_cli_entry));
00599
00600 mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00601
00602
00603 init_logger_chain();
00604
00605
00606 if (logfiles.event_log) {
00607 mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00608 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00609 eventlog = fopen((char *)tmp, "a");
00610 if (eventlog) {
00611 ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
00612 if (option_verbose)
00613 ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp);
00614 } else {
00615 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00616 res = -1;
00617 }
00618 }
00619
00620 if (logfiles.queue_log) {
00621 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, QUEUELOG);
00622 qlog = fopen(tmp, "a");
00623 ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
00624 }
00625 return res;
00626 }
00627
00628 void close_logger(void)
00629 {
00630 struct logchannel *f;
00631
00632 AST_LIST_LOCK(&logchannels);
00633
00634 if (eventlog) {
00635 fclose(eventlog);
00636 eventlog = NULL;
00637 }
00638
00639 if (qlog) {
00640 fclose(qlog);
00641 qlog = NULL;
00642 }
00643
00644 AST_LIST_TRAVERSE(&logchannels, f, list) {
00645 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00646 fclose(f->fileptr);
00647 f->fileptr = NULL;
00648 }
00649 }
00650
00651 closelog();
00652
00653 AST_LIST_UNLOCK(&logchannels);
00654
00655 return;
00656 }
00657
00658 static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args)
00659 {
00660 char buf[BUFSIZ];
00661 char *s;
00662
00663 if (level >= SYSLOG_NLEVELS) {
00664
00665 fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
00666 return;
00667 }
00668 if (level == __LOG_VERBOSE) {
00669 snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)GETTID());
00670 level = __LOG_DEBUG;
00671 } else if (level == __LOG_DTMF) {
00672 snprintf(buf, sizeof(buf), "DTMF[%ld]: ", (long)GETTID());
00673 level = __LOG_DEBUG;
00674 } else {
00675 snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
00676 levels[level], (long)GETTID(), file, line, function);
00677 }
00678 s = buf + strlen(buf);
00679 vsnprintf(s, sizeof(buf) - strlen(buf), fmt, args);
00680 term_strip(s, s, strlen(s) + 1);
00681 syslog(syslog_level_map[level], "%s", buf);
00682 }
00683
00684
00685
00686
00687 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
00688 {
00689 struct logchannel *chan;
00690 struct ast_dynamic_str *buf;
00691 time_t t;
00692 struct tm tm;
00693 char date[256];
00694
00695 va_list ap;
00696
00697 if (!(buf = ast_dynamic_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE)))
00698 return;
00699
00700 if (AST_LIST_EMPTY(&logchannels))
00701 {
00702
00703
00704
00705
00706 if (level != __LOG_VERBOSE) {
00707 int res;
00708 va_start(ap, fmt);
00709 res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap);
00710 va_end(ap);
00711 if (res != AST_DYNSTR_BUILD_FAILED) {
00712 term_filter_escapes(buf->str);
00713 fputs(buf->str, stdout);
00714 }
00715 }
00716 return;
00717 }
00718
00719
00720
00721
00722
00723
00724
00725 if (!option_verbose && !option_debug && (level == __LOG_DEBUG))
00726 return;
00727
00728
00729 if (!(global_logmask & (1 << level)))
00730 return;
00731
00732
00733 if ((level == __LOG_DEBUG) && !ast_strlen_zero(debug_filename) && strcasecmp(debug_filename, file))
00734 return;
00735
00736 time(&t);
00737 ast_localtime(&t, &tm, NULL);
00738 strftime(date, sizeof(date), dateformat, &tm);
00739
00740 AST_LIST_LOCK(&logchannels);
00741
00742 if (logfiles.event_log && level == __LOG_EVENT) {
00743 va_start(ap, fmt);
00744
00745 fprintf(eventlog, "%s asterisk[%ld]: ", date, (long)getpid());
00746 vfprintf(eventlog, fmt, ap);
00747 fflush(eventlog);
00748
00749 va_end(ap);
00750 AST_LIST_UNLOCK(&logchannels);
00751 return;
00752 }
00753
00754 AST_LIST_TRAVERSE(&logchannels, chan, list) {
00755 if (chan->disabled)
00756 break;
00757
00758 if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << level))) {
00759 va_start(ap, fmt);
00760 ast_log_vsyslog(level, file, line, function, fmt, ap);
00761 va_end(ap);
00762
00763 } else if ((chan->logmask & (1 << level)) && (chan->type == LOGTYPE_CONSOLE)) {
00764 char linestr[128];
00765 char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
00766
00767 if (level != __LOG_VERBOSE) {
00768 int res;
00769 sprintf(linestr, "%d", line);
00770 ast_dynamic_str_thread_set(&buf, BUFSIZ, &log_buf,
00771 "[%s] %s[%ld]: %s:%s %s: ",
00772 date,
00773 term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
00774 (long)GETTID(),
00775 term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
00776 term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
00777 term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
00778
00779 term_filter_escapes(buf->str);
00780 ast_console_puts_mutable(buf->str);
00781
00782 va_start(ap, fmt);
00783 res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap);
00784 va_end(ap);
00785 if (res != AST_DYNSTR_BUILD_FAILED)
00786 ast_console_puts_mutable(buf->str);
00787 }
00788
00789 } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
00790 int res;
00791 ast_dynamic_str_thread_set(&buf, BUFSIZ, &log_buf,
00792 "[%s] %s[%ld] %s: ",
00793 date, levels[level], (long)GETTID(), file);
00794 res = fprintf(chan->fileptr, "%s", buf->str);
00795 if (res <= 0 && !ast_strlen_zero(buf->str)) {
00796 fprintf(stderr,"**** Asterisk Logging Error: ***********\n");
00797 if (errno == ENOMEM || errno == ENOSPC) {
00798 fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
00799 } else
00800 fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
00801 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
00802 chan->disabled = 1;
00803 } else {
00804 int res;
00805
00806 va_start(ap, fmt);
00807 res = ast_dynamic_str_thread_set_va(&buf, BUFSIZ, &log_buf, fmt, ap);
00808 va_end(ap);
00809 if (res != AST_DYNSTR_BUILD_FAILED) {
00810 term_strip(buf->str, buf->str, buf->len);
00811 fputs(buf->str, chan->fileptr);
00812 fflush(chan->fileptr);
00813 }
00814 }
00815 }
00816 }
00817
00818 AST_LIST_UNLOCK(&logchannels);
00819
00820 if (filesize_reload_needed) {
00821 reload_logger(1);
00822 ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00823 if (option_verbose)
00824 ast_verbose("Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
00825 }
00826 }
00827
00828 void ast_backtrace(void)
00829 {
00830 #ifdef linux
00831 #ifdef AST_DEVMODE
00832 int count=0, i=0;
00833 void **addresses;
00834 char **strings;
00835
00836 if ((addresses = ast_calloc(MAX_BACKTRACE_FRAMES, sizeof(*addresses)))) {
00837 count = backtrace(addresses, MAX_BACKTRACE_FRAMES);
00838 if ((strings = backtrace_symbols(addresses, count))) {
00839 ast_log(LOG_DEBUG, "Got %d backtrace record%c\n", count, count != 1 ? 's' : ' ');
00840 for (i=0; i < count ; i++) {
00841 #if __WORDSIZE == 32
00842 ast_log(LOG_DEBUG, "#%d: [%08X] %s\n", i, (unsigned int)addresses[i], strings[i]);
00843 #elif __WORDSIZE == 64
00844 ast_log(LOG_DEBUG, "#%d: [%016lX] %s\n", i, (unsigned long)addresses[i], strings[i]);
00845 #endif
00846 }
00847 free(strings);
00848 } else {
00849 ast_log(LOG_DEBUG, "Could not allocate memory for backtrace\n");
00850 }
00851 free(addresses);
00852 }
00853 #else
00854 ast_log(LOG_WARNING, "Must run configure with '--enable-dev-mode' for stack backtraces.\n");
00855 #endif
00856 #else
00857 ast_log(LOG_WARNING, "Inline stack backtraces are only available on the Linux platform.\n");
00858 #endif
00859 }
00860
00861 void ast_verbose(const char *fmt, ...)
00862 {
00863 struct verb *v;
00864 struct ast_dynamic_str *buf;
00865 int res;
00866 va_list ap;
00867
00868 if (ast_opt_timestamp) {
00869 time_t t;
00870 struct tm tm;
00871 char date[40];
00872 char *datefmt;
00873
00874 time(&t);
00875 ast_localtime(&t, &tm, NULL);
00876 strftime(date, sizeof(date), dateformat, &tm);
00877 datefmt = alloca(strlen(date) + 3 + strlen(fmt) + 1);
00878 sprintf(datefmt, "[%s] %s", date, fmt);
00879 fmt = datefmt;
00880 }
00881
00882 if (!(buf = ast_dynamic_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE)))
00883 return;
00884
00885 va_start(ap, fmt);
00886 res = ast_dynamic_str_thread_set_va(&buf, 0, &verbose_buf, fmt, ap);
00887 va_end(ap);
00888
00889 if (res == AST_DYNSTR_BUILD_FAILED)
00890 return;
00891
00892
00893 term_filter_escapes(buf->str);
00894
00895 AST_LIST_LOCK(&verbosers);
00896 AST_LIST_TRAVERSE(&verbosers, v, list)
00897 v->verboser(buf->str);
00898 AST_LIST_UNLOCK(&verbosers);
00899
00900 ast_log(LOG_VERBOSE, "%s", buf->str);
00901 }
00902
00903 int ast_register_verbose(void (*v)(const char *string))
00904 {
00905 struct verb *verb;
00906
00907 if (!(verb = ast_malloc(sizeof(*verb))))
00908 return -1;
00909
00910 verb->verboser = v;
00911
00912 AST_LIST_LOCK(&verbosers);
00913 AST_LIST_INSERT_HEAD(&verbosers, verb, list);
00914 AST_LIST_UNLOCK(&verbosers);
00915
00916 return 0;
00917 }
00918
00919 int ast_unregister_verbose(void (*v)(const char *string))
00920 {
00921 struct verb *cur;
00922
00923 AST_LIST_LOCK(&verbosers);
00924 AST_LIST_TRAVERSE_SAFE_BEGIN(&verbosers, cur, list) {
00925 if (cur->verboser == v) {
00926 AST_LIST_REMOVE_CURRENT(&verbosers, list);
00927 free(cur);
00928 break;
00929 }
00930 }
00931 AST_LIST_TRAVERSE_SAFE_END
00932 AST_LIST_UNLOCK(&verbosers);
00933
00934 return cur ? 0 : -1;
00935 }