From: Aurelien DARRAGON Date: Wed, 22 May 2024 13:19:32 +0000 (+0200) Subject: REORG: log: reorder send log helpers by dependency order X-Git-Tag: v3.1-dev1~28 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ee288a4eef1c0d9758741af6a0e67c7c2796442a;p=thirdparty%2Fhaproxy.git 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. --- diff --git a/include/haproxy/log.h b/include/haproxy/log.h index bc865524f7..8d7b508688 100644 --- a/include/haproxy/log.h +++ b/include/haproxy/log.h @@ -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, ...) __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 or LOG_FORMAT_UNSPEC if not found. */ diff --git a/src/log.c b/src/log.c index b607d793e7..052fc07e14 100644 --- a/src/log.c +++ b/src/log.c @@ -2551,651 +2551,651 @@ static char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, st return ret; } - -/* - * This function sends the syslog message using a printf format string. It - * expects an LF-terminated message. - */ -void send_log(struct proxy *p, int level, const char *format, ...) -{ - va_list argp; - int data_len; - - if (level < 0 || format == NULL || logline == NULL) - return; - - va_start(argp, format); - data_len = vsnprintf(logline, global.max_syslog_len, format, argp); - if (data_len < 0 || data_len > global.max_syslog_len) - data_len = global.max_syslog_len; - va_end(argp); - - __send_log((p ? &p->loggers : NULL), (p ? &p->log_tag : NULL), level, - logline, data_len, default_rfc5424_sd_log_format, 2); -} /* - * This function builds a log header according to settings. + * This function sends a syslog message. + * is the actual log target where log will be sent, * - * If hdr.format is set to LOG_FORMAT_UNSPEC, it tries to determine - * format based on hdr.metadata. It is useful for log-forwarding to be - * able to forward any format without settings. + * Message will be prefixed by header according to setting. + * Final message will be truncated parameter and will be + * terminated with an LF character. * - * This function returns a struct ist array of elements of the header - * nbelem is set to the number of available elements. - * This function returns currently a maximum of NB_LOG_HDR_IST_ELEMENTS - * elements. + * Does not return any error */ -struct ist *build_log_header(struct log_header hdr, size_t *nbelem) +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 { - struct ist ist_vector[NB_LOG_HDR_MAX_ELEMENTS]; - char timestamp_buffer[LOG_LEGACYTIME_LEN+1+1]; - time_t cur_legacy_time; - char priority_buffer[6]; - } hdr_ctx = { .priority_buffer = "<<<<>" }; + 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; - struct tm logtime; - int len; - int fac_level = 0; - time_t time = date.tv_sec; - struct ist *metadata = hdr.metadata; - enum log_fmt format = hdr.format; - int facility = hdr.facility; - int level = hdr.level; + msghdr.msg_iov = iovec; - *nbelem = 0; + /* 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 (format == LOG_FORMAT_UNSPEC) { - format = LOG_FORMAT_RAW; - if (metadata) { - /* If a hostname is set, it appears we want to perform syslog - * because only rfc5427 or rfc3164 support an hostname. - */ - if (metadata[LOG_META_HOST].len) { - /* If a rfc5424 compliant timestamp is used we consider - * that output format is rfc5424, else legacy format - * is used as specified default for local logs - * in documentation. - */ - if ((metadata[LOG_META_TIME].len == 1 && metadata[LOG_META_TIME].ptr[0] == '-') - || (metadata[LOG_META_TIME].len >= LOG_ISOTIME_MINLEN)) - format = LOG_FORMAT_RFC5424; - else - format = LOG_FORMAT_RFC3164; - } - else if (metadata[LOG_META_TAG].len) { - /* Tag is present but no hostname, we should - * consider we try to emit a local log - * in legacy format (analog to RFC3164 but - * with stripped hostname). - */ - format = LOG_FORMAT_LOCAL; - } - else if (metadata[LOG_META_PRIO].len) { - /* the source seems a parsed message - * offering a valid level/prio prefix - * so we consider this format. - */ - format = LOG_FORMAT_PRIO; + 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); } } - /* prepare priority, stored into 1 single elem */ - switch (format) { - case LOG_FORMAT_LOCAL: - case LOG_FORMAT_RFC3164: - case LOG_FORMAT_RFC5424: - case LOG_FORMAT_PRIO: - fac_level = facility << 3; - /* further format ignore the facility */ - __fallthrough; - case LOG_FORMAT_TIMED: - case LOG_FORMAT_SHORT: - fac_level += level; - hdr_ctx.ist_vector[*nbelem].ptr = &hdr_ctx.priority_buffer[3]; /* last digit of the log level */ - do { - *hdr_ctx.ist_vector[*nbelem].ptr = '0' + fac_level % 10; - fac_level /= 10; - hdr_ctx.ist_vector[*nbelem].ptr--; - } while (fac_level && hdr_ctx.ist_vector[*nbelem].ptr > &hdr_ctx.priority_buffer[0]); - *hdr_ctx.ist_vector[*nbelem].ptr = '<'; - hdr_ctx.ist_vector[(*nbelem)++].len = &hdr_ctx.priority_buffer[5] - hdr_ctx.ist_vector[0].ptr; - break; - case LOG_FORMAT_ISO: - case LOG_FORMAT_RAW: - break; - case LOG_FORMAT_UNSPEC: - case LOG_FORMATS: - ABORT_NOW(); + 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); - /* prepare timestamp, stored into a max of 4 elems */ - switch (format) { - case LOG_FORMAT_LOCAL: - case LOG_FORMAT_RFC3164: - /* rfc3164 ex: 'Jan 1 00:00:00 ' */ - if (metadata && metadata[LOG_META_TIME].len == LOG_LEGACYTIME_LEN) { - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TIME]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); - /* time is set, break immediately */ + 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; } - else if (metadata && metadata[LOG_META_TIME].len >= LOG_ISOTIME_MINLEN) { - int month; - char *timestamp = metadata[LOG_META_TIME].ptr; + 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++; - /* iso time always begins like this: '1970-01-01T00:00:00' */ + msghdr.msg_iovlen = i; + msghdr.msg_name = (struct sockaddr *)target->addr; + msghdr.msg_namelen = get_addr_len(target->addr); - /* compute month */ - month = 10*(timestamp[5] - '0') + (timestamp[6] - '0'); - if (month) - month--; - if (month <= 11) { - /* builds log prefix ex: 'Jan 1 ' */ - len = snprintf(hdr_ctx.timestamp_buffer, sizeof(hdr_ctx.timestamp_buffer), - "%s %c%c ", monthname[month], - timestamp[8] != '0' ? timestamp[8] : ' ', - timestamp[9]); - /* we reused the timestamp_buffer, signal that it does not - * contain local time anymore - */ - hdr_ctx.cur_legacy_time = 0; - if (len == 7) { - hdr_ctx.ist_vector[(*nbelem)++] = ist2(&hdr_ctx.timestamp_buffer[0], len); - /* adds 'HH:MM:SS' from iso time */ - hdr_ctx.ist_vector[(*nbelem)++] = ist2(×tamp[11], 8); - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); - /* we successfully reuse iso time, we can break */ - break; - } - } - /* Failed to reuse isotime time, fallback to local legacy time */ - } + sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL); + } - if (unlikely(time != hdr_ctx.cur_legacy_time)) { - /* re-builds timestamp from the current local time */ - get_localtime(time, &logtime); + if (sent < 0) { + static char once; - len = snprintf(hdr_ctx.timestamp_buffer, sizeof(hdr_ctx.timestamp_buffer), - "%s %2d %02d:%02d:%02d ", - monthname[logtime.tm_mon], - logtime.tm_mday, logtime.tm_hour, logtime.tm_min, logtime.tm_sec); - if (len != LOG_LEGACYTIME_LEN+1) - hdr_ctx.cur_legacy_time = 0; - else - hdr_ctx.cur_legacy_time = time; - } - if (likely(hdr_ctx.cur_legacy_time)) - hdr_ctx.ist_vector[(*nbelem)++] = ist2(&hdr_ctx.timestamp_buffer[0], LOG_LEGACYTIME_LEN+1); - else - hdr_ctx.ist_vector[(*nbelem)++] = ist2("Jan 1 00:00:00 ", LOG_LEGACYTIME_LEN+1); - break; - case LOG_FORMAT_RFC5424: - /* adds rfc5425 version prefix */ - hdr_ctx.ist_vector[(*nbelem)++] = ist2("1 ", 2); - if (metadata && metadata[LOG_META_TIME].len == 1 && metadata[LOG_META_TIME].ptr[0] == '-') { - /* submitted len is NILVALUE, it is a valid timestamp for rfc5425 */ - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TIME]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); - break; - } - /* let continue as 'timed' and 'iso' format for usual timestamp */ - __fallthrough; - case LOG_FORMAT_TIMED: - case LOG_FORMAT_ISO: - /* ISO format ex: '1900:01:01T12:00:00.123456Z' - * '1900:01:01T14:00:00+02:00' - * '1900:01:01T10:00:00.123456-02:00' - */ - if (metadata && metadata[LOG_META_TIME].len >= LOG_ISOTIME_MINLEN) { - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TIME]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); - /* time is set, break immediately */ - break; - } - else if (metadata && metadata[LOG_META_TIME].len == LOG_LEGACYTIME_LEN) { - int month; - char *timestamp = metadata[LOG_META_TIME].ptr; - - for (month = 0; month < 12; month++) - if (!memcmp(monthname[month], timestamp, 3)) - break; - - if (month < 12) { - - /* get local time to retrieve year */ - get_localtime(time, &logtime); + 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); + } + } +} - /* year seems changed since log */ - if (logtime.tm_mon < month) - logtime.tm_year--; +/* 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; - /* builds rfc5424 prefix ex: '1900-01-01T' */ - len = snprintf(hdr_ctx.timestamp_buffer, sizeof(hdr_ctx.timestamp_buffer), - "%4d-%02d-%c%cT", - logtime.tm_year+1900, month+1, - timestamp[4] != ' ' ? timestamp[4] : '0', - timestamp[5]); + /* log-balancing logic: */ - /* we reused the timestamp_buffer, signal that it does not - * contain local time anymore - */ - hdr_ctx.cur_legacy_time = 0; - if (len == 11) { - hdr_ctx.ist_vector[(*nbelem)++] = ist2(&hdr_ctx.timestamp_buffer[0], len); - /* adds HH:MM:SS from legacy timestamp */ - hdr_ctx.ist_vector[(*nbelem)++] = ist2(×tamp[7], 8); - /* skip secfraq because it is optional */ - /* according to rfc: -00:00 means we don't know the timezone */ - hdr_ctx.ist_vector[(*nbelem)++] = ist2("-00:00 ", 7); - /* we successfully reuse legacy time, we can break */ - break; - } - } - /* Failed to reuse legacy time, fallback to local iso time */ - } - hdr_ctx.ist_vector[(*nbelem)++] = ist2(timeofday_as_iso_us(1), LOG_ISOTIME_MAXLEN + 1); - break; - case LOG_FORMAT_PRIO: - case LOG_FORMAT_SHORT: - case LOG_FORMAT_RAW: - break; - case LOG_FORMAT_UNSPEC: - case LOG_FORMATS: - ABORT_NOW(); + 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; - /* prepare other meta data, stored into a max of 10 elems */ - switch (format) { - case LOG_FORMAT_RFC3164: - if (metadata && metadata[LOG_META_HOST].len) { - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_HOST]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); - } - else /* the caller MUST fill the hostname, this field is mandatory */ - hdr_ctx.ist_vector[(*nbelem)++] = ist2("localhost ", 10); - __fallthrough; - case LOG_FORMAT_LOCAL: - if (!metadata || !metadata[LOG_META_TAG].len) - break; - - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TAG]; - if (metadata[LOG_META_PID].len) { - hdr_ctx.ist_vector[(*nbelem)++] = ist2("[", 1); - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_PID]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2("]", 1); - } - hdr_ctx.ist_vector[(*nbelem)++] = ist2(": ", 2); - break; - case LOG_FORMAT_RFC5424: - if (metadata && metadata[LOG_META_HOST].len) { - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_HOST]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); - } - else - hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); - - if (metadata && metadata[LOG_META_TAG].len) { - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TAG]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); - } - else - hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); + 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; - if (metadata && metadata[LOG_META_PID].len) { - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_PID]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); - } - else - hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); + /* 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; - if (metadata && metadata[LOG_META_MSGID].len) { - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_MSGID]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + 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); } - else - hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); + } + } - if (metadata && metadata[LOG_META_STDATA].len) { - hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_STDATA]; - hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); - } - else - hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); - break; - case LOG_FORMAT_PRIO: - case LOG_FORMAT_SHORT: - case LOG_FORMAT_TIMED: - case LOG_FORMAT_ISO: - case LOG_FORMAT_RAW: - break; - case LOG_FORMAT_UNSPEC: - case LOG_FORMATS: - ABORT_NOW(); + if (!srv) { + /* no srv available, can't log */ + goto drop; } - return hdr_ctx.ist_vector; + __do_send_log(srv->log_target, hdr, nblogger, maxlen, message, size); + return; + + drop: + _HA_ATOMIC_INC(&dropped_logs); } /* * This function sends a syslog message. - * is the actual log target where log will be sent, - * - * Message will be prefixed by header according to setting. - * Final message will be truncated parameter and will be - * terminated with an LF character. - * - * Does not return any error + * It doesn't care about errors nor does it report them. + * The argument MUST be an array of size + * LOG_META_FIELDS*sizeof(struct ist) containing + * data to build the header. */ -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 void process_send_log(struct list *loggers, int level, int facility, + struct ist *metadata, 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; + struct logger *logger; + int nblogger; - msghdr.msg_iov = iovec; + /* Send log messages to syslog server. */ + nblogger = 0; + list_for_each_entry(logger, loggers, list) { + int in_range = 1; - /* 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--; + /* we can filter the level of the messages that are sent to each logger */ + if (level > logger->level) + continue; - 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 (logger->lb.smp_rgs) { + struct smp_log_range *smp_rg; + uint next_idx, curr_rg; + ullong curr_rg_idx, next_rg_idx; - 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; + 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]; - 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); + /* 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); } - 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); + 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 and 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); + } - msg_header = build_log_header(hdr, &nbelem); - send: - if (target->type == LOG_TARGET_BUFFER) { - struct ist msg; - size_t e_maxlen = maxlen; + if (!tagb || !tagb->area) + tagb = &global.log_tag; - msg = ist2(message, size); + if (tagb) + metadata[LOG_META_TAG] = ist2(tagb->area, tagb->data); - /* make room for the final '\n' which may be forcefully inserted - * by tcp forwarder applet (sink_forward_io_handler) - */ - e_maxlen -= 1; + if (unlikely(curr_pid != getpid())) + metadata[LOG_META_PID].len = 0; - sent = sink_write(target->sink, hdr, e_maxlen, &msg, 1); + if (!metadata[LOG_META_PID].len) { + curr_pid = getpid(); + ltoa_o(curr_pid, pidstr, sizeof(pidstr)); + metadata[LOG_META_PID] = ist2(pidstr, strlen(pidstr)); } - else if (target->addr->ss_family == AF_CUST_EXISTING_FD) { - struct ist msg; - msg = ist2(message, size); + metadata[LOG_META_STDATA] = ist2(sd, sd_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' */ + /* 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--; - 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++; + return process_send_log(loggers, level, -1, metadata, message, size); +} - msghdr.msg_iovlen = i; - msghdr.msg_name = (struct sockaddr *)target->addr; - msghdr.msg_namelen = get_addr_len(target->addr); +/* + * This function sends the syslog message using a printf format string. It + * expects an LF-terminated message. + */ +void send_log(struct proxy *p, int level, const char *format, ...) +{ + va_list argp; + int data_len; - sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL); - } + if (level < 0 || format == NULL || logline == NULL) + return; - if (sent < 0) { - static char once; + va_start(argp, format); + data_len = vsnprintf(logline, global.max_syslog_len, format, argp); + if (data_len < 0 || data_len > global.max_syslog_len) + data_len = global.max_syslog_len; + va_end(argp); - 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); - } - } + __send_log((p ? &p->loggers : NULL), (p ? &p->log_tag : NULL), level, + logline, data_len, default_rfc5424_sd_log_format, 2); } -/* 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. +/* + * This function builds a log header according to settings. + * + * If hdr.format is set to LOG_FORMAT_UNSPEC, it tries to determine + * format based on hdr.metadata. It is useful for log-forwarding to be + * able to forward any format without settings. + * + * This function returns a struct ist array of elements of the header + * nbelem is set to the number of available elements. + * This function returns currently a maximum of NB_LOG_HDR_IST_ELEMENTS + * elements. */ -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 ist *build_log_header(struct log_header hdr, size_t *nbelem) { - struct server *srv = NULL; + static THREAD_LOCAL struct { + struct ist ist_vector[NB_LOG_HDR_MAX_ELEMENTS]; + char timestamp_buffer[LOG_LEGACYTIME_LEN+1+1]; + time_t cur_legacy_time; + char priority_buffer[6]; + } hdr_ctx = { .priority_buffer = "<<<<>" }; - /* log-balancing logic: */ + struct tm logtime; + int len; + int fac_level = 0; + time_t time = date.tv_sec; + struct ist *metadata = hdr.metadata; + enum log_fmt format = hdr.format; + int facility = hdr.facility; + int level = hdr.level; - 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); + *nbelem = 0; + + + if (format == LOG_FORMAT_UNSPEC) { + format = LOG_FORMAT_RAW; + if (metadata) { + /* If a hostname is set, it appears we want to perform syslog + * because only rfc5427 or rfc3164 support an hostname. + */ + if (metadata[LOG_META_HOST].len) { + /* If a rfc5424 compliant timestamp is used we consider + * that output format is rfc5424, else legacy format + * is used as specified default for local logs + * in documentation. + */ + if ((metadata[LOG_META_TIME].len == 1 && metadata[LOG_META_TIME].ptr[0] == '-') + || (metadata[LOG_META_TIME].len >= LOG_ISOTIME_MINLEN)) + format = LOG_FORMAT_RFC5424; + else + format = LOG_FORMAT_RFC3164; + } + else if (metadata[LOG_META_TAG].len) { + /* Tag is present but no hostname, we should + * consider we try to emit a local log + * in legacy format (analog to RFC3164 but + * with stripped hostname). + */ + format = LOG_FORMAT_LOCAL; + } + else if (metadata[LOG_META_PRIO].len) { + /* the source seems a parsed message + * offering a valid level/prio prefix + * so we consider this format. + */ + format = LOG_FORMAT_PRIO; + } + } } - 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); + /* prepare priority, stored into 1 single elem */ + switch (format) { + case LOG_FORMAT_LOCAL: + case LOG_FORMAT_RFC3164: + case LOG_FORMAT_RFC5424: + case LOG_FORMAT_PRIO: + fac_level = facility << 3; + /* further format ignore the facility */ + __fallthrough; + case LOG_FORMAT_TIMED: + case LOG_FORMAT_SHORT: + fac_level += level; + hdr_ctx.ist_vector[*nbelem].ptr = &hdr_ctx.priority_buffer[3]; /* last digit of the log level */ + do { + *hdr_ctx.ist_vector[*nbelem].ptr = '0' + fac_level % 10; + fac_level /= 10; + hdr_ctx.ist_vector[*nbelem].ptr--; + } while (fac_level && hdr_ctx.ist_vector[*nbelem].ptr > &hdr_ctx.priority_buffer[0]); + *hdr_ctx.ist_vector[*nbelem].ptr = '<'; + hdr_ctx.ist_vector[(*nbelem)++].len = &hdr_ctx.priority_buffer[5] - hdr_ctx.ist_vector[0].ptr; + break; + case LOG_FORMAT_ISO: + case LOG_FORMAT_RAW: + break; + case LOG_FORMAT_UNSPEC: + case LOG_FORMATS: + ABORT_NOW(); } - 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); + /* prepare timestamp, stored into a max of 4 elems */ + switch (format) { + case LOG_FORMAT_LOCAL: + case LOG_FORMAT_RFC3164: + /* rfc3164 ex: 'Jan 1 00:00:00 ' */ + if (metadata && metadata[LOG_META_TIME].len == LOG_LEGACYTIME_LEN) { + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TIME]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + /* time is set, break immediately */ + break; + } + else if (metadata && metadata[LOG_META_TIME].len >= LOG_ISOTIME_MINLEN) { + int month; + char *timestamp = metadata[LOG_META_TIME].ptr; + + /* iso time always begins like this: '1970-01-01T00:00:00' */ + + /* compute month */ + month = 10*(timestamp[5] - '0') + (timestamp[6] - '0'); + if (month) + month--; + if (month <= 11) { + /* builds log prefix ex: 'Jan 1 ' */ + len = snprintf(hdr_ctx.timestamp_buffer, sizeof(hdr_ctx.timestamp_buffer), + "%s %c%c ", monthname[month], + timestamp[8] != '0' ? timestamp[8] : ' ', + timestamp[9]); + /* we reused the timestamp_buffer, signal that it does not + * contain local time anymore + */ + hdr_ctx.cur_legacy_time = 0; + if (len == 7) { + hdr_ctx.ist_vector[(*nbelem)++] = ist2(&hdr_ctx.timestamp_buffer[0], len); + /* adds 'HH:MM:SS' from iso time */ + hdr_ctx.ist_vector[(*nbelem)++] = ist2(×tamp[11], 8); + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + /* we successfully reuse iso time, we can break */ + break; + } + } + /* Failed to reuse isotime time, fallback to local legacy time */ } - } - } - - if (!srv) { - /* no srv available, can't log */ - goto drop; - } - __do_send_log(srv->log_target, hdr, nblogger, maxlen, message, size); - return; + if (unlikely(time != hdr_ctx.cur_legacy_time)) { + /* re-builds timestamp from the current local time */ + get_localtime(time, &logtime); - drop: - _HA_ATOMIC_INC(&dropped_logs); -} + len = snprintf(hdr_ctx.timestamp_buffer, sizeof(hdr_ctx.timestamp_buffer), + "%s %2d %02d:%02d:%02d ", + monthname[logtime.tm_mon], + logtime.tm_mday, logtime.tm_hour, logtime.tm_min, logtime.tm_sec); + if (len != LOG_LEGACYTIME_LEN+1) + hdr_ctx.cur_legacy_time = 0; + else + hdr_ctx.cur_legacy_time = time; + } + if (likely(hdr_ctx.cur_legacy_time)) + hdr_ctx.ist_vector[(*nbelem)++] = ist2(&hdr_ctx.timestamp_buffer[0], LOG_LEGACYTIME_LEN+1); + else + hdr_ctx.ist_vector[(*nbelem)++] = ist2("Jan 1 00:00:00 ", LOG_LEGACYTIME_LEN+1); + break; + case LOG_FORMAT_RFC5424: + /* adds rfc5425 version prefix */ + hdr_ctx.ist_vector[(*nbelem)++] = ist2("1 ", 2); + if (metadata && metadata[LOG_META_TIME].len == 1 && metadata[LOG_META_TIME].ptr[0] == '-') { + /* submitted len is NILVALUE, it is a valid timestamp for rfc5425 */ + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TIME]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + break; + } + /* let continue as 'timed' and 'iso' format for usual timestamp */ + __fallthrough; + case LOG_FORMAT_TIMED: + case LOG_FORMAT_ISO: + /* ISO format ex: '1900:01:01T12:00:00.123456Z' + * '1900:01:01T14:00:00+02:00' + * '1900:01:01T10:00:00.123456-02:00' + */ + if (metadata && metadata[LOG_META_TIME].len >= LOG_ISOTIME_MINLEN) { + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TIME]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + /* time is set, break immediately */ + break; + } + else if (metadata && metadata[LOG_META_TIME].len == LOG_LEGACYTIME_LEN) { + int month; + char *timestamp = metadata[LOG_META_TIME].ptr; -/* - * This function sends a syslog message. - * It doesn't care about errors nor does it report them. - * The argument 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; + for (month = 0; month < 12; month++) + if (!memcmp(monthname[month], timestamp, 3)) + break; - /* Send log messages to syslog server. */ - nblogger = 0; - list_for_each_entry(logger, loggers, list) { - int in_range = 1; + if (month < 12) { - /* we can filter the level of the messages that are sent to each logger */ - if (level > logger->level) - continue; + /* get local time to retrieve year */ + get_localtime(time, &logtime); - if (logger->lb.smp_rgs) { - struct smp_log_range *smp_rg; - uint next_idx, curr_rg; - ullong curr_rg_idx, next_rg_idx; + /* year seems changed since log */ + if (logtime.tm_mon < month) + logtime.tm_year--; - 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]; + /* builds rfc5424 prefix ex: '1900-01-01T' */ + len = snprintf(hdr_ctx.timestamp_buffer, sizeof(hdr_ctx.timestamp_buffer), + "%4d-%02d-%c%cT", + logtime.tm_year+1900, month+1, + timestamp[4] != ' ' ? timestamp[4] : '0', + timestamp[5]); - /* 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; + /* we reused the timestamp_buffer, signal that it does not + * contain local time anymore + */ + hdr_ctx.cur_legacy_time = 0; + if (len == 11) { + hdr_ctx.ist_vector[(*nbelem)++] = ist2(&hdr_ctx.timestamp_buffer[0], len); + /* adds HH:MM:SS from legacy timestamp */ + hdr_ctx.ist_vector[(*nbelem)++] = ist2(×tamp[7], 8); + /* skip secfraq because it is optional */ + /* according to rfc: -00:00 means we don't know the timezone */ + hdr_ctx.ist_vector[(*nbelem)++] = ist2("-00:00 ", 7); + /* we successfully reuse legacy time, we can break */ + break; } } - - 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); + /* Failed to reuse legacy time, fallback to local iso time */ } - } + hdr_ctx.ist_vector[(*nbelem)++] = ist2(timeofday_as_iso_us(1), LOG_ISOTIME_MAXLEN + 1); + break; + case LOG_FORMAT_PRIO: + case LOG_FORMAT_SHORT: + case LOG_FORMAT_RAW: + break; + case LOG_FORMAT_UNSPEC: + case LOG_FORMATS: + ABORT_NOW(); } -} - -/* - * This function sends a syslog message. - * It doesn't care about errors nor does it report them. - * The arguments and 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; + /* prepare other meta data, stored into a max of 10 elems */ + switch (format) { + case LOG_FORMAT_RFC3164: + if (metadata && metadata[LOG_META_HOST].len) { + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_HOST]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + } + else /* the caller MUST fill the hostname, this field is mandatory */ + hdr_ctx.ist_vector[(*nbelem)++] = ist2("localhost ", 10); + __fallthrough; + case LOG_FORMAT_LOCAL: + if (!metadata || !metadata[LOG_META_TAG].len) + break; - if (!metadata[LOG_META_HOST].len) { - if (global.log_send_hostname) - metadata[LOG_META_HOST] = ist(global.log_send_hostname); - } + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TAG]; + if (metadata[LOG_META_PID].len) { + hdr_ctx.ist_vector[(*nbelem)++] = ist2("[", 1); + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_PID]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2("]", 1); + } + hdr_ctx.ist_vector[(*nbelem)++] = ist2(": ", 2); + break; + case LOG_FORMAT_RFC5424: + if (metadata && metadata[LOG_META_HOST].len) { + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_HOST]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + } + else + hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); - if (!tagb || !tagb->area) - tagb = &global.log_tag; + if (metadata && metadata[LOG_META_TAG].len) { + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_TAG]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + } + else + hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); - if (tagb) - metadata[LOG_META_TAG] = ist2(tagb->area, tagb->data); + if (metadata && metadata[LOG_META_PID].len) { + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_PID]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + } + else + hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); - if (unlikely(curr_pid != getpid())) - metadata[LOG_META_PID].len = 0; + if (metadata && metadata[LOG_META_MSGID].len) { + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_MSGID]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + } + else + hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); - if (!metadata[LOG_META_PID].len) { - curr_pid = getpid(); - ltoa_o(curr_pid, pidstr, sizeof(pidstr)); - metadata[LOG_META_PID] = ist2(pidstr, strlen(pidstr)); + if (metadata && metadata[LOG_META_STDATA].len) { + hdr_ctx.ist_vector[(*nbelem)++] = metadata[LOG_META_STDATA]; + hdr_ctx.ist_vector[(*nbelem)++] = ist2(" ", 1); + } + else + hdr_ctx.ist_vector[(*nbelem)++] = ist2("- ", 2); + break; + case LOG_FORMAT_PRIO: + case LOG_FORMAT_SHORT: + case LOG_FORMAT_TIMED: + case LOG_FORMAT_ISO: + case LOG_FORMAT_RAW: + break; + case LOG_FORMAT_UNSPEC: + case LOG_FORMATS: + ABORT_NOW(); } - 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); + return hdr_ctx.ist_vector; } const char sess_cookie[8] = "NIDVEOU7"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie, Expired cookie, Old cookie, Unused, unknown */