* - ring buffer, readable from CLI
*/
enum sink_type {
- SINK_TYPE_NEW, // not yet initialized
- SINK_TYPE_FD, // events sent to a file descriptor
- SINK_TYPE_BUFFER, // events sent to a ring buffer
+ SINK_TYPE_FORWARD_DECLARED, // was searched using sink_find_early(), is expected to exist by some component
+ SINK_TYPE_NEW, // not yet initialized
+ SINK_TYPE_FD, // events sent to a file descriptor
+ SINK_TYPE_BUFFER, // events sent to a ring buffer
};
struct sink_forward_target {
struct sink {
struct list sink_list; // position in the sink list
char *name; // sink name
- char *desc; // sink description
+ char *desc; /* sink description:
+ * when forward-declared, holds info about where the
+ * sink was first forward declared, else holds actual
+ * sink description
+ */
char *store; // backing-store file when buffer
enum log_fmt fmt; // format expected by the sink
enum sink_type type; // type of storage
struct sink *cfg_sink;
-struct sink *sink_find(const char *name)
+static struct sink *_sink_find(const char *name)
{
struct sink *sink;
return NULL;
}
+/* returns sink if it really exists */
+struct sink *sink_find(const char *name)
+{
+ struct sink *sink;
+
+ sink = _sink_find(name);
+ if (sink && sink->type != SINK_TYPE_FORWARD_DECLARED)
+ return sink;
+ return NULL;
+}
+
+/* Similar to sink_find(), but intended to be used during config parsing:
+ * tries to resolve sink name, if it fails, creates the sink and marks
+ * it as forward-declared and hope that it will be defined later.
+ *
+ * The caller has to identify itself using <from>, <file> and <line> in
+ * order to report precise error messages in the event that the sink is
+ * never defined later (only the first misuse will be considered).
+ *
+ * It returns the sink on success and NULL on failure (memory error)
+ */
+struct sink *sink_find_early(const char *name, const char *from, const char *file, int line)
+{
+ struct sink *sink;
+
+ /* not expected to be used during runtime */
+ BUG_ON(!(global.mode & MODE_STARTING));
+
+ sink = _sink_find(name);
+ if (sink)
+ return sink;
+
+ /* not found, try to forward-declare it */
+ sink = calloc(1, sizeof(*sink));
+ if (!sink)
+ return NULL;
+
+ sink->name = strdup(name);
+ if (!sink->name)
+ goto err;
+
+ memprintf(&sink->desc, "parsing [%s:%d] : %s", file, line, from);
+ if (!sink->desc)
+ goto err;
+
+ sink->type = SINK_TYPE_FORWARD_DECLARED;
+ LIST_APPEND(&sink_list, &sink->sink_list);
+
+ return sink;
+
+ err:
+ ha_free(&sink->name);
+ ha_free(&sink->desc);
+ ha_free(&sink);
+ return NULL;
+}
+
/* creates a new sink and adds it to the list, it's still generic and not fully
* initialized. Returns NULL on allocation failure. If another one already
* exists with the same name, it will be returned. The caller can detect it as
static struct sink *__sink_new(const char *name, const char *desc, int fmt)
{
struct sink *sink;
+ uint8_t _new = 0;
- sink = sink_find(name);
- if (sink)
+ sink = _sink_find(name);
+ if (sink) {
+ if (sink->type == SINK_TYPE_FORWARD_DECLARED) {
+ ha_free(&sink->desc); // free previous desc
+ goto forward_declared;
+ }
goto end;
+ }
sink = calloc(1, sizeof(*sink));
+ _new = 1;
if (!sink)
goto end;
if (!sink->name)
goto err;
+ forward_declared:
sink->desc = strdup(desc);
if (!sink->desc)
goto err;
/* address will be filled by the caller if needed */
sink->ctx.fd = -1;
sink->ctx.dropped = 0;
- LIST_APPEND(&sink_list, &sink->sink_list);
+ if (_new)
+ LIST_APPEND(&sink_list, &sink->sink_list);
end:
return sink;
sink_new_buf("buf0", "in-memory ring buffer", LOG_FORMAT_TIMED, 1048576);
}
+static int sink_postcheck()
+{
+ struct sink *sink;
+
+ list_for_each_entry(sink, &sink_list, sink_list) {
+ if (sink->type == SINK_TYPE_FORWARD_DECLARED) {
+ /* sink wasn't upgraded to actual sink despite being
+ * forward-declared: it is an error (the sink doesn't
+ * really exist)
+ */
+ ha_alert("%s: sink '%s' doesn't exist.\n", sink->desc, sink->name);
+ return ERR_ALERT | ERR_FATAL;
+ }
+ }
+ return ERR_NONE;
+}
+
static void sink_deinit()
{
struct sink *sink, *sb;
}
INITCALL0(STG_REGISTER, sink_init);
+REGISTER_POST_CHECK(sink_postcheck);
REGISTER_POST_DEINIT(sink_deinit);
static struct cli_kw_list cli_kws = {{ },{