root/src/utils/noit_log.c

Revision 04242928f5428460d4da69245f0f005b56051fc2, 8.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

basic log streamer, need a client to further test it.

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