root/src/utils/noit_log.c

Revision 4bed82ba2ec9a01ba1c538c5f0f2d7c17e0bd687, 9.6 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

update the noit_log new API to allow passing of a context

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