root/src/utils/noit_log.c

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

fixes #313. patch from Piotr Sikora < piotr.sikora@frickle.com >

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2005-2009, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *    * Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *    * Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials provided
14  *      with the distribution.
15  *    * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *      of its contributors may be used to endorse or promote products
17  *      derived from this software without specific prior written
18  *      permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #define DEFAULT_JLOG_SUBSCRIBER "stratcon"
34
35 #include "noit_defines.h"
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <sys/uio.h>
40 #include <sys/time.h>
41 #include <assert.h>
42 #if HAVE_ERRNO_H
43 #include <errno.h>
44 #endif
45 #if HAVE_DIRENT_H
46 #include <dirent.h>
47 #endif
48
49 #define noit_log_impl
50 #include "utils/noit_log.h"
51 #include "utils/noit_hash.h"
52 #include "utils/noit_atomic.h"
53 #include "jlog/jlog.h"
54 #include "jlog/jlog_private.h"
55 #ifdef DTRACE_ENABLED
56 #include "utils/dtrace_probes.h"
57 #else
58 #define NOIT_LOG_LOG(a,b,c,d)
59 #define NOIT_LOG_LOG_ENABLED() 0
60 #endif
61
62 static int DEBUG_LOG_ENABLED() {
63   static int enabled = -1;
64   if(enabled == -1) {
65     char *env = getenv("NOIT_LOG_DEBUG");
66     enabled = env ? atoi(env) : 0;
67   }
68   return enabled;
69 }
70 #define debug_printf(a...) do { \
71   if(DEBUG_LOG_ENABLED()) fprintf(stderr, a); \
72 } while(0)
73
74 struct _noit_log_stream {
75   unsigned enabled:1;
76   unsigned debug:1;
77   unsigned timestamps:1;
78   /* Above is exposed... */
79   char *type;
80   char *name;
81   int mode;
82   char *path;
83   logops_t *ops;
84   void *op_ctx;
85   noit_hash_table *config;
86   struct _noit_log_stream_outlet_list *outlets;
87   pthread_rwlock_t *lock;
88   noit_atomic32_t written;
89   unsigned deps_materialized:1;
90   unsigned debug_below:1;
91   unsigned timestamps_below:1;
92 };
93
94 static noit_hash_table noit_loggers = NOIT_HASH_EMPTY;
95 static noit_hash_table noit_logops = NOIT_HASH_EMPTY;
96 noit_log_stream_t noit_stderr = NULL;
97 noit_log_stream_t noit_error = NULL;
98 noit_log_stream_t noit_debug = NULL;
99
100 int noit_log_global_enabled() {
101   return NOIT_LOG_LOG_ENABLED();
102 }
103
104 #define MATERIALIZE_DEPS(ls) do { \
105   if(!(ls)->deps_materialized) materialize_deps(ls); \
106 } while(0)
107
108 static void materialize_deps(noit_log_stream_t ls) {
109   if(ls->deps_materialized) return;
110   if(ls->debug) ls->debug_below = 1;
111   if(ls->timestamps) ls->timestamps_below = 1;
112   if(ls->debug_below == 0 || ls->timestamps_below == 0) {
113     /* we might have children than need these */
114     struct _noit_log_stream_outlet_list *node;
115     for(node = ls->outlets; node; node = node->next) {
116       MATERIALIZE_DEPS(node->outlet);
117       if(!ls->debug) ls->debug_below = node->outlet->debug_below;
118       if(!ls->timestamps) ls->timestamps_below = node->outlet->timestamps_below;
119     }
120   }
121   ls->deps_materialized = 1;
122 }
123 static int
124 posix_logio_open(noit_log_stream_t ls) {
125   int fd;
126   struct stat sb;
127   ls->mode = 0664;
128   fd = open(ls->path, O_CREAT|O_WRONLY|O_APPEND, ls->mode);
129   debug_printf("opened '%s' => %d\n", ls->path, fd);
130   if(fd < 0) {
131     ls->op_ctx = NULL;
132     return -1;
133   }
134   if(fstat(fd, &sb) == 0) ls->written = (int32_t)sb.st_size;
135   ls->op_ctx = (void *)(vpsized_int)fd;
136   return 0;
137 }
138 static int
139 posix_logio_reopen(noit_log_stream_t ls) {
140   if(ls->path) {
141     int newfd, oldfd, rv = -1;
142     if(ls->lock) pthread_rwlock_wrlock(ls->lock);
143     oldfd = (int)(vpsized_int)ls->op_ctx;
144     newfd = open(ls->path, O_CREAT|O_WRONLY|O_APPEND, ls->mode);
145     ls->written = 0;
146     if(newfd >= 0) {
147       struct stat sb;
148       ls->op_ctx = (void *)(vpsized_int)newfd;
149       if(oldfd >= 0) close(oldfd);
150       rv = 0;
151       if(fstat(newfd, &sb) == 0) ls->written = (int32_t)sb.st_size;
152     }
153     if(ls->lock) pthread_rwlock_unlock(ls->lock);
154     return rv;
155   }
156   return -1;
157 }
158 static int
159 posix_logio_write(noit_log_stream_t ls, const void *buf, size_t len) {
160   int fd, rv = -1;
161   if(ls->lock) pthread_rwlock_rdlock(ls->lock);
162   fd = (int)(vpsized_int)ls->op_ctx;
163   debug_printf("writing to %d\n", fd);
164   if(fd >= 0) rv = write(fd, buf, len);
165   if(ls->lock) pthread_rwlock_unlock(ls->lock);
166   if(rv > 0) noit_atomic_add32(&ls->written, rv);
167   return rv;
168 }
169 static int
170 posix_logio_writev(noit_log_stream_t ls, const struct iovec *iov, int iovcnt) {
171   int fd, rv = -1;
172   if(ls->lock) pthread_rwlock_rdlock(ls->lock);
173   fd = (int)(vpsized_int)ls->op_ctx;
174   debug_printf("writ(v)ing to %d\n", fd);
175   if(fd >= 0) rv = writev(fd, iov, iovcnt);
176   if(ls->lock) pthread_rwlock_unlock(ls->lock);
177   if(rv > 0) noit_atomic_add32(&ls->written, rv);
178   return rv;
179 }
180 static int
181 posix_logio_close(noit_log_stream_t ls) {
182   int fd, rv;
183   if(ls->lock) pthread_rwlock_wrlock(ls->lock);
184   fd = (int)(vpsized_int)ls->op_ctx;
185   rv = close(fd);
186   if(ls->lock) pthread_rwlock_unlock(ls->lock);
187   return rv;
188 }
189 static size_t
190 posix_logio_size(noit_log_stream_t ls) {
191   int fd;
192   size_t s = (size_t)-1;
193   struct stat sb;
194   if(ls->lock) pthread_rwlock_rdlock(ls->lock);
195   fd = (int)(vpsized_int)ls->op_ctx;
196   if(fstat(fd, &sb) == 0) {
197     s = (size_t)sb.st_size;
198   }
199   if(ls->lock) pthread_rwlock_unlock(ls->lock);
200   return s;
201 }
202 static int
203 posix_logio_rename(noit_log_stream_t ls, const char *name) {
204   int rv = 0;
205   char autoname[PATH_MAX];
206   if(name == NOIT_LOG_RENAME_AUTOTIME) {
207     time_t now = time(NULL);
208     snprintf(autoname, sizeof(autoname), "%s.%llu",
209              ls->path, (unsigned long long)now);
210     name = autoname;
211   }
212   if(!strcmp(name, ls->path)) return 0; /* noop */
213   if(ls->lock) pthread_rwlock_rdlock(ls->lock);
214   rv = rename(ls->path, name);
215   if(ls->lock) pthread_rwlock_unlock(ls->lock);
216   return -1;
217 }
218 static logops_t posix_logio_ops = {
219   posix_logio_open,
220   posix_logio_reopen,
221   posix_logio_write,
222   posix_logio_writev,
223   posix_logio_close,
224   posix_logio_size,
225   posix_logio_rename
226 };
227
228 static int
229 jlog_lspath_to_fspath(noit_log_stream_t ls, char *buff, int len,
230                       char **subout) {
231   char *sub;
232   if(subout) *subout = NULL;
233   if(!ls->path) return -1;
234   strlcpy(buff, ls->path, len);
235   sub = strchr(buff, '(');
236   if(sub) {
237     char *esub = strchr(sub, ')');
238     if(esub) {
239       *esub = '\0';
240       *sub = '\0';
241       sub += 1;
242       if(subout) *subout = sub;
243     }
244   }
245   return strlen(buff);
246 }
247
248 /* These next functions arr basically cribbed from jlogctl.c */
249 static int
250 is_datafile(const char *f, u_int32_t *logid) {
251   int i;
252   u_int32_t l = 0;
253   for(i=0; i<8; i++) {
254     if((f[i] >= '0' && f[i] <= '9') ||
255        (f[i] >= 'a' && f[i] <= 'f')) {
256       l <<= 4;
257       l |= (f[i] < 'a') ? (f[i] - '0') : (f[i] - 'a' + 10);
258     }
259     else
260       return 0;
261   }
262   if(f[i] != '\0') return 0;
263   if(logid) *logid = l;
264   return 1;
265 }
266
267 static int
268 jlog_logio_cleanse(noit_log_stream_t ls) {
269   jlog_ctx *log;
270   DIR *d;
271   struct dirent *de, *entry;
272   int cnt = 0;
273   char path[PATH_MAX];
274   int size = 0;
275
276   log = (jlog_ctx *)ls->op_ctx;
277   if(!log) return -1;
278   if(jlog_lspath_to_fspath(ls, path, sizeof(path), NULL) <= 0) return -1;
279   d = opendir(path);
280
281 #ifdef _PC_NAME_MAX
282   size = pathconf(path, _PC_NAME_MAX);
283 #endif
284   size = MIN(size, PATH_MAX + 128);
285   de = alloca(size);
286
287   if(!d) return -1;
288   while(portable_readdir_r(d, de, &entry) == 0 && entry != NULL) {
289     u_int32_t logid;
290     if(is_datafile(entry->d_name, &logid)) {
291       int rv;
292       struct stat st;
293       char fullfile[PATH_MAX];
294       char fullidx[PATH_MAX];
295
296       snprintf(fullfile, sizeof(fullfile), "%s/%s", path, entry->d_name);
297       snprintf(fullidx, sizeof(fullidx), "%s/%s" INDEX_EXT,
298                path, entry->d_name);
299       while((rv = stat(fullfile, &st)) != 0 && errno == EINTR);
300       if(rv == 0) {
301         int readers;
302         readers = __jlog_pending_readers(log, logid);
303         if(readers == 0) {
304           unlink(fullfile);
305           unlink(fullidx);
306         }
307       }
308     }
309   }
310   closedir(d);
311   return cnt;
312 }
313
314 static int
315 jlog_logio_reopen(noit_log_stream_t ls) {
316   char **subs;
317   int i;
318   /* reopening only has the effect of removing temporary subscriptions */
319   /* (they start with ~ in our hair-brained model */
320
321   if(ls->lock) pthread_rwlock_wrlock(ls->lock);
322   if(jlog_ctx_list_subscribers(ls->op_ctx, &subs) == -1)
323     goto bail;
324
325   for(i=0;subs[i];i++)
326     if(subs[i][0] == '~')
327       jlog_ctx_remove_subscriber(ls->op_ctx, subs[i]);
328
329   jlog_ctx_list_subscribers_dispose(ls->op_ctx, subs);
330   jlog_logio_cleanse(ls);
331  bail:
332   if(ls->lock) pthread_rwlock_unlock(ls->lock);
333   return 0;
334 }
335 static int
336 jlog_logio_open(noit_log_stream_t ls) {
337   char path[PATH_MAX], *sub, **subs, *p;
338   jlog_ctx *log = NULL;
339   int i, listed, found;
340
341   if(jlog_lspath_to_fspath(ls, path, sizeof(path), &sub) <= 0) return -1;
342   log = jlog_new(path);
343   if(!log) return -1;
344   /* Open the writer. */
345   if(jlog_ctx_open_writer(log)) {
346     /* If that fails, we'll give one attempt at initiailizing it. */
347     /* But, since we attempted to open it as a writer, it is tainted. */
348     /* path: close, new, init, close, new, writer, add subscriber */
349     jlog_ctx_close(log);
350     log = jlog_new(path);
351     if(jlog_ctx_init(log)) {
352       noitL(noit_error, "Cannot init jlog writer: %s\n",
353             jlog_ctx_err_string(log));
354       jlog_ctx_close(log);
355       return -1;
356     }
357     /* After it is initialized, we can try to reopen it as a writer. */
358     jlog_ctx_close(log);
359     log = jlog_new(path);
360     if(jlog_ctx_open_writer(log)) {
361       noitL(noit_error, "Cannot open jlog writer: %s\n",
362             jlog_ctx_err_string(log));
363       jlog_ctx_close(log);
364       return -1;
365     }
366   }
367
368   /* Add or remove subscribers according to the current configuration. */
369   listed = jlog_ctx_list_subscribers(log, &subs);
370   if(listed == -1) {
371     noitL(noit_error, "Cannot list jlog subscribers: %s\n",
372           jlog_ctx_err_string(log));
373     return -1;
374   }
375
376   if(sub) {
377     /* Match all configured subscribers against jlog's list. */
378     for(p=strtok(sub, ",");p;p=strtok(NULL, ",")) {
379       for(i=0;i<listed;i++) {
380         if((subs[i]) && (strcmp(p, subs[i]) == 0)) {
381           free(subs[i]);
382           subs[i] = NULL;
383           break;
384         }
385       }
386       if(i == listed)
387         jlog_ctx_add_subscriber(log, p, JLOG_BEGIN);
388     }
389
390     /* Remove all unmatched subscribers. */
391     for(i=0;i<listed;i++) {
392       if(subs[i]) {
393         jlog_ctx_remove_subscriber(log, subs[i]);
394         free(subs[i]);
395         subs[i] = NULL;
396       }
397     }
398
399     free(subs);
400     subs = NULL;
401   } else {
402     /* Remove all subscribers other than DEFAULT_JLOG_SUBSCRIBER. */
403     found = 0;
404     for(i=0;i<listed;i++) {
405       if((subs[i]) && (strcmp(DEFAULT_JLOG_SUBSCRIBER, subs[i]) == 0)) {
406         found = 1;
407         continue;
408       }
409       jlog_ctx_remove_subscriber(log, subs[i]);
410     }
411
412     /* Add DEFAULT_JLOG_SUBSCRIBER if it wasn't already on the jlog's list. */
413     if(!found)
414       jlog_ctx_add_subscriber(log, DEFAULT_JLOG_SUBSCRIBER, JLOG_BEGIN);
415
416     jlog_ctx_list_subscribers_dispose(log, subs);
417   }
418
419   ls->op_ctx = log;
420   /* We do this to clean things up */
421   jlog_logio_reopen(ls);
422   return 0;
423 }
424 static int
425 jlog_logio_write(noit_log_stream_t ls, const void *buf, size_t len) {
426   int rv = -1;
427   if(!ls->op_ctx) return -1;
428   pthread_rwlock_rdlock(ls->lock);
429   if(jlog_ctx_write((jlog_ctx *)ls->op_ctx, buf, len) == 0)
430     rv = len;
431   pthread_rwlock_unlock(ls->lock);
432   return rv;
433 }
434 static int
435 jlog_logio_close(noit_log_stream_t ls) {
436   if(ls->op_ctx) {
437     jlog_ctx_close((jlog_ctx *)ls->op_ctx);
438     ls->op_ctx = NULL;
439   }
440   return 0;
441 }
442 static size_t
443 jlog_logio_size(noit_log_stream_t ls) {
444   size_t size;
445   if(!ls->op_ctx) return -1;
446   pthread_rwlock_rdlock(ls->lock);
447   size = jlog_raw_size((jlog_ctx *)ls->op_ctx);
448   pthread_rwlock_unlock(ls->lock);
449   return size;
450 }
451 static int
452 jlog_logio_rename(noit_log_stream_t ls, const char *newname) {
453   /* Not supported (and makes no sense) */
454   return -1;
455 }
456 static logops_t jlog_logio_ops = {
457   jlog_logio_open,
458   jlog_logio_reopen,
459   jlog_logio_write,
460   NULL,
461   jlog_logio_close,
462   jlog_logio_size,
463   jlog_logio_rename
464 };
465
466 void
467 noit_log_init() {
468   noit_hash_init(&noit_loggers);
469   noit_hash_init(&noit_logops);
470   noit_register_logops("file", &posix_logio_ops);
471   noit_register_logops("jlog", &jlog_logio_ops);
472   noit_stderr = noit_log_stream_new_on_fd("stderr", 2, NULL);
473   noit_stderr->timestamps = 1;
474   noit_error = noit_log_stream_new("error", NULL, NULL, NULL, NULL);
475   noit_debug = noit_log_stream_new("debug", NULL, NULL, NULL, NULL);
476 }
477
478 void
479 noit_register_logops(const char *name, logops_t *ops) {
480   noit_hash_store(&noit_logops, strdup(name), strlen(name), ops);
481 }
482
483 void *
484 noit_log_stream_get_ctx(noit_log_stream_t ls) {
485   return ls->op_ctx;
486 }
487
488 void
489 noit_log_stream_set_ctx(noit_log_stream_t ls, void *nctx) {
490   ls->op_ctx = nctx;
491 }
492
493 const char *
494 noit_log_stream_get_type(noit_log_stream_t ls) {
495   return ls->type;
496 }
497
498 const char *
499 noit_log_stream_get_name(noit_log_stream_t ls) {
500   return ls->name;
501 }
502
503 const char *
504 noit_log_stream_get_path(noit_log_stream_t ls) {
505   return ls->path;
506 }
507
508 noit_log_stream_t
509 noit_log_stream_new_on_fd(const char *name, int fd, noit_hash_table *config) {
510   noit_log_stream_t ls;
511   ls = calloc(1, sizeof(*ls));
512   ls->name = strdup(name);
513   ls->ops = &posix_logio_ops;
514   ls->op_ctx = (void *)(vpsized_int)fd;
515   ls->enabled = 1;
516   ls->config = config;
517   ls->lock = calloc(1, sizeof(*ls->lock));
518   pthread_rwlock_init(ls->lock, NULL);
519   /* This double strdup of ls->name is needed, look for the next one
520    * for an explanation.
521    */
522   if(noit_hash_store(&noit_loggers,
523                      strdup(ls->name), strlen(ls->name), ls) == 0) {
524     free(ls->name);
525     free(ls);
526     return NULL;
527   }
528   return ls;
529 }
530
531 noit_log_stream_t
532 noit_log_stream_new_on_file(const char *path, noit_hash_table *config) {
533   return noit_log_stream_new(path, "file", path, NULL, config);
534 }
535
536 noit_log_stream_t
537 noit_log_stream_new(const char *name, const char *type, const char *path,
538                     void *ctx, noit_hash_table *config) {
539   noit_log_stream_t ls, saved;
540   struct _noit_log_stream tmpbuf;
541   ls = calloc(1, sizeof(*ls));
542   ls->name = strdup(name);
543   ls->path = path ? strdup(path) : NULL;
544   ls->type = type ? strdup(type) : NULL;
545   ls->enabled = 1;
546   ls->config = config;
547   if(!type)
548     ls->ops = NULL;
549   else if(!noit_hash_retrieve(&noit_logops, type, strlen(type),
550                               (void **)&ls->ops))
551     goto freebail;
552  
553   if(ls->ops && ls->ops->openop(ls)) goto freebail;
554
555   saved = noit_log_stream_find(name);
556   if(saved) {
557     pthread_rwlock_t *lock = saved->lock;
558     memcpy(&tmpbuf, saved, sizeof(*saved));
559     memcpy(saved, ls, sizeof(*saved));
560     memcpy(ls, &tmpbuf, sizeof(*saved));
561     saved->lock = lock;
562
563     ls->lock = NULL;
564     noit_log_stream_free(ls);
565     ls = saved;
566   }
567   else {
568     /* We strdup the name *again*.  We'going to kansas city shuffle the
569      * ls later (see memcpy above).  However, if don't strdup, then the
570      * noit_log_stream_free up there will sweep our key right our from
571      * under us.
572      */
573     if(noit_hash_store(&noit_loggers,
574                        strdup(ls->name), strlen(ls->name), ls) == 0)
575       goto freebail;
576     ls->lock = calloc(1, sizeof(*ls->lock));
577     pthread_rwlock_init(ls->lock, NULL);
578   }
579   /* This is for things that don't open on paths */
580   if(ctx) ls->op_ctx = ctx;
581   return ls;
582
583  freebail:
584   fprintf(stderr, "Failed to instantiate logger(%s,%s,%s)\n",
585           name, type ? type : "[null]", path ? path : "[null]");
586   free(ls->name);
587   if(ls->path) free(ls->path);
588   if(ls->type) free(ls->type);
589   free(ls);
590   return NULL;
591 }
592
593 noit_log_stream_t
594 noit_log_stream_find(const char *name) {
595   void *vls;
596   if(noit_hash_retrieve(&noit_loggers, name, strlen(name), &vls)) {
597     return (noit_log_stream_t)vls;
598   }
599   return NULL;
600 }
601
602 void
603 noit_log_stream_remove(const char *name) {
604   noit_hash_delete(&noit_loggers, name, strlen(name), NULL, NULL);
605 }
606
607 void
608 noit_log_stream_add_stream(noit_log_stream_t ls, noit_log_stream_t outlet) {
609   struct _noit_log_stream_outlet_list *newnode;
610   newnode = calloc(1, sizeof(*newnode));
611   newnode->outlet = outlet;
612   newnode->next = ls->outlets;
613   ls->outlets = newnode;
614 }
615
616 noit_log_stream_t
617 noit_log_stream_remove_stream(noit_log_stream_t ls, const char *name) {
618   noit_log_stream_t outlet;
619   struct _noit_log_stream_outlet_list *node, *tmp;
620   if(!ls->outlets) return NULL;
621   if(!strcmp(ls->outlets->outlet->name, name)) {
622     node = ls->outlets;
623     ls->outlets = node->next;
624     outlet = node->outlet;
625     free(node);
626     return outlet;
627   }
628   for(node = ls->outlets; node->next; node = node->next) {
629     if(!strcmp(node->next->outlet->name, name)) {
630       /* splice */
631       tmp = node->next;
632       node->next = tmp->next;
633       /* pluck */
634       outlet = tmp->outlet;
635       /* shed */
636       free(tmp);
637       /* return */
638       return outlet;
639     }
640   }
641   return NULL;
642 }
643
644 void noit_log_stream_reopen(noit_log_stream_t ls) {
645   struct _noit_log_stream_outlet_list *node;
646   if(ls->ops) ls->ops->reopenop(ls);
647   for(node = ls->outlets; node; node = node->next) {
648     noit_log_stream_reopen(node->outlet);
649   }
650 }
651
652 int noit_log_stream_rename(noit_log_stream_t ls, const char *newname) {
653   return (ls->ops && ls->ops->renameop) ? ls->ops->renameop(ls, newname) : -1;
654 }
655
656 void
657 noit_log_stream_close(noit_log_stream_t ls) {
658   if(ls->ops) ls->ops->closeop(ls);
659 }
660
661 size_t
662 noit_log_stream_size(noit_log_stream_t ls) {
663   if(ls->ops && ls->ops->sizeop) return ls->ops->sizeop(ls);
664   return -1;
665 }
666
667 size_t
668 noit_log_stream_written(noit_log_stream_t ls) {
669   return ls->written;
670 }
671
672 void
673 noit_log_stream_free(noit_log_stream_t ls) {
674   if(ls) {
675     struct _noit_log_stream_outlet_list *node;
676     if(ls->name) free(ls->name);
677     if(ls->path) free(ls->path);
678     while(ls->outlets) {
679       node = ls->outlets->next;
680       free(ls->outlets);
681       ls->outlets = node;
682     }
683     if(ls->config) {
684       noit_hash_destroy(ls->config, free, free);
685       free(ls->config);
686     }
687     if(ls->lock) {
688       pthread_rwlock_destroy(ls->lock);
689       free(ls->lock);
690     }
691     free(ls);
692   }
693 }
694
695 static int
696 noit_log_writev(noit_log_stream_t ls, const struct iovec *iov, int iovcnt) {
697   /* This emulates writev into a buffer for ops that don't support it */
698   char stackbuff[4096], *tofree = NULL, *buff = NULL;
699   int i, s = 0, ins = 0;
700
701   if(!ls->ops) return -1;
702   if(ls->ops->writevop) return ls->ops->writevop(ls, iov, iovcnt);
703   if(!ls->ops->writeop) return -1;
704   if(iovcnt == 1) return ls->ops->writeop(ls, iov[0].iov_base, iov[0].iov_len);
705
706   for(i=0;i<iovcnt;i++) s+=iov[i].iov_len;
707   if(s > sizeof(stackbuff)) {
708     tofree = buff = malloc(s);
709     if(tofree == NULL) return -1;
710   }
711   else buff = stackbuff;
712   for(i=0;i<iovcnt;i++) {
713     memcpy(buff + ins, iov[i].iov_base, iov[i].iov_len);
714     ins += iov[i].iov_len;
715   }
716   i = ls->ops->writeop(ls, buff, s);
717   if(tofree) free(tofree);
718   return i;
719 }
720
721 static int
722 noit_log_line(noit_log_stream_t ls,
723               const char *timebuf, int timebuflen,
724               const char *debugbuf, int debugbuflen,
725               const char *buffer, size_t len) {
726   int rv = 0;
727   struct _noit_log_stream_outlet_list *node;
728   if(ls->ops) {
729     int iovcnt = 0;
730     struct iovec iov[3];
731     if(ls->timestamps) {
732       iov[iovcnt].iov_base = (void *)timebuf;
733       iov[iovcnt].iov_len = timebuflen;
734       iovcnt++;
735     }
736     if(ls->debug) {
737       iov[iovcnt].iov_base = (void *)debugbuf;
738       iov[iovcnt].iov_len = debugbuflen;
739       iovcnt++;
740     }
741     iov[iovcnt].iov_base = (void *)buffer;
742     iov[iovcnt].iov_len = len;
743     iovcnt++;
744     rv = noit_log_writev(ls, iov, iovcnt);
745   }
746   for(node = ls->outlets; node; node = node->next) {
747     int srv = 0;
748     debug_printf(" %s -> %s\n", ls->name, node->outlet->name);
749     srv = noit_log_line(node->outlet, timebuf, timebuflen, debugbuf, debugbuflen, buffer, len);
750     if(srv) rv = srv;
751   }
752   return rv;
753 }
754 int
755 noit_vlog(noit_log_stream_t ls, struct timeval *now,
756           const char *file, int line,
757           const char *format, va_list arg) {
758   int rv = 0, allocd = 0;
759   char buffer[4096], *dynbuff = NULL;
760 #ifdef va_copy
761   va_list copy;
762 #endif
763
764   if(ls->enabled || NOIT_LOG_LOG_ENABLED()) {
765     int len;
766     char tbuf[48], dbuf[80];
767     int tbuflen = 0, dbuflen = 0;
768     MATERIALIZE_DEPS(ls);
769     if(ls->timestamps_below) {
770       struct tm _tm, *tm;
771       char tempbuf[32];
772       time_t s = (time_t)now->tv_sec;
773       tm = localtime_r(&s, &_tm);
774       strftime(tempbuf, sizeof(tempbuf), "%Y-%m-%d %H:%M:%S", tm);
775       snprintf(tbuf, sizeof(tbuf), "[%s.%06d] ", tempbuf, (int)now->tv_usec);
776       tbuflen = strlen(tbuf);
777     }
778     else tbuf[0] = '\0';
779     if(ls->debug_below) {
780       snprintf(dbuf, sizeof(dbuf), "[%s:%d] ", file, line);
781       dbuflen = strlen(dbuf);
782     }
783     else dbuf[0] = '\0';
784 #ifdef va_copy
785     va_copy(copy, arg);
786     len = vsnprintf(buffer, sizeof(buffer), format, copy);
787     va_end(copy);
788 #else
789     len = vsnprintf(buffer, sizeof(buffer), format, arg);
790 #endif
791     if(len > sizeof(buffer)) {
792       allocd = sizeof(buffer);
793       while(len > allocd) { /* guaranteed true the first time */
794         while(len > allocd) allocd <<= 2;
795         if(dynbuff) free(dynbuff);
796         dynbuff = malloc(allocd);
797         assert(dynbuff);
798 #ifdef va_copy
799         va_copy(copy, arg);
800         len = vsnprintf(dynbuff, allocd, format, copy);
801         va_end(copy);
802 #else
803         len = vsnprintf(dynbuff, allocd, format, arg);
804 #endif
805       }
806       NOIT_LOG_LOG(ls->name, (char *)file, line, dynbuff);
807       if(ls->enabled)
808         rv = noit_log_line(ls, tbuf, tbuflen, dbuf, dbuflen, dynbuff, len);
809       free(dynbuff);
810     }
811     else {
812       NOIT_LOG_LOG(ls->name, (char *)file, line, buffer);
813       if(ls->enabled)
814         rv = noit_log_line(ls, tbuf, tbuflen, dbuf, dbuflen, buffer, len);
815     }
816     if(rv == len) return 0;
817     return -1;
818   }
819   return 0;
820 }
821
822 int
823 noit_log(noit_log_stream_t ls, struct timeval *now,
824          const char *file, int line, const char *format, ...) {
825   int rv;
826   va_list arg;
827   va_start(arg, format);
828   rv = noit_vlog(ls, now, file, line, format, arg);
829   va_end(arg);
830   return rv;
831 }
832
833 int
834 noit_log_reopen_all() {
835   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
836   const char *k;
837   int klen, rv = 0;
838   void *data;
839   noit_log_stream_t ls;
840
841   while(noit_hash_next(&noit_loggers, &iter, &k, &klen, &data)) {
842     ls = data;
843     if(ls->ops) if(ls->ops->reopenop(ls) < 0) rv = -1;
844   }
845   return rv;
846 }
847
Note: See TracBrowser for help on using the browser.