diff --git a/include/proto/sink.h b/include/proto/sink.h index ae493d4ce..0d8dd7dfc 100644 --- a/include/proto/sink.h +++ b/include/proto/sink.h @@ -28,6 +28,7 @@ extern struct list sink_list; struct sink *sink_find(const char *name); +struct sink *sink_new_fd(const char *name, const char *desc, enum sink_fmt fmt, int fd); void sink_write(struct sink *sink, const struct ist msg[], size_t nmsg); #endif /* _PROTO_SINK_H */ diff --git a/include/types/sink.h b/include/types/sink.h index 35333144d..32c056712 100644 --- a/include/types/sink.h +++ b/include/types/sink.h @@ -28,10 +28,11 @@ #include /* A sink may be of several types. For now the following types are supported: - * (none yet) + * - file descriptor (such as stdout) */ enum sink_type { SINK_TYPE_NEW, // not yet initialized + SINK_TYPE_FD, // events sent to a file descriptor }; /* This indicates the default event format, which is the destination's @@ -59,6 +60,7 @@ struct sink { struct { unsigned int dropped; // dropped events since last one. __decl_hathreads(HA_RWLOCK_T lock); // used by some types + int fd; // fd num for FD type sink } ctx; }; diff --git a/src/sink.c b/src/sink.c index 6cebf2aa5..f3e18ccb2 100644 --- a/src/sink.c +++ b/src/sink.c @@ -43,7 +43,7 @@ struct sink *sink_find(const char *name) * exists with the same name, it will be returned. The caller can detect it as * a newly created one has type SINK_TYPE_NEW. */ -static __maybe_unused struct sink *__sink_new(const char *name, const char *desc, enum sink_fmt fmt) +static struct sink *__sink_new(const char *name, const char *desc, enum sink_fmt fmt) { struct sink *sink; @@ -64,6 +64,7 @@ static __maybe_unused struct sink *__sink_new(const char *name, const char *desc sink->syslog_minlvl = 0; sink->maxlen = MAX_SYSLOG_LEN; /* address will be filled by the caller if needed */ + sink->ctx.fd = -1; sink->ctx.dropped = 0; HA_RWLOCK_INIT(&sink->ctx.lock); LIST_ADDQ(&sink_list, &sink->sink_list); @@ -71,6 +72,29 @@ static __maybe_unused struct sink *__sink_new(const char *name, const char *desc return sink; } +/* creates a sink called of type FD associated to fd , format , + * and description . Returns NULL on allocation failure or conflict. + * Perfect duplicates are merged (same type, fd, and name). + */ +struct sink *sink_new_fd(const char *name, const char *desc, enum sink_fmt fmt, int fd) +{ + struct sink *sink; + + sink = __sink_new(name, desc, fmt); + if (!sink || (sink->type == SINK_TYPE_FD && sink->ctx.fd == fd)) + goto end; + + if (sink->type != SINK_TYPE_NEW) { + sink = NULL; + goto end; + } + + sink->type = SINK_TYPE_FD; + sink->ctx.fd = fd; + end: + return sink; +} + /* tries to send message parts (up to 8, ignored above) from message * array to sink . Formating according to the sink's preference is * done here. Lost messages are accounted for in the sink's counter. @@ -109,13 +133,31 @@ void sink_write(struct sink *sink, const struct ist msg[], size_t nmsg) msg++; nmsg--; } - /* now deal with the various sink types here */ + if (sink->type == SINK_TYPE_FD) { + /* For the FD we always emit the trailing \n. It was already provisioned above. */ + iovec[vec].iov_base = "\n"; + iovec[vec].iov_len = 1; + vec++; + + HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &sink->ctx.lock); + sent = writev(sink->ctx.fd, iovec, vec); + HA_RWLOCK_WRUNLOCK(LOGSRV_LOCK, &sink->ctx.lock); + /* sent > 0 if the message was delivered */ + } /* account for errors now */ if (sent <= 0) HA_ATOMIC_ADD(&sink->ctx.dropped, 1); } +static void sink_init() +{ + sink_new_fd("stdout", "standard output (fd#1)", SINK_FMT_RAW, 1); + sink_new_fd("stderr", "standard output (fd#2)", SINK_FMT_RAW, 2); +} + +INITCALL0(STG_REGISTER, sink_init); + /* * Local variables: * c-indent-level: 8