no port is specified, 514 is used by default (the standard syslog
port).
- - A filesystem path to a UNIX domain socket, keeping in mind
+ - A filesystem path to a datagram UNIX domain socket, keeping in mind
considerations for chroot (be sure the path is accessible inside
the chroot) and uid/gid (be sure the path is appropriately
writable).
+ - A file descriptor number in the form "fd@<number>", which may point
+ to a pipe, terminal, or socket. In this case unbuffered logs are used
+ and one writev() call per log is performed. This is a bit expensive
+ but acceptable for most workloads. Messages sent this way will not be
+ truncated but may be dropped, in which case the DroppedLogs counter
+ will be incremented. The writev() call is atomic even on pipes for
+ messages up to PIPE_BUF size, which POSIX recommends to be at least
+ 512 and which is 4096 bytes on most modern operating systems. Any
+ larger message may be interleaved with messages from other processes.
+ Exceptionally for debugging purposes the file descriptor may also be
+ directed to a file, but doing so will significantly slow haproxy down
+ as non-blocking calls will be ignored. Also there will be no way to
+ purge nor rotate this file without restarting the process. Note that
+ the configured syslog format is preserved, so the output is suitable
+ for use with a TCP syslog server.
+
+ - "stdout" / "stderr", which are respectively aliases for "fd@1" and
+ "fd@2", see above.
+
You may want to reference some environment variables in the address
parameter, see section 2.3 about environment variables.
inside the chroot) and uid/gid (be sure the path is
appropriately writable).
- You may want to reference some environment variables in the
- address parameter, see section 2.3 about environment variables.
+ - A file descriptor number in the form "fd@<number>", which may
+ point to a pipe, terminal, or socket. In this case unbuffered
+ logs are used and one writev() call per log is performed. This
+ is a bit expensive but acceptable for most workloads. Messages
+ sent this way will not be truncated but may be dropped, in
+ which case the DroppedLogs counter will be incremented. The
+ writev() call is atomic even on pipes for messages up to
+ PIPE_BUF size, which POSIX recommends to be at least 512 and
+ which is 4096 bytes on most modern operating systems. Any
+ larger message may be interleaved with messages from other
+ processes. Exceptionally for debugging purposes the file
+ descriptor may also be directed to a file, but doing so will
+ significantly slow haproxy down as non-blocking calls will be
+ ignored. Also there will be no way to purge nor rotate this
+ file without restarting the process. Note that the configured
+ syslog format is preserved, so the output is suitable for use
+ with a TCP syslog server.
+
+ - "stdout" / "stderr", which are respectively aliases for "fd@1"
+ and "fd@2", see above.
+
+ You may want to reference some environment variables in the
+ address parameter, see section 2.3 about environment variables.
<length> is an optional maximum line length. Log lines larger than this
value will be truncated before being sent. The reason is that
goto error;
}
+ /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
+ if (strcmp(args[1], "stdout") == 0)
+ args[1] = "fd@1";
+ else if (strcmp(args[1], "stderr") == 0)
+ args[1] = "fd@2";
+
logsrv = calloc(1, sizeof(*logsrv));
if (!logsrv) {
memprintf(err, "out of memory");
if (unlikely(*plogfd < 0)) {
/* socket not successfully initialized yet */
- int proto = logsrv->addr.ss_family == AF_UNIX ? 0 : IPPROTO_UDP;
-
- if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM, proto)) < 0) {
+ if (logsrv->addr.ss_family == AF_UNSPEC) {
+ /* the socket's address is a file descriptor */
+ *plogfd = ((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
+ fcntl(*plogfd, F_SETFL, O_NONBLOCK);
+ }
+ else if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
+ (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
static char once;
if (!once) {
iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
iovec[7].iov_len = 1;
- msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
- msghdr.msg_namelen = get_addr_len(&logsrv->addr);
+ if (logsrv->addr.ss_family == AF_UNSPEC) {
+ /* the target is a direct file descriptor */
+ sent = writev(*plogfd, iovec, 8);
+ }
+ else {
+ msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
+ msghdr.msg_namelen = get_addr_len(&logsrv->addr);
- sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
+ sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
+ }
if (sent < 0) {
static char once;
HA_ATOMIC_ADD(&dropped_logs, 1);
else if (!once) {
once = 1; /* note: no need for atomic ops here */
- ha_alert("sendmsg() failed in logger #%d: %s (errno=%d)\n",
+ ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
nblogger, strerror(errno), errno);
}
}