mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 15:17:01 +02:00
MEDIUM: log: introduce log target
log targets were immediately embedded in logger struct (previously named logsrv) and could not be used outside of this context. In this patch, we're introducing log_target type with the associated helper functions so that it becomes possible to declare and use log targets outside of loggers scope.
This commit is contained in:
parent
18da35c123
commit
a9b185f34e
@ -218,13 +218,25 @@ struct smp_info {
|
||||
ullong curr_rg_idx; /* 63:32 = current range; 31:0 = current index */
|
||||
};
|
||||
|
||||
enum log_target_flags {
|
||||
LOG_TARGET_FL_NONE = 0x00,
|
||||
LOG_TARGET_FL_RESOLVED = 0x01
|
||||
};
|
||||
|
||||
struct log_target {
|
||||
struct sockaddr_storage *addr;
|
||||
union {
|
||||
char *ring_name; /* type = BUFFER - preparsing */
|
||||
struct sink *sink; /* type = BUFFER - postparsing */
|
||||
};
|
||||
enum log_tgt type;
|
||||
uint16_t flags;
|
||||
};
|
||||
|
||||
struct logger {
|
||||
struct list list;
|
||||
struct sockaddr_storage addr;
|
||||
struct log_target target;
|
||||
struct smp_info lb;
|
||||
struct sink *sink;
|
||||
char *ring_name;
|
||||
enum log_tgt type;
|
||||
enum log_fmt format;
|
||||
int facility;
|
||||
int level;
|
||||
|
173
src/log.c
173
src/log.c
@ -734,6 +734,43 @@ int smp_log_range_cmp(const void *a, const void *b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* helper func */
|
||||
static inline void init_log_target(struct log_target *target)
|
||||
{
|
||||
target->type = 0;
|
||||
target->flags = LOG_TARGET_FL_NONE;
|
||||
target->addr = NULL;
|
||||
target->ring_name = NULL;
|
||||
}
|
||||
|
||||
static void deinit_log_target(struct log_target *target)
|
||||
{
|
||||
ha_free(&target->addr);
|
||||
if (!(target->flags & LOG_TARGET_FL_RESOLVED))
|
||||
ha_free(&target->ring_name);
|
||||
}
|
||||
|
||||
/* returns 0 on failure and positive value on success */
|
||||
static int dup_log_target(struct log_target *def, struct log_target *cpy)
|
||||
{
|
||||
BUG_ON((def->flags & LOG_TARGET_FL_RESOLVED)); /* postparsing already done, invalid use */
|
||||
init_log_target(cpy);
|
||||
cpy->addr = malloc(sizeof(*cpy->addr));
|
||||
if (!cpy->addr)
|
||||
goto error;
|
||||
*cpy->addr = *def->addr;
|
||||
if (def->ring_name) {
|
||||
cpy->ring_name = strdup(def->ring_name);
|
||||
if (!cpy->ring_name)
|
||||
goto error;
|
||||
}
|
||||
cpy->type = def->type;
|
||||
return 1;
|
||||
error:
|
||||
deinit_log_target(cpy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* resolves a single logger entry (it is expected to be called
|
||||
* at postparsing stage)
|
||||
*
|
||||
@ -747,10 +784,14 @@ int smp_log_range_cmp(const void *a, const void *b)
|
||||
*/
|
||||
int resolve_logger(struct logger *logger, char **msg)
|
||||
{
|
||||
struct log_target *target = &logger->target;
|
||||
int err_code = ERR_NONE;
|
||||
|
||||
if (logger->type == LOG_TARGET_BUFFER)
|
||||
if (target->type == LOG_TARGET_BUFFER)
|
||||
err_code = sink_resolve_logger_buffer(logger, msg);
|
||||
|
||||
target->flags |= LOG_TARGET_FL_RESOLVED;
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
@ -767,16 +808,12 @@ struct logger *dup_logger(struct logger *def)
|
||||
memcpy(cpy, def, sizeof(*cpy));
|
||||
|
||||
/* default values */
|
||||
cpy->ring_name = NULL;
|
||||
cpy->conf.file = NULL;
|
||||
LIST_INIT(&cpy->list);
|
||||
|
||||
/* special members */
|
||||
if (def->ring_name) {
|
||||
cpy->ring_name = strdup(def->ring_name);
|
||||
if (!cpy->ring_name)
|
||||
if (dup_log_target(&def->target, &cpy->target) == 0)
|
||||
goto error;
|
||||
}
|
||||
if (def->conf.file) {
|
||||
cpy->conf.file = strdup(def->conf.file);
|
||||
if (!cpy->conf.file)
|
||||
@ -801,10 +838,69 @@ void free_logger(struct logger *logger)
|
||||
|
||||
BUG_ON(LIST_INLIST(&logger->list));
|
||||
ha_free(&logger->conf.file);
|
||||
ha_free(&logger->ring_name);
|
||||
deinit_log_target(&logger->target);
|
||||
free(logger);
|
||||
}
|
||||
|
||||
/* Parse single log target
|
||||
* Returns 0 on failure and positive value on success
|
||||
*/
|
||||
static int parse_log_target(char *raw, struct log_target *target, char **err)
|
||||
{
|
||||
int port1, port2, fd;
|
||||
struct protocol *proto;
|
||||
struct sockaddr_storage *sk;
|
||||
|
||||
init_log_target(target);
|
||||
|
||||
/* first, try to allocate log target addr */
|
||||
target->addr = malloc(sizeof(*target->addr));
|
||||
if (!target->addr) {
|
||||
memprintf(err, "memory error");
|
||||
goto error;
|
||||
}
|
||||
|
||||
target->type = LOG_TARGET_DGRAM;
|
||||
if (strncmp(raw, "ring@", 5) == 0) {
|
||||
target->addr->ss_family = AF_UNSPEC;
|
||||
target->type = LOG_TARGET_BUFFER;
|
||||
target->ring_name = strdup(raw + 5);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* parse the target address */
|
||||
sk = str2sa_range(raw, NULL, &port1, &port2, &fd, &proto,
|
||||
err, NULL, NULL,
|
||||
PA_O_RESOLVE | PA_O_PORT_OK | PA_O_RAW_FD | PA_O_DGRAM | PA_O_STREAM | PA_O_DEFAULT_DGRAM);
|
||||
if (!sk)
|
||||
goto error;
|
||||
if (fd != -1)
|
||||
target->type = LOG_TARGET_FD;
|
||||
*target->addr = *sk;
|
||||
|
||||
if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
|
||||
if (!port1)
|
||||
set_host_port(target->addr, SYSLOG_PORT);
|
||||
}
|
||||
|
||||
if (proto && proto->xprt_type == PROTO_TYPE_STREAM) {
|
||||
static unsigned long ring_ids;
|
||||
|
||||
/* Implicit sink buffer will be
|
||||
* initialized in post_check
|
||||
*/
|
||||
target->type = LOG_TARGET_BUFFER;
|
||||
/* compute unique name for the ring */
|
||||
memprintf(&target->ring_name, "ring#%lu", ++ring_ids);
|
||||
}
|
||||
|
||||
done:
|
||||
return 1;
|
||||
error:
|
||||
deinit_log_target(target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse "log" keyword and update <loggers> list accordingly.
|
||||
*
|
||||
@ -821,12 +917,8 @@ void free_logger(struct logger *logger)
|
||||
int parse_logger(char **args, struct list *loggers, int do_del, const char *file, int linenum, char **err)
|
||||
{
|
||||
struct smp_log_range *smp_rgs = NULL;
|
||||
struct sockaddr_storage *sk;
|
||||
struct protocol *proto;
|
||||
struct logger *logger = NULL;
|
||||
int port1, port2;
|
||||
int cur_arg;
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* "no log": delete previous herited or defined syslog
|
||||
@ -1042,43 +1134,10 @@ int parse_logger(char **args, struct list *loggers, int do_del, const char *file
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* now, back to the address */
|
||||
logger->type = LOG_TARGET_DGRAM;
|
||||
if (strncmp(args[1], "ring@", 5) == 0) {
|
||||
logger->addr.ss_family = AF_UNSPEC;
|
||||
logger->type = LOG_TARGET_BUFFER;
|
||||
logger->sink = NULL;
|
||||
logger->ring_name = strdup(args[1] + 5);
|
||||
goto done;
|
||||
}
|
||||
|
||||
sk = str2sa_range(args[1], NULL, &port1, &port2, &fd, &proto,
|
||||
err, NULL, NULL,
|
||||
PA_O_RESOLVE | PA_O_PORT_OK | PA_O_RAW_FD | PA_O_DGRAM | PA_O_STREAM | PA_O_DEFAULT_DGRAM);
|
||||
if (!sk)
|
||||
/* now, back to the log target */
|
||||
if (!parse_log_target(args[1], &logger->target, err))
|
||||
goto error;
|
||||
|
||||
if (fd != -1)
|
||||
logger->type = LOG_TARGET_FD;
|
||||
logger->addr = *sk;
|
||||
|
||||
if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
|
||||
if (!port1)
|
||||
set_host_port(&logger->addr, SYSLOG_PORT);
|
||||
}
|
||||
|
||||
if (proto && proto->xprt_type == PROTO_TYPE_STREAM) {
|
||||
static unsigned long ring_ids;
|
||||
|
||||
/* Implicit sink buffer will be
|
||||
* initialized in post_check
|
||||
*/
|
||||
logger->type = LOG_TARGET_BUFFER;
|
||||
logger->sink = NULL;
|
||||
/* compute uniq name for the ring */
|
||||
memprintf(&logger->ring_name, "ring#%lu", ++ring_ids);
|
||||
}
|
||||
|
||||
done:
|
||||
LIST_APPEND(loggers, &logger->list);
|
||||
return 1;
|
||||
@ -1704,23 +1763,23 @@ static inline void __do_send_log(struct logger *logger, int nblogger, int level,
|
||||
while (size && (message[size-1] == '\n' || (message[size-1] == 0)))
|
||||
size--;
|
||||
|
||||
if (logger->type == LOG_TARGET_BUFFER) {
|
||||
if (logger->target.type == LOG_TARGET_BUFFER) {
|
||||
plogfd = NULL;
|
||||
goto send;
|
||||
}
|
||||
else if (logger->addr.ss_family == AF_CUST_EXISTING_FD) {
|
||||
else if (logger->target.addr->ss_family == AF_CUST_EXISTING_FD) {
|
||||
/* the socket's address is a file descriptor */
|
||||
plogfd = (int *)&((struct sockaddr_in *)&logger->addr)->sin_addr.s_addr;
|
||||
plogfd = (int *)&((struct sockaddr_in *)logger->target.addr)->sin_addr.s_addr;
|
||||
}
|
||||
else if (logger->addr.ss_family == AF_UNIX)
|
||||
else if (logger->target.addr->ss_family == AF_UNIX)
|
||||
plogfd = &logfdunix;
|
||||
else
|
||||
plogfd = &logfdinet;
|
||||
|
||||
if (plogfd && unlikely(*plogfd < 0)) {
|
||||
/* socket not successfully initialized yet */
|
||||
if ((*plogfd = socket(logger->addr.ss_family, SOCK_DGRAM,
|
||||
(logger->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
|
||||
if ((*plogfd = socket(logger->target.addr->ss_family, SOCK_DGRAM,
|
||||
(logger->target.addr->ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
|
||||
static char once;
|
||||
|
||||
if (!once) {
|
||||
@ -1740,7 +1799,7 @@ static inline void __do_send_log(struct logger *logger, int nblogger, int level,
|
||||
|
||||
msg_header = build_log_header(logger->format, level, facility, metadata, &nbelem);
|
||||
send:
|
||||
if (logger->type == LOG_TARGET_BUFFER) {
|
||||
if (logger->target.type == LOG_TARGET_BUFFER) {
|
||||
struct ist msg;
|
||||
size_t maxlen = logger->maxlen;
|
||||
|
||||
@ -1751,9 +1810,9 @@ static inline void __do_send_log(struct logger *logger, int nblogger, int level,
|
||||
*/
|
||||
maxlen -= 1;
|
||||
|
||||
sent = sink_write(logger->sink, maxlen, &msg, 1, level, facility, metadata);
|
||||
sent = sink_write(logger->target.sink, maxlen, &msg, 1, level, facility, metadata);
|
||||
}
|
||||
else if (logger->addr.ss_family == AF_CUST_EXISTING_FD) {
|
||||
else if (logger->target.addr->ss_family == AF_CUST_EXISTING_FD) {
|
||||
struct ist msg;
|
||||
|
||||
msg = ist2(message, size);
|
||||
@ -1786,8 +1845,8 @@ static inline void __do_send_log(struct logger *logger, int nblogger, int level,
|
||||
i++;
|
||||
|
||||
msghdr.msg_iovlen = i;
|
||||
msghdr.msg_name = (struct sockaddr *)&logger->addr;
|
||||
msghdr.msg_namelen = get_addr_len(&logger->addr);
|
||||
msghdr.msg_name = (struct sockaddr *)logger->target.addr;
|
||||
msghdr.msg_namelen = get_addr_len(logger->target.addr);
|
||||
|
||||
sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
|
||||
}
|
||||
|
29
src/sink.c
29
src/sink.c
@ -1184,7 +1184,7 @@ int cfg_parse_ring(const char *file, int linenum, char **args, int kwm)
|
||||
* it returns NULL.
|
||||
*
|
||||
* Note: the sink is created using the name
|
||||
* specified into logger->ring_name
|
||||
* specified into logger->target.ring_name
|
||||
*/
|
||||
struct sink *sink_new_from_logger(struct logger *logger)
|
||||
{
|
||||
@ -1197,7 +1197,7 @@ struct sink *sink_new_from_logger(struct logger *logger)
|
||||
chunk_printf(&trash, "created from log directive declared into '%s' at line %d", logger->conf.file, logger->conf.line);
|
||||
|
||||
/* allocate a new sink buffer */
|
||||
sink = sink_new_ringbuf(logger->ring_name, trash.area, logger->conf.file, logger->conf.line, &err_msg);
|
||||
sink = sink_new_ringbuf(logger->target.ring_name, trash.area, logger->conf.file, logger->conf.line, &err_msg);
|
||||
if (!sink) {
|
||||
ha_alert("%s.\n", err_msg);
|
||||
ha_free(&err_msg);
|
||||
@ -1222,11 +1222,11 @@ struct sink *sink_new_from_logger(struct logger *logger)
|
||||
goto error;
|
||||
|
||||
/* init server */
|
||||
srv->id = strdup(logger->ring_name);
|
||||
srv->id = strdup(logger->target.ring_name);
|
||||
srv->conf.file = strdup(logger->conf.file);
|
||||
srv->conf.line = logger->conf.line;
|
||||
srv->addr = logger->addr;
|
||||
srv->svc_port = get_host_port(&logger->addr);
|
||||
srv->addr = *logger->target.addr;
|
||||
srv->svc_port = get_host_port(logger->target.addr);
|
||||
HA_SPIN_INIT(&srv->lock);
|
||||
|
||||
/* process per thread init */
|
||||
@ -1242,8 +1242,8 @@ struct sink *sink_new_from_logger(struct logger *logger)
|
||||
if (sink_finalize(sink) & ERR_CODE)
|
||||
goto error_final;
|
||||
|
||||
/* reset familyt of logger to consider the ring buffer target */
|
||||
logger->addr.ss_family = AF_UNSPEC;
|
||||
/* reset family of logger to consider the ring buffer target */
|
||||
logger->target.addr->ss_family = AF_UNSPEC;
|
||||
|
||||
return sink;
|
||||
error:
|
||||
@ -1279,20 +1279,21 @@ int cfg_post_parse_ring()
|
||||
* could also be set when no error occured to report a diag warning), thus is
|
||||
* up to the caller to check it and to free it.
|
||||
*/
|
||||
int sink_resolve_logger_buffer(struct logger *target, char **msg)
|
||||
int sink_resolve_logger_buffer(struct logger *logger, char **msg)
|
||||
{
|
||||
struct log_target *target = &logger->target;
|
||||
int err_code = ERR_NONE;
|
||||
struct sink *sink;
|
||||
|
||||
BUG_ON(target->type != LOG_TARGET_BUFFER);
|
||||
BUG_ON(target->type != LOG_TARGET_BUFFER || (target->flags & LOG_TARGET_FL_RESOLVED));
|
||||
sink = sink_find(target->ring_name);
|
||||
if (!sink) {
|
||||
/* LOG_TARGET_BUFFER but !AF_UNSPEC
|
||||
* means we must allocate a sink
|
||||
* buffer to send messages to this logger
|
||||
*/
|
||||
if (target->addr.ss_family != AF_UNSPEC) {
|
||||
sink = sink_new_from_logger(target);
|
||||
if (target->addr->ss_family != AF_UNSPEC) {
|
||||
sink = sink_new_from_logger(logger);
|
||||
if (!sink) {
|
||||
memprintf(msg, "cannot be initialized (failed to create implicit ring)");
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
@ -1310,16 +1311,18 @@ int sink_resolve_logger_buffer(struct logger *target, char **msg)
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto end;
|
||||
}
|
||||
if (sink && target->maxlen > ring_max_payload(sink->ctx.ring)) {
|
||||
if (sink && logger->maxlen > ring_max_payload(sink->ctx.ring)) {
|
||||
memprintf(msg, "uses a max length which exceeds ring capacity ('%s' supports %lu bytes at most)",
|
||||
target->ring_name, (unsigned long)ring_max_payload(sink->ctx.ring));
|
||||
}
|
||||
else if (sink && target->maxlen > sink->maxlen) {
|
||||
else if (sink && logger->maxlen > sink->maxlen) {
|
||||
memprintf(msg, "uses a ring with a smaller maxlen than the one specified on the log directive ('%s' has maxlen = %d), logs will be truncated according to the lowest maxlen between the two",
|
||||
target->ring_name, sink->maxlen);
|
||||
}
|
||||
end:
|
||||
ha_free(&target->ring_name); /* sink is resolved and will replace ring_name hint */
|
||||
target->sink = sink;
|
||||
ha_free(&target->addr); /* we no longer need this */
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user