]> mj.ucw.cz Git - libucw.git/blob - ucw/log-conf.c
Logging: Let log_close_all() ASSERT that all references are gone.
[libucw.git] / ucw / log-conf.c
1 /*
2  *      UCW Library -- Logging: Configuration of Log Streams
3  *
4  *      (c) 2009 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "ucw/lib.h"
11 #include "ucw/log.h"
12 #include "ucw/conf.h"
13 #include "ucw/simple-lists.h"
14
15 #include <string.h>
16 #include <syslog.h>     // FIXME
17
18 struct stream_config {
19   cnode n;
20   char *name;
21   char *file_name;
22   char *syslog_facility;
23   clist substreams;                     // simple_list of names
24   struct log_stream *ls;
25   int mark;                             // Used temporarily in log_config_commit()
26 };
27
28 static char *
29 stream_commit(void *ptr)
30 {
31   struct stream_config *c = ptr;
32
33   if (c->file_name && c->syslog_facility)
34     return "Both FileName and SyslogFacility selected";
35   return NULL;
36 }
37
38 static struct cf_section stream_config = {
39   CF_TYPE(struct stream_config),
40   CF_COMMIT(stream_commit),
41   CF_ITEMS {
42 #define P(x) PTR_TO(struct stream_config, x)
43     CF_STRING("Name", P(name)),
44     CF_STRING("FileName", P(file_name)),
45     CF_STRING("SyslogFacility", P(syslog_facility)),
46     CF_LIST("Substream", P(substreams), &cf_string_list_config),
47 #undef P
48     CF_END
49   }
50 };
51
52 static clist log_stream_confs;
53
54 static struct stream_config *
55 stream_find(const char *name)
56 {
57   CLIST_FOR_EACH(struct stream_config *, c, log_stream_confs)
58     if (!strcmp(c->name, name))
59       return c;
60   return NULL;
61 }
62
63 static char *
64 stream_resolve(struct stream_config *c)
65 {
66   if (c->mark == 2)
67     return NULL;
68   if (c->mark == 1)
69     return cf_printf("Log stream `%s' has substreams which refer to itself", c->name);
70
71   c->mark = 1;
72   char *err;
73   CLIST_FOR_EACH(simp_node *, s, c->substreams)
74     {
75       struct stream_config *d = stream_find(s->s);
76       if (!d)
77         return cf_printf("Log stream `%s' refers to unknown substream `%s'", c->name, s->s);
78       if (err = stream_resolve(d))
79         return err;
80     }
81   c->mark = 2;
82   return NULL;
83 }
84
85 static char *
86 log_config_commit(void *ptr UNUSED)
87 {
88   // Verify uniqueness of names
89   CLIST_FOR_EACH(struct stream_config *, c, log_stream_confs)
90     if (stream_find(c->name) != c)
91       return cf_printf("Log stream `%s' defined twice", c->name);
92
93   // Check that all substreams resolve and that there are no cycles
94   char *err;
95   CLIST_FOR_EACH(struct stream_config *, c, log_stream_confs)
96     if (err = stream_resolve(c))
97       return err;
98
99   return NULL;
100 }
101
102 static struct cf_section log_config = {
103   CF_COMMIT(log_config_commit),
104   CF_ITEMS {
105     CF_LIST("Stream", &log_stream_confs, &stream_config),
106     CF_END
107   }
108 };
109
110 static void CONSTRUCTOR
111 log_config_init(void)
112 {
113   cf_declare_section("Logging", &log_config, 0);
114 }
115
116 char *
117 log_check_configured(const char *name)
118 {
119   if (stream_find(name))
120     return NULL;
121   else
122     return cf_printf("Log stream `%s' not found", name);
123 }
124
125 static struct log_stream *
126 do_new_configured(struct stream_config *c)
127 {
128   struct log_stream *ls;
129   ASSERT(c);
130
131   if (c->ls)
132     return c->ls;
133
134   if (c->file_name)
135     ls = log_new_file(c->file_name);
136   else if (c->syslog_facility)
137     ls = log_new_syslog(LOG_USER, NULL);        // FIXME: Facility
138   else
139     ls = log_new_stream(sizeof(*ls));
140
141   CLIST_FOR_EACH(simp_node *, s, c->substreams)
142     log_add_substream(ls, do_new_configured(stream_find(s->s)));
143
144   c->ls = ls;
145   return ls;
146 }
147
148 struct log_stream *
149 log_new_configured(const char *name)
150 {
151   struct stream_config *c = stream_find(name);
152   if (!c)
153     die("Unable to find log stream %s", name);
154   if (c->ls)
155     return log_ref_stream(c->ls);
156   return do_new_configured(c);
157 }
158
159 #ifdef TEST
160
161 #include "ucw/getopt.h"
162
163 int main(int argc, char **argv)
164 {
165   log_init(argv[0]);
166   int c;
167   while ((c = cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL)) >= 0)
168     die("No options here.");
169
170   struct log_stream *ls = log_new_configured("combined");
171   msg(L_INFO | ls->regnum, "Hello, universe!");
172
173   return 0;
174 }
175
176 #endif