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