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