root/src/utils/noit_log.c

Revision ae34340dde2024044a43857931d99258a1b3a477, 10.7 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

persist the mode and use it on reopen

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