]> mj.ucw.cz Git - libucw.git/blob - ucw/log-stream.c
Logging: The Great Shuffle
[libucw.git] / ucw / log-stream.c
1 /*
2  *      UCW Library -- Logging: Management of Log Streams
3  *
4  *      (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
5  *      (c) 2009 Martin Mares <mj@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include "ucw/lib.h"
12 #include "ucw/clists.h"
13 #include "ucw/simple-lists.h"
14 #include "ucw/log.h"
15
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <sys/time.h>
22 #include <sys/stat.h>
23 #include <time.h>
24 #include <alloca.h>
25 #include <fcntl.h>
26
27 /* Flag indicating initialization of the module */
28 static int ls_initialized = 0;
29
30 /* The head of the list of freed log_streams indexes in ls_streams.ptr (-1 if none free).
31  * Freed positions in ls_streams.ptr are connected into a linked list in the following way:
32  * ls_streams.ptr[ls_streams_free].idata is the index of next freed position (or -1) */
33 static int ls_streams_free = -1;
34
35 /* Initialize the logstream module.
36  * It is not neccessary to call this explicitely as it is called by
37  * the first ls_new()  (for backward compatibility and ease of use). */
38 static void ls_init_module(void)
39 {
40   if (ls_initialized) return;
41
42   /* create the grow array */
43   lsbuf_init(&log_streams);
44   lsbuf_set_size(&log_streams, LS_INIT_STREAMS);
45
46   bzero(log_streams.ptr, sizeof(struct log_stream*) * (log_streams.len));
47   ls_streams_free = -1;
48
49   ls_initialized = 1;
50
51   /* init the default stream (0) as forwarder to fd2 */
52   struct log_stream *ls = ls_new();
53   ASSERT(ls == log_streams.ptr[0]);
54   ASSERT(ls->regnum == 0);
55   ls->name = "default";
56   ls_add_substream(ls, (struct log_stream *) &ls_default_log);
57
58   /* log this */
59   ls_msg(L_DEBUG, "logstream module initialized.");
60 }
61
62 /* close all open streams, un-initialize the module, free all memory,
63  * use only ls_default_log */
64 void ls_close_all(void)
65 {
66   int i;
67
68   if (!ls_initialized) return;
69
70   for (i=0; i<log_streams_after; i++)
71   {
72     if (log_streams.ptr[i]->regnum>=0)
73       ls_close(log_streams.ptr[i]);
74     xfree(log_streams.ptr[i]);
75   }
76
77   /* set to the default state */
78   lsbuf_done(&log_streams);
79   log_streams_after=0;
80   ls_streams_free=-1;
81   ls_initialized = 0;
82 }
83
84 /* add a new substream, malloc()-ate a new simp_node */
85 void ls_add_substream(struct log_stream *where, struct log_stream *what)
86 {
87   ASSERT(where);
88   ASSERT(what);
89
90   simp_node *n = xmalloc(sizeof(simp_node));
91   n->p = what;
92   clist_add_tail(&(where->substreams), (cnode*)n);
93 }
94
95 /* remove all occurences of a substream, free() the simp_node */
96 /* return number of deleted entries */
97 int ls_rm_substream(struct log_stream *where, struct log_stream *what)
98 {
99   void *tmp;
100   int cnt=0;
101   ASSERT(where);
102   ASSERT(what);
103
104   CLIST_FOR_EACH_DELSAFE(simp_node *, i, where->substreams, tmp)
105     if (i->p == what)
106     {
107       clist_remove((cnode*)i);
108       xfree(i);
109       cnt++;
110     }
111   return cnt;
112 }
113
114 /* Return a pointer to a new stream with no handler and an empty substream list. */
115 struct log_stream *ls_new(void)
116 {
117   struct log_stream *l;
118   int index;
119
120   /* initialize the array if not initialized already */
121   if (unlikely(ls_initialized==0))
122     ls_init_module();
123
124   /* there is no closed stream -- allocate a new one */
125   if (ls_streams_free==-1)
126   {
127     /* check the size of the pointer array */
128     lsbuf_grow(&log_streams, log_streams_after+1);
129     ls_streams_free = log_streams_after++;
130     log_streams.ptr[ls_streams_free] = xmalloc(sizeof(struct log_stream));
131     log_streams.ptr[ls_streams_free]->idata = -1;
132     log_streams.ptr[ls_streams_free]->regnum = -1;
133   }
134
135   ASSERT(ls_streams_free>=0);
136
137   /* initialize the stream */
138   index = ls_streams_free;
139   l = log_streams.ptr[index];
140   ls_streams_free = l->idata;
141   memset(l, 0, sizeof(struct log_stream));
142   l->levels = LS_ALL_LEVELS;
143   l->regnum = LS_SET_STRNUM(index);
144   l->substreams.head.next = &(l->substreams.head);
145   l->substreams.head.prev = &(l->substreams.head);
146   return l;
147 }
148
149 /* Close and remember given log_stream */
150 /* does not affect substreams, but frees the .substreams list */
151 void ls_close(struct log_stream *ls)
152 {
153   void *tmp;
154   ASSERT(ls);
155
156   /* xfree() all the simp_nodes from substreams */
157   CLIST_FOR_EACH_DELSAFE(simp_node *, i, ls->substreams, tmp)
158   {
159     clist_remove((cnode*)i);
160     xfree(i);
161   }
162
163   /* close and remember the stream */
164   if (ls->close!=NULL)
165     ls->close(ls);
166   ls->idata = ls_streams_free;
167   ls_streams_free = LS_GET_STRNUM(ls->regnum);
168   ls->regnum = -1;
169 }