2 * UCW Library -- Logging: Management of Log Streams
4 * (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
5 * (c) 2009 Martin Mares <mj@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
13 #include "ucw/log-internal.h"
14 #include "ucw/simple-lists.h"
18 /* Initial number of streams to allocate (must be >=2) */
19 #define LS_INIT_STREAMS 8
21 /* Flag indicating initialization of the module */
22 static int log_initialized = 0;
24 /* The head of the list of freed log_streams indexes in log_streams.ptr (~0U if none free).
25 * Freed positions in log_streams.ptr are connected into a linked list in the following way:
26 * log_streams.ptr[log_streams_free].levels is the index of next freed position (or ~0U) */
27 static uns log_streams_free = ~0U;
29 /* Initialize the logstream module.
30 * It is not neccessary to call this explicitely as it is called by
31 * the first log_new_stream() (for backward compatibility and ease of use). */
38 /* Create the growing array */
39 lsbuf_init(&log_streams);
40 lsbuf_set_size(&log_streams, LS_INIT_STREAMS);
42 bzero(log_streams.ptr, sizeof(struct log_stream*) * (log_streams.len));
43 log_streams_free = ~0U;
47 /* init the default stream (0) as forwarder to fd2 */
48 struct log_stream *ls = log_new_stream(sizeof(*ls));
49 ASSERT(ls == log_streams.ptr[0]);
50 ASSERT(ls->regnum == 0);
52 log_add_substream(ls, &log_stream_default);
61 // Remove substreams of all streams
62 for (int i=0; i < log_streams_after; i++)
63 if (log_streams.ptr[i]->regnum >= 0)
64 log_rm_substream(log_streams.ptr[i], NULL);
66 // Close all streams that remain and free all cached structures
67 for (int i=0; i < log_streams_after; i++)
69 struct log_stream *ls = log_streams.ptr[i];
72 ASSERT(ls->regnum < 0 || !ls->use_count);
76 /* Back to the default state */
77 lsbuf_done(&log_streams);
78 log_streams_after = 0;
79 log_streams_free = ~0U;
84 log_add_substream(struct log_stream *where, struct log_stream *what)
89 simp_node *n = xmalloc(sizeof(simp_node));
90 n->p = log_ref_stream(what);
91 clist_add_tail(&where->substreams, &n->n);
95 log_rm_substream(struct log_stream *where, struct log_stream *what)
101 CLIST_FOR_EACH_DELSAFE(simp_node *, i, where->substreams, tmp)
102 if (i->p == what || !what)
105 log_close_stream(i->p);
113 log_new_stream(size_t size)
115 struct log_stream *l;
118 /* Initialize the data structures if needed */
121 /* Get a free stream, possibly recycling a closed one */
122 if (log_streams_free == ~0U)
124 lsbuf_grow(&log_streams, log_streams_after+1);
125 index = log_streams_after++;
126 l = log_streams.ptr[index] = xmalloc(size);
130 index = log_streams_free;
131 l = xrealloc(log_streams.ptr[index], size);
132 log_streams.ptr[index] = l;
133 log_streams_free = l->levels;
136 /* Initialize the stream */
137 bzero(l, sizeof(*l));
140 l->regnum = LS_SET_STRNUM(index);
141 clist_init(&l->substreams);
142 return log_ref_stream(l);
146 log_close_stream(struct log_stream *ls)
149 ASSERT(ls->use_count);
153 /* Unlink all subtreams */
154 log_rm_substream(ls, NULL);
156 /* Close the stream and add it to the free-list */
159 ls->levels = log_streams_free;
160 log_streams_free = LS_GET_STRNUM(ls->regnum);
166 log_set_format(struct log_stream *ls, uns mask, uns data)
168 ls->msgfmt = (ls->msgfmt & mask) | data;
169 CLIST_FOR_EACH(simp_node *, i, ls->substreams)
170 log_set_format(i->p, mask, data);
173 /*** Registry of type names ***/
175 int log_register_type(const char *name)
179 log_type_names = xmalloc_zero(LS_NUM_TYPES * sizeof(char *));
180 log_type_names[0] = "default";
183 for (id=0; id < LS_NUM_TYPES && log_type_names[id]; id++)
184 if (!strcmp(log_type_names[id], name))
185 return LS_SET_TYPE(id);
186 ASSERT(id < LS_NUM_TYPES);
187 log_type_names[id] = xstrdup(name);
188 return LS_SET_TYPE(id);
191 /** Find a message type by name and return its ID encoded by `LS_SET_TYPE`. Returns -1 if no such type found. **/
192 int log_find_type(const char *name)
194 if (!strcmp(name, "default"))
199 for (uns id=0; id < LS_NUM_TYPES && log_type_names[id]; id++)
200 if (!strcmp(log_type_names[id], name))
201 return LS_SET_TYPE(id);