mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-20 14:05:31 +00:00
MEDIUM: log/sink: re-work and merge of build message API.
This patch merges build message code between sink and log and introduce a new API based on struct ist array to prepare message header with zero copy, targeting the log forwarding feature. Log format 'iso' and 'timed' are now avalaible on logs line. A new log format 'priority' is also added.
This commit is contained in:
parent
3835c0dcb5
commit
546488559a
@ -1051,12 +1051,26 @@ log <address> [len <length>] [format <format>] [sample <ranges>:<smp_size>]
|
|||||||
rfc5424 The RFC5424 syslog message format.
|
rfc5424 The RFC5424 syslog message format.
|
||||||
(https://tools.ietf.org/html/rfc5424)
|
(https://tools.ietf.org/html/rfc5424)
|
||||||
|
|
||||||
|
priority A message containing only a level plus syslog facility between
|
||||||
|
angle brackets such as '<63>', followed by the text. The PID,
|
||||||
|
date, time, process name and system name are omitted. This is
|
||||||
|
designed to be used with a local log server.
|
||||||
|
|
||||||
short A message containing only a level between angle brackets such as
|
short A message containing only a level between angle brackets such as
|
||||||
'<3>', followed by the text. The PID, date, time, process name
|
'<3>', followed by the text. The PID, date, time, process name
|
||||||
and system name are omitted. This is designed to be used with a
|
and system name are omitted. This is designed to be used with a
|
||||||
local log server. This format is compatible with what the systemd
|
local log server. This format is compatible with what the systemd
|
||||||
logger consumes.
|
logger consumes.
|
||||||
|
|
||||||
|
timed A message containing only a level between angle brackets such as
|
||||||
|
'<3>', followed by ISO date and by the text. The PID, process
|
||||||
|
name and system name are omitted. This is designed to be
|
||||||
|
used with a local log server.
|
||||||
|
|
||||||
|
iso A message containing only the ISO date, followed by the text.
|
||||||
|
The PID, process name and system name are omitted. This is
|
||||||
|
designed to be used with a local log server.
|
||||||
|
|
||||||
raw A message containing only the text. The level, PID, date, time,
|
raw A message containing only the text. The level, PID, date, time,
|
||||||
process name and system name are omitted. This is designed to be
|
process name and system name are omitted. This is designed to be
|
||||||
used in containers or during development, where the severity only
|
used in containers or during development, where the severity only
|
||||||
@ -2663,6 +2677,11 @@ format <format>
|
|||||||
local log server. This format is compatible with what the systemd
|
local log server. This format is compatible with what the systemd
|
||||||
logger consumes.
|
logger consumes.
|
||||||
|
|
||||||
|
priority A message containing only a level plus syslog facility between angle
|
||||||
|
brackets such as '<63>', followed by the text. The PID, date, time,
|
||||||
|
process name and system name are omitted. This is designed to be used
|
||||||
|
with a local log server.
|
||||||
|
|
||||||
timed A message containing only a level between angle brackets such as
|
timed A message containing only a level between angle brackets such as
|
||||||
'<3>', followed by ISO date and by the text. The PID, process
|
'<3>', followed by ISO date and by the text. The PID, process
|
||||||
name and system name are omitted. This is designed to be
|
name and system name are omitted. This is designed to be
|
||||||
@ -6778,12 +6797,26 @@ no log
|
|||||||
rfc5424 The RFC5424 syslog message format.
|
rfc5424 The RFC5424 syslog message format.
|
||||||
(https://tools.ietf.org/html/rfc5424)
|
(https://tools.ietf.org/html/rfc5424)
|
||||||
|
|
||||||
|
priority A message containing only a level plus syslog facility between
|
||||||
|
angle brackets such as '<63>', followed by the text. The PID,
|
||||||
|
date, time, process name and system name are omitted. This is
|
||||||
|
designed to be used with a local log server.
|
||||||
|
|
||||||
short A message containing only a level between angle brackets such as
|
short A message containing only a level between angle brackets such as
|
||||||
'<3>', followed by the text. The PID, date, time, process name
|
'<3>', followed by the text. The PID, date, time, process name
|
||||||
and system name are omitted. This is designed to be used with a
|
and system name are omitted. This is designed to be used with a
|
||||||
local log server. This format is compatible with what the
|
local log server. This format is compatible with what the
|
||||||
systemd logger consumes.
|
systemd logger consumes.
|
||||||
|
|
||||||
|
timed A message containing only a level between angle brackets such as
|
||||||
|
'<3>', followed by ISO date and by the text. The PID, process
|
||||||
|
name and system name are omitted. This is designed to be
|
||||||
|
used with a local log server.
|
||||||
|
|
||||||
|
iso A message containing only the ISO date, followed by the text.
|
||||||
|
The PID, process name and system name are omitted. This is
|
||||||
|
designed to be used with a local log server.
|
||||||
|
|
||||||
raw A message containing only the text. The level, PID, date, time,
|
raw A message containing only the text. The level, PID, date, time,
|
||||||
process name and system name are omitted. This is designed to
|
process name and system name are omitted. This is designed to
|
||||||
be used in containers or during development, where the severity
|
be used in containers or during development, where the severity
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#define NB_LOG_FACILITIES 24
|
#define NB_LOG_FACILITIES 24
|
||||||
#define NB_LOG_LEVELS 8
|
#define NB_LOG_LEVELS 8
|
||||||
#define NB_MSG_IOVEC_ELEMENTS 8
|
#define NB_LOG_HDR_MAX_ELEMENTS 15
|
||||||
#define SYSLOG_PORT 514
|
#define SYSLOG_PORT 514
|
||||||
#define UNIQUEID_LEN 128
|
#define UNIQUEID_LEN 128
|
||||||
|
|
||||||
@ -67,14 +67,33 @@
|
|||||||
#define LW_FRTIP 8192 /* frontend IP */
|
#define LW_FRTIP 8192 /* frontend IP */
|
||||||
#define LW_XPRT 16384 /* transport layer information (eg: SSL) */
|
#define LW_XPRT 16384 /* transport layer information (eg: SSL) */
|
||||||
|
|
||||||
|
#define LOG_LEGACYTIME_LEN 15
|
||||||
|
#define LOG_ISOTIME_MINLEN 20
|
||||||
|
#define LOG_ISOTIME_MAXLEN 32
|
||||||
|
|
||||||
/* enum for log format */
|
/* enum for log format */
|
||||||
enum {
|
enum log_fmt {
|
||||||
LOG_FORMAT_RFC3164 = 0,
|
LOG_FORMAT_UNSPEC = 0,
|
||||||
|
LOG_FORMAT_RFC3164,
|
||||||
LOG_FORMAT_RFC5424,
|
LOG_FORMAT_RFC5424,
|
||||||
|
LOG_FORMAT_PRIO,
|
||||||
LOG_FORMAT_SHORT,
|
LOG_FORMAT_SHORT,
|
||||||
|
LOG_FORMAT_TIMED,
|
||||||
|
LOG_FORMAT_ISO,
|
||||||
LOG_FORMAT_RAW,
|
LOG_FORMAT_RAW,
|
||||||
LOG_FORMATS, /* number of supported log formats, must always be last */
|
LOG_FORMATS /* number of supported log formats, must always be last */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* enum log header meta data */
|
||||||
|
enum log_meta {
|
||||||
|
LOG_META_PRIO,
|
||||||
|
LOG_META_TIME,
|
||||||
|
LOG_META_HOST,
|
||||||
|
LOG_META_TAG,
|
||||||
|
LOG_META_PID,
|
||||||
|
LOG_META_MSGID,
|
||||||
|
LOG_META_STDATA,
|
||||||
|
LOG_META_FIELDS /* must always be the last */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* log target types */
|
/* log target types */
|
||||||
@ -210,7 +229,7 @@ struct logsrv {
|
|||||||
struct sink *sink;
|
struct sink *sink;
|
||||||
char *ring_name;
|
char *ring_name;
|
||||||
enum log_tgt type;
|
enum log_tgt type;
|
||||||
int format;
|
enum log_fmt format;
|
||||||
int facility;
|
int facility;
|
||||||
int level;
|
int level;
|
||||||
int minlvl;
|
int minlvl;
|
||||||
|
@ -43,8 +43,6 @@ extern char default_rfc5424_sd_log_format[];
|
|||||||
|
|
||||||
extern unsigned int dropped_logs;
|
extern unsigned int dropped_logs;
|
||||||
|
|
||||||
extern THREAD_LOCAL char *logheader;
|
|
||||||
extern THREAD_LOCAL char *logheader_rfc5424;
|
|
||||||
extern THREAD_LOCAL char *logline;
|
extern THREAD_LOCAL char *logline;
|
||||||
extern THREAD_LOCAL char *logline_rfc5424;
|
extern THREAD_LOCAL char *logline_rfc5424;
|
||||||
|
|
||||||
@ -99,9 +97,9 @@ void send_log(struct proxy *p, int level, const char *format, ...)
|
|||||||
void __send_log(struct list *logsrvs, struct buffer *tag, int level, char *message, size_t size, char *sd, size_t sd_size);
|
void __send_log(struct list *logsrvs, struct buffer *tag, int level, char *message, size_t size, char *sd, size_t sd_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns log format for <fmt> or -1 if not found.
|
* returns log format for <fmt> or LOG_FORMAT_UNSPEC if not found.
|
||||||
*/
|
*/
|
||||||
int get_log_format(const char *fmt);
|
enum log_fmt get_log_format(const char *fmt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns log level for <lev> or -1 if not found.
|
* returns log level for <lev> or -1 if not found.
|
||||||
@ -161,6 +159,7 @@ static inline int build_logline(struct stream *s, char *dst, size_t maxsize, str
|
|||||||
return sess_build_logline(strm_sess(s), s, dst, maxsize, list_format);
|
return sess_build_logline(strm_sess(s), s, dst, maxsize, list_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ist *build_log_header(enum log_fmt format, int level, int facility, struct ist *metadata, size_t *nbelem);
|
||||||
#endif /* _HAPROXY_LOG_H */
|
#endif /* _HAPROXY_LOG_H */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <import/ist.h>
|
#include <import/ist.h>
|
||||||
#include <haproxy/api-t.h>
|
#include <haproxy/api-t.h>
|
||||||
|
#include <haproxy/log-t.h>
|
||||||
|
|
||||||
/* A sink may be of 4 distinct types :
|
/* A sink may be of 4 distinct types :
|
||||||
* - file descriptor (such as stdout)
|
* - file descriptor (such as stdout)
|
||||||
@ -35,18 +36,6 @@ enum sink_type {
|
|||||||
SINK_TYPE_BUFFER, // events sent to a ring buffer
|
SINK_TYPE_BUFFER, // events sent to a ring buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This indicates the default event format, which is the destination's
|
|
||||||
* preferred format, but may be overridden by the source.
|
|
||||||
*/
|
|
||||||
enum sink_fmt {
|
|
||||||
SINK_FMT_RAW, // raw text sent as-is
|
|
||||||
SINK_FMT_SHORT, // raw text prefixed with a syslog level
|
|
||||||
SINK_FMT_ISO, // raw text prefixed with ISO time
|
|
||||||
SINK_FMT_TIMED, // syslog level then ISO
|
|
||||||
SINK_FMT_RFC3164, // regular syslog
|
|
||||||
SINK_FMT_RFC5424, // extended syslog
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sink_forward_target {
|
struct sink_forward_target {
|
||||||
struct server *srv; // used server
|
struct server *srv; // used server
|
||||||
struct appctx *appctx; // appctx of current session
|
struct appctx *appctx; // appctx of current session
|
||||||
@ -60,7 +49,7 @@ struct sink {
|
|||||||
struct list sink_list; // position in the sink list
|
struct list sink_list; // position in the sink list
|
||||||
char *name; // sink name
|
char *name; // sink name
|
||||||
char *desc; // sink description
|
char *desc; // sink description
|
||||||
enum sink_fmt fmt; // format expected by the sink
|
enum log_fmt fmt; // format expected by the sink
|
||||||
enum sink_type type; // type of storage
|
enum sink_type type; // type of storage
|
||||||
uint32_t maxlen; // max message length (truncated above)
|
uint32_t maxlen; // max message length (truncated above)
|
||||||
struct proxy* forward_px; // proxy used to forward
|
struct proxy* forward_px; // proxy used to forward
|
||||||
|
@ -29,11 +29,10 @@
|
|||||||
extern struct list sink_list;
|
extern struct list sink_list;
|
||||||
|
|
||||||
struct sink *sink_find(const char *name);
|
struct sink *sink_find(const char *name);
|
||||||
struct sink *sink_new_fd(const char *name, const char *desc, enum sink_fmt fmt, int fd);
|
struct sink *sink_new_fd(const char *name, const char *desc, enum log_fmt, int fd);
|
||||||
ssize_t __sink_write(struct sink *sink, const struct ist msg[], size_t nmsg,
|
ssize_t __sink_write(struct sink *sink, const struct ist msg[], size_t nmsg,
|
||||||
int level, int facility, struct ist * tag,
|
int level, int facility, struct ist * metadata);
|
||||||
struct ist *pid, struct ist *sd);
|
int sink_announce_dropped(struct sink *sink, int facility);
|
||||||
int sink_announce_dropped(struct sink *sink, int facility, struct ist *pid);
|
|
||||||
|
|
||||||
|
|
||||||
/* tries to send <nmsg> message parts (up to 8, ignored above) from message
|
/* tries to send <nmsg> message parts (up to 8, ignored above) from message
|
||||||
@ -44,8 +43,7 @@ int sink_announce_dropped(struct sink *sink, int facility, struct ist *pid);
|
|||||||
* or <= 0 in other cases.
|
* or <= 0 in other cases.
|
||||||
*/
|
*/
|
||||||
static inline ssize_t sink_write(struct sink *sink, const struct ist msg[], size_t nmsg,
|
static inline ssize_t sink_write(struct sink *sink, const struct ist msg[], size_t nmsg,
|
||||||
int level, int facility, struct ist * tag,
|
int level, int facility, struct ist *metadata)
|
||||||
struct ist *pid, struct ist *sd)
|
|
||||||
{
|
{
|
||||||
ssize_t sent;
|
ssize_t sent;
|
||||||
|
|
||||||
@ -57,7 +55,7 @@ static inline ssize_t sink_write(struct sink *sink, const struct ist msg[], size
|
|||||||
* position.
|
* position.
|
||||||
*/
|
*/
|
||||||
HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &sink->ctx.lock);
|
HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &sink->ctx.lock);
|
||||||
sent = sink_announce_dropped(sink, facility, pid);
|
sent = sink_announce_dropped(sink, facility);
|
||||||
HA_RWLOCK_WRUNLOCK(LOGSRV_LOCK, &sink->ctx.lock);
|
HA_RWLOCK_WRUNLOCK(LOGSRV_LOCK, &sink->ctx.lock);
|
||||||
|
|
||||||
if (!sent) {
|
if (!sent) {
|
||||||
@ -69,7 +67,7 @@ static inline ssize_t sink_write(struct sink *sink, const struct ist msg[], size
|
|||||||
}
|
}
|
||||||
|
|
||||||
HA_RWLOCK_RDLOCK(LOGSRV_LOCK, &sink->ctx.lock);
|
HA_RWLOCK_RDLOCK(LOGSRV_LOCK, &sink->ctx.lock);
|
||||||
sent = __sink_write(sink, msg, nmsg, level, facility, tag, pid, sd);
|
sent = __sink_write(sink, msg, nmsg, level, facility, metadata);
|
||||||
HA_RWLOCK_RDUNLOCK(LOGSRV_LOCK, &sink->ctx.lock);
|
HA_RWLOCK_RDUNLOCK(LOGSRV_LOCK, &sink->ctx.lock);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
760
src/log.c
760
src/log.c
@ -43,57 +43,34 @@
|
|||||||
#include <haproxy/version.h>
|
#include <haproxy/version.h>
|
||||||
|
|
||||||
|
|
||||||
struct log_fmt {
|
struct log_fmt_st {
|
||||||
char *name;
|
char *name;
|
||||||
struct {
|
|
||||||
struct buffer sep1; /* first pid separator */
|
|
||||||
struct buffer sep2; /* second pid separator */
|
|
||||||
} pid;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct log_fmt log_formats[LOG_FORMATS] = {
|
static const struct log_fmt_st log_formats[LOG_FORMATS] = {
|
||||||
[LOG_FORMAT_RFC3164] = {
|
[LOG_FORMAT_RFC3164] = {
|
||||||
.name = "rfc3164",
|
.name = "rfc3164",
|
||||||
.pid = {
|
|
||||||
.sep1 = { .area = "[", .data = 1 },
|
|
||||||
.sep2 = { .area = "]: ", .data = 3 }
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[LOG_FORMAT_RFC5424] = {
|
[LOG_FORMAT_RFC5424] = {
|
||||||
.name = "rfc5424",
|
.name = "rfc5424",
|
||||||
.pid = {
|
},
|
||||||
.sep1 = { .area = " ", .data = 1 },
|
[LOG_FORMAT_PRIO] = {
|
||||||
.sep2 = { .area = " - ", .data = 3 }
|
.name = "priority",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[LOG_FORMAT_SHORT] = {
|
[LOG_FORMAT_SHORT] = {
|
||||||
.name = "short",
|
.name = "short",
|
||||||
.pid = {
|
},
|
||||||
.sep1 = { .area = "", .data = 0 },
|
[LOG_FORMAT_TIMED] = {
|
||||||
.sep2 = { .area = " ", .data = 1 },
|
.name = "timed",
|
||||||
}
|
},
|
||||||
|
[LOG_FORMAT_ISO] = {
|
||||||
|
.name = "iso",
|
||||||
},
|
},
|
||||||
[LOG_FORMAT_RAW] = {
|
[LOG_FORMAT_RAW] = {
|
||||||
.name = "raw",
|
.name = "raw",
|
||||||
.pid = {
|
|
||||||
.sep1 = { .area = "", .data = 0 },
|
|
||||||
.sep2 = { .area = "", .data = 0 },
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
char *get_format_pid_sep1(int format, size_t *len)
|
|
||||||
{
|
|
||||||
*len = log_formats[format].pid.sep1.data;
|
|
||||||
return log_formats[format].pid.sep1.area;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *get_format_pid_sep2(int format, size_t *len)
|
|
||||||
{
|
|
||||||
*len = log_formats[format].pid.sep2.data;
|
|
||||||
return log_formats[format].pid.sep2.area;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This map is used with all the FD_* macros to check whether a particular bit
|
* This map is used with all the FD_* macros to check whether a particular bit
|
||||||
* is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
|
* is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
|
||||||
@ -233,19 +210,6 @@ char default_rfc5424_sd_log_format[] = "- ";
|
|||||||
/* total number of dropped logs */
|
/* total number of dropped logs */
|
||||||
unsigned int dropped_logs = 0;
|
unsigned int dropped_logs = 0;
|
||||||
|
|
||||||
/* This is a global syslog header, common to all outgoing messages in
|
|
||||||
* RFC3164 format. It begins with time-based part and is updated by
|
|
||||||
* update_log_hdr().
|
|
||||||
*/
|
|
||||||
THREAD_LOCAL char *logheader = NULL;
|
|
||||||
THREAD_LOCAL char *logheader_end = NULL;
|
|
||||||
|
|
||||||
/* This is a global syslog header for messages in RFC5424 format. It is
|
|
||||||
* updated by update_log_hdr_rfc5424().
|
|
||||||
*/
|
|
||||||
THREAD_LOCAL char *logheader_rfc5424 = NULL;
|
|
||||||
THREAD_LOCAL char *logheader_rfc5424_end = NULL;
|
|
||||||
|
|
||||||
/* This is a global syslog message buffer, common to all outgoing
|
/* This is a global syslog message buffer, common to all outgoing
|
||||||
* messages. It contains only the data part.
|
* messages. It contains only the data part.
|
||||||
*/
|
*/
|
||||||
@ -922,7 +886,7 @@ int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
|
|||||||
/* after the length, a format may be specified */
|
/* after the length, a format may be specified */
|
||||||
if (strcmp(args[cur_arg], "format") == 0) {
|
if (strcmp(args[cur_arg], "format") == 0) {
|
||||||
logsrv->format = get_log_format(args[cur_arg+1]);
|
logsrv->format = get_log_format(args[cur_arg+1]);
|
||||||
if (logsrv->format < 0) {
|
if (logsrv->format == LOG_FORMAT_UNSPEC) {
|
||||||
memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
|
memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -1179,16 +1143,18 @@ void qfprintf(FILE *out, const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns log format for <fmt> or -1 if not found.
|
* returns log format, LOG_FORMAT_UNSPEC is return if not found.
|
||||||
*/
|
*/
|
||||||
int get_log_format(const char *fmt)
|
enum log_fmt get_log_format(const char *fmt)
|
||||||
{
|
{
|
||||||
int format;
|
enum log_fmt format;
|
||||||
|
|
||||||
format = LOG_FORMATS - 1;
|
format = LOG_FORMATS - 1;
|
||||||
while (format >= 0 && strcmp(log_formats[format].name, fmt))
|
while (format > 0 && log_formats[format].name
|
||||||
|
&& strcmp(log_formats[format].name, fmt))
|
||||||
format--;
|
format--;
|
||||||
|
|
||||||
|
/* Note: 0 is LOG_FORMAT_UNSPEC */
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1431,94 +1397,6 @@ char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const str
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Re-generate time-based part of the syslog header in RFC3164 format at
|
|
||||||
* the beginning of logheader once a second and return the pointer to the
|
|
||||||
* first character after it.
|
|
||||||
*/
|
|
||||||
char *update_log_hdr(const time_t time)
|
|
||||||
{
|
|
||||||
static THREAD_LOCAL long tvsec;
|
|
||||||
static THREAD_LOCAL struct buffer host = { };
|
|
||||||
static THREAD_LOCAL int sep = 0;
|
|
||||||
|
|
||||||
if (unlikely(time != tvsec || logheader_end == NULL)) {
|
|
||||||
/* this string is rebuild only once a second */
|
|
||||||
struct tm tm;
|
|
||||||
int hdr_len;
|
|
||||||
|
|
||||||
tvsec = time;
|
|
||||||
get_localtime(tvsec, &tm);
|
|
||||||
|
|
||||||
if (unlikely(global.log_send_hostname != host.area)) {
|
|
||||||
host.area = global.log_send_hostname;
|
|
||||||
host.data = host.area ? strlen(host.area) : 0;
|
|
||||||
sep = host.data ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hdr_len = snprintf(logheader, global.max_syslog_len,
|
|
||||||
"<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
|
|
||||||
monthname[tm.tm_mon],
|
|
||||||
tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
|
|
||||||
(int)host.data, host.area, sep, "");
|
|
||||||
/* WARNING: depending upon implementations, snprintf may return
|
|
||||||
* either -1 or the number of bytes that would be needed to store
|
|
||||||
* the total message. In both cases, we must adjust it.
|
|
||||||
*/
|
|
||||||
if (hdr_len < 0 || hdr_len > global.max_syslog_len)
|
|
||||||
hdr_len = global.max_syslog_len;
|
|
||||||
|
|
||||||
logheader_end = logheader + hdr_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
logheader_end[0] = 0; // ensure we get rid of any previous attempt
|
|
||||||
|
|
||||||
return logheader_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Re-generate time-based part of the syslog header in RFC5424 format at
|
|
||||||
* the beginning of logheader_rfc5424 once a second and return the pointer
|
|
||||||
* to the first character after it.
|
|
||||||
*/
|
|
||||||
char *update_log_hdr_rfc5424(const time_t time, const suseconds_t frac)
|
|
||||||
{
|
|
||||||
static THREAD_LOCAL long tvsec;
|
|
||||||
const char *gmt_offset;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
|
|
||||||
/* this string is rebuild only once a second */
|
|
||||||
struct tm tm;
|
|
||||||
int hdr_len;
|
|
||||||
|
|
||||||
tvsec = time;
|
|
||||||
get_localtime(tvsec, &tm);
|
|
||||||
gmt_offset = get_gmt_offset(time, &tm);
|
|
||||||
|
|
||||||
hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
|
|
||||||
"<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d.000000%.3s:%.2s %s ",
|
|
||||||
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
|
|
||||||
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
|
||||||
gmt_offset, gmt_offset+3,
|
|
||||||
global.log_send_hostname ? global.log_send_hostname : hostname);
|
|
||||||
/* WARNING: depending upon implementations, snprintf may return
|
|
||||||
* either -1 or the number of bytes that would be needed to store
|
|
||||||
* the total message. In both cases, we must adjust it.
|
|
||||||
*/
|
|
||||||
if (hdr_len < 0 || hdr_len > global.max_syslog_len)
|
|
||||||
hdr_len = global.max_syslog_len;
|
|
||||||
|
|
||||||
logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* utoa_pad add a trailing '\0' so we save the char to restore */
|
|
||||||
c = logheader_rfc5424[33];
|
|
||||||
utoa_pad(frac, logheader_rfc5424 + 27, 7);
|
|
||||||
logheader_rfc5424[33] = c;
|
|
||||||
|
|
||||||
logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
|
|
||||||
|
|
||||||
return logheader_rfc5424_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function sends the syslog message using a printf format string. It
|
* This function sends the syslog message using a printf format string. It
|
||||||
@ -1541,52 +1419,325 @@ void send_log(struct proxy *p, int level, const char *format, ...)
|
|||||||
__send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
|
__send_log((p ? &p->logsrvs : 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 of given format using given
|
||||||
|
* metadata, if format is set to LOF_FORMAT_UNSPEC, it tries
|
||||||
|
* to determine format based on given metadas. 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.
|
||||||
|
* Thos function returns currently a maximum of NB_LOG_HDR_IST_ELEMENTS
|
||||||
|
* elements.
|
||||||
|
*/
|
||||||
|
struct ist *build_log_header(enum log_fmt format, int level, int facility,
|
||||||
|
struct ist *metadata, size_t *nbelem)
|
||||||
|
{
|
||||||
|
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 = "<<<<>" };
|
||||||
|
|
||||||
|
struct tm logtime;
|
||||||
|
int len;
|
||||||
|
int fac_level = 0;
|
||||||
|
time_t time = date.tv_sec;
|
||||||
|
|
||||||
|
*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_PRIO].len) {
|
||||||
|
/* the source seems a parsed message
|
||||||
|
* offering a valid level/prio prefix
|
||||||
|
* so we consider this format.
|
||||||
|
*/
|
||||||
|
format = LOG_FORMAT_PRIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare priority, stored into 1 single elem */
|
||||||
|
switch (format) {
|
||||||
|
case LOG_FORMAT_RFC3164:
|
||||||
|
case LOG_FORMAT_RFC5424:
|
||||||
|
case LOG_FORMAT_PRIO:
|
||||||
|
fac_level = facility << 3;
|
||||||
|
/* further format ignore the facility */
|
||||||
|
/* fall through */
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* prepare timestamp, stored into a max of 4 elems */
|
||||||
|
switch (format) {
|
||||||
|
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 immediatly */
|
||||||
|
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 (unlikely(time != hdr_ctx.cur_legacy_time)) {
|
||||||
|
/* re-builds timestamp from the current local time */
|
||||||
|
get_localtime(time, &logtime);
|
||||||
|
|
||||||
|
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] == '-') {
|
||||||
|
/* submited 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 */
|
||||||
|
/* fall through */
|
||||||
|
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 immediatly */
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* year seems changed since log */
|
||||||
|
if (logtime.tm_mon < month)
|
||||||
|
logtime.tm_year--;
|
||||||
|
|
||||||
|
/* 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]);
|
||||||
|
|
||||||
|
/* 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 optionnal */
|
||||||
|
/* 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
hdr_ctx.ist_vector[(*nbelem)++] = ist2("localhost ", 10);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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 (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 && 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
return hdr_ctx.ist_vector;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function sends a syslog message to <logsrv>.
|
* This function sends a syslog message to <logsrv>.
|
||||||
* <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
|
* The argument <metadata> MUST be an array of size
|
||||||
* Same thing for <sd> and <sd_size> which are used for the structured-data part
|
* LOG_META_FIELDS*sizeof(struct ist) containing data to build the header.
|
||||||
* in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
|
|
||||||
* It overrides the last byte of the message vector with an LF character.
|
* It overrides the last byte of the message vector with an LF character.
|
||||||
* Does not return any error,
|
* Does not return any error,
|
||||||
*/
|
*/
|
||||||
static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
|
static inline void __do_send_log(struct logsrv *logsrv, int nblogger, int level, int facility, struct ist *metadata, char *message, size_t size)
|
||||||
int level, char *message, size_t size, char *sd, size_t sd_size,
|
|
||||||
char *tag_str, size_t tag_size)
|
|
||||||
{
|
{
|
||||||
static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
|
static THREAD_LOCAL struct iovec iovec[NB_LOG_HDR_MAX_ELEMENTS+1+1] = { }; /* header elements + message + LF */
|
||||||
static THREAD_LOCAL struct msghdr msghdr = {
|
static THREAD_LOCAL struct msghdr msghdr = {
|
||||||
//.msg_iov = iovec,
|
//.msg_iov = iovec,
|
||||||
.msg_iovlen = NB_MSG_IOVEC_ELEMENTS
|
.msg_iovlen = NB_LOG_HDR_MAX_ELEMENTS+2
|
||||||
};
|
};
|
||||||
static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
|
static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
|
||||||
static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
|
static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
|
||||||
static THREAD_LOCAL char *dataptr = NULL;
|
|
||||||
time_t time = date.tv_sec;
|
|
||||||
char *hdr, *hdr_ptr = NULL;
|
|
||||||
size_t hdr_size;
|
|
||||||
int fac_level;
|
|
||||||
int *plogfd;
|
int *plogfd;
|
||||||
char *pid_sep1 = "", *pid_sep2 = "";
|
|
||||||
char logheader_short[3];
|
|
||||||
int sent;
|
int sent;
|
||||||
int maxlen;
|
size_t nbelem;
|
||||||
int hdr_max = 0;
|
struct ist *msg_header = NULL;
|
||||||
int tag_max = 0;
|
|
||||||
int pid_sep1_max = 0;
|
|
||||||
int pid_max = 0;
|
|
||||||
int pid_sep2_max = 0;
|
|
||||||
int sd_max = 0;
|
|
||||||
int max = 0;
|
|
||||||
|
|
||||||
msghdr.msg_iov = iovec;
|
msghdr.msg_iov = iovec;
|
||||||
|
|
||||||
dataptr = message;
|
|
||||||
|
|
||||||
/* historically some messages used to already contain the trailing LF
|
/* historically some messages used to already contain the trailing LF
|
||||||
* or Zero. Let's remove all trailing LF or Zero
|
* or Zero. Let's remove all trailing LF or Zero
|
||||||
*/
|
*/
|
||||||
while (size && ((dataptr[size-1] == '\n' || (dataptr[size-1] == 0))))
|
while (size && (message[size-1] == '\n' || (message[size-1] == 0)))
|
||||||
size--;
|
size--;
|
||||||
|
|
||||||
if (logsrv->type == LOG_TARGET_FD) {
|
if (logsrv->type == LOG_TARGET_FD) {
|
||||||
@ -1623,161 +1774,47 @@ static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (logsrv->format) {
|
msg_header = build_log_header(logsrv->format, level, facility, metadata, &nbelem);
|
||||||
case LOG_FORMAT_RFC3164:
|
send:
|
||||||
hdr = logheader;
|
|
||||||
hdr_ptr = update_log_hdr(time);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LOG_FORMAT_RFC5424:
|
|
||||||
hdr = logheader_rfc5424;
|
|
||||||
hdr_ptr = update_log_hdr_rfc5424(time, date.tv_usec);
|
|
||||||
sd_max = sd_size; /* the SD part allowed only in RFC5424 */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LOG_FORMAT_SHORT:
|
|
||||||
/* all fields are known, skip the header generation */
|
|
||||||
hdr = logheader_short;
|
|
||||||
hdr[0] = '<';
|
|
||||||
hdr[1] = '0' + MAX(level, logsrv->minlvl);
|
|
||||||
hdr[2] = '>';
|
|
||||||
hdr_ptr = hdr;
|
|
||||||
hdr_max = 3;
|
|
||||||
maxlen = logsrv->maxlen - hdr_max;
|
|
||||||
max = MIN(size, maxlen - 1);
|
|
||||||
goto send;
|
|
||||||
|
|
||||||
case LOG_FORMAT_RAW:
|
|
||||||
/* all fields are known, skip the header generation */
|
|
||||||
hdr_ptr = hdr = "";
|
|
||||||
hdr_max = 0;
|
|
||||||
maxlen = logsrv->maxlen;
|
|
||||||
max = MIN(size, maxlen - 1);
|
|
||||||
goto send;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return; /* must never happen */
|
|
||||||
}
|
|
||||||
|
|
||||||
hdr_size = hdr_ptr - hdr;
|
|
||||||
|
|
||||||
/* For each target, we may have a different facility.
|
|
||||||
* We can also have a different log level for each message.
|
|
||||||
* This induces variations in the message header length.
|
|
||||||
* Since we don't want to recompute it each time, nor copy it every
|
|
||||||
* time, we only change the facility in the pre-computed header,
|
|
||||||
* and we change the pointer to the header accordingly.
|
|
||||||
*/
|
|
||||||
fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
|
|
||||||
hdr_ptr = hdr + 3; /* last digit of the log level */
|
|
||||||
do {
|
|
||||||
*hdr_ptr = '0' + fac_level % 10;
|
|
||||||
fac_level /= 10;
|
|
||||||
hdr_ptr--;
|
|
||||||
} while (fac_level && hdr_ptr > hdr);
|
|
||||||
*hdr_ptr = '<';
|
|
||||||
|
|
||||||
hdr_max = hdr_size - (hdr_ptr - hdr);
|
|
||||||
|
|
||||||
/* time-based header */
|
|
||||||
if (unlikely(hdr_size >= logsrv->maxlen)) {
|
|
||||||
hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
|
|
||||||
sd_max = 0;
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
|
|
||||||
maxlen = logsrv->maxlen - hdr_max;
|
|
||||||
|
|
||||||
/* tag */
|
|
||||||
tag_max = tag_size;
|
|
||||||
if (unlikely(tag_max >= maxlen)) {
|
|
||||||
tag_max = maxlen - 1;
|
|
||||||
sd_max = 0;
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
|
|
||||||
maxlen -= tag_max;
|
|
||||||
|
|
||||||
/* first pid separator */
|
|
||||||
pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
|
|
||||||
if (unlikely(pid_sep1_max >= maxlen)) {
|
|
||||||
pid_sep1_max = maxlen - 1;
|
|
||||||
sd_max = 0;
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
|
|
||||||
maxlen -= pid_sep1_max;
|
|
||||||
|
|
||||||
/* pid */
|
|
||||||
pid_max = pid_size;
|
|
||||||
if (unlikely(pid_size >= maxlen)) {
|
|
||||||
pid_size = maxlen - 1;
|
|
||||||
sd_max = 0;
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
|
|
||||||
maxlen -= pid_size;
|
|
||||||
|
|
||||||
/* second pid separator */
|
|
||||||
pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
|
|
||||||
if (unlikely(pid_sep2_max >= maxlen)) {
|
|
||||||
pid_sep2_max = maxlen - 1;
|
|
||||||
sd_max = 0;
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
|
|
||||||
maxlen -= pid_sep2_max;
|
|
||||||
|
|
||||||
/* structured-data */
|
|
||||||
if (sd_max >= maxlen) {
|
|
||||||
sd_max = maxlen - 1;
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
|
|
||||||
max = MIN(size, maxlen - sd_max - 1);
|
|
||||||
send:
|
|
||||||
if (logsrv->addr.ss_family == AF_UNSPEC) {
|
if (logsrv->addr.ss_family == AF_UNSPEC) {
|
||||||
/* the target is a file descriptor or a ring buffer */
|
struct ist msg;
|
||||||
struct ist msg[7];
|
|
||||||
|
msg = ist2(message, size);
|
||||||
|
if (msg.len > logsrv->maxlen)
|
||||||
|
msg.len = logsrv->maxlen;
|
||||||
|
|
||||||
if (logsrv->type == LOG_TARGET_BUFFER) {
|
if (logsrv->type == LOG_TARGET_BUFFER) {
|
||||||
msg[0] = ist2(message, MIN(size, logsrv->maxlen));
|
sent = sink_write(logsrv->sink, &msg, 1, level, logsrv->facility, metadata);
|
||||||
msg[1] = ist2(tag_str, tag_size);
|
|
||||||
msg[2] = ist2(pid_str, pid_size);
|
|
||||||
msg[3] = ist2(sd, sd_size);
|
|
||||||
sent = sink_write(logsrv->sink, msg, 1, level, logsrv->facility, &msg[1], &msg[2], &msg[3]);
|
|
||||||
}
|
|
||||||
else /* LOG_TARGET_FD */ {
|
|
||||||
msg[0] = ist2(hdr_ptr, hdr_max);
|
|
||||||
msg[1] = ist2(tag_str, tag_max);
|
|
||||||
msg[2] = ist2(pid_sep1, pid_sep1_max);
|
|
||||||
msg[3] = ist2(pid_str, pid_max);
|
|
||||||
msg[4] = ist2(pid_sep2, pid_sep2_max);
|
|
||||||
msg[5] = ist2(sd, sd_max);
|
|
||||||
msg[6] = ist2(dataptr, max);
|
|
||||||
sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
|
|
||||||
}
|
}
|
||||||
|
else /* LOG_TARGET_FD */
|
||||||
|
sent = fd_write_frag_line(*plogfd, logsrv->maxlen, msg_header, nbelem, &msg, 1, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iovec[0].iov_base = hdr_ptr;
|
int i = 0;
|
||||||
iovec[0].iov_len = hdr_max;
|
int totlen = logsrv->maxlen;
|
||||||
iovec[1].iov_base = tag_str;
|
|
||||||
iovec[1].iov_len = tag_max;
|
|
||||||
iovec[2].iov_base = pid_sep1;
|
|
||||||
iovec[2].iov_len = pid_sep1_max;
|
|
||||||
iovec[3].iov_base = pid_str;
|
|
||||||
iovec[3].iov_len = pid_max;
|
|
||||||
iovec[4].iov_base = pid_sep2;
|
|
||||||
iovec[4].iov_len = pid_sep2_max;
|
|
||||||
iovec[5].iov_base = sd;
|
|
||||||
iovec[5].iov_len = sd_max;
|
|
||||||
iovec[6].iov_base = dataptr;
|
|
||||||
iovec[6].iov_len = max;
|
|
||||||
iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
|
|
||||||
iovec[7].iov_len = 1;
|
|
||||||
|
|
||||||
|
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 *)&logsrv->addr;
|
msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
|
||||||
msghdr.msg_namelen = get_addr_len(&logsrv->addr);
|
msghdr.msg_namelen = get_addr_len(&logsrv->addr);
|
||||||
|
|
||||||
@ -1800,34 +1837,15 @@ send:
|
|||||||
/*
|
/*
|
||||||
* This function sends a syslog message.
|
* This function sends a syslog message.
|
||||||
* It doesn't care about errors nor does it report them.
|
* It doesn't care about errors nor does it report them.
|
||||||
* The arguments <sd> and <sd_size> are used for the structured-data part
|
* The argument <metadata> MUST be an array of size
|
||||||
* in RFC5424 formatted syslog messages.
|
* LOG_META_FIELDS*sizeof(struct ist) containing
|
||||||
|
* data to build the header.
|
||||||
*/
|
*/
|
||||||
void __send_log(struct list *logsrvs, struct buffer *tag, int level,
|
void process_send_log(struct list *logsrvs, int level, int facility,
|
||||||
char *message, size_t size, char *sd, size_t sd_size)
|
struct ist *metadata, char *message, size_t size)
|
||||||
{
|
{
|
||||||
struct logsrv *logsrv;
|
struct logsrv *logsrv;
|
||||||
int nblogger;
|
int nblogger;
|
||||||
static THREAD_LOCAL int curr_pid;
|
|
||||||
static THREAD_LOCAL char pidstr[100];
|
|
||||||
static THREAD_LOCAL struct buffer pid;
|
|
||||||
|
|
||||||
if (logsrvs == NULL) {
|
|
||||||
if (!LIST_ISEMPTY(&global.logsrvs)) {
|
|
||||||
logsrvs = &global.logsrvs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!tag || !tag->area)
|
|
||||||
tag = &global.log_tag;
|
|
||||||
|
|
||||||
if (!logsrvs || LIST_ISEMPTY(logsrvs))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (unlikely(curr_pid != getpid())) {
|
|
||||||
curr_pid = getpid();
|
|
||||||
ltoa_o(curr_pid, pidstr, sizeof(pidstr));
|
|
||||||
chunk_initstr(&pid, pidstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send log messages to syslog server. */
|
/* Send log messages to syslog server. */
|
||||||
nblogger = 0;
|
nblogger = 0;
|
||||||
@ -1856,11 +1874,63 @@ void __send_log(struct list *logsrvs, struct buffer *tag, int level,
|
|||||||
HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
|
HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
|
||||||
}
|
}
|
||||||
if (in_range)
|
if (in_range)
|
||||||
__do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
|
__do_send_log(logsrv, ++nblogger, MAX(level, logsrv->minlvl),
|
||||||
message, size, sd, sd_size, tag->area, tag->data);
|
(facility == -1) ? logsrv->facility : facility,
|
||||||
|
metadata, 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 *logsrvs, 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 (logsrvs == NULL) {
|
||||||
|
if (!LIST_ISEMPTY(&global.logsrvs)) {
|
||||||
|
logsrvs = &global.logsrvs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!logsrvs || LIST_ISEMPTY(logsrvs))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!metadata[LOG_META_HOST].len) {
|
||||||
|
if (global.log_send_hostname)
|
||||||
|
metadata[LOG_META_HOST] = ist2(global.log_send_hostname, strlen(global.log_send_hostname));
|
||||||
|
else
|
||||||
|
metadata[LOG_META_HOST] = ist2(hostname, strlen(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(logsrvs, 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),
|
||||||
@ -1958,13 +2028,9 @@ INITCALL0(STG_PREPARE, init_log);
|
|||||||
/* Initialize log buffers used for syslog messages */
|
/* Initialize log buffers used for syslog messages */
|
||||||
int init_log_buffers()
|
int init_log_buffers()
|
||||||
{
|
{
|
||||||
logheader = my_realloc2(logheader, global.max_syslog_len + 1);
|
|
||||||
logheader_end = NULL;
|
|
||||||
logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
|
|
||||||
logheader_rfc5424_end = NULL;
|
|
||||||
logline = my_realloc2(logline, global.max_syslog_len + 1);
|
logline = my_realloc2(logline, global.max_syslog_len + 1);
|
||||||
logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
|
logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
|
||||||
if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
|
if (!logline || !logline_rfc5424)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1972,13 +2038,9 @@ int init_log_buffers()
|
|||||||
/* Deinitialize log buffers used for syslog messages */
|
/* Deinitialize log buffers used for syslog messages */
|
||||||
void deinit_log_buffers()
|
void deinit_log_buffers()
|
||||||
{
|
{
|
||||||
free(logheader);
|
|
||||||
free(logheader_rfc5424);
|
|
||||||
free(logline);
|
free(logline);
|
||||||
free(logline_rfc5424);
|
free(logline_rfc5424);
|
||||||
ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
|
ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
|
||||||
logheader = NULL;
|
|
||||||
logheader_rfc5424 = NULL;
|
|
||||||
logline = NULL;
|
logline = NULL;
|
||||||
logline_rfc5424 = NULL;
|
logline_rfc5424 = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1483,7 +1483,7 @@ static int sample_conv_debug(const struct arg *arg_p, struct sample *smp, void *
|
|||||||
|
|
||||||
done:
|
done:
|
||||||
line = ist2(buf->area, buf->data);
|
line = ist2(buf->area, buf->data);
|
||||||
sink_write(sink, &line, 1, 0, 0, NULL, NULL, NULL);
|
sink_write(sink, &line, 1, 0, 0, NULL);
|
||||||
end:
|
end:
|
||||||
free_trash_chunk(buf);
|
free_trash_chunk(buf);
|
||||||
return 1;
|
return 1;
|
||||||
|
150
src/sink.c
150
src/sink.c
@ -50,7 +50,7 @@ struct sink *sink_find(const char *name)
|
|||||||
* exists with the same name, it will be returned. The caller can detect it as
|
* exists with the same name, it will be returned. The caller can detect it as
|
||||||
* a newly created one has type SINK_TYPE_NEW.
|
* a newly created one has type SINK_TYPE_NEW.
|
||||||
*/
|
*/
|
||||||
static struct sink *__sink_new(const char *name, const char *desc, enum sink_fmt fmt)
|
static struct sink *__sink_new(const char *name, const char *desc, int fmt)
|
||||||
{
|
{
|
||||||
struct sink *sink;
|
struct sink *sink;
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ static struct sink *__sink_new(const char *name, const char *desc, enum sink_fmt
|
|||||||
* and description <desc>. Returns NULL on allocation failure or conflict.
|
* and description <desc>. Returns NULL on allocation failure or conflict.
|
||||||
* Perfect duplicates are merged (same type, fd, and name).
|
* Perfect duplicates are merged (same type, fd, and name).
|
||||||
*/
|
*/
|
||||||
struct sink *sink_new_fd(const char *name, const char *desc, enum sink_fmt fmt, int fd)
|
struct sink *sink_new_fd(const char *name, const char *desc, enum log_fmt fmt, int fd)
|
||||||
{
|
{
|
||||||
struct sink *sink;
|
struct sink *sink;
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ struct sink *sink_new_fd(const char *name, const char *desc, enum sink_fmt fmt,
|
|||||||
* Perfect duplicates are merged (same type and name). If sizes differ, the
|
* Perfect duplicates are merged (same type and name). If sizes differ, the
|
||||||
* largest one is kept.
|
* largest one is kept.
|
||||||
*/
|
*/
|
||||||
struct sink *sink_new_buf(const char *name, const char *desc, enum sink_fmt fmt, size_t size)
|
struct sink *sink_new_buf(const char *name, const char *desc, enum log_fmt fmt, size_t size)
|
||||||
{
|
{
|
||||||
struct sink *sink;
|
struct sink *sink;
|
||||||
|
|
||||||
@ -147,87 +147,16 @@ struct sink *sink_new_buf(const char *name, const char *desc, enum sink_fmt fmt,
|
|||||||
* messages when there are any. It returns >0 if it could write anything,
|
* messages when there are any. It returns >0 if it could write anything,
|
||||||
* <=0 otherwise.
|
* <=0 otherwise.
|
||||||
*/
|
*/
|
||||||
ssize_t __sink_write(struct sink *sink, const struct ist msg[], size_t nmsg,
|
ssize_t __sink_write(struct sink *sink, const struct ist msg[], size_t nmsg,
|
||||||
int level, int facility, struct ist *tag,
|
int level, int facility, struct ist *metadata)
|
||||||
struct ist *pid, struct ist *sd)
|
{
|
||||||
{
|
struct ist *pfx = NULL;
|
||||||
int log_format;
|
|
||||||
char short_hdr[4];
|
|
||||||
struct ist pfx[6];
|
|
||||||
size_t npfx = 0;
|
size_t npfx = 0;
|
||||||
char *hdr_ptr;
|
|
||||||
int fac_level;
|
|
||||||
|
|
||||||
if (sink->fmt == SINK_FMT_RAW)
|
if (sink->fmt == LOG_FORMAT_RAW)
|
||||||
goto send;
|
goto send;
|
||||||
|
|
||||||
if (sink->fmt == SINK_FMT_SHORT || sink->fmt == SINK_FMT_TIMED) {
|
pfx = build_log_header(sink->fmt, level, facility, metadata, &npfx);
|
||||||
short_hdr[0] = '<';
|
|
||||||
short_hdr[1] = '0' + level;
|
|
||||||
short_hdr[2] = '>';
|
|
||||||
|
|
||||||
pfx[npfx].ptr = short_hdr;
|
|
||||||
pfx[npfx].len = 3;
|
|
||||||
npfx++;
|
|
||||||
if (sink->fmt == SINK_FMT_SHORT)
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (sink->fmt == SINK_FMT_ISO || sink->fmt == SINK_FMT_TIMED) {
|
|
||||||
pfx[npfx].ptr = timeofday_as_iso_us(1);
|
|
||||||
pfx[npfx].len = 33;
|
|
||||||
npfx++;
|
|
||||||
goto send;
|
|
||||||
}
|
|
||||||
else if (sink->fmt == SINK_FMT_RFC5424) {
|
|
||||||
pfx[npfx].ptr = logheader_rfc5424;
|
|
||||||
pfx[npfx].len = update_log_hdr_rfc5424(date.tv_sec, date.tv_usec) - pfx[npfx].ptr;
|
|
||||||
log_format = LOG_FORMAT_RFC5424;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pfx[npfx].ptr = logheader;
|
|
||||||
pfx[npfx].len = update_log_hdr(date.tv_sec) - pfx[npfx].ptr;
|
|
||||||
log_format = LOG_FORMAT_RFC3164;
|
|
||||||
sd = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fac_level = (facility << 3) + level;
|
|
||||||
hdr_ptr = pfx[npfx].ptr + 3; /* last digit of the log level */
|
|
||||||
do {
|
|
||||||
*hdr_ptr = '0' + fac_level % 10;
|
|
||||||
fac_level /= 10;
|
|
||||||
hdr_ptr--;
|
|
||||||
} while (fac_level && hdr_ptr > pfx[npfx].ptr);
|
|
||||||
*hdr_ptr = '<';
|
|
||||||
pfx[npfx].len -= hdr_ptr - pfx[npfx].ptr;
|
|
||||||
pfx[npfx].ptr = hdr_ptr;
|
|
||||||
npfx++;
|
|
||||||
|
|
||||||
if (tag && tag->len) {
|
|
||||||
pfx[npfx].ptr = tag->ptr;
|
|
||||||
pfx[npfx].len = tag->len;
|
|
||||||
npfx++;
|
|
||||||
}
|
|
||||||
pfx[npfx].ptr = get_format_pid_sep1(log_format, &pfx[npfx].len);
|
|
||||||
if (pfx[npfx].len)
|
|
||||||
npfx++;
|
|
||||||
|
|
||||||
if (pid && pid->len) {
|
|
||||||
pfx[npfx].ptr = pid->ptr;
|
|
||||||
pfx[npfx].len = pid->len;
|
|
||||||
npfx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
pfx[npfx].ptr = get_format_pid_sep2(log_format, &pfx[npfx].len);
|
|
||||||
if (pfx[npfx].len)
|
|
||||||
npfx++;
|
|
||||||
|
|
||||||
if (sd && sd->len) {
|
|
||||||
pfx[npfx].ptr = sd->ptr;
|
|
||||||
pfx[npfx].len = sd->len;
|
|
||||||
npfx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
send:
|
send:
|
||||||
if (sink->type == SINK_TYPE_FD) {
|
if (sink->type == SINK_TYPE_FD) {
|
||||||
@ -244,25 +173,41 @@ send:
|
|||||||
* called under an exclusive lock on the sink to avoid multiple produces doing
|
* called under an exclusive lock on the sink to avoid multiple produces doing
|
||||||
* the same. On success, >0 is returned, otherwise <=0 on failure.
|
* the same. On success, >0 is returned, otherwise <=0 on failure.
|
||||||
*/
|
*/
|
||||||
int sink_announce_dropped(struct sink *sink, int facility, struct ist *pid)
|
int sink_announce_dropped(struct sink *sink, int facility)
|
||||||
{
|
{
|
||||||
|
static THREAD_LOCAL struct ist metadata[LOG_META_FIELDS];
|
||||||
|
static THREAD_LOCAL pid_t curr_pid;
|
||||||
|
static THREAD_LOCAL char pidstr[16];
|
||||||
unsigned int dropped;
|
unsigned int dropped;
|
||||||
struct buffer msg;
|
struct buffer msg;
|
||||||
struct ist msgvec[1];
|
struct ist msgvec[1];
|
||||||
char logbuf[64];
|
char logbuf[64];
|
||||||
struct ist sd;
|
|
||||||
struct ist tag;
|
|
||||||
|
|
||||||
while (unlikely((dropped = sink->ctx.dropped) > 0)) {
|
while (unlikely((dropped = sink->ctx.dropped) > 0)) {
|
||||||
chunk_init(&msg, logbuf, sizeof(logbuf));
|
chunk_init(&msg, logbuf, sizeof(logbuf));
|
||||||
chunk_printf(&msg, "%u event%s dropped", dropped, dropped > 1 ? "s" : "");
|
chunk_printf(&msg, "%u event%s dropped", dropped, dropped > 1 ? "s" : "");
|
||||||
msgvec[0] = ist2(msg.area, msg.data);
|
msgvec[0] = ist2(msg.area, msg.data);
|
||||||
|
|
||||||
sd.ptr = default_rfc5424_sd_log_format;
|
if (!metadata[LOG_META_HOST].len) {
|
||||||
sd.len = 2;
|
if (global.log_send_hostname)
|
||||||
tag.ptr = global.log_tag.area;
|
metadata[LOG_META_HOST] = ist2(global.log_send_hostname, strlen(global.log_send_hostname));
|
||||||
tag.len = global.log_tag.data;
|
else
|
||||||
if (__sink_write(sink, msgvec, 1, LOG_NOTICE, facility, &tag, pid, &sd) <= 0)
|
metadata[LOG_META_HOST] = ist2(hostname, strlen(hostname));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!metadata[LOG_META_TAG].len)
|
||||||
|
metadata[LOG_META_TAG] = ist2(global.log_tag.area, global.log_tag.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));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__sink_write(sink, msgvec, 1, LOG_NOTICE, facility, metadata) <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
/* success! */
|
/* success! */
|
||||||
HA_ATOMIC_SUB(&sink->ctx.dropped, dropped);
|
HA_ATOMIC_SUB(&sink->ctx.dropped, dropped);
|
||||||
@ -818,7 +763,7 @@ int cfg_parse_ring(const char *file, int linenum, char **args, int kwm)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_sink = sink_new_buf(args[1], args[1] , SINK_FMT_RAW, size);
|
cfg_sink = sink_new_buf(args[1], args[1], LOG_FORMAT_RAW, size);
|
||||||
if (!cfg_sink || cfg_sink->type != SINK_TYPE_BUFFER) {
|
if (!cfg_sink || cfg_sink->type != SINK_TYPE_BUFFER) {
|
||||||
ha_alert("parsing [%s:%d] : unable to create a new sink buffer for ring '%s'.\n", file, linenum, args[1]);
|
ha_alert("parsing [%s:%d] : unable to create a new sink buffer for ring '%s'.\n", file, linenum, args[1]);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
@ -909,25 +854,8 @@ int cfg_parse_ring(const char *file, int linenum, char **args, int kwm)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(args[1], "raw") == 0) {
|
cfg_sink->fmt = get_log_format(args[1]);
|
||||||
cfg_sink->fmt = SINK_FMT_RAW;
|
if (cfg_sink->fmt == LOG_FORMAT_UNSPEC) {
|
||||||
}
|
|
||||||
else if (strcmp(args[1], "short") == 0) {
|
|
||||||
cfg_sink->fmt = SINK_FMT_SHORT;
|
|
||||||
}
|
|
||||||
else if (strcmp(args[1], "iso") == 0) {
|
|
||||||
cfg_sink->fmt = SINK_FMT_ISO;
|
|
||||||
}
|
|
||||||
else if (strcmp(args[1], "timed") == 0) {
|
|
||||||
cfg_sink->fmt = SINK_FMT_TIMED;
|
|
||||||
}
|
|
||||||
else if (strcmp(args[1], "rfc3164") == 0) {
|
|
||||||
cfg_sink->fmt = SINK_FMT_RFC3164;
|
|
||||||
}
|
|
||||||
else if (strcmp(args[1], "rfc5424") == 0) {
|
|
||||||
cfg_sink->fmt = SINK_FMT_RFC5424;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ha_alert("parsing [%s:%d] : unknown format '%s'.\n", file, linenum, args[1]);
|
ha_alert("parsing [%s:%d] : unknown format '%s'.\n", file, linenum, args[1]);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto err;
|
goto err;
|
||||||
@ -1079,9 +1007,9 @@ int post_sink_resolve()
|
|||||||
|
|
||||||
static void sink_init()
|
static void sink_init()
|
||||||
{
|
{
|
||||||
sink_new_fd("stdout", "standard output (fd#1)", SINK_FMT_RAW, 1);
|
sink_new_fd("stdout", "standard output (fd#1)", LOG_FORMAT_RAW, 1);
|
||||||
sink_new_fd("stderr", "standard output (fd#2)", SINK_FMT_RAW, 2);
|
sink_new_fd("stderr", "standard output (fd#2)", LOG_FORMAT_RAW, 2);
|
||||||
sink_new_buf("buf0", "in-memory ring buffer", SINK_FMT_TIMED, 1048576);
|
sink_new_buf("buf0", "in-memory ring buffer", LOG_FORMAT_TIMED, 1048576);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sink_deinit()
|
static void sink_deinit()
|
||||||
|
@ -230,7 +230,7 @@ void __trace(enum trace_level level, uint64_t mask, struct trace_source *src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (src->sink)
|
if (src->sink)
|
||||||
sink_write(src->sink, line, words, 0, 0, NULL, NULL, NULL);
|
sink_write(src->sink, line, words, 0, 0, NULL);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
/* check if we need to stop the trace now */
|
/* check if we need to stop the trace now */
|
||||||
|
Loading…
Reference in New Issue
Block a user