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:
Aurelien DARRAGON 2023-09-11 16:10:37 +02:00 committed by Christopher Faulet
parent 18da35c123
commit a9b185f34e
3 changed files with 149 additions and 75 deletions

View File

@ -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
View File

@ -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);
}

View File

@ -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;
}