ignore-persist - - X X
load-server-state-from-file X - X X
log (*) X X X X
+log-balance X - X X
log-format X X X -
log-format-sd X X X -
log-tag X X X X
when used as a complement this can help troubleshooting by
having the logs instantly available.
+ - A log backend in the form "backend@<name>", which will send
+ log messages to the corresponding log backend responsible for
+ sending the message to the proper server according to the
+ backend's lb settings. A log backend is a backend section with
+ "mode log" set (see "mode" for more information).
+
- An explicit stream address prefix such as "tcp@","tcp6@",
"tcp4@" or "uxst@" will allocate an implicit ring buffer with
a stream forward server targeting the given address.
# level and send in tcp
log "${LOCAL_SYSLOG}:514" local0 notice # send to local server
+log-balance <algorithm> [ <arguments> ]
+
+ Define the load balancing algorithm to be used in a log backend.
+ ("mode log" enabled)
+
+ May be used in sections : defaults | frontend | listen | backend
+ yes | no | yes | yes
+ Arguments :
+ <algorithm> is the algorithm used to select a server when doing load
+ balancing. This only applies when no persistence information
+ is available, or when a connection is redispatched to another
+ server. <algorithm> may be one of the following :
+
+ roundrobin Each server is used in turns. This is the smoothest and
+ fairest algorithm when the server's processing time remains
+ equally distributed.
+
+ <arguments> is an optional list of arguments which may be needed by some
+ algorithms.
+
+ The load balancing algorithm of a log backend is set to roundrobin when
+ no other algorithm has been set. The algorithm may only be set once for each
+ log backend. The above algorithms support the "backup" server option and the
+ "allbackups" proxy option. However server "weight" is not supported and will
+ be ignored.
+
+ Examples :
+
+ global
+ log backend@mylog-rrb local0 # send all logs to mylog-rrb backend
+
+ backend mylog-rrb
+ mode log
+ log-balance roundrobin
+
+ server s1 udp@127.0.0.1:514 # will receive 50% of log messages
+ server s2 udp@127.0.0.1:514
log-format <string>
Specifies the log format string to use for traffic logs
See also : "server", global section's "maxconn", "fullconn"
-mode { tcp|http }
+mode { tcp|http|log }
Set the running mode or protocol of the instance
May be used in sections : defaults | frontend | listen | backend
yes | yes | yes | yes
processing and switching will be possible. This is the mode which
brings HAProxy most of its value.
+ log When used in a backend section, it will turn the backend into a
+ log backend. Such backend can be used as a log destination for
+ any "log" directive by using the "backend@<name>" syntax. Log
+ messages will be distributed to the servers from the backend
+ according to the lb settings which can be configured using the
+ "log-balance" keyword (in place of the "balance" keyword for TCP
+ and HTTP backends). Log backends support UDP servers by prefixing
+ the server's address with the "udp@" prefix. Common backend and
+ server features are supported, but not TCP or HTTP related ones.
+
When doing content switching, it is mandatory that the frontend and the
backend are in the same mode (generally HTTP), otherwise the configuration
will be refused.
log-proto <logproto>
The "log-proto" specifies the protocol used to forward event messages to
- a server configured in a ring section. Possible values are "legacy"
+ a server configured in a log or ring section. Possible values are "legacy"
and "octet-count" corresponding respectively to "Non-transparent-framing"
and "Octet counting" in rfc6587. "legacy" is the default.
struct lb_fwlc fwlc;
struct lb_chash chash;
struct lb_fas fas;
+ struct {
+ struct server **srv; /* array containing in-use log servers */
+ struct list avail; /* servers available for lb are registered in this list */
+ uint32_t lastid; /* last relative id used */
+ } log; /* used in log-balancing context (PR_MODE_SYSLOG backend) */
};
int algo; /* load balancing algorithm and variants: BE_LB_* */
int tot_wact, tot_wbck; /* total effective weights of active and backup servers */
const char *backend_lb_algo_str(int algo);
int backend_parse_balance(const char **args, char **err, struct proxy *curproxy);
+int backend_parse_log_balance(const char **args, char **err, struct proxy *curproxy);
int tcp_persist_rdp_cookie(struct stream *s, struct channel *req, int an_bit);
int be_downtime(struct proxy *px);
LOG_TARGET_DGRAM = 0, // datagram address (udp, unix socket)
LOG_TARGET_FD, // file descriptor
LOG_TARGET_BUFFER, // ring buffer
+ LOG_TARGET_BACKEND, // backend with SYSLOG mode
};
/* lists of fields that can be logged, for logformat_node->type */
struct log_target {
struct sockaddr_storage *addr;
union {
- char *ring_name; /* type = BUFFER - preparsing */
- struct sink *sink; /* type = BUFFER - postparsing */
+ char *ring_name; /* type = BUFFER - preparsing */
+ struct sink *sink; /* type = BUFFER - postparsing */
+ char *be_name; /* type = BACKEND - preparsing */
+ struct proxy *be; /* type = BACKEND - postparsing */
+ char *resolv_name; /* generic - preparsing */
};
enum log_tgt type;
uint16_t flags;
char *rdr_pfx; /* the redirection prefix */
struct proxy *proxy; /* the proxy this server belongs to */
- const struct mux_proto_list *mux_proto; /* the mux to use for all outgoing connections (specified by the "proto" keyword) */
+ const struct mux_proto_list *mux_proto; /* the mux to use for all outgoing connections (specified by the "proto" keyword) */
+ struct log_target *log_target; /* when 'mode log' is enabled, target facility used to transport log messages */
unsigned maxconn, minconn; /* max # of active sessions (0 = unlimited), min# for dynamic limit. */
struct srv_per_thread *per_thr; /* array of per-thread stuff such as connections lists */
struct srv_per_tgroup *per_tgrp; /* array of per-tgroup stuff such as idle conns */
THREAD_PAD(63);
__decl_thread(HA_SPINLOCK_T lock); /* may enclose the proxy's lock, must not be taken under */
unsigned npos, lpos; /* next and last positions in the LB tree, protected by LB lock */
- struct eb32_node lb_node; /* node used for tree-based load balancing */
+ union {
+ struct eb32_node lb_node; /* node used for tree-based load balancing */
+ struct list lb_list; /* elem used for list-based load balancing */
+ };
struct server *next_full; /* next server in the temporary full list */
/* usually atomically updated by any thread during parsing or on end of request */
char *hostname; /* server hostname */
struct sockaddr_storage init_addr; /* plain IP address specified on the init-addr line */
unsigned int init_addr_methods; /* initial address setting, 3-bit per method, ends at 0, enough to store 10 entries */
- enum srv_log_proto log_proto; /* used proto to emit messages on server lines from ring section */
+ enum srv_log_proto log_proto; /* used proto to emit messages on server lines from log or ring section */
char *sni_expr; /* Temporary variable to store a sample expression for SNI */
struct {
#define SRV_PARSE_PARSE_ADDR 0x08 /* required to parse the server address in the second argument */
#define SRV_PARSE_DYNAMIC 0x10 /* dynamic server created at runtime with cli */
#define SRV_PARSE_INITIAL_RESOLVE 0x20 /* resolve immediately the fqdn to an ip address */
+#define SRV_PARSE_IN_LOG_BE 0x40 /* keyword in log backend */
#endif /* _HAPROXY_SERVER_T_H */
return 0;
}
+/* This function parses a "balance" statement in a log backend section
+ * describing <curproxy>. It returns -1 if there is any error, otherwise zero.
+ * If it returns -1, it will write an error message into the <err> buffer which
+ * will automatically be allocated and must be passed as NULL. The trailing '\n'
+ * will not be written. The function must be called with <args> pointing to the
+ * first word after "balance".
+ */
+int backend_parse_log_balance(const char **args, char **err, struct proxy *curproxy)
+{
+ if (!*(args[0])) {
+ /* if no option is set, use round-robin by default */
+ curproxy->lbprm.algo &= ~BE_LB_ALGO;
+ curproxy->lbprm.algo |= BE_LB_ALGO_RR;
+ return 0;
+ }
+
+ if (strcmp(args[0], "roundrobin") == 0) {
+ curproxy->lbprm.algo &= ~BE_LB_ALGO;
+ curproxy->lbprm.algo |= BE_LB_ALGO_RR;
+ }
+ else {
+ memprintf(err, "only supports 'roundrobin' option");
+ return -1;
+ }
+ return 0;
+}
+
/************************************************************************/
/* All supported sample and ACL keywords must be declared here. */
"use-server", "force-persist", "ignore-persist", "force-persist",
"stick-table", "stick", "stats", "option", "default_backend",
"http-reuse", "monitor", "transparent", "maxconn", "backlog",
- "fullconn", "dispatch", "balance", "hash-type",
+ "fullconn", "dispatch", "balance", "log-balance", "hash-type",
"hash-balance-factor", "unique-id-format", "unique-id-header",
"log-format", "log-format-sd", "log-tag", "log", "source", "usesrc",
"error-log-format",
if ((strcmp(args[0], "server") == 0)) {
err_code |= parse_server(file, linenum, args,
curproxy, curr_defproxy,
+ (curproxy->mode == PR_MODE_SYSLOG ? SRV_PARSE_IN_LOG_BE : 0) |
SRV_PARSE_PARSE_ADDR);
if (err_code & ERR_FATAL)
else if (strcmp(args[0], "default-server") == 0) {
err_code |= parse_server(file, linenum, args,
curproxy, curr_defproxy,
+ (curproxy->mode == PR_MODE_SYSLOG ? SRV_PARSE_IN_LOG_BE : 0) |
SRV_PARSE_DEFAULT_SERVER);
if (err_code & ERR_FATAL)
else if (strcmp(args[0], "server-template") == 0) {
err_code |= parse_server(file, linenum, args,
curproxy, curr_defproxy,
+ (curproxy->mode == PR_MODE_SYSLOG ? SRV_PARSE_IN_LOG_BE : 0) |
SRV_PARSE_TEMPLATE|SRV_PARSE_PARSE_ADDR);
if (err_code & ERR_FATAL)
if (strcmp(args[1], "http") == 0) curproxy->mode = PR_MODE_HTTP;
else if (strcmp(args[1], "tcp") == 0) curproxy->mode = PR_MODE_TCP;
+ else if (strcmp(args[1], "log") == 0 && (curproxy->cap & PR_CAP_BE)) curproxy->mode = PR_MODE_SYSLOG;
else if (strcmp(args[1], "health") == 0) {
ha_alert("parsing [%s:%d] : 'mode health' doesn't exist anymore. Please use 'http-request return status 200' instead.\n", file, linenum);
err_code |= ERR_ALERT | ERR_FATAL;
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
+ /* mode log shares lbprm struct with other modes, but makes a different use of it,
+ * thus, we must ensure that defproxy settings cannot persist between incompatibles
+ * modes at this point.
+ */
+ if ((curr_defproxy->mode == PR_MODE_SYSLOG && curproxy->mode != PR_MODE_SYSLOG) ||
+ (curr_defproxy->mode != PR_MODE_SYSLOG && curproxy->mode == PR_MODE_SYSLOG)) {
+ /* lbprm settings from incompatible defproxy, back to defaults */
+ memset(&curproxy->lbprm, 0, sizeof(curproxy->lbprm));
+ }
}
else if (strcmp(args[0], "id") == 0) {
struct eb32_node *node;
goto out;
}
}
+ else if (strcmp(args[0], "log-balance") == 0) { /* set log-balancing with optional algorithm */
+ if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
+ err_code |= ERR_WARN;
+ if (curproxy->mode != PR_MODE_SYSLOG) {
+ ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], "only available for log backends");
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+
+ if (backend_parse_log_balance((const char **)args + 1, &errmsg, curproxy) < 0) {
+ ha_alert("parsing [%s:%d] : %s %s\n", file, linenum, args[0], errmsg);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ }
else if (strcmp(args[0], "hash-type") == 0) { /* set hashing method */
/**
* The syntax for hash-type config element is
* on what LB algorithm was chosen.
*/
+ if (curproxy->mode == PR_MODE_SYSLOG) {
+ /* log load-balancing requires special init that is performed
+ * during log-postparsing step
+ */
+ goto skip_server_lb_init;
+ }
curproxy->lbprm.algo &= ~(BE_LB_LKUP | BE_LB_PROP_DYN);
switch (curproxy->lbprm.algo & BE_LB_KIND) {
case BE_LB_KIND_RR:
}
break;
}
+ skip_server_lb_init:
HA_RWLOCK_INIT(&curproxy->lbprm.lock);
if (curproxy->options & PR_O_LOGASAP)
target->type = 0;
target->flags = LOG_TARGET_FL_NONE;
target->addr = NULL;
- target->ring_name = NULL;
+ target->resolv_name = NULL;
}
static void deinit_log_target(struct log_target *target)
{
ha_free(&target->addr);
if (!(target->flags & LOG_TARGET_FL_RESOLVED))
- ha_free(&target->ring_name);
+ ha_free(&target->resolv_name);
}
/* returns 0 on failure and positive value on success */
goto error;
*cpy->addr = *def->addr;
}
- if (def->ring_name) {
- cpy->ring_name = strdup(def->ring_name);
- if (!cpy->ring_name)
+ if (def->resolv_name) {
+ cpy->resolv_name = strdup(def->resolv_name);
+ if (!cpy->resolv_name)
goto error;
}
cpy->type = def->type;
return 0;
}
+/* must be called under the lbprm lock */
+static void _log_backend_srv_queue(struct server *srv)
+{
+ struct proxy *p = srv->proxy;
+
+ /* queue the server in the proxy lb array to make it easily searcheable by
+ * log-balance algorithms. Here we use the srv array as a general server
+ * pool of in-use servers, lookup is done using a relative positional id
+ * (array is contiguous)
+ *
+ * We use the avail server list to get a quick hand on available servers
+ * (those that are UP)
+ */
+ if (srv->flags & SRV_F_BACKUP) {
+ if (!p->srv_act)
+ p->lbprm.log.srv[p->srv_bck] = srv;
+ p->srv_bck++;
+ }
+ else {
+ if (!p->srv_act) {
+ /* we will be switching to act tree in LB logic, thus we need to
+ * reset the lastid
+ */
+ HA_ATOMIC_STORE(&p->lbprm.log.lastid, 0);
+ }
+ p->lbprm.log.srv[p->srv_act] = srv;
+ p->srv_act++;
+ }
+ /* append the server to the list of available servers */
+ LIST_APPEND(&p->lbprm.log.avail, &srv->lb_list);
+}
+
+static void log_backend_srv_up(struct server *srv)
+{
+ struct proxy *p = srv->proxy;
+
+ if (!srv_lb_status_changed(srv))
+ return; /* nothing to do */
+ if (srv_currently_usable(srv) || !srv_willbe_usable(srv))
+ return; /* false alarm */
+
+ HA_RWLOCK_WRLOCK(LBPRM_LOCK, &p->lbprm.lock);
+ _log_backend_srv_queue(srv);
+ HA_RWLOCK_WRUNLOCK(LBPRM_LOCK, &p->lbprm.lock);
+}
+
+/* must be called under lbprm lock */
+static void _log_backend_srv_recalc(struct proxy *p)
+{
+ unsigned int it = 0;
+ struct server *cur_srv;
+
+ list_for_each_entry(cur_srv, &p->lbprm.log.avail, lb_list) {
+ uint8_t backup = cur_srv->flags & SRV_F_BACKUP;
+
+ if ((!p->srv_act && backup) ||
+ (p->srv_act && !backup))
+ p->lbprm.log.srv[it++] = cur_srv;
+ }
+}
+
+/* must be called under the lbprm lock */
+static void _log_backend_srv_dequeue(struct server *srv)
+{
+ struct proxy *p = srv->proxy;
+
+ if (srv->flags & SRV_F_BACKUP) {
+ p->srv_bck--;
+ }
+ else {
+ p->srv_act--;
+ if (!p->srv_act) {
+ /* we will be switching to bck tree in LB logic, thus we need to
+ * reset the lastid
+ */
+ HA_ATOMIC_STORE(&p->lbprm.log.lastid, 0);
+ }
+ }
+
+ /* remove the srv from the list of available (UP) servers */
+ LIST_DELETE(&srv->lb_list);
+
+ /* reconstruct the array of usable servers */
+ _log_backend_srv_recalc(p);
+}
+
+static void log_backend_srv_down(struct server *srv)
+{
+ struct proxy *p = srv->proxy;
+
+ if (!srv_lb_status_changed(srv))
+ return; /* nothing to do */
+ if (!srv_currently_usable(srv) || srv_willbe_usable(srv))
+ return; /* false alarm */
+
+ HA_RWLOCK_WRLOCK(LBPRM_LOCK, &p->lbprm.lock);
+ _log_backend_srv_dequeue(srv);
+ HA_RWLOCK_WRUNLOCK(LBPRM_LOCK, &p->lbprm.lock);
+}
+
+static int postcheck_log_backend(struct proxy *be)
+{
+ char *msg = NULL;
+ struct server *srv;
+ int err_code = ERR_NONE;
+ int target_type = -1; // -1 is unused in log_tgt enum
+
+ if (be->mode != PR_MODE_SYSLOG ||
+ (be->flags & (PR_FL_DISABLED|PR_FL_STOPPED)))
+ return ERR_NONE; /* nothing to do */
+
+ /* First time encoutering this log backend, perform some init
+ */
+ be->lbprm.set_server_status_up = log_backend_srv_up;
+ be->lbprm.set_server_status_down = log_backend_srv_down;
+ be->lbprm.log.lastid = 0; /* initial value */
+ LIST_INIT(&be->lbprm.log.avail);
+
+ /* alloc srv array (it will be used for active and backup server lists in turn,
+ * so we ensure that the longest list will fit
+ */
+ be->lbprm.log.srv = calloc(MAX(be->srv_act, be->srv_bck), sizeof(struct server *));
+
+ if (!be->lbprm.log.srv ) {
+ memprintf(&msg, "memory error when allocating server array (%d entries)",
+ MAX(be->srv_act, be->srv_bck));
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+
+ /* reinit srv counters, lbprm queueing will recount */
+ be->srv_act = 0;
+ be->srv_bck = 0;
+
+ /* finish the initialization of proxy's servers */
+ srv = be->srv;
+ while (srv) {
+ if (target_type == -1)
+ target_type = srv->log_target->type;
+ if (target_type != srv->log_target->type) {
+ memprintf(&msg, "cannot mix server types within a log backend, '%s' srv's network type differs from previous server", srv->id);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+ if (target_type == LOG_TARGET_BUFFER) {
+ srv->log_target->sink = sink_new_from_srv(srv, "log backend");
+ if (!srv->log_target->sink) {
+ memprintf(&msg, "error when creating sink from '%s' log server", srv->id);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+ }
+ srv->cur_eweight = 1; /* ignore weights, all servers have the same weight */
+ _log_backend_srv_queue(srv);
+ srv = srv->next;
+ }
+ end:
+ if (err_code & ERR_CODE) {
+ ha_free(&be->lbprm.log.srv); /* free log servers array */
+ ha_alert("log backend '%s': failed to initialize: %s.\n", be->id, msg);
+ ha_free(&msg);
+ }
+
+ return err_code;
+}
+
/* resolves a single logger entry (it is expected to be called
* at postparsing stage)
*
if (target->type == LOG_TARGET_BUFFER)
err_code = sink_resolve_logger_buffer(logger, msg);
+ else if (target->type == LOG_TARGET_BACKEND) {
+ struct proxy *be;
+ /* special case */
+ be = proxy_find_by_name(target->be_name, PR_CAP_BE, 0);
+ if (!be) {
+ memprintf(msg, "uses unknown log backend '%s'", target->be_name);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+ else if (be->mode != PR_MODE_SYSLOG) {
+ memprintf(msg, "uses incompatible log backend '%s'", target->be_name);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto end;
+ }
+ ha_free(&target->be_name); /* backend is resolved and will replace name hint */
+ target->be = be;
+ }
+
+ end:
target->flags |= LOG_TARGET_FL_RESOLVED;
return err_code;
target->ring_name = strdup(raw + 5);
goto done;
}
+ else if (strncmp(raw, "backend@", 8) == 0) {
+ target->type = LOG_TARGET_BACKEND;
+ target->be_name = strdup(raw + 8);
+ goto done;
+ }
/* try to allocate log target addr */
target->addr = malloc(sizeof(*target->addr));
}
}
+/* 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;
+ uint32_t targetid = ~0; /* default value to check if it was explicitly assigned */
+ uint32_t nb_srv;
+
+ HA_RWLOCK_RDLOCK(LBPRM_LOCK, &be->lbprm.lock);
+
+ if (be->srv_act) {
+ nb_srv = be->srv_act;
+ }
+ else if (be->srv_bck) {
+ /* no more active servers but backup ones are, switch to backup farm */
+ nb_srv = be->srv_bck;
+ if (!(be->options & PR_O_USE_ALL_BK)) {
+ /* log balancing disabled on backup farm */
+ targetid = 0; /* use first server */
+ goto skip_lb;
+ }
+ }
+ else {
+ /* no srv available, can't log */
+ goto drop;
+ }
+
+ /* log-balancing logic: */
+
+ if ((be->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_RR) {
+ /* Atomically load and update lastid since it's not protected
+ * by any write lock
+ *
+ * Wrapping is expected and could lead to unexpected ID reset in the
+ * middle of a cycle, but given that this only happens once in every
+ * 4 billions it is quite negligible
+ */
+ targetid = HA_ATOMIC_FETCH_ADD(&be->lbprm.log.lastid, 1) % nb_srv;
+ }
+
+ skip_lb:
+
+ if (targetid == ~0) {
+ /* no target assigned, nothing to do */
+ goto drop;
+ }
+
+ /* find server based on targetid */
+ srv = be->lbprm.log.srv[targetid];
+ HA_RWLOCK_RDUNLOCK(LBPRM_LOCK, &be->lbprm.lock);
+
+ __do_send_log(srv->log_target, hdr, nblogger, maxlen, message, size);
+ return;
+
+ drop:
+ HA_RWLOCK_RDUNLOCK(LBPRM_LOCK, &be->lbprm.lock);
+ _HA_ATOMIC_INC(&dropped_logs);
+}
+
/*
* This function sends a syslog message.
* It doesn't care about errors nor does it report them.
hdr.facility = (facility == -1) ? logger->facility : facility;
hdr.format = logger->format;
hdr.metadata = metadata;
- __do_send_log(&logger->target, hdr, ++nblogger, logger->maxlen, message, size);
+
+ 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);
+ }
}
}
}
/* config parsers for this section */
REGISTER_CONFIG_SECTION("log-forward", cfg_parse_log_forward, NULL);
REGISTER_POST_CHECK(postresolve_loggers);
+REGISTER_POST_PROXY_CHECK(postcheck_log_backend);
REGISTER_PER_THREAD_ALLOC(init_log_buffers);
REGISTER_PER_THREAD_FREE(deinit_log_buffers);
free(p->conf.uif_file);
if ((p->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_MAP)
free(p->lbprm.map.srv);
+ if (p->mode == PR_MODE_SYSLOG)
+ free(p->lbprm.log.srv);
if (p->conf.logformat_sd_string != default_rfc5424_sd_log_format)
free(p->conf.logformat_sd_string);
{ "ws", srv_parse_ws, 1, 1, 1 }, /* websocket protocol */
{ "id", srv_parse_id, 1, 0, 1 }, /* set id# of server */
{ "init-addr", srv_parse_init_addr, 1, 1, 0 }, /* */
- { "log-proto", srv_parse_log_proto, 1, 1, 0 }, /* Set the protocol for event messages, only relevant in a ring section */
+ { "log-proto", srv_parse_log_proto, 1, 1, 0 }, /* Set the protocol for event messages, only relevant in a log or ring section */
{ "maxconn", srv_parse_maxconn, 1, 1, 1 }, /* Set the max number of concurrent connection */
{ "maxqueue", srv_parse_maxqueue, 1, 1, 1 }, /* Set the max number of connection to put in queue */
{ "max-reuse", srv_parse_max_reuse, 1, 1, 0 }, /* Set the max number of requests on a connection, -1 means unlimited */
free(srv->resolvers_id);
free(srv->addr_node.key);
free(srv->lb_nodes);
+ free(srv->log_target);
if (xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->destroy_srv)
xprt_get(XPRT_SSL)->destroy_srv(srv);
const char *err = NULL;
int err_code = 0;
char *fqdn = NULL;
+ struct protocol *proto;
int tmpl_range_low = 0, tmpl_range_high = 0;
char *errmsg = NULL;
if (!(parse_flags & SRV_PARSE_PARSE_ADDR))
goto skip_addr;
- sk = str2sa_range(args[*cur_arg], &port, &port1, &port2, NULL, NULL,
+ sk = str2sa_range(args[*cur_arg], &port, &port1, &port2, NULL, &proto,
&errmsg, NULL, &fqdn,
+ (parse_flags & SRV_PARSE_IN_LOG_BE ? PA_O_DGRAM : PA_O_CONNECT) |
(parse_flags & SRV_PARSE_INITIAL_RESOLVE ? PA_O_RESOLVE : 0) | PA_O_PORT_OK |
(parse_flags & SRV_PARSE_IN_PEER_SECTION ? PA_O_PORT_MAND : PA_O_PORT_OFS) |
- PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT);
+ PA_O_STREAM | PA_O_XPRT);
if (!sk) {
ha_alert("%s\n", errmsg);
err_code |= ERR_ALERT | ERR_FATAL;
}
}
+ if ((parse_flags & SRV_PARSE_IN_LOG_BE) && proto) {
+ /* mode log enabled, and found proto:
+ * pre-resolve related log target from known infos
+ */
+ newsrv->log_target = malloc(sizeof(*newsrv->log_target));
+ if (!newsrv->log_target) {
+ ha_alert("memory error when allocating log server\n");
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ newsrv->log_target->addr = &newsrv->addr;
+ switch (proto->xprt_type) {
+ case PROTO_TYPE_DGRAM:
+ newsrv->log_target->type = LOG_TARGET_DGRAM;
+ break;
+ case PROTO_TYPE_STREAM:
+ /* for now BUFFER type only supports TCP server to it's almost
+ * explicit. This will require ring buffer creation during log
+ * postresolving step.
+ */
+ newsrv->log_target->type = LOG_TARGET_BUFFER;
+ break;
+ default:
+ ha_alert("log server type not supported for log backend server.\n");
+ err_code |= ERR_ALERT | ERR_FATAL;
+ break;
+ }
+ }
+
newsrv->addr = *sk;
newsrv->svc_port = port;
/*
return 1;
}
+ if (be->mode == PR_MODE_SYSLOG) {
+ cli_err(appctx," Dynamic servers cannot be used with log backends.");
+ return 1;
+ }
+
/* At this point, some operations might not be thread-safe anymore. This
* might be the case for parsing handlers which were designed to run
* only at the starting stage on single-thread mode.