]> mj.ucw.cz Git - libucw.git/blob - ucw/log-conf.c
Logging: Improved log-syslog.
[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>
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   if (c->syslog_facility && !log_syslog_facility_exists(c->syslog_facility))
36     return cf_printf("SyslogFacility `%s' is not recognized", c->syslog_facility);
37   return NULL;
38 }
39
40 static struct cf_section stream_config = {
41   CF_TYPE(struct stream_config),
42   CF_COMMIT(stream_commit),
43   CF_ITEMS {
44 #define P(x) PTR_TO(struct stream_config, x)
45     CF_STRING("Name", P(name)),
46     CF_STRING("FileName", P(file_name)),
47     CF_STRING("SyslogFacility", P(syslog_facility)),
48     CF_LIST("Substream", P(substreams), &cf_string_list_config),
49 #undef P
50     CF_END
51   }
52 };
53
54 static clist log_stream_confs;
55
56 static struct stream_config *
57 stream_find(const char *name)
58 {
59   CLIST_FOR_EACH(struct stream_config *, c, log_stream_confs)
60     if (!strcmp(c->name, name))
61       return c;
62   return NULL;
63 }
64
65 static char *
66 stream_resolve(struct stream_config *c)
67 {
68   if (c->mark == 2)
69     return NULL;
70   if (c->mark == 1)
71     return cf_printf("Log stream `%s' has substreams which refer to itself", c->name);
72
73   c->mark = 1;
74   char *err;
75   CLIST_FOR_EACH(simp_node *, s, c->substreams)
76     {
77       struct stream_config *d = stream_find(s->s);
78       if (!d)
79         return cf_printf("Log stream `%s' refers to unknown substream `%s'", c->name, s->s);
80       if (err = stream_resolve(d))
81         return err;
82     }
83   c->mark = 2;
84   return NULL;
85 }
86
87 static char *
88 log_config_commit(void *ptr UNUSED)
89 {
90   // Verify uniqueness of names
91   CLIST_FOR_EACH(struct stream_config *, c, log_stream_confs)
92     if (stream_find(c->name) != c)
93       return cf_printf("Log stream `%s' defined twice", c->name);
94
95   // Check that all substreams resolve and that there are no cycles
96   char *err;
97   CLIST_FOR_EACH(struct stream_config *, c, log_stream_confs)
98     if (err = stream_resolve(c))
99       return err;
100
101   return NULL;
102 }
103
104 static struct cf_section log_config = {
105   CF_COMMIT(log_config_commit),
106   CF_ITEMS {
107     CF_LIST("Stream", &log_stream_confs, &stream_config),
108     CF_END
109   }
110 };
111
112 static void CONSTRUCTOR
113 log_config_init(void)
114 {
115   cf_declare_section("Logging", &log_config, 0);
116 }
117
118 char *
119 log_check_configured(const char *name)
120 {
121   if (stream_find(name))
122     return NULL;
123   else
124     return cf_printf("Log stream `%s' not found", name);
125 }
126
127 static struct log_stream *
128 do_new_configured(struct stream_config *c)
129 {
130   struct log_stream *ls;
131   ASSERT(c);
132
133   if (c->ls)
134     return c->ls;
135
136   if (c->file_name)
137     ls = log_new_file(c->file_name);
138   else if (c->syslog_facility)
139     ls = log_new_syslog(c->syslog_facility, 0);         // FIXME: Logging of PID
140   else
141     ls = log_new_stream(sizeof(*ls));
142
143   CLIST_FOR_EACH(simp_node *, s, c->substreams)
144     log_add_substream(ls, do_new_configured(stream_find(s->s)));
145
146   c->ls = ls;
147   return ls;
148 }
149
150 struct log_stream *
151 log_new_configured(const char *name)
152 {
153   struct stream_config *c = stream_find(name);
154   if (!c)
155     die("Unable to find log stream %s", name);
156   if (c->ls)
157     return log_ref_stream(c->ls);
158   return do_new_configured(c);
159 }
160
161 #ifdef TEST
162
163 #include "ucw/getopt.h"
164
165 int main(int argc, char **argv)
166 {
167   log_init(argv[0]);
168   int c;
169   while ((c = cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL)) >= 0)
170     die("No options here.");
171
172   struct log_stream *ls = log_new_configured("combined");
173   msg(L_INFO | ls->regnum, "Hello, universe!");
174
175   log_close_all();
176   return 0;
177 }
178
179 #endif