Version 0.1.0 from FTP
[asterisk/asterisk.git] / logger.c
1 /*
2  * Cheops Next Generation
3  * 
4  * Mark Spencer <markster@marko.net>
5  *
6  * Copyright(C) 1999, Adtran, Inc.
7  * 
8  * Distributed under the terms of the GNU General Public License (GPL) Version 2
9  *
10  * Logging routines
11  *
12  */
13
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <time.h>
18 #include <asterisk/logger.h>
19 #include <asterisk/options.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <pthread.h>
24 #include <sys/stat.h>
25 #include "asterisk.h"
26
27 #define AST_EVENT_LOG AST_LOG_DIR "/" EVENTLOG
28
29 #define MAX_MSG_QUEUE 200
30
31 static pthread_mutex_t msglist_lock = PTHREAD_MUTEX_INITIALIZER;
32
33 static struct msglist {
34         char *msg;
35         struct msglist *next;
36 } *list = NULL, *last = NULL;
37
38 static int msgcnt = 0;
39
40 static FILE *eventlog = NULL;
41
42 static char *levels[] = {
43         "DEBUG",
44         "EVENT",
45         "NOTICE",
46         "WARNING",
47         "ERROR"
48 };
49
50 static struct verb {
51         void (*verboser)(char *string, int opos, int replacelast, int complete);
52         struct verb *next;
53 } *verboser = NULL;
54
55 int init_logger(void)
56 {
57
58         mkdir(AST_LOG_DIR, 0755);
59         eventlog = fopen(AST_EVENT_LOG, "a");
60         if (eventlog) {
61                 ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
62                 if (option_verbose)
63                         ast_verbose("Asterisk Event Logger Started\n");
64                 return 0;
65         } else 
66                 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
67         return -1;
68 }
69
70 extern void ast_log(int level, char *file, int line, char *function, char *fmt, ...)
71 {
72         char date[256];
73         time_t t;
74         struct tm *tm;
75
76         va_list ap;
77         va_start(ap, fmt);
78
79         if (level == 1 /* Event */) {
80                 time(&t);
81                 tm = localtime(&t);
82                 if (tm) {
83                         /* Log events into the event log file, with a different format */
84                         strftime(date, sizeof(date), "%b %e %T", tm);
85                         fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
86                         vfprintf(eventlog, fmt, ap);
87                         fflush(eventlog);
88                 } else
89                         ast_log(LOG_WARNING, "Unable to retrieve local time?\n");
90         } else {
91                 fprintf(stdout, "%s: File %s, Line %d (%s): ", levels[level], file, line, function);
92                 vfprintf(stdout, fmt, ap);
93                 fflush(stdout);
94         }
95         va_end(ap);
96 }
97
98 extern void ast_verbose(char *fmt, ...)
99 {
100         static char stuff[256];
101         static int pos = 0, opos;
102         static int replacelast = 0, complete;
103         struct msglist *m;
104         struct verb *v;
105         va_list ap;
106         va_start(ap, fmt);
107         pthread_mutex_lock(&msglist_lock);
108         vsnprintf(stuff + pos, sizeof(stuff) - pos, fmt, ap);
109         opos = pos;
110         pos = strlen(stuff);
111         if (fmt[strlen(fmt)-1] == '\n') 
112                 complete = 1;
113         else
114                 complete=0;
115         if (complete) {
116                 if (msgcnt < MAX_MSG_QUEUE) {
117                         /* Allocate new structure */
118                         m = malloc(sizeof(struct msglist));
119                         msgcnt++;
120                 } else {
121                         /* Recycle the oldest entry */
122                         m = list;
123                         list = list->next;
124                         free(m->msg);
125                 }
126                 if (m) {
127                         m->msg = strdup(stuff);
128                         if (m->msg) {
129                                 if (last)
130                                         last->next = m;
131                                 else
132                                         list = m;
133                                 m->next = NULL;
134                                 last = m;
135                         } else {
136                                 msgcnt--;
137                                 ast_log(LOG_DEBUG, "Out of memory\n");
138                                 free(m);
139                         }
140                 }
141         }
142         if (verboser) {
143                 v = verboser;
144                 while(v) {
145                         v->verboser(stuff, opos, replacelast, complete);
146                         v = v->next;
147                 }
148         } else
149                 fprintf(stdout, stuff + opos);
150
151         if (fmt[strlen(fmt)-1] != '\n') 
152                 replacelast = 1;
153         else 
154                 replacelast = pos = 0;
155         
156         va_end(ap);
157         pthread_mutex_unlock(&msglist_lock);
158 }
159
160
161 int ast_register_verbose(void (*v)(char *string, int opos, int replacelast, int complete)) 
162 {
163         struct msglist *m;
164         struct verb *tmp;
165         /* XXX Should be more flexible here, taking > 1 verboser XXX */
166         if ((tmp = malloc(sizeof (struct verb)))) {
167                 tmp->verboser = v;
168                 pthread_mutex_lock(&msglist_lock);
169                 tmp->next = verboser;
170                 verboser = tmp;
171                 m = list;
172                 while(m) {
173                         /* Send all the existing entries that we have queued (i.e. they're likely to have missed) */
174                         v(m->msg, 0, 0, 1);
175                         m = m->next;
176                 }
177                 pthread_mutex_unlock(&msglist_lock);
178                 return 0;
179         }
180         return -1;
181 }
182
183 int ast_unregister_verbose(void (*v)(char *string, int opos, int replacelast, int complete))
184 {
185         int res = -1;
186         struct verb *tmp, *tmpl=NULL;
187         pthread_mutex_lock(&msglist_lock);
188         tmp = verboser;
189         while(tmp) {
190                 if (tmp->verboser == v) {
191                         if (tmpl)
192                                 tmpl->next = tmp->next;
193                         else
194                                 verboser = tmp->next;
195                         break;
196                 }
197                 tmpl = tmp;
198                 tmp = tmp->next;
199         }
200         if (tmp)
201                 res = 0;
202         pthread_mutex_unlock(&msglist_lock);
203         return res;
204 }