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 <hdr> settings.
+ * This function sends a syslog message.
+ * <target> 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 <hdr> setting.
+ * Final message will be truncated <maxlen> 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.
- * <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
+ * 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 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 <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);
+ }
- 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 <hdr> 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 <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;
+ 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 <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;
+ /* 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 */