4 * Mark Spencer <markster@marko.net>
6 * Copyright(C)1999, Linux Support Services, Inc.
8 * Distributed under the terms of the GNU General Public License (GPL) Version 2
19 #include <asterisk/lock.h>
20 #include <asterisk/options.h>
21 #include <asterisk/channel.h>
22 #include <asterisk/config.h>
23 #include <asterisk/term.h>
24 #include <asterisk/cli.h>
25 #include <asterisk/utils.h>
34 #define SYSLOG_NAMES /* so we can map syslog facilities names to their numeric values,
35 from <syslog.h> which is included by logger.h */
37 static int syslog_level_map[] = {
39 LOG_INFO, /* arbitrary equivalent of LOG_EVENT */
45 #define SYSLOG_NLEVELS 6
47 #include <asterisk/logger.h>
49 #define MAX_MSG_QUEUE 200
51 static char dateformat[256] = "%b %e %T"; /* Original Asterisk Format */
52 AST_MUTEX_DEFINE_STATIC(msglist_lock);
53 AST_MUTEX_DEFINE_STATIC(loglock);
54 static int pending_logger_reload = 0;
56 static struct msglist {
59 } *list = NULL, *last = NULL;
63 int facility; /* syslog */
64 int syslog; /* syslog flag */
65 int console; /* console logging */
66 FILE *fileptr; /* logfile logging */
68 struct logchannel *next;
71 static struct logchannel *logchannels = NULL;
73 static int msgcnt = 0;
75 static FILE *eventlog = NULL;
77 static char *levels[] = {
86 static int colors[] = {
95 static int make_components(char *s, int lineno)
101 w = strsep(&stringp, ",");
103 while(*w && (*w < 33))
105 if (!strcasecmp(w, "error"))
106 res |= (1 << __LOG_ERROR);
107 else if (!strcasecmp(w, "warning"))
108 res |= (1 << __LOG_WARNING);
109 else if (!strcasecmp(w, "notice"))
110 res |= (1 << __LOG_NOTICE);
111 else if (!strcasecmp(w, "event"))
112 res |= (1 << __LOG_EVENT);
113 else if (!strcasecmp(w, "debug"))
114 res |= (1 << __LOG_DEBUG);
115 else if (!strcasecmp(w, "verbose"))
116 res |= (1 << __LOG_VERBOSE);
118 fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
120 w = strsep(&stringp, ",");
125 static struct logchannel *make_logchannel(char *channel, char *components, int lineno)
127 struct logchannel *chan;
131 if (ast_strlen_zero(channel))
133 chan = malloc(sizeof(struct logchannel));
136 memset(chan, 0, sizeof(struct logchannel));
137 if (!strcasecmp(channel, "console")) {
139 } else if (!strncasecmp(channel, "syslog", 6)) {
142 * syslog.facility => level,level,level
144 facility = strchr(channel, '.');
145 if(!facility++ || !facility) {
149 * Walk through the list of facilitynames (defined in sys/syslog.h)
150 * to see if we can find the one we have been given
153 cptr = facilitynames;
154 while (cptr->c_name) {
155 if (!strncasecmp(facility, cptr->c_name, sizeof(cptr->c_name))) {
156 chan->facility = cptr->c_val;
161 if (0 > chan->facility) {
162 fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
168 openlog("asterisk", LOG_PID, chan->facility);
170 if (channel[0] == '/')
171 strncpy(chan->filename, channel, sizeof(chan->filename) - 1);
173 snprintf(chan->filename, sizeof(chan->filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, channel);
174 chan->fileptr = fopen(chan->filename, "a");
175 if (!chan->fileptr) {
176 /* Can't log here, since we're called with a lock */
177 fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
180 chan->logmask = make_components(components, lineno);
185 static void init_logger_chain(void)
187 struct logchannel *chan, *cur;
188 struct ast_config *cfg;
189 struct ast_variable *var;
192 /* delete our list of log channels */
193 ast_mutex_lock(&loglock);
201 ast_mutex_unlock(&loglock);
206 cfg = ast_load("logger.conf");
208 /* If no config file, we're fine */
212 ast_mutex_lock(&loglock);
213 if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
214 (void)strncpy(dateformat,s,sizeof(dateformat));
216 var = ast_variable_browse(cfg, "logfiles");
218 chan = make_logchannel(var->name, var->value, var->lineno);
220 chan->next = logchannels;
227 ast_mutex_unlock(&loglock);
230 static FILE *qlog = NULL;
231 AST_MUTEX_DEFINE_STATIC(qloglock);
233 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
236 ast_mutex_lock(&qloglock);
239 fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
240 vfprintf(qlog, fmt, ap);
245 ast_mutex_unlock(&qloglock);
248 static void queue_log_init(void)
252 ast_mutex_lock(&qloglock);
258 snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, "queue_log");
259 qlog = fopen(filename, "a");
260 ast_mutex_unlock(&qloglock);
262 ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
264 ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
267 int reload_logger(int rotate)
269 char old[AST_CONFIG_MAX_PATH];
270 char new[AST_CONFIG_MAX_PATH];
271 struct logchannel *f;
275 ast_mutex_lock(&loglock);
284 mkdir((char *)ast_config_AST_LOG_DIR, 0755);
285 snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
289 snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x);
290 myf = fopen((char *)new, "r");
299 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
302 eventlog = fopen(old, "a");
306 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
310 strncpy(old, f->filename, sizeof(old));
313 snprintf(new, sizeof(new), "%s.%d", f->filename, x);
314 myf = fopen((char *)new, "r");
324 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
330 ast_mutex_unlock(&loglock);
336 ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
338 ast_verbose("Asterisk Event Logger restarted\n");
341 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
343 pending_logger_reload = 0;
347 static int handle_logger_reload(int fd, int argc, char *argv[])
351 ast_cli(fd, "Failed to reloadthe logger\n");
352 return RESULT_FAILURE;
355 return RESULT_SUCCESS;
358 static int handle_logger_rotate(int fd, int argc, char *argv[])
362 ast_cli(fd, "Failed to reloadthe logger\n");
363 return RESULT_FAILURE;
366 return RESULT_SUCCESS;
370 void (*verboser)(const char *string, int opos, int replacelast, int complete);
375 static char logger_reload_help[] =
376 "Usage: logger reload\n"
377 " Reloads the logger subsystem state. Use after restarting syslogd(8)\n";
379 static char logger_rotate_help[] =
380 "Usage: logger rotate\n"
381 " Rotates and Reopens the log files.\n";
383 static struct ast_cli_entry reload_logger_cli =
384 { { "logger", "reload", NULL },
385 handle_logger_reload, "Reopens the log files",
386 logger_reload_help };
388 static struct ast_cli_entry rotate_logger_cli =
389 { { "logger", "rotate", NULL },
390 handle_logger_rotate, "Rotates and reopens the log files",
391 logger_rotate_help };
393 static int handle_SIGXFSZ(int sig) {
394 /* Indicate need to reload */
395 pending_logger_reload = 1;
399 int init_logger(void)
403 /* auto rotate if sig SIGXFSZ comes a-knockin */
404 (void) signal(SIGXFSZ,(void *) handle_SIGXFSZ);
406 /* register the relaod logger cli command */
407 ast_cli_register(&reload_logger_cli);
408 ast_cli_register(&rotate_logger_cli);
410 /* initialize queue logger */
413 /* create the eventlog */
414 mkdir((char *)ast_config_AST_LOG_DIR, 0755);
415 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
416 eventlog = fopen((char *)tmp, "a");
419 ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
421 ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp);
424 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
426 /* create log channels */
431 static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args) {
434 if(level >= SYSLOG_NLEVELS) {
435 /* we are locked here, so cannot ast_log() */
436 fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
439 if(level == __LOG_VERBOSE) {
440 snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)pthread_self());
443 snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
444 levels[level], (long)pthread_self(), file, line, function);
446 vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, args);
447 syslog(syslog_level_map[level], "%s", buf);
451 * send log messages to syslog and/or the console
453 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
455 struct logchannel *chan;
463 if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
467 /* begin critical section */
468 ast_mutex_lock(&loglock);
471 localtime_r(&t, &tm);
472 strftime(date, sizeof(date), dateformat, &tm);
475 if (level == __LOG_EVENT) {
478 fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
479 vfprintf(eventlog, fmt, ap);
483 ast_mutex_unlock(&loglock);
490 if (chan->syslog && (chan->logmask & (1 << level))) {
492 ast_log_vsyslog(level, file, line, function, fmt, ap);
494 } else if ((chan->logmask & (1 << level)) && (chan->console)) {
496 char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
498 if(level != __LOG_VERBOSE) {
499 sprintf(linestr, "%d", line);
500 snprintf(buf, sizeof(buf), "%s %s[%ld]: %s:%s %s: ",
502 term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
503 (long)pthread_self(),
504 term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
505 term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
506 term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
508 ast_console_puts(buf);
510 vsnprintf(buf, sizeof(buf), fmt, ap);
512 ast_console_puts(buf);
514 } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
515 snprintf(buf, sizeof(buf), "%s %s[%ld]: ", date,
516 levels[level], (long)pthread_self());
517 fprintf(chan->fileptr, buf);
519 vsnprintf(buf, sizeof(buf), fmt, ap);
521 fputs(buf, chan->fileptr);
522 fflush(chan->fileptr);
528 * we don't have the logger chain configured yet,
529 * so just log to stdout
531 if (level != __LOG_VERBOSE) {
533 vsnprintf(buf, sizeof(buf), fmt, ap);
539 ast_mutex_unlock(&loglock);
540 /* end critical section */
541 if (pending_logger_reload) {
543 ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ\n");
545 ast_verbose("Rotated Logs Per SIGXFSZ\n");
549 extern void ast_verbose(const char *fmt, ...)
551 static char stuff[4096];
552 static int pos = 0, opos;
553 static int replacelast = 0, complete;
558 ast_mutex_lock(&msglist_lock);
559 vsnprintf(stuff + pos, sizeof(stuff) - pos, fmt, ap);
562 if (fmt[strlen(fmt)-1] == '\n')
567 if (msgcnt < MAX_MSG_QUEUE) {
568 /* Allocate new structure */
569 m = malloc(sizeof(struct msglist));
572 /* Recycle the oldest entry */
578 m->msg = strdup(stuff);
588 ast_log(LOG_ERROR, "Out of memory\n");
596 v->verboser(stuff, opos, replacelast, complete);
600 fprintf(stdout, stuff + opos); */
602 ast_log(LOG_VERBOSE, stuff);
604 if (fmt[strlen(fmt)-1] != '\n')
607 replacelast = pos = 0;
610 ast_mutex_unlock(&msglist_lock);
613 int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
617 ast_mutex_lock(&msglist_lock);
619 /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
623 ast_mutex_unlock(&msglist_lock);
627 int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
631 /* XXX Should be more flexible here, taking > 1 verboser XXX */
632 if ((tmp = malloc(sizeof (struct verb)))) {
634 ast_mutex_lock(&msglist_lock);
635 tmp->next = verboser;
639 /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
643 ast_mutex_unlock(&msglist_lock);
649 int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
652 struct verb *tmp, *tmpl=NULL;
653 ast_mutex_lock(&msglist_lock);
656 if (tmp->verboser == v) {
658 tmpl->next = tmp->next;
660 verboser = tmp->next;
669 ast_mutex_unlock(&msglist_lock);