2 * UCW Library -- Logging: Configuration of Log Streams
4 * (c) 2009 Martin Mares <mj@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
13 #include "ucw/simple-lists.h"
18 struct stream_config {
22 char *syslog_facility;
24 clist types; // simple_list of names
25 clist substreams; // simple_list of names
26 int microseconds; // Enable logging of precise timestamps
30 struct log_stream *ls;
31 int mark; // Used temporarily in log_config_commit()
35 stream_init(void *ptr)
37 struct stream_config *c = ptr;
44 stream_commit(void *ptr)
46 struct stream_config *c = ptr;
48 if (c->file_name && c->syslog_facility)
49 return "Both FileName and SyslogFacility selected";
50 if (c->syslog_facility && !log_syslog_facility_exists(c->syslog_facility))
51 return cf_printf("SyslogFacility `%s' is not recognized", c->syslog_facility);
52 if (c->syslog_facility && c->microseconds)
53 return "Syslog streams do not support microsecond precision";
57 static const char * const level_names[] = {
64 static struct cf_section stream_config = {
65 CF_TYPE(struct stream_config),
67 CF_COMMIT(stream_commit),
69 #define P(x) PTR_TO(struct stream_config, x)
70 CF_STRING("Name", P(name)),
71 CF_STRING("FileName", P(file_name)),
72 CF_STRING("SyslogFacility", P(syslog_facility)),
73 CF_BITMAP_LOOKUP("Levels", P(levels), level_names),
74 CF_LIST("Types", P(types), &cf_string_list_config),
75 CF_LIST("Substream", P(substreams), &cf_string_list_config),
76 CF_INT("Microseconds", P(microseconds)),
77 CF_INT("ShowTypes", P(show_types)),
78 CF_INT("SyslogPID", P(syslog_pids)),
79 CF_INT("ErrorsFatal", P(errors_fatal)),
85 static clist log_stream_confs;
87 static struct stream_config *
88 stream_find(const char *name)
90 CLIST_FOR_EACH(struct stream_config *, c, log_stream_confs)
91 if (!strcmp(c->name, name))
97 stream_resolve(struct stream_config *c)
102 return cf_printf("Log stream `%s' has substreams which refer to itself", c->name);
106 CLIST_FOR_EACH(simp_node *, s, c->substreams)
108 struct stream_config *d = stream_find(s->s);
110 return cf_printf("Log stream `%s' refers to unknown substream `%s'", c->name, s->s);
111 if (err = stream_resolve(d))
119 log_config_commit(void *ptr UNUSED)
121 // Verify uniqueness of names
122 CLIST_FOR_EACH(struct stream_config *, c, log_stream_confs)
123 if (stream_find(c->name) != c)
124 return cf_printf("Log stream `%s' defined twice", c->name);
126 // Check that all substreams resolve and that there are no cycles
128 CLIST_FOR_EACH(struct stream_config *, c, log_stream_confs)
129 if (err = stream_resolve(c))
135 static struct cf_section log_config = {
136 CF_COMMIT(log_config_commit),
138 CF_LIST("Stream", &log_stream_confs, &stream_config),
143 static void CONSTRUCTOR
144 log_config_init(void)
146 cf_declare_section("Logging", &log_config, 0);
150 log_check_configured(const char *name)
152 if (stream_find(name))
155 return cf_printf("Log stream `%s' not found", name);
158 static struct log_stream *
159 do_new_configured(struct stream_config *c)
161 struct log_stream *ls;
168 ls = log_new_file(c->file_name);
169 else if (c->syslog_facility)
170 ls = log_new_syslog(c->syslog_facility, (c->syslog_pids ? LOG_PID : 0));
172 ls = log_new_stream(sizeof(*ls));
174 CLIST_FOR_EACH(simp_node *, s, c->substreams)
175 log_add_substream(ls, do_new_configured(stream_find(s->s)));
177 ls->levels = c->levels;
179 ls->msgfmt |= LSFMT_USEC;
181 ls->msgfmt |= LSFMT_TYPE;
183 ls->stream_flags |= LSFLAG_ERR_IS_FATAL;
185 if (!clist_empty(&c->types))
188 CLIST_FOR_EACH(simp_node *, s, c->types)
189 if (!strcmp(s->s, "all"))
194 * We intentionally ignore unknown types as not all types are known
195 * to all programs sharing a common configuration file. This is also
196 * the reason why Types is a list and not a bitmap.
198 int type = log_find_type(s->s);
200 ls->types |= 1 << LS_GET_TYPE(type);
209 log_new_configured(const char *name)
211 struct stream_config *c = stream_find(name);
213 die("Unable to find log stream %s", name);
215 return log_ref_stream(c->ls);
216 return do_new_configured(c);
220 log_configured(const char *name)
222 struct log_stream *ls = log_new_configured(name);
223 struct log_stream *def = log_stream_by_flags(0);
224 log_rm_substream(def, NULL);
225 log_add_substream(def, ls);
226 log_close_stream(ls);
231 #include "ucw/getopt.h"
233 int main(int argc, char **argv)
237 while ((c = cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL)) >= 0)
238 die("No options here.");
240 int type = log_register_type("foo");
241 struct log_stream *ls = log_new_configured("combined");
242 msg(L_INFO | ls->regnum | type, "Hello, universe!");