root/src/utils/noit_log.c

Revision a136e6147196fd1969fa920391a6d55ed3975fde, 8.6 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 11 years ago)

rework a lot of config stuff, add docs in a bad place.. README.txt? come on Theo.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #define DEFAULT_JLOG_SUBSCRIBER "stratcond"
7
8 #include "noit_defines.h"
9 #include <stdio.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12 #include <sys/time.h>
13
14 #include "utils/noit_log.h"
15 #include "utils/noit_hash.h"
16 #include "jlog/jlog.h"
17
18 static noit_hash_table noit_loggers = NOIT_HASH_EMPTY;
19 static noit_hash_table noit_logops = NOIT_HASH_EMPTY;
20 noit_log_stream_t noit_stderr = NULL;
21 noit_log_stream_t noit_error = NULL;
22 noit_log_stream_t noit_debug = NULL;
23
24 static int
25 posix_logio_open(noit_log_stream_t ls) {
26   int fd;
27   fd = open(ls->path, O_CREAT|O_WRONLY|O_APPEND);
28   if(fd < 0) {
29     ls->op_ctx = NULL;
30     return -1;
31   }
32   ls->op_ctx = (void *)fd;
33   return 0;
34 }
35 static int
36 posix_logio_reopen(noit_log_stream_t ls) {
37   if(ls->path) {
38     int newfd, oldfd;
39     oldfd = (int)ls->op_ctx;
40     newfd = open(ls->path, O_CREAT|O_WRONLY|O_APPEND);
41     if(newfd >= 0) {
42       ls->op_ctx = (void *)newfd;
43       if(oldfd >= 0) close(oldfd);
44       return 0;
45     }
46   }
47   return -1;
48 }
49 static int
50 posix_logio_write(noit_log_stream_t ls, const void *buf, size_t len) {
51   int fd;
52   fd = (int)ls->op_ctx;
53   if(fd < 0) return -1;
54   return write(fd, buf, len);
55 }
56 static int
57 posix_logio_close(noit_log_stream_t ls) {
58   int fd;
59   fd = (int)ls->op_ctx;
60   return close(fd);
61 }
62 static logops_t posix_logio_ops = {
63   posix_logio_open,
64   posix_logio_reopen,
65   posix_logio_write,
66   posix_logio_close,
67 };
68
69 static int
70 jlog_logio_open(noit_log_stream_t ls) {
71   jlog_ctx *log = NULL;
72   if(!ls->path) return -1;
73   log = jlog_new(ls->path);
74   if(!log) return -1;
75   /* Open the writer. */
76   if(jlog_ctx_open_writer(log)) {
77     /* If that fails, we'll give one attempt at initiailizing it. */
78     /* But, since we attempted to open it as a writer, it is tainted. */
79     /* path: close, new, init, close, new, writer, add subscriber */
80     jlog_ctx_close(log);
81     log = jlog_new(ls->path);
82     if(jlog_ctx_init(log)) {
83       noitL(noit_error, "Cannot init jlog writer: %s\n",
84             jlog_ctx_err_string(log));
85       jlog_ctx_close(log);
86       return -1;
87     }
88     /* After it is initialized, we can try to reopen it as a writer. */
89     jlog_ctx_close(log);
90     log = jlog_new(ls->path);
91     if(jlog_ctx_open_writer(log)) {
92       noitL(noit_error, "Cannot open jlog writer: %s\n",
93             jlog_ctx_err_string(log));
94       jlog_ctx_close(log);
95       return -1;
96     }
97     /* The first time we open after an init, we should add the subscriber. */
98     jlog_ctx_add_subscriber(log, DEFAULT_JLOG_SUBSCRIBER, JLOG_BEGIN);
99   }
100   ls->op_ctx = log;
101   return 0;
102 }
103 static int
104 jlog_logio_reopen(noit_log_stream_t ls) {
105   return 0;
106 }
107 static int
108 jlog_logio_write(noit_log_stream_t ls, const void *buf, size_t len) {
109   if(!ls->op_ctx) return -1;
110   if(jlog_ctx_write((jlog_ctx *)ls->op_ctx, buf, len) != 0)
111     return -1;
112   return len;
113 }
114 static int
115 jlog_logio_close(noit_log_stream_t ls) {
116   if(ls->op_ctx) {
117     jlog_ctx_close((jlog_ctx *)ls->op_ctx);
118     ls->op_ctx = NULL;
119   }
120   return 0;
121 }
122 static logops_t jlog_logio_ops = {
123   jlog_logio_open,
124   jlog_logio_reopen,
125   jlog_logio_write,
126   jlog_logio_close,
127 };
128
129 void
130 noit_log_init() {
131   noit_hash_init(&noit_loggers);
132   noit_hash_init(&noit_logops);
133   noit_register_logops("file", &posix_logio_ops);
134   noit_register_logops("jlog", &jlog_logio_ops);
135   noit_stderr = noit_log_stream_new_on_fd("stderr", 2, NULL);
136   noit_error = noit_log_stream_new("error", NULL, NULL, NULL);
137   noit_debug = noit_log_stream_new("debug", NULL, NULL, NULL);
138 }
139
140 void
141 noit_register_logops(const char *name, logops_t *ops) {
142   noit_hash_store(&noit_logops, strdup(name), strlen(name), ops);
143 }
144
145 noit_log_stream_t
146 noit_log_stream_new_on_fd(const char *name, int fd, noit_hash_table *config) {
147   noit_log_stream_t ls;
148   ls = calloc(1, sizeof(*ls));
149   ls->name = strdup(name);
150   ls->ops = &posix_logio_ops;
151   ls->op_ctx = (void *)fd;
152   ls->enabled = 1;
153   ls->config = config;
154   /* This double strdup of ls->name is needed, look for the next one
155    * for an explanation.
156    */
157   if(noit_hash_store(&noit_loggers,
158                      strdup(ls->name), strlen(ls->name), ls) == 0) {
159     free(ls->name);
160     free(ls);
161     return NULL;
162   }
163   return ls;
164 }
165
166 noit_log_stream_t
167 noit_log_stream_new_on_file(const char *path, noit_hash_table *config) {
168   return noit_log_stream_new(path, "file", path, config);
169 }
170
171 noit_log_stream_t
172 noit_log_stream_new(const char *name, const char *type, const char *path,
173                     noit_hash_table *config) {
174   noit_log_stream_t ls, saved;
175   struct _noit_log_stream tmpbuf;
176   ls = calloc(1, sizeof(*ls));
177   ls->name = strdup(name);
178   ls->path = path ? strdup(path) : NULL;
179   ls->enabled = 1;
180   ls->config = config;
181   if(!type)
182     ls->ops = NULL;
183   else if(!noit_hash_retrieve(&noit_logops, type, strlen(type),
184                               (void **)&ls->ops))
185     goto freebail;
186  
187   if(ls->ops && ls->ops->openop(ls)) goto freebail;
188
189   saved = noit_log_stream_find(name);
190   if(saved) {
191     memcpy(&tmpbuf, saved, sizeof(*saved));
192     memcpy(saved, ls, sizeof(*saved));
193     memcpy(ls, &tmpbuf, sizeof(*saved));
194     noit_log_stream_free(ls);
195     ls = saved;
196   }
197   else
198     /* We strdup the name *again*.  We'going to kansas city shuffle the
199      * ls later (see memcpy above).  However, if don't strdup, then the
200      * noit_log_stream_free up there will sweep our key right our from
201      * under us.
202      */
203     if(noit_hash_store(&noit_loggers,
204                        strdup(ls->name), strlen(ls->name), ls) == 0)
205       goto freebail;
206
207   return ls;
208
209  freebail:
210   fprintf(stderr, "Failed to instantiate logger(%s,%s,%s)\n",
211           name, type ? type : "[null]", path ? path : "[null]");
212   free(ls->name);
213   if(ls->path) free(ls->path);
214   free(ls);
215   return NULL;
216 }
217
218 noit_log_stream_t
219 noit_log_stream_find(const char *name) {
220   noit_log_stream_t ls;
221   if(noit_hash_retrieve(&noit_loggers, name, strlen(name), (void **)&ls)) {
222     return ls;
223   }
224   return NULL;
225 }
226
227 void
228 noit_log_stream_remove(const char *name) {
229   noit_hash_delete(&noit_loggers, name, strlen(name), NULL, NULL);
230 }
231
232 void
233 noit_log_stream_add_stream(noit_log_stream_t ls, noit_log_stream_t outlet) {
234   struct _noit_log_stream_outlet_list *newnode;
235   newnode = calloc(1, sizeof(*newnode));
236   newnode->outlet = outlet;
237   newnode->next = ls->outlets;
238   ls->outlets = newnode;
239 }
240
241 noit_log_stream_t
242 noit_log_stream_remove_stream(noit_log_stream_t ls, const char *name) {
243   noit_log_stream_t outlet;
244   struct _noit_log_stream_outlet_list *node, *tmp;
245   if(!ls->outlets) return NULL;
246   if(!strcmp(ls->outlets->outlet->name, name)) {
247     node = ls->outlets;
248     ls->outlets = node->next;
249     outlet = node->outlet;
250     free(node);
251     return outlet;
252   }
253   for(node = ls->outlets; node->next; node = node->next) {
254     if(!strcmp(node->next->outlet->name, name)) {
255       /* splice */
256       tmp = node->next;
257       node->next = tmp->next;
258       /* pluck */
259       outlet = tmp->outlet;
260       /* shed */
261       free(tmp);
262       /* return */
263       return outlet;
264     }
265   }
266   return NULL;
267 }
268
269 void noit_log_stream_reopen(noit_log_stream_t ls) {
270   struct _noit_log_stream_outlet_list *node;
271   if(ls->ops) ls->ops->reopenop(ls);
272   for(node = ls->outlets; node; node = node->next) {
273     noit_log_stream_reopen(node->outlet);
274   }
275 }
276
277 void
278 noit_log_stream_close(noit_log_stream_t ls) {
279   if(ls->ops) ls->ops->closeop(ls);
280 }
281
282 void
283 noit_log_stream_free(noit_log_stream_t ls) {
284   if(ls) {
285     struct _noit_log_stream_outlet_list *node;
286     if(ls->name) free(ls->name);
287     if(ls->path) free(ls->path);
288     while(ls->outlets) {
289       node = ls->outlets->next;
290       free(ls->outlets);
291       ls->outlets = node;
292     }
293     if(ls->config) {
294       noit_hash_destroy(ls->config, free, free);
295       free(ls->config);
296     }
297     free(ls);
298   }
299 }
300
301 void
302 noit_vlog(noit_log_stream_t ls, struct timeval *now,
303           const char *file, int line,
304           const char *format, va_list arg) {
305   char buffer[4096];
306   struct _noit_log_stream_outlet_list *node;
307 #ifdef va_copy
308   va_list copy;
309 #endif
310
311   if(ls->enabled) {
312     int len;
313     if(ls->ops) {
314 #ifdef va_copy
315       va_copy(copy, arg);
316       len = vsnprintf(buffer, sizeof(buffer), format, copy);
317       va_end(copy);
318 #else
319       len = vsnprintf(buffer, sizeof(buffer), format, arg);
320 #endif
321       ls->ops->writeop(ls, buffer, len); /* Not much one can do about errors */
322     }
323
324     for(node = ls->outlets; node; node = node->next) {
325   #ifdef va_copy
326       va_copy(copy, arg);
327       noit_vlog(node->outlet, now, file, line, format, copy);
328       va_end(copy);
329   #else
330       noit_vlog(node->outlet, now, file, line, format, arg);
331   #endif
332     }
333   }
334 }
335
336 void
337 noit_log(noit_log_stream_t ls, struct timeval *now,
338          const char *file, int line, const char *format, ...) {
339   va_list arg;
340   va_start(arg, format);
341   noit_vlog(ls, now, file, line, format, arg);
342   va_end(arg);
343 }
344
Note: See TracBrowser for help on using the browser.