blob: f2480b436718b75db446d3592715085f9ea388a8 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * General logging functions.
3 *
Willy Tarreaub7f694f2008-06-22 17:18:02 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreau8a3f52f2012-12-20 21:23:42 +010013#include <ctype.h>
Willy Tarreauc8f24f82007-11-30 18:38:35 +010014#include <fcntl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020015#include <stdarg.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
20#include <time.h>
21#include <unistd.h>
Robert Tsai81ae1952007-12-05 10:47:29 +010022#include <errno.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020023
24#include <sys/time.h>
Willy Tarreau077edcb2016-08-10 18:30:56 +020025#include <sys/uio.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020026
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020027#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020028#include <haproxy/applet-t.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020029#include <haproxy/cli.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020030#include <haproxy/fd.h>
Willy Tarreau762d7a52020-06-04 11:23:07 +020031#include <haproxy/frontend.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020032#include <haproxy/global.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +020033#include <haproxy/http.h>
Willy Tarreauaeed4a82020-06-04 22:01:04 +020034#include <haproxy/log.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020035#include <haproxy/ring.h>
36#include <haproxy/sample.h>
37#include <haproxy/sink.h>
Willy Tarreau209108d2020-06-04 20:30:20 +020038#include <haproxy/ssl_sock.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020039#include <haproxy/stream.h>
Willy Tarreau5e539c92020-06-04 20:45:39 +020040#include <haproxy/stream_interface.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020041#include <haproxy/time.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020042#include <haproxy/tools.h>
Willy Tarreaud6788052020-05-27 15:59:00 +020043#include <haproxy/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020044
Willy Tarreaubaaee002006-06-26 02:48:02 +020045
Dragan Dosen43885c72015-10-01 13:18:13 +020046struct log_fmt {
47 char *name;
48 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020049 struct buffer sep1; /* first pid separator */
50 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020051 } pid;
52};
53
54static const struct log_fmt log_formats[LOG_FORMATS] = {
55 [LOG_FORMAT_RFC3164] = {
56 .name = "rfc3164",
57 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020058 .sep1 = { .area = "[", .data = 1 },
59 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020060 }
61 },
62 [LOG_FORMAT_RFC5424] = {
63 .name = "rfc5424",
64 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020065 .sep1 = { .area = " ", .data = 1 },
66 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020067 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010068 },
69 [LOG_FORMAT_SHORT] = {
70 .name = "short",
71 .pid = {
72 .sep1 = { .area = "", .data = 0 },
73 .sep2 = { .area = " ", .data = 1 },
74 }
75 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010076 [LOG_FORMAT_RAW] = {
77 .name = "raw",
78 .pid = {
79 .sep1 = { .area = "", .data = 0 },
80 .sep2 = { .area = "", .data = 0 },
81 }
82 },
Dragan Dosen1322d092015-09-22 16:05:32 +020083};
84
Emeric Brunbd163812020-05-06 14:33:46 +020085char *get_format_pid_sep1(int format, size_t *len)
86{
87 *len = log_formats[format].pid.sep1.data;
88 return log_formats[format].pid.sep1.area;
89}
90
91char *get_format_pid_sep2(int format, size_t *len)
92{
93 *len = log_formats[format].pid.sep2.data;
94 return log_formats[format].pid.sep2.area;
95}
96
Dragan Dosen835b9212016-02-12 13:23:03 +010097/*
98 * This map is used with all the FD_* macros to check whether a particular bit
Willy Tarreau1bfd6022019-06-07 11:10:07 +020099 * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
100 * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
101 * that the byte should be escaped. Be careful to always pass bytes from 0 to
102 * 255 exclusively to the macros.
Dragan Dosen835b9212016-02-12 13:23:03 +0100103 */
Willy Tarreau1bfd6022019-06-07 11:10:07 +0200104long rfc5424_escape_map[(256/8) / sizeof(long)];
105long hdr_encode_map[(256/8) / sizeof(long)];
106long url_encode_map[(256/8) / sizeof(long)];
107long http_encode_map[(256/8) / sizeof(long)];
Dragan Dosen835b9212016-02-12 13:23:03 +0100108
Dragan Dosen835b9212016-02-12 13:23:03 +0100109
Willy Tarreaubaaee002006-06-26 02:48:02 +0200110const char *log_facilities[NB_LOG_FACILITIES] = {
111 "kern", "user", "mail", "daemon",
112 "auth", "syslog", "lpr", "news",
113 "uucp", "cron", "auth2", "ftp",
114 "ntp", "audit", "alert", "cron2",
115 "local0", "local1", "local2", "local3",
116 "local4", "local5", "local6", "local7"
117};
118
Willy Tarreaubaaee002006-06-26 02:48:02 +0200119const char *log_levels[NB_LOG_LEVELS] = {
120 "emerg", "alert", "crit", "err",
121 "warning", "notice", "info", "debug"
122};
123
Willy Tarreau570f2212013-06-10 16:42:09 +0200124const char sess_term_cond[16] = "-LcCsSPRIDKUIIII"; /* normal, Local, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal, Down, Killed, Up, -- */
Willy Tarreaub8750a82006-09-03 09:56:00 +0200125const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200126
William Lallemand723b73a2012-02-08 16:37:49 +0100127
128/* log_format */
129struct logformat_type {
130 char *name;
131 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100132 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200133 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100134 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100135 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100136};
137
William Lallemandb7ff6a32012-03-02 14:35:21 +0100138int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
139
William Lallemand723b73a2012-02-08 16:37:49 +0100140/* log_format variable names */
141static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200142 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100143
144 /* please keep these lines sorted ! */
145 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
146 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
147 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
148 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +0100149 { "ID", LOG_FMT_UNIQUEID, PR_MODE_TCP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200150 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200151 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200152 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100153 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200154 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
155 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
156 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
157 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
158 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
159 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200160 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100161 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200162 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Damien Claisse57c8eb92020-04-28 12:09:19 +0000163 { "Tu", LOG_FMT_TU, PR_MODE_TCP, LW_BYTES, NULL }, /* Tu = Tt -Ti */
Willy Tarreau2beef582012-12-20 17:22:52 +0100164 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
165 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200166 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100167 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200168 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100169 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
170 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200171 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200172 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
173 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100174 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
175 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200176 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
177 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100178 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200179 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
180 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
181 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
182 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000183 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
184 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000185 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000186 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
187 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200188 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100189 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200190 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100191 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
192 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100193 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100194 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
195 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
196 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
197 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
198 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200199 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
200 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100201 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200202 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
203 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
204 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100205 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
206 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
207
208 /* The following tags are deprecated and will be removed soon */
209 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
210 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200211 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
212 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
213 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
214 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100215 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
216 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
217 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
218 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
219 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200220 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100221};
222
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200223char default_http_log_format[] = "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"; // default format
224char clf_http_log_format[] = "%{+Q}o %{-Q}ci - - [%trg] %r %ST %B \"\" \"\" %cp %ms %ft %b %s %TR %Tw %Tc %Tr %Ta %tsc %ac %fc %bc %sc %rc %sq %bq %CC %CS %hrl %hsl";
Willy Tarreau2beef582012-12-20 17:22:52 +0100225char default_tcp_log_format[] = "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq";
William Lallemand723b73a2012-02-08 16:37:49 +0100226char *log_format = NULL;
227
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200228/* Default string used for structured-data part in RFC5424 formatted
229 * syslog messages.
230 */
231char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200232
Willy Tarreau13ef7732018-11-12 07:25:28 +0100233/* total number of dropped logs */
234unsigned int dropped_logs = 0;
235
Dragan Dosen1322d092015-09-22 16:05:32 +0200236/* This is a global syslog header, common to all outgoing messages in
237 * RFC3164 format. It begins with time-based part and is updated by
238 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200239 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200240THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200241THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200242
Dragan Dosen1322d092015-09-22 16:05:32 +0200243/* This is a global syslog header for messages in RFC5424 format. It is
244 * updated by update_log_hdr_rfc5424().
245 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200246THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200247THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200248
Dragan Dosen59cee972015-09-19 22:09:02 +0200249/* This is a global syslog message buffer, common to all outgoing
250 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100251 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200252THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100253
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200254/* A global syslog message buffer, common to all RFC5424 syslog messages.
255 * Currently, it is used for generating the structured-data part.
256 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200257THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200258
Christopher Fauletd4696382017-10-24 11:44:05 +0200259/* A global buffer used to store all startup alerts/warnings. It will then be
260 * retrieve on the CLI. */
Willy Tarreau869efd52019-11-15 15:16:57 +0100261static struct ring *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200262
William Lallemand723b73a2012-02-08 16:37:49 +0100263struct logformat_var_args {
264 char *name;
265 int mask;
266};
267
268struct logformat_var_args var_args_list[] = {
269// global
270 { "M", LOG_OPT_MANDATORY },
271 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200272 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100273 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100274 { 0, 0 }
275};
276
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200277/* return the name of the directive used in the current proxy for which we're
278 * currently parsing a header, when it is known.
279 */
280static inline const char *fmt_directive(const struct proxy *curproxy)
281{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100282 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200283 case ARGC_ACL:
284 return "acl";
285 case ARGC_STK:
286 return "stick";
287 case ARGC_TRK:
288 return "track-sc";
289 case ARGC_LOG:
290 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200291 case ARGC_LOGSD:
292 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100293 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100294 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100295 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100296 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200297 case ARGC_UIF:
298 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100299 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200300 return "redirect";
301 case ARGC_CAP:
302 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200303 case ARGC_SRV:
304 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200305 case ARGC_SPOE:
306 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100307 case ARGC_UBK:
308 return "use_backend";
Christopher Faulet3b967c12020-05-15 15:47:44 +0200309 case ARGC_HERR:
310 return "http-error";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100311 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200312 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100313 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200314}
315
William Lallemand723b73a2012-02-08 16:37:49 +0100316/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100317 * callback used to configure addr source retrieval
318 */
319int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
320{
321 curproxy->options2 |= PR_O2_SRC_ADDR;
322
323 return 0;
324}
325
326
327/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100328 * Parse args in a logformat_var. Returns 0 in error
329 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100330 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100331int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100332{
333 int i = 0;
334 int end = 0;
335 int flags = 0; // 1 = + 2 = -
336 char *sp = NULL; // start pointer
337
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100338 if (args == NULL) {
339 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100340 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100341 }
William Lallemand723b73a2012-02-08 16:37:49 +0100342
343 while (1) {
344 if (*args == '\0')
345 end = 1;
346
347 if (*args == '+') {
348 // add flag
349 sp = args + 1;
350 flags = 1;
351 }
352 if (*args == '-') {
353 // delete flag
354 sp = args + 1;
355 flags = 2;
356 }
357
358 if (*args == '\0' || *args == ',') {
359 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100360 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100361 if (strcmp(sp, var_args_list[i].name) == 0) {
362 if (flags == 1) {
363 node->options |= var_args_list[i].mask;
364 break;
365 } else if (flags == 2) {
366 node->options &= ~var_args_list[i].mask;
367 break;
368 }
369 }
370 }
371 sp = NULL;
372 if (end)
373 break;
374 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100375 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100376 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100377 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100378}
379
380/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100381 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
382 * must pass the args part in the <arg> pointer with its length in <arg_len>,
383 * and varname with its length in <var> and <var_len> respectively. <arg> is
384 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100385 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100386 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100387int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100388{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100389 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200390 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100391
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100392 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
393 if (strlen(logformat_keywords[j].name) == var_len &&
394 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
395 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200396 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100397 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100398 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200399 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100400 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100401 node->type = logformat_keywords[j].type;
402 node->options = *defoptions;
403 if (arg_len) {
404 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100405 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200406 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100407 }
408 if (node->type == LOG_FMT_GLOBAL) {
409 *defoptions = node->options;
410 free(node->arg);
411 free(node);
412 } else {
413 if (logformat_keywords[j].config_callback &&
414 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200415 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100416 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100417 curproxy->to_log |= logformat_keywords[j].lw;
418 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100419 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100420 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100421 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
422 curproxy->conf.args.file, curproxy->conf.args.line,
423 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100424 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100425 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100426 memprintf(err, "format variable '%s' is reserved for HTTP mode",
427 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200428 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100429 }
William Lallemand723b73a2012-02-08 16:37:49 +0100430 }
431 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100432
433 j = var[var_len];
434 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100435 memprintf(err, "no such format variable '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%'", var);
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100436 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200437
438 error_free:
439 if (node) {
440 free(node->arg);
441 free(node);
442 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100443 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100444}
445
446/*
447 * push to the logformat linked list
448 *
449 * start: start pointer
450 * end: end text pointer
451 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100452 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100453 *
454 * LOG_TEXT: copy chars from start to end excluding end.
455 *
456*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100457int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100458{
459 char *str;
460
Willy Tarreaua3571662012-12-20 21:59:12 +0100461 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200462 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100463 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100464 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100465 return 0;
466 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200467 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100468 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100469 str[end - start] = '\0';
470 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100471 node->type = LOG_FMT_TEXT; // type string
472 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100473 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200474 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100475 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100476 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100477 return 0;
478 }
William Lallemand1d705562012-03-12 12:46:41 +0100479 node->type = LOG_FMT_SEPARATOR;
480 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100481 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100482 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100483}
484
485/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100486 * Parse the sample fetch expression <text> and add a node to <list_format> upon
487 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100488 * should work. The curpx->conf.args.ctx must be set by the caller. If an end pointer
489 * is passed in <endptr>, it will be updated with the pointer to the first character
490 * not part of the sample expression.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100491 *
492 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100493 */
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100494int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err, char **endptr)
Willy Tarreauc8368452012-12-21 00:09:23 +0100495{
496 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200497 struct sample_expr *expr = NULL;
498 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100499 int cmd_arg;
500
501 cmd[0] = text;
502 cmd[1] = "";
503 cmd_arg = 0;
504
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100505 expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args, endptr);
Willy Tarreauc8368452012-12-21 00:09:23 +0100506 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100507 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200508 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100509 }
510
Vincent Bernat02779b62016-04-03 13:48:43 +0200511 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100512 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100513 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200514 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100515 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100516 node->type = LOG_FMT_EXPR;
517 node->expr = expr;
518 node->options = options;
519
520 if (arg_len) {
521 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100522 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200523 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100524 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100525 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100526 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
527
Willy Tarreau434c57c2013-01-08 01:10:24 +0100528 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100529 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
530
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100531 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100532 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
533 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200534 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100535 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100536
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200537 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100538 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100539 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100540
William Lallemand65ad6e12014-01-31 15:08:02 +0100541 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
542 * needed with some sample fetches (eg: ssl*). We always set it for
543 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100544 */
545 curpx->to_log |= LW_XPRT;
Christopher Fauletd2236cd2020-04-06 18:29:14 +0200546 if (curpx->http_needed)
547 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100548 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100549 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200550
551 error_free:
552 release_sample_expr(expr);
553 if (node) {
554 free(node->arg);
555 free(node);
556 }
557 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100558}
559
560/*
William Lallemand723b73a2012-02-08 16:37:49 +0100561 * Parse the log_format string and fill a linked list.
562 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200563 * You can set arguments using { } : %{many arguments}varname.
564 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100565 *
Ilya Shipitsinae40dbc2020-04-04 12:59:53 +0500566 * fmt: the string to parse
William Lallemand1d705562012-03-12 12:46:41 +0100567 * curproxy: the proxy affected
568 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100569 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100570 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100571 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100572 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100573 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100574int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100575{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100576 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100577 char *arg = NULL; /* start pointer for args */
578 char *var = NULL; /* start pointer for vars */
579 int arg_len = 0;
580 int var_len = 0;
581 int cformat; /* current token format */
582 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100583 struct logformat_node *tmplf, *back;
584
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100585 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100586 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100587 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100588 return 0;
589 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200590 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200591
William Lallemand723b73a2012-02-08 16:37:49 +0100592 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100593 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100594 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200595 release_sample_expr(tmplf->expr);
596 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100597 free(tmplf);
598 }
599
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100600 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100601 pformat = cformat;
602
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100603 if (!*str)
604 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100605
Joseph Herlant85b40592018-11-15 12:10:04 -0800606 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100607 * second have all common paths processed at one place. The common paths are the ones
608 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
609 * We use the common LF_INIT state to dispatch to the different final states.
610 */
611 switch (pformat) {
612 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100613 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100614 arg_len = var_len = 0;
615 if (*str == '{') { // optional argument
616 cformat = LF_STARG;
617 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100618 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100619 else if (*str == '[') {
620 cformat = LF_STEXPR;
621 var = str + 1; // store expr in variable name
622 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100623 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100624 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100625 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100626 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100627 else if (*str == '%')
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500628 cformat = LF_TEXT; // convert this character to a literal (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100629 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100630 /* single '%' followed by blank or digit, send them both */
631 cformat = LF_TEXT;
632 pformat = LF_TEXT; /* finally we include the previous char as well */
633 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600634 memprintf(err, "unexpected variable name near '%c' at position %d line : '%s'. Maybe you want to write a single '%%', use the syntax '%%%%'",
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100635 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100636 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100637
638 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100639 else
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500640 cformat = LF_INIT; // handle other cases of literals
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100641 break;
642
643 case LF_STARG: // text immediately following '%{'
644 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100645 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100646 arg_len = str - arg;
647 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100648 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100649 break;
650
651 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100652 if (*str == '[') {
653 cformat = LF_STEXPR;
654 var = str + 1; // store expr in variable name
655 break;
656 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100657 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100658 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100659 var = str;
660 break;
661 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100662 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100663 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100664
Willy Tarreauc8368452012-12-21 00:09:23 +0100665 case LF_STEXPR: // text immediately following '%['
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100666 /* the whole sample expression is parsed at once,
667 * returning the pointer to the first character not
668 * part of the expression, which MUST be the trailing
669 * angle bracket.
670 */
671 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str))
672 goto fail;
673
674 if (*str == ']') {
675 // end of arg, go on with next state
676 cformat = pformat = LF_EDEXPR;
677 sp = str;
678 }
679 else {
680 char c = *str;
681 *str = 0;
Willy Tarreau90807112020-02-25 08:16:33 +0100682 if (isprint((unsigned char)c))
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100683 memprintf(err, "expected ']' after '%s', but found '%c'", var, c);
684 else
685 memprintf(err, "missing ']' after '%s'", var);
Dragan Dosen2866acf2020-06-30 21:16:43 +0200686 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100687 }
688 break;
689
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100690 case LF_VAR: // text part of a variable name
691 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100692 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100693 cformat = LF_INIT; // not variable name anymore
694 break;
695
Willy Tarreauc8368452012-12-21 00:09:23 +0100696 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100697 cformat = LF_INIT;
698 }
699
700 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
701 switch (*str) {
702 case '%': cformat = LF_STARTVAR; break;
703 case ' ': cformat = LF_SEPARATOR; break;
704 case 0 : cformat = LF_END; break;
705 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100706 }
707 }
708
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100709 if (cformat != pformat || pformat == LF_SEPARATOR) {
710 switch (pformat) {
711 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100712 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100713 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100714 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100715 case LF_STEXPR:
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100716 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &sp))
Willy Tarreau51013e82019-12-11 12:05:39 +0100717 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100718 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100719 case LF_TEXT:
720 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100721 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100722 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100723 break;
724 }
725 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100726 }
727 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100728
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100729 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100730 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100731 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100732 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100733 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100734
735 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100736 fail:
737 free(backfmt);
738 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100739}
740
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200741/*
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500742 * Parse the first range of indexes from a string made of a list of comma separated
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200743 * ranges of indexes. Note that an index may be considered as a particular range
744 * with a high limit to the low limit.
745 */
746int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
747{
748 char *end, *p;
749
750 *low = *high = 0;
751
752 p = *arg;
753 end = strchr(p, ',');
754 if (!end)
755 end = p + strlen(p);
756
757 *high = *low = read_uint((const char **)&p, end);
758 if (!*low || (p != end && *p != '-'))
759 goto err;
760
761 if (p == end)
762 goto done;
763
764 p++;
765 *high = read_uint((const char **)&p, end);
766 if (!*high || *high <= *low || p != end)
767 goto err;
768
769 done:
770 if (*end == ',')
771 end++;
772 *arg = end;
773 return 1;
774
775 err:
776 memprintf(err, "wrong sample range '%s'", *arg);
777 return 0;
778}
779
780/*
781 * Returns 1 if the range defined by <low> and <high> overlaps
782 * one of them in <rgs> array of ranges with <sz> the size of this
783 * array, 0 if not.
784 */
785int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
786 unsigned int low, unsigned int high, char **err)
787{
788 size_t i;
789
790 for (i = 0; i < sz; i++) {
791 if ((low >= rgs[i].low && low <= rgs[i].high) ||
792 (high >= rgs[i].low && high <= rgs[i].high)) {
793 memprintf(err, "ranges are overlapping");
794 return 1;
795 }
796 }
797
798 return 0;
799}
800
801int smp_log_range_cmp(const void *a, const void *b)
802{
803 const struct smp_log_range *rg_a = a;
804 const struct smp_log_range *rg_b = b;
805
806 if (rg_a->high < rg_b->low)
807 return -1;
808 else if (rg_a->low > rg_b->high)
809 return 1;
810
811 return 0;
812}
813
814/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200815 * Parse "log" keyword and update <logsrvs> list accordingly.
816 *
817 * When <do_del> is set, it means the "no log" line was parsed, so all log
818 * servers in <logsrvs> are released.
819 *
820 * Otherwise, we try to parse the "log" line. First of all, when the list is not
821 * the global one, we look for the parameter "global". If we find it,
822 * global.logsrvs is copied. Else we parse each arguments.
823 *
824 * The function returns 1 in success case, otherwise, it returns 0 and err is
825 * filled.
826 */
827int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
828{
829 struct sockaddr_storage *sk;
830 struct logsrv *logsrv = NULL;
831 int port1, port2;
832 int cur_arg;
833
834 /*
835 * "no log": delete previous herited or defined syslog
836 * servers.
837 */
838 if (do_del) {
839 struct logsrv *back;
840
841 if (*(args[1]) != 0) {
842 memprintf(err, "'no log' does not expect arguments");
843 goto error;
844 }
845
846 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
847 LIST_DEL(&logsrv->list);
848 free(logsrv);
849 }
850 return 1;
851 }
852
853 /*
854 * "log global": copy global.logrsvs linked list to the end of logsrvs
855 * list. But first, we check (logsrvs != global.logsrvs).
856 */
857 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
858 if (logsrvs == &global.logsrvs) {
859 memprintf(err, "'global' is not supported for a global syslog server");
860 goto error;
861 }
862 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200863 struct logsrv *node;
864
865 list_for_each_entry(node, logsrvs, list) {
866 if (node->ref == logsrv)
867 goto skip_logsrv;
868 }
869
870 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200871 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200872 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200873 LIST_INIT(&node->list);
874 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200875
876 skip_logsrv:
877 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200878 }
879 return 1;
880 }
881
882 /*
883 * "log <address> ...: parse a syslog server line
884 */
885 if (*(args[1]) == 0 || *(args[2]) == 0) {
886 memprintf(err, "expects <address> and <facility> %s as arguments",
887 ((logsrvs == &global.logsrvs) ? "" : "or global"));
888 goto error;
889 }
890
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100891 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
892 if (strcmp(args[1], "stdout") == 0)
893 args[1] = "fd@1";
894 else if (strcmp(args[1], "stderr") == 0)
895 args[1] = "fd@2";
896
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200897 logsrv = calloc(1, sizeof(*logsrv));
898 if (!logsrv) {
899 memprintf(err, "out of memory");
900 goto error;
901 }
902
903 /* skip address for now, it will be parsed at the end */
904 cur_arg = 2;
905
906 /* just after the address, a length may be specified */
907 logsrv->maxlen = MAX_SYSLOG_LEN;
908 if (strcmp(args[cur_arg], "len") == 0) {
909 int len = atoi(args[cur_arg+1]);
910 if (len < 80 || len > 65535) {
911 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
912 args[cur_arg+1]);
913 goto error;
914 }
915 logsrv->maxlen = len;
916 cur_arg += 2;
917 }
918 if (logsrv->maxlen > global.max_syslog_len)
919 global.max_syslog_len = logsrv->maxlen;
920
921 /* after the length, a format may be specified */
922 if (strcmp(args[cur_arg], "format") == 0) {
923 logsrv->format = get_log_format(args[cur_arg+1]);
924 if (logsrv->format < 0) {
925 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
926 goto error;
927 }
928 cur_arg += 2;
929 }
930
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200931 if (strcmp(args[cur_arg], "sample") == 0) {
932 unsigned low, high;
933 char *p, *beg, *end, *smp_sz_str;
934 struct smp_log_range *smp_rgs = NULL;
935 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
936
937 p = args[cur_arg+1];
938 smp_sz_str = strchr(p, ':');
939 if (!smp_sz_str) {
940 memprintf(err, "Missing sample size");
941 goto error;
942 }
943
944 *smp_sz_str++ = '\0';
945
946 end = p + strlen(p);
947
948 while (p != end) {
949 if (!get_logsrv_smp_range(&low, &high, &p, err))
950 goto error;
951
952 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
953 goto error;
954
955 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
956 if (!smp_rgs) {
957 memprintf(err, "out of memory error");
958 goto error;
959 }
960
961 smp_rgs[smp_rgs_sz].low = low;
962 smp_rgs[smp_rgs_sz].high = high;
963 smp_rgs[smp_rgs_sz].sz = high - low + 1;
964 smp_rgs[smp_rgs_sz].curr_idx = 0;
965 if (smp_rgs[smp_rgs_sz].high > smp_sz)
966 smp_sz = smp_rgs[smp_rgs_sz].high;
967 smp_rgs_sz++;
968 }
969
Tim Duesterhus21648002019-06-23 22:10:10 +0200970 if (smp_rgs == NULL) {
971 memprintf(err, "no sampling ranges given");
972 goto error;
973 }
974
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200975 beg = smp_sz_str;
976 end = beg + strlen(beg);
977 new_smp_sz = read_uint((const char **)&beg, end);
978 if (!new_smp_sz || beg != end) {
979 memprintf(err, "wrong sample size '%s' for sample range '%s'",
980 smp_sz_str, args[cur_arg+1]);
981 goto error;
982 }
983
984 if (new_smp_sz < smp_sz) {
985 memprintf(err, "sample size %zu should be greater or equal to "
986 "%zu the maximum of the high ranges limits",
987 new_smp_sz, smp_sz);
988 goto error;
989 }
990 smp_sz = new_smp_sz;
991
992 /* Let's order <smp_rgs> array. */
993 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
994
995 logsrv->lb.smp_rgs = smp_rgs;
996 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
997 logsrv->lb.smp_sz = smp_sz;
998
999 cur_arg += 2;
1000 }
Frédéric Lécailled803e472019-04-25 07:42:09 +02001001 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001002 /* parse the facility */
1003 logsrv->facility = get_log_facility(args[cur_arg]);
1004 if (logsrv->facility < 0) {
1005 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
1006 goto error;
1007 }
1008 cur_arg++;
1009
1010 /* parse the max syslog level (default: debug) */
1011 logsrv->level = 7;
1012 if (*(args[cur_arg])) {
1013 logsrv->level = get_log_level(args[cur_arg]);
1014 if (logsrv->level < 0) {
1015 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
1016 goto error;
1017 }
1018 cur_arg++;
1019 }
1020
1021 /* parse the limit syslog level (default: emerg) */
1022 logsrv->minlvl = 0;
1023 if (*(args[cur_arg])) {
1024 logsrv->minlvl = get_log_level(args[cur_arg]);
1025 if (logsrv->minlvl < 0) {
1026 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
1027 goto error;
1028 }
1029 cur_arg++;
1030 }
1031
1032 /* Too many args */
1033 if (*(args[cur_arg])) {
1034 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1035 goto error;
1036 }
1037
1038 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001039 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001040 if (strncmp(args[1], "ring@", 5) == 0) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001041 logsrv->addr.ss_family = AF_UNSPEC;
1042 logsrv->type = LOG_TARGET_BUFFER;
Emeric Brun99c453d2020-05-25 15:01:04 +02001043 logsrv->sink = NULL;
1044 logsrv->ring_name = strdup(args[1] + 5);
Willy Tarreauc046d162019-08-30 15:24:59 +02001045 goto done;
1046 }
1047
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001048 if (strncmp(args[1], "fd@", 3) == 0)
1049 logsrv->type = LOG_TARGET_FD;
1050
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001051 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1052 if (!sk)
1053 goto error;
1054 logsrv->addr = *sk;
1055
1056 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1057 if (port1 != port2) {
1058 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1059 goto error;
1060 }
1061 logsrv->addr = *sk;
1062 if (!port1)
1063 set_host_port(&logsrv->addr, SYSLOG_PORT);
1064 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001065 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001066 LIST_ADDQ(logsrvs, &logsrv->list);
1067 return 1;
1068
1069 error:
1070 free(logsrv);
1071 return 0;
1072}
1073
1074
Christopher Fauletd4696382017-10-24 11:44:05 +02001075/* Generic function to display messages prefixed by a label */
1076static void print_message(const char *label, const char *fmt, va_list argp)
1077{
1078 struct tm tm;
1079 char *head, *msg;
1080
1081 head = msg = NULL;
1082
1083 get_localtime(date.tv_sec, &tm);
1084 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1085 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1086 memvprintf(&msg, fmt, argp);
1087
Willy Tarreau869efd52019-11-15 15:16:57 +01001088 if (global.mode & MODE_STARTING) {
1089 if (unlikely(!startup_logs))
1090 startup_logs = ring_new(STARTUP_LOG_SIZE);
1091
1092 if (likely(startup_logs)) {
1093 struct ist m[2];
1094
1095 m[0] = ist(head);
1096 m[1] = ist(msg);
1097 /* trim the trailing '\n' */
1098 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1099 m[1].len--;
1100 ring_write(startup_logs, ~0, 0, 0, m, 2);
1101 }
1102 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001103
1104 fprintf(stderr, "%s%s", head, msg);
1105 fflush(stderr);
1106
1107 free(head);
1108 free(msg);
1109}
1110
Willy Tarreaubaaee002006-06-26 02:48:02 +02001111/*
1112 * Displays the message on stderr with the date and pid. Overrides the quiet
1113 * mode during startup.
1114 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001115void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001116{
1117 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001118
1119 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Willy Tarreaubb869862020-04-16 10:52:41 +02001120 if (!(warned & WARN_EXEC_PATH)) {
1121 const char *path = get_exec_path();
1122
1123 warned |= WARN_EXEC_PATH;
1124 ha_notice("haproxy version is %s\n", haproxy_version);
1125 if (path)
1126 ha_notice("path to executable is %s\n", path);
1127 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001128 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001129 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001130 va_end(argp);
1131 }
1132}
1133
1134
1135/*
1136 * Displays the message on stderr with the date and pid.
1137 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001138void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001139{
1140 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001141
Willy Tarreaubebd2122020-04-15 16:06:11 +02001142 warned |= WARN_ANY;
1143
Willy Tarreaubaaee002006-06-26 02:48:02 +02001144 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1145 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001146 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001147 va_end(argp);
1148 }
1149}
1150
1151/*
William Lallemand9c56a222018-11-21 18:04:52 +01001152 * Displays the message on stderr with the date and pid.
1153 */
1154void ha_notice(const char *fmt, ...)
1155{
1156 va_list argp;
1157
1158 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1159 va_start(argp, fmt);
1160 print_message("NOTICE", fmt, argp);
1161 va_end(argp);
1162 }
1163}
1164
1165/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001166 * Displays the message on <out> only if quiet mode is not set.
1167 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001168void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001169{
1170 va_list argp;
1171
1172 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1173 va_start(argp, fmt);
1174 vfprintf(out, fmt, argp);
1175 fflush(out);
1176 va_end(argp);
1177 }
1178}
1179
1180/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001181 * returns log format for <fmt> or -1 if not found.
1182 */
1183int get_log_format(const char *fmt)
1184{
1185 int format;
1186
1187 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001188 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001189 format--;
1190
1191 return format;
1192}
1193
1194/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001195 * returns log level for <lev> or -1 if not found.
1196 */
1197int get_log_level(const char *lev)
1198{
1199 int level;
1200
1201 level = NB_LOG_LEVELS - 1;
1202 while (level >= 0 && strcmp(log_levels[level], lev))
1203 level--;
1204
1205 return level;
1206}
1207
Willy Tarreaubaaee002006-06-26 02:48:02 +02001208/*
1209 * returns log facility for <fac> or -1 if not found.
1210 */
1211int get_log_facility(const char *fac)
1212{
1213 int facility;
1214
1215 facility = NB_LOG_FACILITIES - 1;
1216 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1217 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001218
Willy Tarreaubaaee002006-06-26 02:48:02 +02001219 return facility;
1220}
1221
William Lallemanda1cc3812012-02-08 16:38:44 +01001222/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001223 * Encode the string.
1224 *
1225 * When using the +E log format option, it will try to escape '"\]'
1226 * characters with '\' as prefix. The same prefix should not be used as
1227 * <escape>.
1228 */
1229static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001230 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001231 const char *string,
1232 struct logformat_node *node)
1233{
1234 if (node->options & LOG_OPT_ESC) {
1235 if (start < stop) {
1236 stop--; /* reserve one byte for the final '\0' */
1237 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001238 if (!ha_bit_test((unsigned char)(*string), map)) {
1239 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001240 *start++ = *string;
1241 else {
1242 if (start + 2 >= stop)
1243 break;
1244 *start++ = '\\';
1245 *start++ = *string;
1246 }
1247 }
1248 else {
1249 if (start + 3 >= stop)
1250 break;
1251 *start++ = escape;
1252 *start++ = hextab[(*string >> 4) & 15];
1253 *start++ = hextab[*string & 15];
1254 }
1255 string++;
1256 }
1257 *start = '\0';
1258 }
1259 }
1260 else {
1261 return encode_string(start, stop, escape, map, string);
1262 }
1263
1264 return start;
1265}
1266
1267/*
1268 * Encode the chunk.
1269 *
1270 * When using the +E log format option, it will try to escape '"\]'
1271 * characters with '\' as prefix. The same prefix should not be used as
1272 * <escape>.
1273 */
1274static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001275 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001276 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001277 struct logformat_node *node)
1278{
1279 char *str, *end;
1280
1281 if (node->options & LOG_OPT_ESC) {
1282 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001283 str = chunk->area;
1284 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001285
1286 stop--; /* reserve one byte for the final '\0' */
1287 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001288 if (!ha_bit_test((unsigned char)(*str), map)) {
1289 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001290 *start++ = *str;
1291 else {
1292 if (start + 2 >= stop)
1293 break;
1294 *start++ = '\\';
1295 *start++ = *str;
1296 }
1297 }
1298 else {
1299 if (start + 3 >= stop)
1300 break;
1301 *start++ = escape;
1302 *start++ = hextab[(*str >> 4) & 15];
1303 *start++ = hextab[*str & 15];
1304 }
1305 str++;
1306 }
1307 *start = '\0';
1308 }
1309 }
1310 else {
1311 return encode_chunk(start, stop, escape, map, chunk);
1312 }
1313
1314 return start;
1315}
1316
1317/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001318 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001319 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001320 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001321 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001322 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001323char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const struct logformat_node *node)
William Lallemanda1cc3812012-02-08 16:38:44 +01001324{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001325 if (size < 2)
1326 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001327
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001328 if (node->options & LOG_OPT_QUOTE) {
1329 *(dst++) = '"';
1330 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001331 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001332
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001333 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001334 if (++len > size)
1335 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001336 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001337 char *ret;
1338
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001339 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001340 if (ret == NULL || *ret != '\0')
1341 return NULL;
1342 len = ret - dst;
1343 }
1344 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001345 len = strlcpy2(dst, src, len);
1346 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001347
1348 size -= len;
1349 dst += len;
1350 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001351 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1352 if (size < 2)
1353 return NULL;
1354 *(dst++) = '-';
1355 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001356
1357 if (node->options & LOG_OPT_QUOTE) {
1358 if (size < 2)
1359 return NULL;
1360 *(dst++) = '"';
1361 }
1362
1363 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001364 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001365}
1366
Willy Tarreau26ffa852018-09-05 15:23:10 +02001367static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001368{
1369 return lf_text_len(dst, src, size, size, node);
1370}
1371
William Lallemand5f232402012-04-05 18:02:55 +02001372/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001373 * Write a IP address to the log string
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001374 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001375 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001376char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001377{
1378 char *ret = dst;
1379 int iret;
1380 char pn[INET6_ADDRSTRLEN];
1381
1382 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001383 unsigned char *addr = NULL;
1384 switch (sockaddr->sa_family) {
1385 case AF_INET:
1386 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1387 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1388 break;
1389 case AF_INET6:
1390 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1391 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1392 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1393 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1394 break;
1395 default:
1396 return NULL;
1397 }
William Lallemand5f232402012-04-05 18:02:55 +02001398 if (iret < 0 || iret > size)
1399 return NULL;
1400 ret += iret;
1401 } else {
1402 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1403 ret = lf_text(dst, pn, size, node);
1404 if (ret == NULL)
1405 return NULL;
1406 }
1407 return ret;
1408}
1409
1410/*
1411 * Write a port to the log
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001412 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001413 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001414char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001415{
1416 char *ret = dst;
1417 int iret;
1418
1419 if (node->options & LOG_OPT_HEXA) {
1420 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1421 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1422 if (iret < 0 || iret > size)
1423 return NULL;
1424 ret += iret;
1425 } else {
1426 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1427 if (ret == NULL)
1428 return NULL;
1429 }
1430 return ret;
1431}
1432
Dragan Dosen1322d092015-09-22 16:05:32 +02001433/* Re-generate time-based part of the syslog header in RFC3164 format at
1434 * the beginning of logheader once a second and return the pointer to the
1435 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001436 */
Emeric Brunbd163812020-05-06 14:33:46 +02001437char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001438{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001439 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001440 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001441 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001442
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001443 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001444 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001445 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001446 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001447
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001448 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001449 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001450
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001451 if (unlikely(global.log_send_hostname != host.area)) {
1452 host.area = global.log_send_hostname;
1453 host.data = host.area ? strlen(host.area) : 0;
1454 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001455 }
1456
Dragan Dosen59cee972015-09-19 22:09:02 +02001457 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001458 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001459 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001460 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001461 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001462 /* WARNING: depending upon implementations, snprintf may return
1463 * either -1 or the number of bytes that would be needed to store
1464 * the total message. In both cases, we must adjust it.
1465 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001466 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1467 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001468
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001469 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001470 }
1471
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001472 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001473
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001474 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001475}
1476
Dragan Dosen1322d092015-09-22 16:05:32 +02001477/* Re-generate time-based part of the syslog header in RFC5424 format at
1478 * the beginning of logheader_rfc5424 once a second and return the pointer
1479 * to the first character after it.
1480 */
Emeric Brunbd163812020-05-06 14:33:46 +02001481char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001482{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001483 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001484 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001485
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001486 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001487 /* this string is rebuild only once a second */
1488 struct tm tm;
1489 int hdr_len;
1490
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001491 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001492 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001493 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001494
1495 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001496 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001497 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001498 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001499 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001500 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001501 /* WARNING: depending upon implementations, snprintf may return
1502 * either -1 or the number of bytes that would be needed to store
1503 * the total message. In both cases, we must adjust it.
1504 */
1505 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1506 hdr_len = global.max_syslog_len;
1507
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001508 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001509 }
1510
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001511 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001512
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001513 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001514}
1515
William Lallemand2a4a44f2012-02-06 16:00:33 +01001516/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001517 * This function sends the syslog message using a printf format string. It
1518 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001519 */
1520void send_log(struct proxy *p, int level, const char *format, ...)
1521{
1522 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001523 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001524
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001525 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001526 return;
1527
William Lallemand2a4a44f2012-02-06 16:00:33 +01001528 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001529 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001530 if (data_len < 0 || data_len > global.max_syslog_len)
1531 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001532 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001533
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001534 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1535 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001536}
1537
1538/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001539 * This function sends a syslog message to <logsrv>.
1540 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1541 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1542 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001543 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001544 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001545 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001546static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1547 int level, char *message, size_t size, char *sd, size_t sd_size,
1548 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001549{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001550 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1551 static THREAD_LOCAL struct msghdr msghdr = {
1552 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001553 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1554 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001555 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1556 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1557 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001558 time_t time = date.tv_sec;
Emeric Brune709e1e2020-05-06 17:23:59 +02001559 char *hdr, *hdr_ptr = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +02001560 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001561 int fac_level;
1562 int *plogfd;
1563 char *pid_sep1 = "", *pid_sep2 = "";
1564 char logheader_short[3];
1565 int sent;
1566 int maxlen;
1567 int hdr_max = 0;
1568 int tag_max = 0;
1569 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001570 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001571 int pid_sep2_max = 0;
1572 int sd_max = 0;
1573 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001574
1575 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001576
1577 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001578
Emeric Brunfa9d7802020-05-28 14:21:33 +02001579 /* historically some messages used to already contain the trailing LF
1580 * or Zero. Let's remove all trailing LF or Zero
1581 */
1582 while (size && ((dataptr[size-1] == '\n' || (dataptr[size-1] == 0))))
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001583 size--;
1584
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001585 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001586 /* the socket's address is a file descriptor */
1587 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001588 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001589 else if (logsrv->type == LOG_TARGET_BUFFER) {
1590 plogfd = NULL;
Emeric Brune709e1e2020-05-06 17:23:59 +02001591 goto send;
Willy Tarreauc046d162019-08-30 15:24:59 +02001592 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001593 else if (logsrv->addr.ss_family == AF_UNIX)
1594 plogfd = &logfdunix;
1595 else
1596 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001597
Willy Tarreauc046d162019-08-30 15:24:59 +02001598 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001599 /* socket not successfully initialized yet */
1600 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1601 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1602 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001603
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001604 if (!once) {
1605 once = 1; /* note: no need for atomic ops here */
1606 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1607 nblogger, strerror(errno), errno);
1608 }
1609 return;
1610 } else {
1611 /* we don't want to receive anything on this socket */
1612 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1613 /* does nothing under Linux, maybe needed for others */
1614 shutdown(*plogfd, SHUT_RD);
1615 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1616 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001617 }
1618
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001619 switch (logsrv->format) {
1620 case LOG_FORMAT_RFC3164:
1621 hdr = logheader;
1622 hdr_ptr = update_log_hdr(time);
1623 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001624
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001625 case LOG_FORMAT_RFC5424:
1626 hdr = logheader_rfc5424;
1627 hdr_ptr = update_log_hdr_rfc5424(time);
1628 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1629 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001630
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001631 case LOG_FORMAT_SHORT:
1632 /* all fields are known, skip the header generation */
1633 hdr = logheader_short;
1634 hdr[0] = '<';
1635 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1636 hdr[2] = '>';
1637 hdr_ptr = hdr;
1638 hdr_max = 3;
1639 maxlen = logsrv->maxlen - hdr_max;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001640 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001641 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001642
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001643 case LOG_FORMAT_RAW:
1644 /* all fields are known, skip the header generation */
1645 hdr_ptr = hdr = "";
1646 hdr_max = 0;
1647 maxlen = logsrv->maxlen;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001648 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001649 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001650
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001651 default:
1652 return; /* must never happen */
1653 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001654
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001655 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001656
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001657 /* For each target, we may have a different facility.
1658 * We can also have a different log level for each message.
1659 * This induces variations in the message header length.
1660 * Since we don't want to recompute it each time, nor copy it every
1661 * time, we only change the facility in the pre-computed header,
1662 * and we change the pointer to the header accordingly.
1663 */
1664 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1665 hdr_ptr = hdr + 3; /* last digit of the log level */
1666 do {
1667 *hdr_ptr = '0' + fac_level % 10;
1668 fac_level /= 10;
1669 hdr_ptr--;
1670 } while (fac_level && hdr_ptr > hdr);
1671 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001672
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001673 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001674
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001675 /* time-based header */
1676 if (unlikely(hdr_size >= logsrv->maxlen)) {
1677 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1678 sd_max = 0;
1679 goto send;
1680 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001681
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001682 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001683
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001684 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001685 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001686 if (unlikely(tag_max >= maxlen)) {
1687 tag_max = maxlen - 1;
1688 sd_max = 0;
1689 goto send;
1690 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001691
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001692 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001693
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001694 /* first pid separator */
1695 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1696 if (unlikely(pid_sep1_max >= maxlen)) {
1697 pid_sep1_max = maxlen - 1;
1698 sd_max = 0;
1699 goto send;
1700 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001701
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001702 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1703 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001704
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001705 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001706 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001707 if (unlikely(pid_size >= maxlen)) {
1708 pid_size = maxlen - 1;
1709 sd_max = 0;
1710 goto send;
1711 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001712
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001713 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001714
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001715 /* second pid separator */
1716 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1717 if (unlikely(pid_sep2_max >= maxlen)) {
1718 pid_sep2_max = maxlen - 1;
1719 sd_max = 0;
1720 goto send;
1721 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001722
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001723 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1724 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001725
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001726 /* structured-data */
1727 if (sd_max >= maxlen) {
1728 sd_max = maxlen - 1;
1729 goto send;
1730 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001731
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001732 max = MIN(size, maxlen - sd_max - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001733send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001734 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001735 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001736 struct ist msg[7];
1737
Emeric Brune709e1e2020-05-06 17:23:59 +02001738 if (logsrv->type == LOG_TARGET_BUFFER) {
1739 msg[0] = ist2(message, MIN(size, logsrv->maxlen));
1740 msg[1] = ist2(tag_str, tag_size);
1741 msg[2] = ist2(pid_str, pid_size);
1742 msg[3] = ist2(sd, sd_size);
1743 sent = sink_write(logsrv->sink, msg, 1, level, logsrv->facility, &msg[1], &msg[2], &msg[3]);
1744 }
1745 else /* LOG_TARGET_FD */ {
1746 msg[0] = ist2(hdr_ptr, hdr_max);
1747 msg[1] = ist2(tag_str, tag_max);
1748 msg[2] = ist2(pid_sep1, pid_sep1_max);
1749 msg[3] = ist2(pid_str, pid_max);
1750 msg[4] = ist2(pid_sep2, pid_sep2_max);
1751 msg[5] = ist2(sd, sd_max);
1752 msg[6] = ist2(dataptr, max);
Willy Tarreauc046d162019-08-30 15:24:59 +02001753 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Emeric Brune709e1e2020-05-06 17:23:59 +02001754 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001755 }
1756 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001757 iovec[0].iov_base = hdr_ptr;
1758 iovec[0].iov_len = hdr_max;
1759 iovec[1].iov_base = tag_str;
1760 iovec[1].iov_len = tag_max;
1761 iovec[2].iov_base = pid_sep1;
1762 iovec[2].iov_len = pid_sep1_max;
1763 iovec[3].iov_base = pid_str;
1764 iovec[3].iov_len = pid_max;
1765 iovec[4].iov_base = pid_sep2;
1766 iovec[4].iov_len = pid_sep2_max;
1767 iovec[5].iov_base = sd;
1768 iovec[5].iov_len = sd_max;
1769 iovec[6].iov_base = dataptr;
1770 iovec[6].iov_len = max;
1771 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1772 iovec[7].iov_len = 1;
1773
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001774 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1775 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001776
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001777 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1778 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001779
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001780 if (sent < 0) {
1781 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001782
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001783 if (errno == EAGAIN)
1784 _HA_ATOMIC_ADD(&dropped_logs, 1);
1785 else if (!once) {
1786 once = 1; /* note: no need for atomic ops here */
1787 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1788 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001789 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001790 }
1791}
Dragan Dosen59cee972015-09-19 22:09:02 +02001792
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001793/*
1794 * This function sends a syslog message.
1795 * It doesn't care about errors nor does it report them.
1796 * The arguments <sd> and <sd_size> are used for the structured-data part
1797 * in RFC5424 formatted syslog messages.
1798 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001799void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1800 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001801{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001802 struct logsrv *logsrv;
1803 int nblogger;
1804 static THREAD_LOCAL int curr_pid;
1805 static THREAD_LOCAL char pidstr[100];
1806 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001807
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001808 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001809 if (!LIST_ISEMPTY(&global.logsrvs)) {
1810 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001811 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001812 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001813 if (!tag || !tag->area)
1814 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001815
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001816 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001817 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001818
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001819 if (unlikely(curr_pid != getpid())) {
1820 curr_pid = getpid();
1821 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1822 chunk_initstr(&pid, pidstr);
1823 }
1824
1825 /* Send log messages to syslog server. */
1826 nblogger = 0;
1827 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001828 static THREAD_LOCAL int in_range = 1;
1829
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001830 /* we can filter the level of the messages that are sent to each logger */
1831 if (level > logsrv->level)
1832 continue;
1833
Frédéric Lécailled803e472019-04-25 07:42:09 +02001834 if (logsrv->lb.smp_rgs) {
1835 struct smp_log_range *curr_rg;
1836
1837 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1838 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1839 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1840 if (in_range) {
1841 /* Let's consume this range. */
1842 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1843 if (!curr_rg->curr_idx) {
1844 /* If consumed, let's select the next range. */
1845 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1846 }
1847 }
1848 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1849 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1850 }
1851 if (in_range)
1852 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1853 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001854 }
1855}
1856
1857
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001858const char sess_cookie[8] = "NIDVEOU7"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie, Expired cookie, Old cookie, Unused, unknown */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001859const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1860 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1861 Set-cookie Updated, unknown, unknown */
1862
William Lallemand1d705562012-03-12 12:46:41 +01001863/*
1864 * try to write a character if there is enough space, or goto out
1865 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001866#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001867 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001868 *(tmplog++) = (x); \
1869 } else { \
1870 goto out; \
1871 } \
1872 } while(0)
1873
Dragan Dosen835b9212016-02-12 13:23:03 +01001874
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001875/* Initializes some log data at boot */
1876static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001877{
1878 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001879 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001880
1881 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1882 * inside PARAM-VALUE should be escaped with '\' as prefix.
1883 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1884 * details.
1885 */
1886 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1887
1888 tmp = "\"\\]";
1889 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001890 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001891 tmp++;
1892 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001893
1894 /* initialize the log header encoding map : '{|}"#' should be encoded with
1895 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1896 * URL encoding only requires '"', '#' to be encoded as well as non-
1897 * printable characters above.
1898 */
1899 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1900 memset(url_encode_map, 0, sizeof(url_encode_map));
1901 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001902 ha_bit_set(i, hdr_encode_map);
1903 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001904 }
1905 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001906 ha_bit_set(i, hdr_encode_map);
1907 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001908 }
1909
1910 tmp = "\"#{|}";
1911 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001912 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001913 tmp++;
1914 }
1915
1916 tmp = "\"#";
1917 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001918 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001919 tmp++;
1920 }
1921
1922 /* initialize the http header encoding map. The draft httpbis define the
1923 * header content as:
1924 *
1925 * HTTP-message = start-line
1926 * *( header-field CRLF )
1927 * CRLF
1928 * [ message-body ]
1929 * header-field = field-name ":" OWS field-value OWS
1930 * field-value = *( field-content / obs-fold )
1931 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1932 * obs-fold = CRLF 1*( SP / HTAB )
1933 * field-vchar = VCHAR / obs-text
1934 * VCHAR = %x21-7E
1935 * obs-text = %x80-FF
1936 *
1937 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1938 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001939 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001940 */
1941 memset(http_encode_map, 0, sizeof(http_encode_map));
1942 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001943 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001944 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001945 ha_bit_set(i, http_encode_map);
1946 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001947}
William Lallemand1d705562012-03-12 12:46:41 +01001948
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001949INITCALL0(STG_PREPARE, init_log);
1950
Christopher Faulet0132d062017-07-26 15:33:35 +02001951/* Initialize log buffers used for syslog messages */
1952int init_log_buffers()
1953{
1954 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001955 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001956 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001957 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001958 logline = my_realloc2(logline, global.max_syslog_len + 1);
1959 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1960 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1961 return 0;
1962 return 1;
1963}
1964
1965/* Deinitialize log buffers used for syslog messages */
1966void deinit_log_buffers()
1967{
1968 free(logheader);
1969 free(logheader_rfc5424);
1970 free(logline);
1971 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001972 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001973 logheader = NULL;
1974 logheader_rfc5424 = NULL;
1975 logline = NULL;
1976 logline_rfc5424 = NULL;
1977}
1978
Willy Tarreaudf974472012-12-28 02:44:01 +01001979/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1980 * <maxsize> characters. Returns the size of the output string in characters,
1981 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001982 * is not zero. It requires a valid session and optionally a stream. If the
1983 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001984 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001985int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t maxsize, struct list *list_format)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001986{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001987 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001988 struct proxy *be;
1989 struct http_txn *txn;
1990 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001991 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001992 unsigned int s_flags;
1993 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001994 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001995 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001996 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001997 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001998 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001999 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002000 int t_request;
2001 int hdr;
2002 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002003 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01002004 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01002005 char *ret;
2006 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002007 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002008 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002009 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002010
William Lallemandbddd4fd2012-02-27 11:23:10 +01002011 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002012
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002013 if (likely(s)) {
2014 be = s->be;
2015 txn = s->txn;
2016 be_conn = cs_conn(objt_cs(s->si[1].end));
2017 s_flags = s->flags;
2018 uniq_id = s->uniq_id;
2019 logs = &s->logs;
2020 } else {
2021 /* we have no stream so we first need to initialize a few
2022 * things that are needed later. We do increment the request
2023 * ID so that it's uniquely assigned to this request just as
2024 * if the request had reached the point of being processed.
2025 * A request error is reported as it's the only element we have
2026 * here and which justifies emitting such a log.
2027 */
2028 be = fe;
2029 txn = NULL;
2030 be_conn = NULL;
2031 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002032 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002033
2034 /* prepare a valid log structure */
2035 tmp_strm_log.tv_accept = sess->tv_accept;
2036 tmp_strm_log.accept_date = sess->accept_date;
2037 tmp_strm_log.t_handshake = sess->t_handshake;
2038 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
2039 tv_zero(&tmp_strm_log.tv_request);
2040 tmp_strm_log.t_queue = -1;
2041 tmp_strm_log.t_connect = -1;
2042 tmp_strm_log.t_data = -1;
2043 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2044 tmp_strm_log.bytes_in = 0;
2045 tmp_strm_log.bytes_out = 0;
2046 tmp_strm_log.prx_queue_pos = 0;
2047 tmp_strm_log.srv_queue_pos = 0;
2048
2049 logs = &tmp_strm_log;
2050 }
2051
William Lallemandbddd4fd2012-02-27 11:23:10 +01002052 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002053 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2054 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002055
William Lallemand1d705562012-03-12 12:46:41 +01002056 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002057
William Lallemandbddd4fd2012-02-27 11:23:10 +01002058 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002059 if (LIST_ISEMPTY(list_format))
2060 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002061
William Lallemand1d705562012-03-12 12:46:41 +01002062 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002063 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002064 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002065 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002066 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002067
Willy Tarreauc8368452012-12-21 00:09:23 +01002068 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002069 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002070 if (!last_isspace) {
2071 LOGCHAR(' ');
2072 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002073 }
2074 break;
2075
William Lallemand1d705562012-03-12 12:46:41 +01002076 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002077 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002078 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002079 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002080 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002081 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002082 last_isspace = 0;
2083 break;
2084
Willy Tarreauc8368452012-12-21 00:09:23 +01002085 case LOG_FMT_EXPR: // sample expression, may be request or response
2086 key = NULL;
Christopher Faulet5f940702020-04-06 10:40:02 +02002087 if (tmp->options & LOG_OPT_REQ_CAP)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002088 key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
Christopher Faulet5f940702020-04-06 10:40:02 +02002089 if (!key && (tmp->options & LOG_OPT_RES_CAP))
Adis Nezirovic79beb242015-07-06 15:41:02 +02002090 key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002091 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002092 ret = lf_encode_chunk(tmplog, dst + maxsize,
2093 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002094 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002095 ret = lf_text_len(tmplog,
2096 key ? key->data.u.str.area : NULL,
2097 key ? key->data.u.str.data : 0,
2098 dst + maxsize - tmplog,
2099 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002100 if (ret == 0)
2101 goto out;
2102 tmplog = ret;
2103 last_isspace = 0;
2104 break;
2105
Willy Tarreau2beef582012-12-20 17:22:52 +01002106 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002107 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002108 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002109 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002110 else
2111 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002112 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002113 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002114 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002115 last_isspace = 0;
2116 break;
2117
Willy Tarreau2beef582012-12-20 17:22:52 +01002118 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002119 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002120 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002121 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002122 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002123 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002124 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002125 dst + maxsize - tmplog, tmp);
2126 }
William Lallemand5f232402012-04-05 18:02:55 +02002127 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002128 else
2129 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2130
William Lallemand5f232402012-04-05 18:02:55 +02002131 if (ret == NULL)
2132 goto out;
2133 tmplog = ret;
2134 last_isspace = 0;
2135 break;
2136
Willy Tarreau2beef582012-12-20 17:22:52 +01002137 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002138 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002139 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002140 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002141 }
2142 else
2143 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2144
William Lallemand1d705562012-03-12 12:46:41 +01002145 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002146 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002147 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002148 last_isspace = 0;
2149 break;
2150
Willy Tarreau2beef582012-12-20 17:22:52 +01002151 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002152 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002153 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002154 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002155 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002156 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002157 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002158 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002159 else
2160 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2161
William Lallemand5f232402012-04-05 18:02:55 +02002162 if (ret == NULL)
2163 goto out;
2164 tmplog = ret;
2165 last_isspace = 0;
2166 break;
2167
Willy Tarreau2beef582012-12-20 17:22:52 +01002168 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002169 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002170 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002171 else
2172 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2173
William Lallemand1d705562012-03-12 12:46:41 +01002174 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002175 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002176 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002177 last_isspace = 0;
2178 break;
2179
Willy Tarreau2beef582012-12-20 17:22:52 +01002180 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002181 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002182 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002183 else
2184 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2185
William Lallemand5f232402012-04-05 18:02:55 +02002186 if (ret == NULL)
2187 goto out;
2188 tmplog = ret;
2189 last_isspace = 0;
2190 break;
2191
Willy Tarreau2beef582012-12-20 17:22:52 +01002192 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002193 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002194 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002195 else
2196 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2197
William Lallemand5f232402012-04-05 18:02:55 +02002198 if (ret == NULL)
2199 goto out;
2200 tmplog = ret;
2201 last_isspace = 0;
2202 break;
2203
Willy Tarreau2beef582012-12-20 17:22:52 +01002204 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002205 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002206 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002207 else
2208 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2209
William Lallemand1d705562012-03-12 12:46:41 +01002210 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002211 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002212 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002213 last_isspace = 0;
2214 break;
2215
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002216 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002217 get_localtime(logs->accept_date.tv_sec, &tm);
2218 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002219 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002220 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002221 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002222 last_isspace = 0;
2223 break;
2224
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002225 case LOG_FMT_tr: // %tr = start of request date
2226 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002227 tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002228 get_localtime(tv.tv_sec, &tm);
2229 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2230 if (ret == NULL)
2231 goto out;
2232 tmplog = ret;
2233 last_isspace = 0;
2234 break;
2235
2236 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002237 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002238 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002239 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002240 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002241 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002242 last_isspace = 0;
2243 break;
2244
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002245 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002246 tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002247 get_gmtime(tv.tv_sec, &tm);
2248 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2249 if (ret == NULL)
2250 goto out;
2251 tmplog = ret;
2252 last_isspace = 0;
2253 break;
2254
2255 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002256 get_localtime(logs->accept_date.tv_sec, &tm);
2257 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002258 if (ret == NULL)
2259 goto out;
2260 tmplog = ret;
2261 last_isspace = 0;
2262 break;
2263
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002264 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002265 tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002266 get_localtime(tv.tv_sec, &tm);
2267 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2268 if (ret == NULL)
2269 goto out;
2270 tmplog = ret;
2271 last_isspace = 0;
2272 break;
2273
William Lallemand5f232402012-04-05 18:02:55 +02002274 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002275 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002276 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002277 if (iret < 0 || iret > dst + maxsize - tmplog)
2278 goto out;
2279 last_isspace = 0;
2280 tmplog += iret;
2281 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002282 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002283 if (ret == NULL)
2284 goto out;
2285 tmplog = ret;
2286 last_isspace = 0;
2287 }
2288 break;
2289
William Lallemand1d705562012-03-12 12:46:41 +01002290 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002291 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002292 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002293 if (iret < 0 || iret > dst + maxsize - tmplog)
2294 goto out;
2295 last_isspace = 0;
2296 tmplog += iret;
2297 } else {
2298 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002299 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002300 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002301 tmplog, 4);
2302 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002303 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002304 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002305 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002306 }
2307 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002308
William Lallemand1d705562012-03-12 12:46:41 +01002309 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002310 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002311 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002312 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002313 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002314 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002315 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002316 break;
2317
Willy Tarreau773d65f2012-10-12 14:56:11 +02002318 case LOG_FMT_FRONTEND_XPRT: // %ft
2319 src = fe->id;
2320 if (tmp->options & LOG_OPT_QUOTE)
2321 LOGCHAR('"');
2322 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2323 if (iret == 0)
2324 goto out;
2325 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002326 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002327 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002328 if (tmp->options & LOG_OPT_QUOTE)
2329 LOGCHAR('"');
2330 last_isspace = 0;
2331 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002332#ifdef USE_OPENSSL
2333 case LOG_FMT_SSL_CIPHER: // %sslc
2334 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002335 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002336 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002337 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002338 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002339 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2340 if (ret == NULL)
2341 goto out;
2342 tmplog = ret;
2343 last_isspace = 0;
2344 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002345
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002346 case LOG_FMT_SSL_VERSION: // %sslv
2347 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002348 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002349 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002350 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002351 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002352 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2353 if (ret == NULL)
2354 goto out;
2355 tmplog = ret;
2356 last_isspace = 0;
2357 break;
2358#endif
William Lallemand1d705562012-03-12 12:46:41 +01002359 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002360 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002361 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002362 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002363 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002364 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002365 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002366 break;
2367
William Lallemand1d705562012-03-12 12:46:41 +01002368 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002369 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002370 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002371 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002372 break;
2373 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002374 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002375 break;
2376 default:
2377 src = "<NOSRV>";
2378 break;
2379 }
William Lallemand5f232402012-04-05 18:02:55 +02002380 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002381 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002382 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002383 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002384 last_isspace = 0;
2385 break;
2386
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002387 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002388 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002389 if (ret == NULL)
2390 goto out;
2391 tmplog = ret;
2392 last_isspace = 0;
2393 break;
2394
2395 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002396 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002397 if (ret == NULL)
2398 goto out;
2399 tmplog = ret;
2400 last_isspace = 0;
2401 break;
2402
2403 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002404 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002405 tmplog, dst + maxsize - tmplog);
2406 if (ret == NULL)
2407 goto out;
2408 tmplog = ret;
2409 last_isspace = 0;
2410 break;
2411
2412 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002413 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002414 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002415 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002416 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002417 last_isspace = 0;
2418 break;
2419
William Lallemand1d705562012-03-12 12:46:41 +01002420 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002421 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002422 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002423 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002424 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002425 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002426 last_isspace = 0;
2427 break;
2428
William Lallemand1d705562012-03-12 12:46:41 +01002429 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002430 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002431 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002432 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002433 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002434 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002435 last_isspace = 0;
2436 break;
2437
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002438 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002439 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002440 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002441 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002442 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002443 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002444 last_isspace = 0;
2445 break;
2446
Willy Tarreau27b639d2016-05-17 17:55:27 +02002447 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002448 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002449 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002450 tmplog, dst + maxsize - tmplog);
2451 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002452 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002453 tmplog, dst + maxsize - tmplog);
2454 if (ret == NULL)
2455 goto out;
2456 tmplog = ret;
2457 last_isspace = 0;
2458 break;
2459
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002460 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2461 if (!(fe->to_log & LW_BYTES))
2462 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002463 ret = ltoa_o(logs->t_close - (logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0),
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002464 tmplog, dst + maxsize - tmplog);
2465 if (ret == NULL)
2466 goto out;
2467 tmplog = ret;
2468 last_isspace = 0;
2469 break;
2470
2471 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002472 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002473 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002474 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002475 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002476 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002477 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002478 last_isspace = 0;
2479 break;
2480
Damien Claisse57c8eb92020-04-28 12:09:19 +00002481 case LOG_FMT_TU: // %Tu = total time seen by user = Tt - Ti
2482 if (!(fe->to_log & LW_BYTES))
2483 LOGCHAR('+');
2484 ret = ltoa_o(logs->t_close - (logs->t_idle >= 0 ? logs->t_idle : 0),
2485 tmplog, dst + maxsize - tmplog);
2486 if (ret == NULL)
2487 goto out;
2488 tmplog = ret;
2489 last_isspace = 0;
2490 break;
2491
Willy Tarreau2beef582012-12-20 17:22:52 +01002492 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002493 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002494 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002495 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002496 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002497 last_isspace = 0;
2498 break;
2499
William Lallemand1d705562012-03-12 12:46:41 +01002500 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002501 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002502 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002503 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002504 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002505 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002506 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002507 last_isspace = 0;
2508 break;
2509
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002510 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002511 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002512 if (ret == NULL)
2513 goto out;
2514 tmplog = ret;
2515 last_isspace = 0;
2516 break;
2517
Willy Tarreau2beef582012-12-20 17:22:52 +01002518 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002519 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002520 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002521 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002522 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002523 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002524 last_isspace = 0;
2525 break;
2526
Willy Tarreau2beef582012-12-20 17:22:52 +01002527 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002528 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002529 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002530 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002531 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002532 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002533 last_isspace = 0;
2534 break;
2535
William Lallemand1d705562012-03-12 12:46:41 +01002536 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002537 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2538 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002539 *tmplog = '\0';
2540 last_isspace = 0;
2541 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002542
William Lallemand1d705562012-03-12 12:46:41 +01002543 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002544 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2545 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002546 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2547 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002548 last_isspace = 0;
2549 break;
2550
William Lallemand1d705562012-03-12 12:46:41 +01002551 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002552 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002553 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002554 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002555 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002556 last_isspace = 0;
2557 break;
2558
William Lallemand1d705562012-03-12 12:46:41 +01002559 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002560 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002561 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002562 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002563 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002564 last_isspace = 0;
2565 break;
2566
William Lallemand1d705562012-03-12 12:46:41 +01002567 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002568 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002569 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002570 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002571 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002572 last_isspace = 0;
2573 break;
2574
William Lallemand1d705562012-03-12 12:46:41 +01002575 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002576 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002577 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002578 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002579 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002580 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002581 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002582 last_isspace = 0;
2583 break;
2584
William Lallemand1d705562012-03-12 12:46:41 +01002585 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002586 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002587 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002588 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002589 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002590 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002591 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002592 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002593 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002594 last_isspace = 0;
2595 break;
2596
William Lallemand1d705562012-03-12 12:46:41 +01002597 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002598 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002599 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002600 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002601 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002602 last_isspace = 0;
2603 break;
2604
William Lallemand1d705562012-03-12 12:46:41 +01002605 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002606 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002607 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002608 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002609 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002610 last_isspace = 0;
2611 break;
2612
William Lallemand1d705562012-03-12 12:46:41 +01002613 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002614 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002615 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002616 if (tmp->options & LOG_OPT_QUOTE)
2617 LOGCHAR('"');
2618 LOGCHAR('{');
2619 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2620 if (hdr)
2621 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002622 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002623 ret = lf_encode_string(tmplog, dst + maxsize,
2624 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002625 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002626 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002627 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002628 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002629 }
2630 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002631 if (tmp->options & LOG_OPT_QUOTE)
2632 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002633 last_isspace = 0;
2634 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002635 break;
2636
William Lallemand1d705562012-03-12 12:46:41 +01002637 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002638 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002639 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002640 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2641 if (hdr > 0)
2642 LOGCHAR(' ');
2643 if (tmp->options & LOG_OPT_QUOTE)
2644 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002645 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002646 ret = lf_encode_string(tmplog, dst + maxsize,
2647 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002648 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002649 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002650 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002651 } else if (!(tmp->options & LOG_OPT_QUOTE))
2652 LOGCHAR('-');
2653 if (tmp->options & LOG_OPT_QUOTE)
2654 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002655 last_isspace = 0;
2656 }
2657 }
2658 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002659
William Lallemand1d705562012-03-12 12:46:41 +01002660
2661 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002662 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002663 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002664 if (tmp->options & LOG_OPT_QUOTE)
2665 LOGCHAR('"');
2666 LOGCHAR('{');
2667 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2668 if (hdr)
2669 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002670 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002671 ret = lf_encode_string(tmplog, dst + maxsize,
2672 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002673 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002674 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002675 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002676 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002677 }
2678 LOGCHAR('}');
2679 last_isspace = 0;
2680 if (tmp->options & LOG_OPT_QUOTE)
2681 LOGCHAR('"');
2682 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002683 break;
2684
William Lallemand1d705562012-03-12 12:46:41 +01002685 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002686 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002687 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002688 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2689 if (hdr > 0)
2690 LOGCHAR(' ');
2691 if (tmp->options & LOG_OPT_QUOTE)
2692 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002693 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002694 ret = lf_encode_string(tmplog, dst + maxsize,
2695 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002696 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002697 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002698 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002699 } else if (!(tmp->options & LOG_OPT_QUOTE))
2700 LOGCHAR('-');
2701 if (tmp->options & LOG_OPT_QUOTE)
2702 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002703 last_isspace = 0;
2704 }
2705 }
2706 break;
2707
William Lallemand1d705562012-03-12 12:46:41 +01002708 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002709 /* Request */
2710 if (tmp->options & LOG_OPT_QUOTE)
2711 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002712 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002713 ret = lf_encode_string(tmplog, dst + maxsize,
2714 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002715 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002716 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002717 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002718 if (tmp->options & LOG_OPT_QUOTE)
2719 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002720 last_isspace = 0;
2721 break;
William Lallemand5f232402012-04-05 18:02:55 +02002722
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002723 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002724 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002725
Willy Tarreaub7636d12015-06-17 19:58:02 +02002726 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002727 LOGCHAR('"');
2728
2729 end = uri + strlen(uri);
2730 // look for the first whitespace character
2731 while (uri < end && !HTTP_IS_SPHT(*uri))
2732 uri++;
2733
2734 // keep advancing past multiple spaces
2735 while (uri < end && HTTP_IS_SPHT(*uri)) {
2736 uri++; nspaces++;
2737 }
2738
2739 // look for first space or question mark after url
2740 spc = uri;
2741 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2742 spc++;
2743
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002744 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002745 chunk.area = "<BADREQ>";
2746 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002747 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002748 chunk.area = uri;
2749 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002750 }
2751
Dragan Dosen835b9212016-02-12 13:23:03 +01002752 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002753 if (ret == NULL || *ret != '\0')
2754 goto out;
2755
2756 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002757 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002758 LOGCHAR('"');
2759
2760 last_isspace = 0;
2761 break;
2762
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002763 case LOG_FMT_HTTP_QUERY: // %HQ
2764 if (tmp->options & LOG_OPT_QUOTE)
2765 LOGCHAR('"');
2766
Willy Tarreau57bc8912016-04-25 17:09:40 +02002767 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002768 chunk.area = "<BADREQ>";
2769 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002770 } else {
2771 uri = txn->uri;
2772 end = uri + strlen(uri);
2773 // look for the first question mark
2774 while (uri < end && *uri != '?')
2775 uri++;
2776
2777 qmark = uri;
2778 // look for first space or question mark after url
2779 while (uri < end && !HTTP_IS_SPHT(*uri))
2780 uri++;
2781
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002782 chunk.area = qmark;
2783 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002784 }
2785
Dragan Dosen835b9212016-02-12 13:23:03 +01002786 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002787 if (ret == NULL || *ret != '\0')
2788 goto out;
2789
2790 tmplog = ret;
2791 if (tmp->options & LOG_OPT_QUOTE)
2792 LOGCHAR('"');
2793
2794 last_isspace = 0;
2795 break;
2796
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002797 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002798 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002799
Willy Tarreaub7636d12015-06-17 19:58:02 +02002800 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002801 LOGCHAR('"');
2802
2803 end = uri + strlen(uri);
2804 // look for the first whitespace character
2805 while (uri < end && !HTTP_IS_SPHT(*uri))
2806 uri++;
2807
2808 // keep advancing past multiple spaces
2809 while (uri < end && HTTP_IS_SPHT(*uri)) {
2810 uri++; nspaces++;
2811 }
2812
2813 // look for first space after url
2814 spc = uri;
2815 while (spc < end && !HTTP_IS_SPHT(*spc))
2816 spc++;
2817
Willy Tarreau57bc8912016-04-25 17:09:40 +02002818 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002819 chunk.area = "<BADREQ>";
2820 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002821 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002822 chunk.area = uri;
2823 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002824 }
2825
Dragan Dosen835b9212016-02-12 13:23:03 +01002826 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002827 if (ret == NULL || *ret != '\0')
2828 goto out;
2829
2830 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002831 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002832 LOGCHAR('"');
2833
2834 last_isspace = 0;
2835 break;
2836
2837 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002838 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002839 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002840 LOGCHAR('"');
2841
2842 end = uri + strlen(uri);
2843 // look for the first whitespace character
2844 spc = uri;
2845 while (spc < end && !HTTP_IS_SPHT(*spc))
2846 spc++;
2847
2848 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002849 chunk.area = "<BADREQ>";
2850 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002851 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002852 chunk.area = uri;
2853 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002854 }
2855
Dragan Dosen835b9212016-02-12 13:23:03 +01002856 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002857 if (ret == NULL || *ret != '\0')
2858 goto out;
2859
2860 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002861 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002862 LOGCHAR('"');
2863
2864 last_isspace = 0;
2865 break;
2866
2867 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002868 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002869 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002870 LOGCHAR('"');
2871
2872 end = uri + strlen(uri);
2873 // look for the first whitespace character
2874 while (uri < end && !HTTP_IS_SPHT(*uri))
2875 uri++;
2876
2877 // keep advancing past multiple spaces
2878 while (uri < end && HTTP_IS_SPHT(*uri)) {
2879 uri++; nspaces++;
2880 }
2881
2882 // look for the next whitespace character
2883 while (uri < end && !HTTP_IS_SPHT(*uri))
2884 uri++;
2885
2886 // keep advancing past multiple spaces
2887 while (uri < end && HTTP_IS_SPHT(*uri))
2888 uri++;
2889
Willy Tarreau57bc8912016-04-25 17:09:40 +02002890 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002891 chunk.area = "<BADREQ>";
2892 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002893 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002894 chunk.area = "HTTP/0.9";
2895 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002896 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002897 chunk.area = uri;
2898 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002899 }
2900
Dragan Dosen835b9212016-02-12 13:23:03 +01002901 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002902 if (ret == NULL || *ret != '\0')
2903 goto out;
2904
2905 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002906 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002907 LOGCHAR('"');
2908
2909 last_isspace = 0;
2910 break;
2911
William Lallemand5f232402012-04-05 18:02:55 +02002912 case LOG_FMT_COUNTER: // %rt
2913 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002914 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002915 if (iret < 0 || iret > dst + maxsize - tmplog)
2916 goto out;
2917 last_isspace = 0;
2918 tmplog += iret;
2919 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002920 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002921 if (ret == NULL)
2922 goto out;
2923 tmplog = ret;
2924 last_isspace = 0;
2925 }
2926 break;
2927
Willy Tarreau7346acb2014-08-28 15:03:15 +02002928 case LOG_FMT_LOGCNT: // %lc
2929 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002930 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002931 if (iret < 0 || iret > dst + maxsize - tmplog)
2932 goto out;
2933 last_isspace = 0;
2934 tmplog += iret;
2935 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002936 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002937 if (ret == NULL)
2938 goto out;
2939 tmplog = ret;
2940 last_isspace = 0;
2941 }
2942 break;
2943
William Lallemand5f232402012-04-05 18:02:55 +02002944 case LOG_FMT_HOSTNAME: // %H
2945 src = hostname;
2946 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2947 if (ret == NULL)
2948 goto out;
2949 tmplog = ret;
2950 last_isspace = 0;
2951 break;
2952
2953 case LOG_FMT_PID: // %pid
2954 if (tmp->options & LOG_OPT_HEXA) {
2955 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2956 if (iret < 0 || iret > dst + maxsize - tmplog)
2957 goto out;
2958 last_isspace = 0;
2959 tmplog += iret;
2960 } else {
2961 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2962 if (ret == NULL)
2963 goto out;
2964 tmplog = ret;
2965 last_isspace = 0;
2966 }
2967 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002968
2969 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002970 ret = NULL;
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002971 if (s)
2972 ret = lf_text_len(tmplog, s->unique_id.ptr, s->unique_id.len, maxsize - (tmplog - dst), tmp);
2973 else
2974 ret = lf_text_len(tmplog, NULL, 0, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002975 if (ret == NULL)
2976 goto out;
2977 tmplog = ret;
2978 last_isspace = 0;
2979 break;
2980
William Lallemandbddd4fd2012-02-27 11:23:10 +01002981 }
2982 }
2983
2984out:
William Lallemand1d705562012-03-12 12:46:41 +01002985 /* *tmplog is a unused character */
2986 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002987 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002988
Willy Tarreaubaaee002006-06-26 02:48:02 +02002989}
2990
William Lallemand1d705562012-03-12 12:46:41 +01002991/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002992 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002993 * Will not log if the frontend has no log defined.
2994 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002995void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002996{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002997 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002998 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002999 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01003000
3001 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02003002 err = (s->flags & SF_REDISP) ||
3003 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
3004 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01003005 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02003006 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003007
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003008 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01003009 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003010
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003011 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01003012 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003013
Willy Tarreauabcd5142013-06-11 17:18:02 +02003014 if (s->logs.level) { /* loglevel was overridden */
3015 if (s->logs.level == -1) {
3016 s->logs.logwait = 0; /* logs disabled */
3017 return;
3018 }
3019 level = s->logs.level - 1;
3020 }
3021 else {
3022 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003023 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02003024 level = LOG_ERR;
3025 }
William Lallemand1d705562012-03-12 12:46:41 +01003026
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003027 /* if unique-id was not generated */
Tim Duesterhusa17e6622020-03-05 20:19:02 +01003028 if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Tim Duesterhus2825b4b2020-02-28 15:13:34 +01003029 stream_generate_unique_id(s, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003030 }
3031
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003032 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3033 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
3034 &sess->fe->logformat_sd);
3035 }
3036
Dragan Dosen59cee972015-09-19 22:09:02 +02003037 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01003038 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003039 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003040 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3041 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01003042 s->logs.logwait = 0;
3043 }
3044}
William Lallemandbddd4fd2012-02-27 11:23:10 +01003045
Willy Tarreau53839352018-09-05 19:51:10 +02003046/*
3047 * send a minimalist log for the session. Will not log if the frontend has no
3048 * log defined. It is assumed that this is only used to report anomalies that
3049 * cannot lead to the creation of a regular stream. Because of this the log
3050 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
3051 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003052 * function to report unimportant events. It is safe to call this function with
3053 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02003054 */
3055void sess_log(struct session *sess)
3056{
3057 int size, level;
3058 int sd_size = 0;
3059
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003060 if (!sess)
3061 return;
3062
Willy Tarreau53839352018-09-05 19:51:10 +02003063 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3064 return;
3065
3066 level = LOG_INFO;
3067 if (sess->fe->options2 & PR_O2_LOGERRORS)
3068 level = LOG_ERR;
3069
3070 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3071 sd_size = sess_build_logline(sess, NULL,
3072 logline_rfc5424, global.max_syslog_len,
3073 &sess->fe->logformat_sd);
3074 }
3075
3076 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3077 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003078 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003079 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3080 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003081 }
3082}
3083
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003084void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3085{
3086 va_list argp;
3087 int data_len;
3088
3089 if (level < 0 || format == NULL || logline == NULL)
3090 return;
3091
3092 va_start(argp, format);
3093 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3094 if (data_len < 0 || data_len > global.max_syslog_len)
3095 data_len = global.max_syslog_len;
3096 va_end(argp);
3097
3098 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3099}
3100
Willy Tarreau869efd52019-11-15 15:16:57 +01003101/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3102static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003103{
Willy Tarreau869efd52019-11-15 15:16:57 +01003104 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3105 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003106
Willy Tarreau869efd52019-11-15 15:16:57 +01003107 if (!startup_logs)
3108 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3109
3110 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003111}
3112
3113/* register cli keywords */
3114static struct cli_kw_list cli_kws = {{ },{
3115 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003116 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003117 {{},}
3118}};
3119
Willy Tarreau0108d902018-11-25 19:14:37 +01003120INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3121
Willy Tarreau082b6282019-05-22 14:42:12 +02003122REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3123REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003124
Willy Tarreaubaaee002006-06-26 02:48:02 +02003125/*
3126 * Local variables:
3127 * c-indent-level: 8
3128 * c-basic-offset: 8
3129 * End:
3130 */