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
18 #include <asterisk/lock.h>
19 #include <asterisk/logger.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>
33 #define MAX_MSG_QUEUE 200
35 static ast_mutex_t msglist_lock = AST_MUTEX_INITIALIZER;
36 static ast_mutex_t loglock = AST_MUTEX_INITIALIZER;
38 static struct msglist {
41 } *list = NULL, *last = NULL;
50 static struct logfile *logfiles = NULL;
52 static int msgcnt = 0;
54 static FILE *eventlog = NULL;
56 static char *levels[] = {
64 static int colors[] = {
72 static int make_components(char *s, int lineno)
78 w = strsep(&stringp, ",");
80 while(*w && (*w < 33))
82 if (!strcasecmp(w, "debug"))
84 else if (!strcasecmp(w, "notice"))
86 else if (!strcasecmp(w, "warning"))
88 else if (!strcasecmp(w, "error"))
91 fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
93 w = strsep(&stringp, ",");
98 static struct logfile *make_logfile(char *fn, char *components, int lineno)
104 f = malloc(sizeof(struct logfile));
106 memset(f, 0, sizeof(f));
107 strncpy(f->fn, fn, sizeof(f->fn) - 1);
108 if (!strcasecmp(fn, "ignore")) {
110 } else if (!strcasecmp(fn, "console")) {
114 strncpy(tmp, fn, sizeof(tmp) - 1);
116 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, fn);
117 f->f = fopen(tmp, "a");
119 /* Can't log here, since we're called with a lock */
120 fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", tmp, strerror(errno));
123 f->logflags = make_components(components, lineno);
129 static void init_logger_chain(void)
131 struct logfile *f, *cur;
132 struct ast_config *cfg;
133 struct ast_variable *var;
135 ast_mutex_lock(&loglock);
137 /* Free anything that is here */
141 if (f->f && (f->f != stdout) && (f->f != stderr))
149 ast_mutex_unlock(&loglock);
150 cfg = ast_load("logger.conf");
151 ast_mutex_lock(&loglock);
153 /* If no config file, we're fine */
155 ast_mutex_unlock(&loglock);
158 var = ast_variable_browse(cfg, "logfiles");
160 f = make_logfile(var->name, var->value, var->lineno);
168 /* Gotta have at least one. We'll make a NULL one */
169 logfiles = make_logfile("ignore", "", -1);
172 ast_mutex_unlock(&loglock);
177 int reload_logger(void)
179 char tmp[AST_CONFIG_MAX_PATH];
180 ast_mutex_lock(&loglock);
183 mkdir((char *)ast_config_AST_LOG_DIR, 0755);
184 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
185 eventlog = fopen((char *)tmp, "a");
186 ast_mutex_unlock(&loglock);
190 ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
192 ast_verbose("Asterisk Event Logger restarted\n");
195 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
200 static int handle_logger_reload(int fd, int argc, char *argv[])
204 ast_cli(fd, "Failed to reloadthe logger\n");
205 return RESULT_FAILURE;
208 return RESULT_SUCCESS;
212 void (*verboser)(const char *string, int opos, int replacelast, int complete);
217 static char logger_reload_help[] =
218 "Usage: logger reload\n"
219 " Reopens the log files. Use after a rotating the log files\n";
221 static struct ast_cli_entry reload_logger_cli =
222 { { "logger", "reload", NULL },
223 handle_logger_reload, "Reopens the log files",
224 logger_reload_help };
227 int init_logger(void)
229 char tmp[AST_CONFIG_MAX_PATH];
231 /* register the relaod logger cli command */
232 ast_cli_register(&reload_logger_cli);
234 mkdir((char *)ast_config_AST_LOG_DIR, 0755);
235 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
236 eventlog = fopen((char *)tmp, "a");
239 ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
241 ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp);
244 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
250 extern void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
263 if (!option_verbose && !option_debug && (!level)) {
266 ast_mutex_lock(&loglock);
267 if (level == 1 /* Event */) {
271 /* Log events into the event log file, with a different format */
272 strftime(date, sizeof(date), "%b %e %T", &tm);
273 fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
275 vfprintf(eventlog, fmt, ap);
279 /** Cannot use ast_log() from locked section of ast_log()!
280 ast_log(LOG_WARNING, "Unable to retrieve local time?\n"); **/
281 fprintf(stderr, "ast_log: Unable to retrieve local time for %ld?\n", (long)t);
286 if (f->logflags & (1 << level) && f->f) {
287 if ((f->f != stdout) && (f->f != stderr)) {
290 strftime(date, sizeof(date), "%b %e %T", &tm);
291 fprintf(f->f, "%s %s[%ld]: File %s, Line %d (%s): ", date, levels[level], (long)pthread_self(), file, line, function);
293 sprintf(linestr, "%d", line);
294 fprintf(f->f, "%s[%ld]: File %s, Line %s (%s): ",
295 term_color(tmp, levels[level], colors[level], 0, sizeof(tmp)),
296 (long)pthread_self(),
297 term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
298 term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
299 term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
302 vfprintf(f->f, fmt, ap);
309 fprintf(stdout, "%s[%ld]: File %s, Line %d (%s): ", levels[level], (long)pthread_self(), file, line, function);
311 vfprintf(stdout, fmt, ap);
316 ast_mutex_unlock(&loglock);
319 extern void ast_verbose(const char *fmt, ...)
321 static char stuff[4096];
322 static int pos = 0, opos;
323 static int replacelast = 0, complete;
328 ast_mutex_lock(&msglist_lock);
329 vsnprintf(stuff + pos, sizeof(stuff) - pos, fmt, ap);
332 if (fmt[strlen(fmt)-1] == '\n')
337 if (msgcnt < MAX_MSG_QUEUE) {
338 /* Allocate new structure */
339 m = malloc(sizeof(struct msglist));
342 /* Recycle the oldest entry */
348 m->msg = strdup(stuff);
358 ast_log(LOG_DEBUG, "Out of memory\n");
366 v->verboser(stuff, opos, replacelast, complete);
370 fprintf(stdout, stuff + opos); */
372 if (fmt[strlen(fmt)-1] != '\n')
375 replacelast = pos = 0;
377 ast_mutex_unlock(&msglist_lock);
380 int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
384 ast_mutex_lock(&msglist_lock);
386 /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
390 ast_mutex_unlock(&msglist_lock);
394 int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
398 /* XXX Should be more flexible here, taking > 1 verboser XXX */
399 if ((tmp = malloc(sizeof (struct verb)))) {
401 ast_mutex_lock(&msglist_lock);
402 tmp->next = verboser;
406 /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
410 ast_mutex_unlock(&msglist_lock);
416 int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
419 struct verb *tmp, *tmpl=NULL;
420 ast_mutex_lock(&msglist_lock);
423 if (tmp->verboser == v) {
425 tmpl->next = tmp->next;
427 verboser = tmp->next;
436 ast_mutex_unlock(&msglist_lock);