mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 15:17:01 +02:00
REORG: log: reorder send log helpers by dependency order
This commit looks messy, but all it does is reorganize send_log() helpers by dependency order to remove the need of forward-declaring some of them. Also, since they're all internal helpers, let's explicitly mark them as static to prevent any misuse.
This commit is contained in:
parent
cf913c2f90
commit
ee288a4eef
@ -122,15 +122,6 @@ int parse_logger(char **args, struct list *loggers, int do_del, const char *file
|
|||||||
void send_log(struct proxy *p, int level, const char *format, ...)
|
void send_log(struct proxy *p, int level, const char *format, ...)
|
||||||
__attribute__ ((format(printf, 3, 4)));
|
__attribute__ ((format(printf, 3, 4)));
|
||||||
|
|
||||||
/*
|
|
||||||
* This function sends a syslog message to all loggers of a proxy,
|
|
||||||
* or to global loggers if the proxy is NULL.
|
|
||||||
* It also tries not to waste too much time computing the message header.
|
|
||||||
* It doesn't care about errors nor does it report them.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void __send_log(struct list *loggers, struct buffer *tag, int level, char *message, size_t size, char *sd, size_t sd_size);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns log format for <fmt> or LOG_FORMAT_UNSPEC if not found.
|
* returns log format for <fmt> or LOG_FORMAT_UNSPEC if not found.
|
||||||
*/
|
*/
|
||||||
|
636
src/log.c
636
src/log.c
@ -2551,6 +2551,323 @@ static char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, st
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function sends a syslog message.
|
||||||
|
* <target> is the actual log target where log will be sent,
|
||||||
|
*
|
||||||
|
* Message will be prefixed by header according to <hdr> setting.
|
||||||
|
* Final message will be truncated <maxlen> parameter and will be
|
||||||
|
* terminated with an LF character.
|
||||||
|
*
|
||||||
|
* Does not return any error
|
||||||
|
*/
|
||||||
|
static inline void __do_send_log(struct log_target *target, struct log_header hdr,
|
||||||
|
int nblogger, size_t maxlen,
|
||||||
|
char *message, size_t size)
|
||||||
|
{
|
||||||
|
static THREAD_LOCAL struct iovec iovec[NB_LOG_HDR_MAX_ELEMENTS+1+1] = { }; /* header elements + message + LF */
|
||||||
|
static THREAD_LOCAL struct msghdr msghdr = {
|
||||||
|
//.msg_iov = iovec,
|
||||||
|
.msg_iovlen = NB_LOG_HDR_MAX_ELEMENTS+2
|
||||||
|
};
|
||||||
|
static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
|
||||||
|
static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
|
||||||
|
int *plogfd;
|
||||||
|
int sent;
|
||||||
|
size_t nbelem;
|
||||||
|
struct ist *msg_header = NULL;
|
||||||
|
|
||||||
|
msghdr.msg_iov = iovec;
|
||||||
|
|
||||||
|
/* historically some messages used to already contain the trailing LF
|
||||||
|
* or Zero. Let's remove all trailing LF or Zero
|
||||||
|
*/
|
||||||
|
while (size && (message[size-1] == '\n' || (message[size-1] == 0)))
|
||||||
|
size--;
|
||||||
|
|
||||||
|
if (target->type == LOG_TARGET_BUFFER) {
|
||||||
|
plogfd = NULL;
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
else if (target->addr->ss_family == AF_CUST_EXISTING_FD) {
|
||||||
|
/* the socket's address is a file descriptor */
|
||||||
|
plogfd = (int *)&((struct sockaddr_in *)target->addr)->sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
else if (target->addr->ss_family == AF_UNIX)
|
||||||
|
plogfd = &logfdunix;
|
||||||
|
else
|
||||||
|
plogfd = &logfdinet;
|
||||||
|
|
||||||
|
if (plogfd && unlikely(*plogfd < 0)) {
|
||||||
|
/* socket not successfully initialized yet */
|
||||||
|
if ((*plogfd = socket(target->addr->ss_family, SOCK_DGRAM,
|
||||||
|
(target->addr->ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
|
||||||
|
static char once;
|
||||||
|
|
||||||
|
if (!once) {
|
||||||
|
once = 1; /* note: no need for atomic ops here */
|
||||||
|
ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
|
||||||
|
nblogger, strerror(errno), errno);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* we don't want to receive anything on this socket */
|
||||||
|
setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
|
||||||
|
/* we may want to adjust the output buffer (tune.sndbuf.backend) */
|
||||||
|
if (global.tune.backend_sndbuf)
|
||||||
|
setsockopt(*plogfd, SOL_SOCKET, SO_SNDBUF, &global.tune.backend_sndbuf, sizeof(global.tune.backend_sndbuf));
|
||||||
|
/* does nothing under Linux, maybe needed for others */
|
||||||
|
shutdown(*plogfd, SHUT_RD);
|
||||||
|
fd_set_cloexec(*plogfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_header = build_log_header(hdr, &nbelem);
|
||||||
|
send:
|
||||||
|
if (target->type == LOG_TARGET_BUFFER) {
|
||||||
|
struct ist msg;
|
||||||
|
size_t e_maxlen = maxlen;
|
||||||
|
|
||||||
|
msg = ist2(message, size);
|
||||||
|
|
||||||
|
/* make room for the final '\n' which may be forcefully inserted
|
||||||
|
* by tcp forwarder applet (sink_forward_io_handler)
|
||||||
|
*/
|
||||||
|
e_maxlen -= 1;
|
||||||
|
|
||||||
|
sent = sink_write(target->sink, hdr, e_maxlen, &msg, 1);
|
||||||
|
}
|
||||||
|
else if (target->addr->ss_family == AF_CUST_EXISTING_FD) {
|
||||||
|
struct ist msg;
|
||||||
|
|
||||||
|
msg = ist2(message, size);
|
||||||
|
|
||||||
|
sent = fd_write_frag_line(*plogfd, maxlen, msg_header, nbelem, &msg, 1, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int i = 0;
|
||||||
|
int totlen = maxlen - 1; /* save space for the final '\n' */
|
||||||
|
|
||||||
|
for (i = 0 ; i < nbelem ; i++ ) {
|
||||||
|
iovec[i].iov_base = msg_header[i].ptr;
|
||||||
|
iovec[i].iov_len = msg_header[i].len;
|
||||||
|
if (totlen <= iovec[i].iov_len) {
|
||||||
|
iovec[i].iov_len = totlen;
|
||||||
|
totlen = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
totlen -= iovec[i].iov_len;
|
||||||
|
}
|
||||||
|
if (totlen) {
|
||||||
|
iovec[i].iov_base = message;
|
||||||
|
iovec[i].iov_len = size;
|
||||||
|
if (totlen <= iovec[i].iov_len)
|
||||||
|
iovec[i].iov_len = totlen;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
iovec[i].iov_base = "\n"; /* insert a \n at the end of the message */
|
||||||
|
iovec[i].iov_len = 1;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
msghdr.msg_iovlen = i;
|
||||||
|
msghdr.msg_name = (struct sockaddr *)target->addr;
|
||||||
|
msghdr.msg_namelen = get_addr_len(target->addr);
|
||||||
|
|
||||||
|
sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sent < 0) {
|
||||||
|
static char once;
|
||||||
|
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
|
_HA_ATOMIC_INC(&dropped_logs);
|
||||||
|
else if (!once) {
|
||||||
|
once = 1; /* note: no need for atomic ops here */
|
||||||
|
ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
|
||||||
|
nblogger, strerror(errno), errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* does the same as __do_send_log() does for a single target, but here the log
|
||||||
|
* will be sent according to the log backend's lb settings. The function will
|
||||||
|
* leverage __do_send_log() function to actually send the log messages.
|
||||||
|
*/
|
||||||
|
static inline void __do_send_log_backend(struct proxy *be, struct log_header hdr,
|
||||||
|
int nblogger, size_t maxlen,
|
||||||
|
char *message, size_t size)
|
||||||
|
{
|
||||||
|
struct server *srv = NULL;
|
||||||
|
|
||||||
|
/* log-balancing logic: */
|
||||||
|
|
||||||
|
if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_RR) {
|
||||||
|
srv = fwrr_get_next_server(be, NULL);
|
||||||
|
}
|
||||||
|
else if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_SS) {
|
||||||
|
/* sticky mode: use first server in the pool, which will always stay
|
||||||
|
* first during dequeuing and requeuing, unless it becomes unavailable
|
||||||
|
* and will be replaced by another one
|
||||||
|
*/
|
||||||
|
srv = ss_get_server(be);
|
||||||
|
}
|
||||||
|
else if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_RND) {
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
hash = statistical_prng(); /* random */
|
||||||
|
srv = chash_get_server_hash(be, hash, NULL);
|
||||||
|
}
|
||||||
|
else if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_LH) {
|
||||||
|
struct sample result;
|
||||||
|
|
||||||
|
/* log-balance hash */
|
||||||
|
memset(&result, 0, sizeof(result));
|
||||||
|
result.data.type = SMP_T_STR;
|
||||||
|
result.flags = SMP_F_CONST;
|
||||||
|
result.data.u.str.area = message;
|
||||||
|
result.data.u.str.data = size;
|
||||||
|
result.data.u.str.size = size + 1; /* with terminating NULL byte */
|
||||||
|
if (sample_process_cnv(be->lbprm.expr, &result)) {
|
||||||
|
/* gen_hash takes binary input, ensure that we provide such value to it */
|
||||||
|
if (result.data.type == SMP_T_BIN || sample_casts[result.data.type][SMP_T_BIN]) {
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
sample_casts[result.data.type][SMP_T_BIN](&result);
|
||||||
|
hash = gen_hash(be, result.data.u.str.area, result.data.u.str.data);
|
||||||
|
srv = map_get_server_hash(be, hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!srv) {
|
||||||
|
/* no srv available, can't log */
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
__do_send_log(srv->log_target, hdr, nblogger, maxlen, message, size);
|
||||||
|
return;
|
||||||
|
|
||||||
|
drop:
|
||||||
|
_HA_ATOMIC_INC(&dropped_logs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function sends a syslog message.
|
||||||
|
* It doesn't care about errors nor does it report them.
|
||||||
|
* The argument <metadata> MUST be an array of size
|
||||||
|
* LOG_META_FIELDS*sizeof(struct ist) containing
|
||||||
|
* data to build the header.
|
||||||
|
*/
|
||||||
|
static void process_send_log(struct list *loggers, int level, int facility,
|
||||||
|
struct ist *metadata, char *message, size_t size)
|
||||||
|
{
|
||||||
|
struct logger *logger;
|
||||||
|
int nblogger;
|
||||||
|
|
||||||
|
/* Send log messages to syslog server. */
|
||||||
|
nblogger = 0;
|
||||||
|
list_for_each_entry(logger, loggers, list) {
|
||||||
|
int in_range = 1;
|
||||||
|
|
||||||
|
/* we can filter the level of the messages that are sent to each logger */
|
||||||
|
if (level > logger->level)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (logger->lb.smp_rgs) {
|
||||||
|
struct smp_log_range *smp_rg;
|
||||||
|
uint next_idx, curr_rg;
|
||||||
|
ullong curr_rg_idx, next_rg_idx;
|
||||||
|
|
||||||
|
curr_rg_idx = _HA_ATOMIC_LOAD(&logger->lb.curr_rg_idx);
|
||||||
|
do {
|
||||||
|
next_idx = (curr_rg_idx & 0xFFFFFFFFU) + 1;
|
||||||
|
curr_rg = curr_rg_idx >> 32;
|
||||||
|
smp_rg = &logger->lb.smp_rgs[curr_rg];
|
||||||
|
|
||||||
|
/* check if the index we're going to take is within range */
|
||||||
|
in_range = smp_rg->low <= next_idx && next_idx <= smp_rg->high;
|
||||||
|
if (in_range) {
|
||||||
|
/* Let's consume this range. */
|
||||||
|
if (next_idx == smp_rg->high) {
|
||||||
|
/* If consumed, let's select the next range. */
|
||||||
|
curr_rg = (curr_rg + 1) % logger->lb.smp_rgs_sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next_idx = next_idx % logger->lb.smp_sz;
|
||||||
|
next_rg_idx = ((ullong)curr_rg << 32) + next_idx;
|
||||||
|
} while (!_HA_ATOMIC_CAS(&logger->lb.curr_rg_idx, &curr_rg_idx, next_rg_idx) &&
|
||||||
|
__ha_cpu_relax());
|
||||||
|
}
|
||||||
|
if (in_range) {
|
||||||
|
struct log_header hdr;
|
||||||
|
|
||||||
|
hdr.level = MAX(level, logger->minlvl);
|
||||||
|
hdr.facility = (facility == -1) ? logger->facility : facility;
|
||||||
|
hdr.format = logger->format;
|
||||||
|
hdr.metadata = metadata;
|
||||||
|
|
||||||
|
nblogger += 1;
|
||||||
|
if (logger->target.type == LOG_TARGET_BACKEND) {
|
||||||
|
__do_send_log_backend(logger->target.be, hdr, nblogger, logger->maxlen, message, size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* normal target */
|
||||||
|
__do_send_log(&logger->target, hdr, nblogger, logger->maxlen, message, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function sends a syslog message.
|
||||||
|
* It doesn't care about errors nor does it report them.
|
||||||
|
* The arguments <sd> and <sd_size> are used for the structured-data part
|
||||||
|
* in RFC5424 formatted syslog messages.
|
||||||
|
*/
|
||||||
|
static void __send_log(struct list *loggers, struct buffer *tagb, int level,
|
||||||
|
char *message, size_t size, char *sd, size_t sd_size)
|
||||||
|
{
|
||||||
|
static THREAD_LOCAL pid_t curr_pid;
|
||||||
|
static THREAD_LOCAL char pidstr[16];
|
||||||
|
static THREAD_LOCAL struct ist metadata[LOG_META_FIELDS];
|
||||||
|
|
||||||
|
if (loggers == NULL) {
|
||||||
|
if (!LIST_ISEMPTY(&global.loggers)) {
|
||||||
|
loggers = &global.loggers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!loggers || LIST_ISEMPTY(loggers))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!metadata[LOG_META_HOST].len) {
|
||||||
|
if (global.log_send_hostname)
|
||||||
|
metadata[LOG_META_HOST] = ist(global.log_send_hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tagb || !tagb->area)
|
||||||
|
tagb = &global.log_tag;
|
||||||
|
|
||||||
|
if (tagb)
|
||||||
|
metadata[LOG_META_TAG] = ist2(tagb->area, tagb->data);
|
||||||
|
|
||||||
|
if (unlikely(curr_pid != getpid()))
|
||||||
|
metadata[LOG_META_PID].len = 0;
|
||||||
|
|
||||||
|
if (!metadata[LOG_META_PID].len) {
|
||||||
|
curr_pid = getpid();
|
||||||
|
ltoa_o(curr_pid, pidstr, sizeof(pidstr));
|
||||||
|
metadata[LOG_META_PID] = ist2(pidstr, strlen(pidstr));
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata[LOG_META_STDATA] = ist2(sd, sd_size);
|
||||||
|
|
||||||
|
/* Remove trailing space of structured data */
|
||||||
|
while (metadata[LOG_META_STDATA].len && metadata[LOG_META_STDATA].ptr[metadata[LOG_META_STDATA].len-1] == ' ')
|
||||||
|
metadata[LOG_META_STDATA].len--;
|
||||||
|
|
||||||
|
return process_send_log(loggers, level, -1, metadata, message, size);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function sends the syslog message using a printf format string. It
|
* This function sends the syslog message using a printf format string. It
|
||||||
@ -2573,6 +2890,7 @@ void send_log(struct proxy *p, int level, const char *format, ...)
|
|||||||
__send_log((p ? &p->loggers : NULL), (p ? &p->log_tag : NULL), level,
|
__send_log((p ? &p->loggers : NULL), (p ? &p->log_tag : NULL), level,
|
||||||
logline, data_len, default_rfc5424_sd_log_format, 2);
|
logline, data_len, default_rfc5424_sd_log_format, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function builds a log header according to <hdr> settings.
|
* This function builds a log header according to <hdr> settings.
|
||||||
*
|
*
|
||||||
@ -2880,324 +3198,6 @@ struct ist *build_log_header(struct log_header hdr, size_t *nbelem)
|
|||||||
return hdr_ctx.ist_vector;
|
return hdr_ctx.ist_vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This function sends a syslog message.
|
|
||||||
* <target> is the actual log target where log will be sent,
|
|
||||||
*
|
|
||||||
* Message will be prefixed by header according to <hdr> setting.
|
|
||||||
* Final message will be truncated <maxlen> parameter and will be
|
|
||||||
* terminated with an LF character.
|
|
||||||
*
|
|
||||||
* Does not return any error
|
|
||||||
*/
|
|
||||||
static inline void __do_send_log(struct log_target *target, struct log_header hdr,
|
|
||||||
int nblogger, size_t maxlen,
|
|
||||||
char *message, size_t size)
|
|
||||||
{
|
|
||||||
static THREAD_LOCAL struct iovec iovec[NB_LOG_HDR_MAX_ELEMENTS+1+1] = { }; /* header elements + message + LF */
|
|
||||||
static THREAD_LOCAL struct msghdr msghdr = {
|
|
||||||
//.msg_iov = iovec,
|
|
||||||
.msg_iovlen = NB_LOG_HDR_MAX_ELEMENTS+2
|
|
||||||
};
|
|
||||||
static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
|
|
||||||
static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
|
|
||||||
int *plogfd;
|
|
||||||
int sent;
|
|
||||||
size_t nbelem;
|
|
||||||
struct ist *msg_header = NULL;
|
|
||||||
|
|
||||||
msghdr.msg_iov = iovec;
|
|
||||||
|
|
||||||
/* historically some messages used to already contain the trailing LF
|
|
||||||
* or Zero. Let's remove all trailing LF or Zero
|
|
||||||
*/
|
|
||||||
while (size && (message[size-1] == '\n' || (message[size-1] == 0)))
|
|
||||||
size--;
|
|
||||||
|
|
||||||
if (target->type == LOG_TARGET_BUFFER) {
|
|
||||||
plogfd = NULL;
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
else if (target->addr->ss_family == AF_CUST_EXISTING_FD) {
|
|
||||||
/* the socket's address is a file descriptor */
|
|
||||||
plogfd = (int *)&((struct sockaddr_in *)target->addr)->sin_addr.s_addr;
|
|
||||||
}
|
|
||||||
else if (target->addr->ss_family == AF_UNIX)
|
|
||||||
plogfd = &logfdunix;
|
|
||||||
else
|
|
||||||
plogfd = &logfdinet;
|
|
||||||
|
|
||||||
if (plogfd && unlikely(*plogfd < 0)) {
|
|
||||||
/* socket not successfully initialized yet */
|
|
||||||
if ((*plogfd = socket(target->addr->ss_family, SOCK_DGRAM,
|
|
||||||
(target->addr->ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
|
|
||||||
static char once;
|
|
||||||
|
|
||||||
if (!once) {
|
|
||||||
once = 1; /* note: no need for atomic ops here */
|
|
||||||
ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
|
|
||||||
nblogger, strerror(errno), errno);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
/* we don't want to receive anything on this socket */
|
|
||||||
setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
|
|
||||||
/* we may want to adjust the output buffer (tune.sndbuf.backend) */
|
|
||||||
if (global.tune.backend_sndbuf)
|
|
||||||
setsockopt(*plogfd, SOL_SOCKET, SO_SNDBUF, &global.tune.backend_sndbuf, sizeof(global.tune.backend_sndbuf));
|
|
||||||
/* does nothing under Linux, maybe needed for others */
|
|
||||||
shutdown(*plogfd, SHUT_RD);
|
|
||||||
fd_set_cloexec(*plogfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
msg_header = build_log_header(hdr, &nbelem);
|
|
||||||
send:
|
|
||||||
if (target->type == LOG_TARGET_BUFFER) {
|
|
||||||
struct ist msg;
|
|
||||||
size_t e_maxlen = maxlen;
|
|
||||||
|
|
||||||
msg = ist2(message, size);
|
|
||||||
|
|
||||||
/* make room for the final '\n' which may be forcefully inserted
|
|
||||||
* by tcp forwarder applet (sink_forward_io_handler)
|
|
||||||
*/
|
|
||||||
e_maxlen -= 1;
|
|
||||||
|
|
||||||
sent = sink_write(target->sink, hdr, e_maxlen, &msg, 1);
|
|
||||||
}
|
|
||||||
else if (target->addr->ss_family == AF_CUST_EXISTING_FD) {
|
|
||||||
struct ist msg;
|
|
||||||
|
|
||||||
msg = ist2(message, size);
|
|
||||||
|
|
||||||
sent = fd_write_frag_line(*plogfd, maxlen, msg_header, nbelem, &msg, 1, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int i = 0;
|
|
||||||
int totlen = maxlen - 1; /* save space for the final '\n' */
|
|
||||||
|
|
||||||
for (i = 0 ; i < nbelem ; i++ ) {
|
|
||||||
iovec[i].iov_base = msg_header[i].ptr;
|
|
||||||
iovec[i].iov_len = msg_header[i].len;
|
|
||||||
if (totlen <= iovec[i].iov_len) {
|
|
||||||
iovec[i].iov_len = totlen;
|
|
||||||
totlen = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
totlen -= iovec[i].iov_len;
|
|
||||||
}
|
|
||||||
if (totlen) {
|
|
||||||
iovec[i].iov_base = message;
|
|
||||||
iovec[i].iov_len = size;
|
|
||||||
if (totlen <= iovec[i].iov_len)
|
|
||||||
iovec[i].iov_len = totlen;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
iovec[i].iov_base = "\n"; /* insert a \n at the end of the message */
|
|
||||||
iovec[i].iov_len = 1;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
msghdr.msg_iovlen = i;
|
|
||||||
msghdr.msg_name = (struct sockaddr *)target->addr;
|
|
||||||
msghdr.msg_namelen = get_addr_len(target->addr);
|
|
||||||
|
|
||||||
sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sent < 0) {
|
|
||||||
static char once;
|
|
||||||
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
|
||||||
_HA_ATOMIC_INC(&dropped_logs);
|
|
||||||
else if (!once) {
|
|
||||||
once = 1; /* note: no need for atomic ops here */
|
|
||||||
ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
|
|
||||||
nblogger, strerror(errno), errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* does the same as __do_send_log() does for a single target, but here the log
|
|
||||||
* will be sent according to the log backend's lb settings. The function will
|
|
||||||
* leverage __do_send_log() function to actually send the log messages.
|
|
||||||
*/
|
|
||||||
static inline void __do_send_log_backend(struct proxy *be, struct log_header hdr,
|
|
||||||
int nblogger, size_t maxlen,
|
|
||||||
char *message, size_t size)
|
|
||||||
{
|
|
||||||
struct server *srv = NULL;
|
|
||||||
|
|
||||||
/* log-balancing logic: */
|
|
||||||
|
|
||||||
if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_RR) {
|
|
||||||
srv = fwrr_get_next_server(be, NULL);
|
|
||||||
}
|
|
||||||
else if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_SS) {
|
|
||||||
/* sticky mode: use first server in the pool, which will always stay
|
|
||||||
* first during dequeuing and requeuing, unless it becomes unavailable
|
|
||||||
* and will be replaced by another one
|
|
||||||
*/
|
|
||||||
srv = ss_get_server(be);
|
|
||||||
}
|
|
||||||
else if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_RND) {
|
|
||||||
unsigned int hash;
|
|
||||||
|
|
||||||
hash = statistical_prng(); /* random */
|
|
||||||
srv = chash_get_server_hash(be, hash, NULL);
|
|
||||||
}
|
|
||||||
else if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_LH) {
|
|
||||||
struct sample result;
|
|
||||||
|
|
||||||
/* log-balance hash */
|
|
||||||
memset(&result, 0, sizeof(result));
|
|
||||||
result.data.type = SMP_T_STR;
|
|
||||||
result.flags = SMP_F_CONST;
|
|
||||||
result.data.u.str.area = message;
|
|
||||||
result.data.u.str.data = size;
|
|
||||||
result.data.u.str.size = size + 1; /* with terminating NULL byte */
|
|
||||||
if (sample_process_cnv(be->lbprm.expr, &result)) {
|
|
||||||
/* gen_hash takes binary input, ensure that we provide such value to it */
|
|
||||||
if (result.data.type == SMP_T_BIN || sample_casts[result.data.type][SMP_T_BIN]) {
|
|
||||||
unsigned int hash;
|
|
||||||
|
|
||||||
sample_casts[result.data.type][SMP_T_BIN](&result);
|
|
||||||
hash = gen_hash(be, result.data.u.str.area, result.data.u.str.data);
|
|
||||||
srv = map_get_server_hash(be, hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!srv) {
|
|
||||||
/* no srv available, can't log */
|
|
||||||
goto drop;
|
|
||||||
}
|
|
||||||
|
|
||||||
__do_send_log(srv->log_target, hdr, nblogger, maxlen, message, size);
|
|
||||||
return;
|
|
||||||
|
|
||||||
drop:
|
|
||||||
_HA_ATOMIC_INC(&dropped_logs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function sends a syslog message.
|
|
||||||
* It doesn't care about errors nor does it report them.
|
|
||||||
* The argument <metadata> MUST be an array of size
|
|
||||||
* LOG_META_FIELDS*sizeof(struct ist) containing
|
|
||||||
* data to build the header.
|
|
||||||
*/
|
|
||||||
void process_send_log(struct list *loggers, int level, int facility,
|
|
||||||
struct ist *metadata, char *message, size_t size)
|
|
||||||
{
|
|
||||||
struct logger *logger;
|
|
||||||
int nblogger;
|
|
||||||
|
|
||||||
/* Send log messages to syslog server. */
|
|
||||||
nblogger = 0;
|
|
||||||
list_for_each_entry(logger, loggers, list) {
|
|
||||||
int in_range = 1;
|
|
||||||
|
|
||||||
/* we can filter the level of the messages that are sent to each logger */
|
|
||||||
if (level > logger->level)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (logger->lb.smp_rgs) {
|
|
||||||
struct smp_log_range *smp_rg;
|
|
||||||
uint next_idx, curr_rg;
|
|
||||||
ullong curr_rg_idx, next_rg_idx;
|
|
||||||
|
|
||||||
curr_rg_idx = _HA_ATOMIC_LOAD(&logger->lb.curr_rg_idx);
|
|
||||||
do {
|
|
||||||
next_idx = (curr_rg_idx & 0xFFFFFFFFU) + 1;
|
|
||||||
curr_rg = curr_rg_idx >> 32;
|
|
||||||
smp_rg = &logger->lb.smp_rgs[curr_rg];
|
|
||||||
|
|
||||||
/* check if the index we're going to take is within range */
|
|
||||||
in_range = smp_rg->low <= next_idx && next_idx <= smp_rg->high;
|
|
||||||
if (in_range) {
|
|
||||||
/* Let's consume this range. */
|
|
||||||
if (next_idx == smp_rg->high) {
|
|
||||||
/* If consumed, let's select the next range. */
|
|
||||||
curr_rg = (curr_rg + 1) % logger->lb.smp_rgs_sz;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next_idx = next_idx % logger->lb.smp_sz;
|
|
||||||
next_rg_idx = ((ullong)curr_rg << 32) + next_idx;
|
|
||||||
} while (!_HA_ATOMIC_CAS(&logger->lb.curr_rg_idx, &curr_rg_idx, next_rg_idx) &&
|
|
||||||
__ha_cpu_relax());
|
|
||||||
}
|
|
||||||
if (in_range) {
|
|
||||||
struct log_header hdr;
|
|
||||||
|
|
||||||
hdr.level = MAX(level, logger->minlvl);
|
|
||||||
hdr.facility = (facility == -1) ? logger->facility : facility;
|
|
||||||
hdr.format = logger->format;
|
|
||||||
hdr.metadata = metadata;
|
|
||||||
|
|
||||||
nblogger += 1;
|
|
||||||
if (logger->target.type == LOG_TARGET_BACKEND) {
|
|
||||||
__do_send_log_backend(logger->target.be, hdr, nblogger, logger->maxlen, message, size);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* normal target */
|
|
||||||
__do_send_log(&logger->target, hdr, nblogger, logger->maxlen, message, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function sends a syslog message.
|
|
||||||
* It doesn't care about errors nor does it report them.
|
|
||||||
* The arguments <sd> and <sd_size> are used for the structured-data part
|
|
||||||
* in RFC5424 formatted syslog messages.
|
|
||||||
*/
|
|
||||||
void __send_log(struct list *loggers, struct buffer *tagb, int level,
|
|
||||||
char *message, size_t size, char *sd, size_t sd_size)
|
|
||||||
{
|
|
||||||
static THREAD_LOCAL pid_t curr_pid;
|
|
||||||
static THREAD_LOCAL char pidstr[16];
|
|
||||||
static THREAD_LOCAL struct ist metadata[LOG_META_FIELDS];
|
|
||||||
|
|
||||||
if (loggers == NULL) {
|
|
||||||
if (!LIST_ISEMPTY(&global.loggers)) {
|
|
||||||
loggers = &global.loggers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!loggers || LIST_ISEMPTY(loggers))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!metadata[LOG_META_HOST].len) {
|
|
||||||
if (global.log_send_hostname)
|
|
||||||
metadata[LOG_META_HOST] = ist(global.log_send_hostname);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tagb || !tagb->area)
|
|
||||||
tagb = &global.log_tag;
|
|
||||||
|
|
||||||
if (tagb)
|
|
||||||
metadata[LOG_META_TAG] = ist2(tagb->area, tagb->data);
|
|
||||||
|
|
||||||
if (unlikely(curr_pid != getpid()))
|
|
||||||
metadata[LOG_META_PID].len = 0;
|
|
||||||
|
|
||||||
if (!metadata[LOG_META_PID].len) {
|
|
||||||
curr_pid = getpid();
|
|
||||||
ltoa_o(curr_pid, pidstr, sizeof(pidstr));
|
|
||||||
metadata[LOG_META_PID] = ist2(pidstr, strlen(pidstr));
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata[LOG_META_STDATA] = ist2(sd, sd_size);
|
|
||||||
|
|
||||||
/* Remove trailing space of structured data */
|
|
||||||
while (metadata[LOG_META_STDATA].len && metadata[LOG_META_STDATA].ptr[metadata[LOG_META_STDATA].len-1] == ' ')
|
|
||||||
metadata[LOG_META_STDATA].len--;
|
|
||||||
|
|
||||||
return process_send_log(loggers, level, -1, metadata, message, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char sess_cookie[8] = "NIDVEOU7"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie, Expired cookie, Old cookie, Unused, unknown */
|
const char sess_cookie[8] = "NIDVEOU7"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie, Expired cookie, Old cookie, Unused, unknown */
|
||||||
const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
|
const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
|
||||||
Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
|
Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
|
||||||
|
Loading…
Reference in New Issue
Block a user