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