mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-21 22:01:31 +02:00
MEDIUM: log: add support for logging to a ring buffer
Now by prefixing a log server with "ring@<name>" it's possible to send the logs to a ring buffer. One nice thing is that it allows multiple sessions to consult the logs in real time in parallel over the CLI, and without requiring file system access. At the moment, ring0 is created as a default sink for tracing purposes and is available. No option is provided to create new rings though this is trivial to add to the global section.
This commit is contained in:
parent
f3dc30f6de
commit
c046d167e4
@ -933,6 +933,12 @@ log <address> [len <length>] [format <format>] [sample <ranges>:<smp_size>]
|
|||||||
- "stdout" / "stderr", which are respectively aliases for "fd@1" and
|
- "stdout" / "stderr", which are respectively aliases for "fd@1" and
|
||||||
"fd@2", see above.
|
"fd@2", see above.
|
||||||
|
|
||||||
|
- A ring buffer in the form "ring@<name>", which will correspond to an
|
||||||
|
in-memory ring buffer accessible over the CLI using the "show events"
|
||||||
|
command, which will also list existing rings and their sizes. Such
|
||||||
|
buffers are lost on reload or restart but when used as a complement
|
||||||
|
this can help troubleshooting by having the logs instantly available.
|
||||||
|
|
||||||
You may want to reference some environment variables in the address
|
You may want to reference some environment variables in the address
|
||||||
parameter, see section 2.3 about environment variables.
|
parameter, see section 2.3 about environment variables.
|
||||||
|
|
||||||
@ -5385,6 +5391,13 @@ no log
|
|||||||
- "stdout" / "stderr", which are respectively aliases for "fd@1"
|
- "stdout" / "stderr", which are respectively aliases for "fd@1"
|
||||||
and "fd@2", see above.
|
and "fd@2", see above.
|
||||||
|
|
||||||
|
- A ring buffer in the form "ring@<name>", which will correspond
|
||||||
|
to an in-memory ring buffer accessible over the CLI using the
|
||||||
|
"show events" command, which will also list existing rings and
|
||||||
|
their sizes. Such buffers are lost on reload or restart but
|
||||||
|
when used as a complement this can help troubleshooting by
|
||||||
|
having the logs instantly available.
|
||||||
|
|
||||||
You may want to reference some environment variables in the
|
You may want to reference some environment variables in the
|
||||||
address parameter, see section 2.3 about environment variables.
|
address parameter, see section 2.3 about environment variables.
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <common/config.h>
|
#include <common/config.h>
|
||||||
#include <common/hathreads.h>
|
#include <common/hathreads.h>
|
||||||
#include <common/mini-clist.h>
|
#include <common/mini-clist.h>
|
||||||
|
#include <types/ring.h>
|
||||||
|
|
||||||
#define NB_LOG_FACILITIES 24
|
#define NB_LOG_FACILITIES 24
|
||||||
#define NB_LOG_LEVELS 8
|
#define NB_LOG_LEVELS 8
|
||||||
@ -51,6 +52,7 @@ enum {
|
|||||||
enum log_tgt {
|
enum log_tgt {
|
||||||
LOG_TARGET_DGRAM = 0, // datagram address (udp, unix socket)
|
LOG_TARGET_DGRAM = 0, // datagram address (udp, unix socket)
|
||||||
LOG_TARGET_FD, // file descriptor
|
LOG_TARGET_FD, // file descriptor
|
||||||
|
LOG_TARGET_BUFFER, // ring buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
/* lists of fields that can be logged */
|
/* lists of fields that can be logged */
|
||||||
@ -203,6 +205,7 @@ struct logsrv {
|
|||||||
struct list list;
|
struct list list;
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
struct smp_info lb;
|
struct smp_info lb;
|
||||||
|
struct ring *ring;
|
||||||
enum log_tgt type;
|
enum log_tgt type;
|
||||||
int format;
|
int format;
|
||||||
int facility;
|
int facility;
|
||||||
|
29
src/log.c
29
src/log.c
@ -39,7 +39,9 @@
|
|||||||
#include <proto/fd.h>
|
#include <proto/fd.h>
|
||||||
#include <proto/frontend.h>
|
#include <proto/frontend.h>
|
||||||
#include <proto/log.h>
|
#include <proto/log.h>
|
||||||
|
#include <proto/ring.h>
|
||||||
#include <proto/sample.h>
|
#include <proto/sample.h>
|
||||||
|
#include <proto/sink.h>
|
||||||
#include <proto/ssl_sock.h>
|
#include <proto/ssl_sock.h>
|
||||||
#include <proto/stream.h>
|
#include <proto/stream.h>
|
||||||
#include <proto/stream_interface.h>
|
#include <proto/stream_interface.h>
|
||||||
@ -1000,6 +1002,20 @@ int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
|
|||||||
|
|
||||||
/* now, back to the address */
|
/* now, back to the address */
|
||||||
logsrv->type = LOG_TARGET_DGRAM;
|
logsrv->type = LOG_TARGET_DGRAM;
|
||||||
|
if (strncmp(args[1], "ring@", 5) == 0) {
|
||||||
|
struct sink *sink = sink_find(args[1] + 5);
|
||||||
|
|
||||||
|
if (!sink || sink->type != SINK_TYPE_BUFFER) {
|
||||||
|
memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
logsrv->addr.ss_family = AF_UNSPEC;
|
||||||
|
logsrv->type = LOG_TARGET_BUFFER;
|
||||||
|
logsrv->ring = sink->ctx.ring;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (strncmp(args[1], "fd@", 3) == 0)
|
if (strncmp(args[1], "fd@", 3) == 0)
|
||||||
logsrv->type = LOG_TARGET_FD;
|
logsrv->type = LOG_TARGET_FD;
|
||||||
|
|
||||||
@ -1017,6 +1033,7 @@ int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
|
|||||||
if (!port1)
|
if (!port1)
|
||||||
set_host_port(&logsrv->addr, SYSLOG_PORT);
|
set_host_port(&logsrv->addr, SYSLOG_PORT);
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
LIST_ADDQ(logsrvs, &logsrv->list);
|
LIST_ADDQ(logsrvs, &logsrv->list);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@ -1510,12 +1527,15 @@ static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_
|
|||||||
/* the socket's address is a file descriptor */
|
/* the socket's address is a file descriptor */
|
||||||
plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
|
plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
|
||||||
}
|
}
|
||||||
|
else if (logsrv->type == LOG_TARGET_BUFFER) {
|
||||||
|
plogfd = NULL;
|
||||||
|
}
|
||||||
else if (logsrv->addr.ss_family == AF_UNIX)
|
else if (logsrv->addr.ss_family == AF_UNIX)
|
||||||
plogfd = &logfdunix;
|
plogfd = &logfdunix;
|
||||||
else
|
else
|
||||||
plogfd = &logfdinet;
|
plogfd = &logfdinet;
|
||||||
|
|
||||||
if (unlikely(*plogfd < 0)) {
|
if (plogfd && unlikely(*plogfd < 0)) {
|
||||||
/* socket not successfully initialized yet */
|
/* socket not successfully initialized yet */
|
||||||
if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
|
if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
|
||||||
(logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
|
(logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
|
||||||
@ -1652,7 +1672,7 @@ static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_
|
|||||||
max = MIN(size, maxlen - sd_max) - 1;
|
max = MIN(size, maxlen - sd_max) - 1;
|
||||||
send:
|
send:
|
||||||
if (logsrv->addr.ss_family == AF_UNSPEC) {
|
if (logsrv->addr.ss_family == AF_UNSPEC) {
|
||||||
/* the target is a direct file descriptor */
|
/* the target is a file descriptor or a ring buffer */
|
||||||
struct ist msg[7];
|
struct ist msg[7];
|
||||||
|
|
||||||
msg[0].ptr = hdr_ptr; msg[0].len = hdr_max;
|
msg[0].ptr = hdr_ptr; msg[0].len = hdr_max;
|
||||||
@ -1663,7 +1683,10 @@ send:
|
|||||||
msg[5].ptr = sd; msg[5].len = sd_max;
|
msg[5].ptr = sd; msg[5].len = sd_max;
|
||||||
msg[6].ptr = dataptr; msg[6].len = max;
|
msg[6].ptr = dataptr; msg[6].len = max;
|
||||||
|
|
||||||
sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
|
if (logsrv->type == LOG_TARGET_BUFFER)
|
||||||
|
sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
|
||||||
|
else /* LOG_TARGET_FD */
|
||||||
|
sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iovec[0].iov_base = hdr_ptr;
|
iovec[0].iov_base = hdr_ptr;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user