blob: 87b12fc38661035fd468bae67ad7bc00421f1a80 [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 Tarreau2dd0d472006-06-29 17:53:05 +020028#include <common/standard.h>
Willy Tarreaufb278672006-10-15 15:38:50 +020029#include <common/time.h>
Willy Tarreaubb869862020-04-16 10:52:41 +020030#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020031
Christopher Fauletc1b730a2017-10-24 12:00:51 +020032#include <types/cli.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020033#include <types/global.h>
William Lallemand723b73a2012-02-08 16:37:49 +010034#include <types/log.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020035
Christopher Fauletc1b730a2017-10-24 12:00:51 +020036#include <proto/applet.h>
37#include <proto/cli.h>
Willy Tarreaud52a7f82019-08-30 14:05:35 +020038#include <proto/fd.h>
William Lallemand5f232402012-04-05 18:02:55 +020039#include <proto/frontend.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020040#include <proto/log.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020041#include <proto/ring.h>
Willy Tarreauc8368452012-12-21 00:09:23 +010042#include <proto/sample.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020043#include <proto/sink.h>
Willy Tarreauc125cef2019-05-10 09:58:43 +020044#include <proto/ssl_sock.h>
Willy Tarreaufb0afa72015-04-03 14:46:27 +020045#include <proto/stream.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010046#include <proto/stream_interface.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020047
Dragan Dosen43885c72015-10-01 13:18:13 +020048struct log_fmt {
49 char *name;
50 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020051 struct buffer sep1; /* first pid separator */
52 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020053 } pid;
54};
55
56static const struct log_fmt log_formats[LOG_FORMATS] = {
57 [LOG_FORMAT_RFC3164] = {
58 .name = "rfc3164",
59 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020060 .sep1 = { .area = "[", .data = 1 },
61 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020062 }
63 },
64 [LOG_FORMAT_RFC5424] = {
65 .name = "rfc5424",
66 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020067 .sep1 = { .area = " ", .data = 1 },
68 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020069 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010070 },
71 [LOG_FORMAT_SHORT] = {
72 .name = "short",
73 .pid = {
74 .sep1 = { .area = "", .data = 0 },
75 .sep2 = { .area = " ", .data = 1 },
76 }
77 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010078 [LOG_FORMAT_RAW] = {
79 .name = "raw",
80 .pid = {
81 .sep1 = { .area = "", .data = 0 },
82 .sep2 = { .area = "", .data = 0 },
83 }
84 },
Dragan Dosen1322d092015-09-22 16:05:32 +020085};
86
Emeric Brunbd163812020-05-06 14:33:46 +020087char *get_format_pid_sep1(int format, size_t *len)
88{
89 *len = log_formats[format].pid.sep1.data;
90 return log_formats[format].pid.sep1.area;
91}
92
93char *get_format_pid_sep2(int format, size_t *len)
94{
95 *len = log_formats[format].pid.sep2.data;
96 return log_formats[format].pid.sep2.area;
97}
98
Dragan Dosen835b9212016-02-12 13:23:03 +010099/*
100 * This map is used with all the FD_* macros to check whether a particular bit
Willy Tarreau1bfd6022019-06-07 11:10:07 +0200101 * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
102 * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
103 * that the byte should be escaped. Be careful to always pass bytes from 0 to
104 * 255 exclusively to the macros.
Dragan Dosen835b9212016-02-12 13:23:03 +0100105 */
Willy Tarreau1bfd6022019-06-07 11:10:07 +0200106long rfc5424_escape_map[(256/8) / sizeof(long)];
107long hdr_encode_map[(256/8) / sizeof(long)];
108long url_encode_map[(256/8) / sizeof(long)];
109long http_encode_map[(256/8) / sizeof(long)];
Dragan Dosen835b9212016-02-12 13:23:03 +0100110
Dragan Dosen835b9212016-02-12 13:23:03 +0100111
Willy Tarreaubaaee002006-06-26 02:48:02 +0200112const char *log_facilities[NB_LOG_FACILITIES] = {
113 "kern", "user", "mail", "daemon",
114 "auth", "syslog", "lpr", "news",
115 "uucp", "cron", "auth2", "ftp",
116 "ntp", "audit", "alert", "cron2",
117 "local0", "local1", "local2", "local3",
118 "local4", "local5", "local6", "local7"
119};
120
Willy Tarreaubaaee002006-06-26 02:48:02 +0200121const char *log_levels[NB_LOG_LEVELS] = {
122 "emerg", "alert", "crit", "err",
123 "warning", "notice", "info", "debug"
124};
125
Willy Tarreau570f2212013-06-10 16:42:09 +0200126const 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 +0200127const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200128
William Lallemand723b73a2012-02-08 16:37:49 +0100129
130/* log_format */
131struct logformat_type {
132 char *name;
133 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100134 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200135 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100136 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100137 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100138};
139
William Lallemandb7ff6a32012-03-02 14:35:21 +0100140int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
141
William Lallemand723b73a2012-02-08 16:37:49 +0100142/* log_format variable names */
143static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200144 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100145
146 /* please keep these lines sorted ! */
147 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
148 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
149 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
150 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +0100151 { "ID", LOG_FMT_UNIQUEID, PR_MODE_TCP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200152 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200153 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200154 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100155 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200156 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
157 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
158 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
159 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
160 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
161 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200162 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100163 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200164 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Damien Claisse57c8eb92020-04-28 12:09:19 +0000165 { "Tu", LOG_FMT_TU, PR_MODE_TCP, LW_BYTES, NULL }, /* Tu = Tt -Ti */
Willy Tarreau2beef582012-12-20 17:22:52 +0100166 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
167 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200168 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100169 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200170 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100171 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
172 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200173 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200174 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
175 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100176 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
177 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200178 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
179 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100180 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200181 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
182 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
183 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
184 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000185 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
186 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000187 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000188 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
189 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200190 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100191 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200192 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100193 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
194 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100195 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100196 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
197 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
198 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
199 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
200 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200201 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
202 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100203 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200204 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
205 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
206 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100207 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
208 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
209
210 /* The following tags are deprecated and will be removed soon */
211 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
212 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200213 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
214 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
215 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
216 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100217 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
218 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
219 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
220 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
221 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200222 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100223};
224
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200225char 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
226char 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 +0100227char 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 +0100228char *log_format = NULL;
229
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200230/* Default string used for structured-data part in RFC5424 formatted
231 * syslog messages.
232 */
233char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200234
Willy Tarreau13ef7732018-11-12 07:25:28 +0100235/* total number of dropped logs */
236unsigned int dropped_logs = 0;
237
Dragan Dosen1322d092015-09-22 16:05:32 +0200238/* This is a global syslog header, common to all outgoing messages in
239 * RFC3164 format. It begins with time-based part and is updated by
240 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200241 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200242THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200243THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200244
Dragan Dosen1322d092015-09-22 16:05:32 +0200245/* This is a global syslog header for messages in RFC5424 format. It is
246 * updated by update_log_hdr_rfc5424().
247 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200248THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200249THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200250
Dragan Dosen59cee972015-09-19 22:09:02 +0200251/* This is a global syslog message buffer, common to all outgoing
252 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100253 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200254THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100255
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200256/* A global syslog message buffer, common to all RFC5424 syslog messages.
257 * Currently, it is used for generating the structured-data part.
258 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200259THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200260
Christopher Fauletd4696382017-10-24 11:44:05 +0200261/* A global buffer used to store all startup alerts/warnings. It will then be
262 * retrieve on the CLI. */
Willy Tarreau869efd52019-11-15 15:16:57 +0100263static struct ring *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200264
William Lallemand723b73a2012-02-08 16:37:49 +0100265struct logformat_var_args {
266 char *name;
267 int mask;
268};
269
270struct logformat_var_args var_args_list[] = {
271// global
272 { "M", LOG_OPT_MANDATORY },
273 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200274 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100275 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100276 { 0, 0 }
277};
278
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200279/* return the name of the directive used in the current proxy for which we're
280 * currently parsing a header, when it is known.
281 */
282static inline const char *fmt_directive(const struct proxy *curproxy)
283{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100284 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200285 case ARGC_ACL:
286 return "acl";
287 case ARGC_STK:
288 return "stick";
289 case ARGC_TRK:
290 return "track-sc";
291 case ARGC_LOG:
292 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200293 case ARGC_LOGSD:
294 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100295 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100296 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100297 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100298 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200299 case ARGC_UIF:
300 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100301 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200302 return "redirect";
303 case ARGC_CAP:
304 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200305 case ARGC_SRV:
306 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200307 case ARGC_SPOE:
308 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100309 case ARGC_UBK:
310 return "use_backend";
Christopher Faulet3b967c12020-05-15 15:47:44 +0200311 case ARGC_HERR:
312 return "http-error";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100313 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200314 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100315 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200316}
317
William Lallemand723b73a2012-02-08 16:37:49 +0100318/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100319 * callback used to configure addr source retrieval
320 */
321int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
322{
323 curproxy->options2 |= PR_O2_SRC_ADDR;
324
325 return 0;
326}
327
328
329/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100330 * Parse args in a logformat_var. Returns 0 in error
331 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100332 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100333int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100334{
335 int i = 0;
336 int end = 0;
337 int flags = 0; // 1 = + 2 = -
338 char *sp = NULL; // start pointer
339
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100340 if (args == NULL) {
341 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100342 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100343 }
William Lallemand723b73a2012-02-08 16:37:49 +0100344
345 while (1) {
346 if (*args == '\0')
347 end = 1;
348
349 if (*args == '+') {
350 // add flag
351 sp = args + 1;
352 flags = 1;
353 }
354 if (*args == '-') {
355 // delete flag
356 sp = args + 1;
357 flags = 2;
358 }
359
360 if (*args == '\0' || *args == ',') {
361 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100362 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100363 if (strcmp(sp, var_args_list[i].name) == 0) {
364 if (flags == 1) {
365 node->options |= var_args_list[i].mask;
366 break;
367 } else if (flags == 2) {
368 node->options &= ~var_args_list[i].mask;
369 break;
370 }
371 }
372 }
373 sp = NULL;
374 if (end)
375 break;
376 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100377 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100378 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100379 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100380}
381
382/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100383 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
384 * must pass the args part in the <arg> pointer with its length in <arg_len>,
385 * and varname with its length in <var> and <var_len> respectively. <arg> is
386 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100387 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100388 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100389int 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 +0100390{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100391 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200392 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100393
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100394 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
395 if (strlen(logformat_keywords[j].name) == var_len &&
396 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
397 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200398 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100399 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100400 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200401 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100402 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100403 node->type = logformat_keywords[j].type;
404 node->options = *defoptions;
405 if (arg_len) {
406 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100407 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200408 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100409 }
410 if (node->type == LOG_FMT_GLOBAL) {
411 *defoptions = node->options;
412 free(node->arg);
413 free(node);
414 } else {
415 if (logformat_keywords[j].config_callback &&
416 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200417 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100418 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100419 curproxy->to_log |= logformat_keywords[j].lw;
420 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100421 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100422 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100423 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
424 curproxy->conf.args.file, curproxy->conf.args.line,
425 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100426 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100427 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100428 memprintf(err, "format variable '%s' is reserved for HTTP mode",
429 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200430 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100431 }
William Lallemand723b73a2012-02-08 16:37:49 +0100432 }
433 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100434
435 j = var[var_len];
436 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100437 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 +0100438 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200439
440 error_free:
441 if (node) {
442 free(node->arg);
443 free(node);
444 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100445 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100446}
447
448/*
449 * push to the logformat linked list
450 *
451 * start: start pointer
452 * end: end text pointer
453 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100454 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100455 *
456 * LOG_TEXT: copy chars from start to end excluding end.
457 *
458*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100459int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100460{
461 char *str;
462
Willy Tarreaua3571662012-12-20 21:59:12 +0100463 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200464 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100465 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100466 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100467 return 0;
468 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200469 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100470 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100471 str[end - start] = '\0';
472 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100473 node->type = LOG_FMT_TEXT; // type string
474 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100475 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200476 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100477 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100478 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100479 return 0;
480 }
William Lallemand1d705562012-03-12 12:46:41 +0100481 node->type = LOG_FMT_SEPARATOR;
482 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100483 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100484 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100485}
486
487/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100488 * Parse the sample fetch expression <text> and add a node to <list_format> upon
489 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100490 * should work. The curpx->conf.args.ctx must be set by the caller. If an end pointer
491 * is passed in <endptr>, it will be updated with the pointer to the first character
492 * not part of the sample expression.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100493 *
494 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100495 */
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100496int 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 +0100497{
498 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200499 struct sample_expr *expr = NULL;
500 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100501 int cmd_arg;
502
503 cmd[0] = text;
504 cmd[1] = "";
505 cmd_arg = 0;
506
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100507 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 +0100508 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100509 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200510 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100511 }
512
Vincent Bernat02779b62016-04-03 13:48:43 +0200513 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100514 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100515 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200516 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100517 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100518 node->type = LOG_FMT_EXPR;
519 node->expr = expr;
520 node->options = options;
521
522 if (arg_len) {
523 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100524 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200525 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100526 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100527 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100528 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
529
Willy Tarreau434c57c2013-01-08 01:10:24 +0100530 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100531 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
532
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100533 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100534 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
535 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200536 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100537 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100538
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200539 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100540 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100541 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100542
William Lallemand65ad6e12014-01-31 15:08:02 +0100543 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
544 * needed with some sample fetches (eg: ssl*). We always set it for
545 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100546 */
547 curpx->to_log |= LW_XPRT;
Christopher Fauletd2236cd2020-04-06 18:29:14 +0200548 if (curpx->http_needed)
549 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100550 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100551 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200552
553 error_free:
554 release_sample_expr(expr);
555 if (node) {
556 free(node->arg);
557 free(node);
558 }
559 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100560}
561
562/*
William Lallemand723b73a2012-02-08 16:37:49 +0100563 * Parse the log_format string and fill a linked list.
564 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200565 * You can set arguments using { } : %{many arguments}varname.
566 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100567 *
Ilya Shipitsinae40dbc2020-04-04 12:59:53 +0500568 * fmt: the string to parse
William Lallemand1d705562012-03-12 12:46:41 +0100569 * curproxy: the proxy affected
570 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100571 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100572 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100573 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100574 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100575 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100576int 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 +0100577{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100578 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100579 char *arg = NULL; /* start pointer for args */
580 char *var = NULL; /* start pointer for vars */
581 int arg_len = 0;
582 int var_len = 0;
583 int cformat; /* current token format */
584 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100585 struct logformat_node *tmplf, *back;
586
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100587 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100588 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100589 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100590 return 0;
591 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200592 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200593
William Lallemand723b73a2012-02-08 16:37:49 +0100594 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100595 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100596 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200597 release_sample_expr(tmplf->expr);
598 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100599 free(tmplf);
600 }
601
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100602 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100603 pformat = cformat;
604
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100605 if (!*str)
606 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100607
Joseph Herlant85b40592018-11-15 12:10:04 -0800608 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100609 * second have all common paths processed at one place. The common paths are the ones
610 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
611 * We use the common LF_INIT state to dispatch to the different final states.
612 */
613 switch (pformat) {
614 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100615 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100616 arg_len = var_len = 0;
617 if (*str == '{') { // optional argument
618 cformat = LF_STARG;
619 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100620 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100621 else if (*str == '[') {
622 cformat = LF_STEXPR;
623 var = str + 1; // store expr in variable name
624 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100625 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100626 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100627 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100628 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100629 else if (*str == '%')
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500630 cformat = LF_TEXT; // convert this character to a literal (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100631 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100632 /* single '%' followed by blank or digit, send them both */
633 cformat = LF_TEXT;
634 pformat = LF_TEXT; /* finally we include the previous char as well */
635 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600636 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 +0100637 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100638 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100639
640 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100641 else
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500642 cformat = LF_INIT; // handle other cases of literals
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100643 break;
644
645 case LF_STARG: // text immediately following '%{'
646 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100647 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100648 arg_len = str - arg;
649 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100650 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100651 break;
652
653 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100654 if (*str == '[') {
655 cformat = LF_STEXPR;
656 var = str + 1; // store expr in variable name
657 break;
658 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100659 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100660 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100661 var = str;
662 break;
663 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100664 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100665 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100666
Willy Tarreauc8368452012-12-21 00:09:23 +0100667 case LF_STEXPR: // text immediately following '%['
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100668 /* the whole sample expression is parsed at once,
669 * returning the pointer to the first character not
670 * part of the expression, which MUST be the trailing
671 * angle bracket.
672 */
673 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str))
674 goto fail;
675
676 if (*str == ']') {
677 // end of arg, go on with next state
678 cformat = pformat = LF_EDEXPR;
679 sp = str;
680 }
681 else {
682 char c = *str;
683 *str = 0;
Willy Tarreau90807112020-02-25 08:16:33 +0100684 if (isprint((unsigned char)c))
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100685 memprintf(err, "expected ']' after '%s', but found '%c'", var, c);
686 else
687 memprintf(err, "missing ']' after '%s'", var);
Willy Tarreauc8368452012-12-21 00:09:23 +0100688 }
689 break;
690
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100691 case LF_VAR: // text part of a variable name
692 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100693 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100694 cformat = LF_INIT; // not variable name anymore
695 break;
696
Willy Tarreauc8368452012-12-21 00:09:23 +0100697 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100698 cformat = LF_INIT;
699 }
700
701 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
702 switch (*str) {
703 case '%': cformat = LF_STARTVAR; break;
704 case ' ': cformat = LF_SEPARATOR; break;
705 case 0 : cformat = LF_END; break;
706 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100707 }
708 }
709
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100710 if (cformat != pformat || pformat == LF_SEPARATOR) {
711 switch (pformat) {
712 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100713 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100714 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100715 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100716 case LF_STEXPR:
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100717 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &sp))
Willy Tarreau51013e82019-12-11 12:05:39 +0100718 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100719 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100720 case LF_TEXT:
721 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100722 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100723 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100724 break;
725 }
726 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100727 }
728 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100729
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100730 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100731 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100732 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100733 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100734 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100735
736 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100737 fail:
738 free(backfmt);
739 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100740}
741
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200742/*
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500743 * 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 +0200744 * ranges of indexes. Note that an index may be considered as a particular range
745 * with a high limit to the low limit.
746 */
747int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
748{
749 char *end, *p;
750
751 *low = *high = 0;
752
753 p = *arg;
754 end = strchr(p, ',');
755 if (!end)
756 end = p + strlen(p);
757
758 *high = *low = read_uint((const char **)&p, end);
759 if (!*low || (p != end && *p != '-'))
760 goto err;
761
762 if (p == end)
763 goto done;
764
765 p++;
766 *high = read_uint((const char **)&p, end);
767 if (!*high || *high <= *low || p != end)
768 goto err;
769
770 done:
771 if (*end == ',')
772 end++;
773 *arg = end;
774 return 1;
775
776 err:
777 memprintf(err, "wrong sample range '%s'", *arg);
778 return 0;
779}
780
781/*
782 * Returns 1 if the range defined by <low> and <high> overlaps
783 * one of them in <rgs> array of ranges with <sz> the size of this
784 * array, 0 if not.
785 */
786int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
787 unsigned int low, unsigned int high, char **err)
788{
789 size_t i;
790
791 for (i = 0; i < sz; i++) {
792 if ((low >= rgs[i].low && low <= rgs[i].high) ||
793 (high >= rgs[i].low && high <= rgs[i].high)) {
794 memprintf(err, "ranges are overlapping");
795 return 1;
796 }
797 }
798
799 return 0;
800}
801
802int smp_log_range_cmp(const void *a, const void *b)
803{
804 const struct smp_log_range *rg_a = a;
805 const struct smp_log_range *rg_b = b;
806
807 if (rg_a->high < rg_b->low)
808 return -1;
809 else if (rg_a->low > rg_b->high)
810 return 1;
811
812 return 0;
813}
814
815/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200816 * Parse "log" keyword and update <logsrvs> list accordingly.
817 *
818 * When <do_del> is set, it means the "no log" line was parsed, so all log
819 * servers in <logsrvs> are released.
820 *
821 * Otherwise, we try to parse the "log" line. First of all, when the list is not
822 * the global one, we look for the parameter "global". If we find it,
823 * global.logsrvs is copied. Else we parse each arguments.
824 *
825 * The function returns 1 in success case, otherwise, it returns 0 and err is
826 * filled.
827 */
828int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
829{
830 struct sockaddr_storage *sk;
831 struct logsrv *logsrv = NULL;
832 int port1, port2;
833 int cur_arg;
834
835 /*
836 * "no log": delete previous herited or defined syslog
837 * servers.
838 */
839 if (do_del) {
840 struct logsrv *back;
841
842 if (*(args[1]) != 0) {
843 memprintf(err, "'no log' does not expect arguments");
844 goto error;
845 }
846
847 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
848 LIST_DEL(&logsrv->list);
849 free(logsrv);
850 }
851 return 1;
852 }
853
854 /*
855 * "log global": copy global.logrsvs linked list to the end of logsrvs
856 * list. But first, we check (logsrvs != global.logsrvs).
857 */
858 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
859 if (logsrvs == &global.logsrvs) {
860 memprintf(err, "'global' is not supported for a global syslog server");
861 goto error;
862 }
863 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200864 struct logsrv *node;
865
866 list_for_each_entry(node, logsrvs, list) {
867 if (node->ref == logsrv)
868 goto skip_logsrv;
869 }
870
871 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200872 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200873 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200874 LIST_INIT(&node->list);
875 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200876
877 skip_logsrv:
878 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200879 }
880 return 1;
881 }
882
883 /*
884 * "log <address> ...: parse a syslog server line
885 */
886 if (*(args[1]) == 0 || *(args[2]) == 0) {
887 memprintf(err, "expects <address> and <facility> %s as arguments",
888 ((logsrvs == &global.logsrvs) ? "" : "or global"));
889 goto error;
890 }
891
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100892 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
893 if (strcmp(args[1], "stdout") == 0)
894 args[1] = "fd@1";
895 else if (strcmp(args[1], "stderr") == 0)
896 args[1] = "fd@2";
897
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200898 logsrv = calloc(1, sizeof(*logsrv));
899 if (!logsrv) {
900 memprintf(err, "out of memory");
901 goto error;
902 }
903
904 /* skip address for now, it will be parsed at the end */
905 cur_arg = 2;
906
907 /* just after the address, a length may be specified */
908 logsrv->maxlen = MAX_SYSLOG_LEN;
909 if (strcmp(args[cur_arg], "len") == 0) {
910 int len = atoi(args[cur_arg+1]);
911 if (len < 80 || len > 65535) {
912 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
913 args[cur_arg+1]);
914 goto error;
915 }
916 logsrv->maxlen = len;
917 cur_arg += 2;
918 }
919 if (logsrv->maxlen > global.max_syslog_len)
920 global.max_syslog_len = logsrv->maxlen;
921
922 /* after the length, a format may be specified */
923 if (strcmp(args[cur_arg], "format") == 0) {
924 logsrv->format = get_log_format(args[cur_arg+1]);
925 if (logsrv->format < 0) {
926 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
927 goto error;
928 }
929 cur_arg += 2;
930 }
931
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200932 if (strcmp(args[cur_arg], "sample") == 0) {
933 unsigned low, high;
934 char *p, *beg, *end, *smp_sz_str;
935 struct smp_log_range *smp_rgs = NULL;
936 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
937
938 p = args[cur_arg+1];
939 smp_sz_str = strchr(p, ':');
940 if (!smp_sz_str) {
941 memprintf(err, "Missing sample size");
942 goto error;
943 }
944
945 *smp_sz_str++ = '\0';
946
947 end = p + strlen(p);
948
949 while (p != end) {
950 if (!get_logsrv_smp_range(&low, &high, &p, err))
951 goto error;
952
953 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
954 goto error;
955
956 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
957 if (!smp_rgs) {
958 memprintf(err, "out of memory error");
959 goto error;
960 }
961
962 smp_rgs[smp_rgs_sz].low = low;
963 smp_rgs[smp_rgs_sz].high = high;
964 smp_rgs[smp_rgs_sz].sz = high - low + 1;
965 smp_rgs[smp_rgs_sz].curr_idx = 0;
966 if (smp_rgs[smp_rgs_sz].high > smp_sz)
967 smp_sz = smp_rgs[smp_rgs_sz].high;
968 smp_rgs_sz++;
969 }
970
Tim Duesterhus21648002019-06-23 22:10:10 +0200971 if (smp_rgs == NULL) {
972 memprintf(err, "no sampling ranges given");
973 goto error;
974 }
975
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200976 beg = smp_sz_str;
977 end = beg + strlen(beg);
978 new_smp_sz = read_uint((const char **)&beg, end);
979 if (!new_smp_sz || beg != end) {
980 memprintf(err, "wrong sample size '%s' for sample range '%s'",
981 smp_sz_str, args[cur_arg+1]);
982 goto error;
983 }
984
985 if (new_smp_sz < smp_sz) {
986 memprintf(err, "sample size %zu should be greater or equal to "
987 "%zu the maximum of the high ranges limits",
988 new_smp_sz, smp_sz);
989 goto error;
990 }
991 smp_sz = new_smp_sz;
992
993 /* Let's order <smp_rgs> array. */
994 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
995
996 logsrv->lb.smp_rgs = smp_rgs;
997 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
998 logsrv->lb.smp_sz = smp_sz;
999
1000 cur_arg += 2;
1001 }
Frédéric Lécailled803e472019-04-25 07:42:09 +02001002 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001003 /* parse the facility */
1004 logsrv->facility = get_log_facility(args[cur_arg]);
1005 if (logsrv->facility < 0) {
1006 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
1007 goto error;
1008 }
1009 cur_arg++;
1010
1011 /* parse the max syslog level (default: debug) */
1012 logsrv->level = 7;
1013 if (*(args[cur_arg])) {
1014 logsrv->level = get_log_level(args[cur_arg]);
1015 if (logsrv->level < 0) {
1016 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
1017 goto error;
1018 }
1019 cur_arg++;
1020 }
1021
1022 /* parse the limit syslog level (default: emerg) */
1023 logsrv->minlvl = 0;
1024 if (*(args[cur_arg])) {
1025 logsrv->minlvl = get_log_level(args[cur_arg]);
1026 if (logsrv->minlvl < 0) {
1027 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
1028 goto error;
1029 }
1030 cur_arg++;
1031 }
1032
1033 /* Too many args */
1034 if (*(args[cur_arg])) {
1035 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1036 goto error;
1037 }
1038
1039 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001040 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001041 if (strncmp(args[1], "ring@", 5) == 0) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001042 logsrv->addr.ss_family = AF_UNSPEC;
1043 logsrv->type = LOG_TARGET_BUFFER;
Emeric Brun99c453d2020-05-25 15:01:04 +02001044 logsrv->sink = NULL;
1045 logsrv->ring_name = strdup(args[1] + 5);
Willy Tarreauc046d162019-08-30 15:24:59 +02001046 goto done;
1047 }
1048
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001049 if (strncmp(args[1], "fd@", 3) == 0)
1050 logsrv->type = LOG_TARGET_FD;
1051
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001052 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1053 if (!sk)
1054 goto error;
1055 logsrv->addr = *sk;
1056
1057 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1058 if (port1 != port2) {
1059 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1060 goto error;
1061 }
1062 logsrv->addr = *sk;
1063 if (!port1)
1064 set_host_port(&logsrv->addr, SYSLOG_PORT);
1065 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001066 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001067 LIST_ADDQ(logsrvs, &logsrv->list);
1068 return 1;
1069
1070 error:
1071 free(logsrv);
1072 return 0;
1073}
1074
1075
Christopher Fauletd4696382017-10-24 11:44:05 +02001076/* Generic function to display messages prefixed by a label */
1077static void print_message(const char *label, const char *fmt, va_list argp)
1078{
1079 struct tm tm;
1080 char *head, *msg;
1081
1082 head = msg = NULL;
1083
1084 get_localtime(date.tv_sec, &tm);
1085 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1086 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1087 memvprintf(&msg, fmt, argp);
1088
Willy Tarreau869efd52019-11-15 15:16:57 +01001089 if (global.mode & MODE_STARTING) {
1090 if (unlikely(!startup_logs))
1091 startup_logs = ring_new(STARTUP_LOG_SIZE);
1092
1093 if (likely(startup_logs)) {
1094 struct ist m[2];
1095
1096 m[0] = ist(head);
1097 m[1] = ist(msg);
1098 /* trim the trailing '\n' */
1099 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1100 m[1].len--;
1101 ring_write(startup_logs, ~0, 0, 0, m, 2);
1102 }
1103 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001104
1105 fprintf(stderr, "%s%s", head, msg);
1106 fflush(stderr);
1107
1108 free(head);
1109 free(msg);
1110}
1111
Willy Tarreaubaaee002006-06-26 02:48:02 +02001112/*
1113 * Displays the message on stderr with the date and pid. Overrides the quiet
1114 * mode during startup.
1115 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001116void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001117{
1118 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001119
1120 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Willy Tarreaubb869862020-04-16 10:52:41 +02001121 if (!(warned & WARN_EXEC_PATH)) {
1122 const char *path = get_exec_path();
1123
1124 warned |= WARN_EXEC_PATH;
1125 ha_notice("haproxy version is %s\n", haproxy_version);
1126 if (path)
1127 ha_notice("path to executable is %s\n", path);
1128 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001129 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001130 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001131 va_end(argp);
1132 }
1133}
1134
1135
1136/*
1137 * Displays the message on stderr with the date and pid.
1138 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001139void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001140{
1141 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001142
Willy Tarreaubebd2122020-04-15 16:06:11 +02001143 warned |= WARN_ANY;
1144
Willy Tarreaubaaee002006-06-26 02:48:02 +02001145 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1146 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001147 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001148 va_end(argp);
1149 }
1150}
1151
1152/*
William Lallemand9c56a222018-11-21 18:04:52 +01001153 * Displays the message on stderr with the date and pid.
1154 */
1155void ha_notice(const char *fmt, ...)
1156{
1157 va_list argp;
1158
1159 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1160 va_start(argp, fmt);
1161 print_message("NOTICE", fmt, argp);
1162 va_end(argp);
1163 }
1164}
1165
1166/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001167 * Displays the message on <out> only if quiet mode is not set.
1168 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001169void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001170{
1171 va_list argp;
1172
1173 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1174 va_start(argp, fmt);
1175 vfprintf(out, fmt, argp);
1176 fflush(out);
1177 va_end(argp);
1178 }
1179}
1180
1181/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001182 * returns log format for <fmt> or -1 if not found.
1183 */
1184int get_log_format(const char *fmt)
1185{
1186 int format;
1187
1188 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001189 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001190 format--;
1191
1192 return format;
1193}
1194
1195/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001196 * returns log level for <lev> or -1 if not found.
1197 */
1198int get_log_level(const char *lev)
1199{
1200 int level;
1201
1202 level = NB_LOG_LEVELS - 1;
1203 while (level >= 0 && strcmp(log_levels[level], lev))
1204 level--;
1205
1206 return level;
1207}
1208
Willy Tarreaubaaee002006-06-26 02:48:02 +02001209/*
1210 * returns log facility for <fac> or -1 if not found.
1211 */
1212int get_log_facility(const char *fac)
1213{
1214 int facility;
1215
1216 facility = NB_LOG_FACILITIES - 1;
1217 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1218 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001219
Willy Tarreaubaaee002006-06-26 02:48:02 +02001220 return facility;
1221}
1222
William Lallemanda1cc3812012-02-08 16:38:44 +01001223/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001224 * Encode the string.
1225 *
1226 * When using the +E log format option, it will try to escape '"\]'
1227 * characters with '\' as prefix. The same prefix should not be used as
1228 * <escape>.
1229 */
1230static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001231 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001232 const char *string,
1233 struct logformat_node *node)
1234{
1235 if (node->options & LOG_OPT_ESC) {
1236 if (start < stop) {
1237 stop--; /* reserve one byte for the final '\0' */
1238 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001239 if (!ha_bit_test((unsigned char)(*string), map)) {
1240 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001241 *start++ = *string;
1242 else {
1243 if (start + 2 >= stop)
1244 break;
1245 *start++ = '\\';
1246 *start++ = *string;
1247 }
1248 }
1249 else {
1250 if (start + 3 >= stop)
1251 break;
1252 *start++ = escape;
1253 *start++ = hextab[(*string >> 4) & 15];
1254 *start++ = hextab[*string & 15];
1255 }
1256 string++;
1257 }
1258 *start = '\0';
1259 }
1260 }
1261 else {
1262 return encode_string(start, stop, escape, map, string);
1263 }
1264
1265 return start;
1266}
1267
1268/*
1269 * Encode the chunk.
1270 *
1271 * When using the +E log format option, it will try to escape '"\]'
1272 * characters with '\' as prefix. The same prefix should not be used as
1273 * <escape>.
1274 */
1275static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001276 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001277 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001278 struct logformat_node *node)
1279{
1280 char *str, *end;
1281
1282 if (node->options & LOG_OPT_ESC) {
1283 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001284 str = chunk->area;
1285 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001286
1287 stop--; /* reserve one byte for the final '\0' */
1288 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001289 if (!ha_bit_test((unsigned char)(*str), map)) {
1290 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001291 *start++ = *str;
1292 else {
1293 if (start + 2 >= stop)
1294 break;
1295 *start++ = '\\';
1296 *start++ = *str;
1297 }
1298 }
1299 else {
1300 if (start + 3 >= stop)
1301 break;
1302 *start++ = escape;
1303 *start++ = hextab[(*str >> 4) & 15];
1304 *start++ = hextab[*str & 15];
1305 }
1306 str++;
1307 }
1308 *start = '\0';
1309 }
1310 }
1311 else {
1312 return encode_chunk(start, stop, escape, map, chunk);
1313 }
1314
1315 return start;
1316}
1317
1318/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001319 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001320 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001321 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001322 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001323 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001324char *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 +01001325{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001326 if (size < 2)
1327 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001328
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001329 if (node->options & LOG_OPT_QUOTE) {
1330 *(dst++) = '"';
1331 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001332 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001333
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001334 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001335 if (++len > size)
1336 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001337 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001338 char *ret;
1339
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001340 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001341 if (ret == NULL || *ret != '\0')
1342 return NULL;
1343 len = ret - dst;
1344 }
1345 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001346 len = strlcpy2(dst, src, len);
1347 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001348
1349 size -= len;
1350 dst += len;
1351 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001352 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1353 if (size < 2)
1354 return NULL;
1355 *(dst++) = '-';
1356 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001357
1358 if (node->options & LOG_OPT_QUOTE) {
1359 if (size < 2)
1360 return NULL;
1361 *(dst++) = '"';
1362 }
1363
1364 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001365 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001366}
1367
Willy Tarreau26ffa852018-09-05 15:23:10 +02001368static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001369{
1370 return lf_text_len(dst, src, size, size, node);
1371}
1372
William Lallemand5f232402012-04-05 18:02:55 +02001373/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001374 * Write a IP address to the log string
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001375 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001376 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001377char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001378{
1379 char *ret = dst;
1380 int iret;
1381 char pn[INET6_ADDRSTRLEN];
1382
1383 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001384 unsigned char *addr = NULL;
1385 switch (sockaddr->sa_family) {
1386 case AF_INET:
1387 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1388 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1389 break;
1390 case AF_INET6:
1391 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1392 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1393 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1394 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1395 break;
1396 default:
1397 return NULL;
1398 }
William Lallemand5f232402012-04-05 18:02:55 +02001399 if (iret < 0 || iret > size)
1400 return NULL;
1401 ret += iret;
1402 } else {
1403 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1404 ret = lf_text(dst, pn, size, node);
1405 if (ret == NULL)
1406 return NULL;
1407 }
1408 return ret;
1409}
1410
1411/*
1412 * Write a port to the log
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001413 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001414 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001415char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001416{
1417 char *ret = dst;
1418 int iret;
1419
1420 if (node->options & LOG_OPT_HEXA) {
1421 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1422 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1423 if (iret < 0 || iret > size)
1424 return NULL;
1425 ret += iret;
1426 } else {
1427 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1428 if (ret == NULL)
1429 return NULL;
1430 }
1431 return ret;
1432}
1433
Dragan Dosen1322d092015-09-22 16:05:32 +02001434/* Re-generate time-based part of the syslog header in RFC3164 format at
1435 * the beginning of logheader once a second and return the pointer to the
1436 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001437 */
Emeric Brunbd163812020-05-06 14:33:46 +02001438char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001439{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001440 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001441 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001442 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001443
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001444 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001445 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001446 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001447 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001448
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001449 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001450 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001451
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001452 if (unlikely(global.log_send_hostname != host.area)) {
1453 host.area = global.log_send_hostname;
1454 host.data = host.area ? strlen(host.area) : 0;
1455 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001456 }
1457
Dragan Dosen59cee972015-09-19 22:09:02 +02001458 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001459 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001460 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001461 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001462 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001463 /* WARNING: depending upon implementations, snprintf may return
1464 * either -1 or the number of bytes that would be needed to store
1465 * the total message. In both cases, we must adjust it.
1466 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001467 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1468 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001469
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001470 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001471 }
1472
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001473 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001474
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001475 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001476}
1477
Dragan Dosen1322d092015-09-22 16:05:32 +02001478/* Re-generate time-based part of the syslog header in RFC5424 format at
1479 * the beginning of logheader_rfc5424 once a second and return the pointer
1480 * to the first character after it.
1481 */
Emeric Brunbd163812020-05-06 14:33:46 +02001482char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001483{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001484 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001485 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001486
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001487 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001488 /* this string is rebuild only once a second */
1489 struct tm tm;
1490 int hdr_len;
1491
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001492 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001493 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001494 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001495
1496 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001497 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001498 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001499 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001500 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001501 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001502 /* WARNING: depending upon implementations, snprintf may return
1503 * either -1 or the number of bytes that would be needed to store
1504 * the total message. In both cases, we must adjust it.
1505 */
1506 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1507 hdr_len = global.max_syslog_len;
1508
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001509 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001510 }
1511
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001512 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001513
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001514 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001515}
1516
William Lallemand2a4a44f2012-02-06 16:00:33 +01001517/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001518 * This function sends the syslog message using a printf format string. It
1519 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001520 */
1521void send_log(struct proxy *p, int level, const char *format, ...)
1522{
1523 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001524 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001525
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001526 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001527 return;
1528
William Lallemand2a4a44f2012-02-06 16:00:33 +01001529 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001530 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001531 if (data_len < 0 || data_len > global.max_syslog_len)
1532 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001533 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001534
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001535 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1536 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001537}
1538
1539/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001540 * This function sends a syslog message to <logsrv>.
1541 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1542 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1543 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001544 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001545 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001546 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001547static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1548 int level, char *message, size_t size, char *sd, size_t sd_size,
1549 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001550{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001551 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1552 static THREAD_LOCAL struct msghdr msghdr = {
1553 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001554 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1555 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001556 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1557 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1558 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001559 time_t time = date.tv_sec;
Emeric Brune709e1e2020-05-06 17:23:59 +02001560 char *hdr, *hdr_ptr = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +02001561 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001562 int fac_level;
1563 int *plogfd;
1564 char *pid_sep1 = "", *pid_sep2 = "";
1565 char logheader_short[3];
1566 int sent;
1567 int maxlen;
1568 int hdr_max = 0;
1569 int tag_max = 0;
1570 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001571 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001572 int pid_sep2_max = 0;
1573 int sd_max = 0;
1574 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001575
1576 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001577
1578 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001579
Emeric Brunfa9d7802020-05-28 14:21:33 +02001580 /* historically some messages used to already contain the trailing LF
1581 * or Zero. Let's remove all trailing LF or Zero
1582 */
1583 while (size && ((dataptr[size-1] == '\n' || (dataptr[size-1] == 0))))
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001584 size--;
1585
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001586 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001587 /* the socket's address is a file descriptor */
1588 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001589 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001590 else if (logsrv->type == LOG_TARGET_BUFFER) {
1591 plogfd = NULL;
Emeric Brune709e1e2020-05-06 17:23:59 +02001592 goto send;
Willy Tarreauc046d162019-08-30 15:24:59 +02001593 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001594 else if (logsrv->addr.ss_family == AF_UNIX)
1595 plogfd = &logfdunix;
1596 else
1597 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001598
Willy Tarreauc046d162019-08-30 15:24:59 +02001599 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001600 /* socket not successfully initialized yet */
1601 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1602 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1603 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001604
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001605 if (!once) {
1606 once = 1; /* note: no need for atomic ops here */
1607 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1608 nblogger, strerror(errno), errno);
1609 }
1610 return;
1611 } else {
1612 /* we don't want to receive anything on this socket */
1613 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1614 /* does nothing under Linux, maybe needed for others */
1615 shutdown(*plogfd, SHUT_RD);
1616 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1617 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001618 }
1619
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001620 switch (logsrv->format) {
1621 case LOG_FORMAT_RFC3164:
1622 hdr = logheader;
1623 hdr_ptr = update_log_hdr(time);
1624 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001625
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001626 case LOG_FORMAT_RFC5424:
1627 hdr = logheader_rfc5424;
1628 hdr_ptr = update_log_hdr_rfc5424(time);
1629 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1630 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001631
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001632 case LOG_FORMAT_SHORT:
1633 /* all fields are known, skip the header generation */
1634 hdr = logheader_short;
1635 hdr[0] = '<';
1636 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1637 hdr[2] = '>';
1638 hdr_ptr = hdr;
1639 hdr_max = 3;
1640 maxlen = logsrv->maxlen - hdr_max;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001641 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001642 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001643
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001644 case LOG_FORMAT_RAW:
1645 /* all fields are known, skip the header generation */
1646 hdr_ptr = hdr = "";
1647 hdr_max = 0;
1648 maxlen = logsrv->maxlen;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001649 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001650 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001651
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001652 default:
1653 return; /* must never happen */
1654 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001655
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001656 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001657
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001658 /* For each target, we may have a different facility.
1659 * We can also have a different log level for each message.
1660 * This induces variations in the message header length.
1661 * Since we don't want to recompute it each time, nor copy it every
1662 * time, we only change the facility in the pre-computed header,
1663 * and we change the pointer to the header accordingly.
1664 */
1665 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1666 hdr_ptr = hdr + 3; /* last digit of the log level */
1667 do {
1668 *hdr_ptr = '0' + fac_level % 10;
1669 fac_level /= 10;
1670 hdr_ptr--;
1671 } while (fac_level && hdr_ptr > hdr);
1672 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001673
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001674 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001675
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001676 /* time-based header */
1677 if (unlikely(hdr_size >= logsrv->maxlen)) {
1678 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1679 sd_max = 0;
1680 goto send;
1681 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001682
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001683 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001684
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001685 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001686 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001687 if (unlikely(tag_max >= maxlen)) {
1688 tag_max = maxlen - 1;
1689 sd_max = 0;
1690 goto send;
1691 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001692
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001693 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001694
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001695 /* first pid separator */
1696 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1697 if (unlikely(pid_sep1_max >= maxlen)) {
1698 pid_sep1_max = maxlen - 1;
1699 sd_max = 0;
1700 goto send;
1701 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001702
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001703 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1704 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001705
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001706 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001707 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001708 if (unlikely(pid_size >= maxlen)) {
1709 pid_size = maxlen - 1;
1710 sd_max = 0;
1711 goto send;
1712 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001713
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001714 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001715
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001716 /* second pid separator */
1717 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1718 if (unlikely(pid_sep2_max >= maxlen)) {
1719 pid_sep2_max = maxlen - 1;
1720 sd_max = 0;
1721 goto send;
1722 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001723
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001724 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1725 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001726
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001727 /* structured-data */
1728 if (sd_max >= maxlen) {
1729 sd_max = maxlen - 1;
1730 goto send;
1731 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001732
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001733 max = MIN(size, maxlen - sd_max - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001734send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001735 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001736 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001737 struct ist msg[7];
1738
Emeric Brune709e1e2020-05-06 17:23:59 +02001739 if (logsrv->type == LOG_TARGET_BUFFER) {
1740 msg[0] = ist2(message, MIN(size, logsrv->maxlen));
1741 msg[1] = ist2(tag_str, tag_size);
1742 msg[2] = ist2(pid_str, pid_size);
1743 msg[3] = ist2(sd, sd_size);
1744 sent = sink_write(logsrv->sink, msg, 1, level, logsrv->facility, &msg[1], &msg[2], &msg[3]);
1745 }
1746 else /* LOG_TARGET_FD */ {
1747 msg[0] = ist2(hdr_ptr, hdr_max);
1748 msg[1] = ist2(tag_str, tag_max);
1749 msg[2] = ist2(pid_sep1, pid_sep1_max);
1750 msg[3] = ist2(pid_str, pid_max);
1751 msg[4] = ist2(pid_sep2, pid_sep2_max);
1752 msg[5] = ist2(sd, sd_max);
1753 msg[6] = ist2(dataptr, max);
Willy Tarreauc046d162019-08-30 15:24:59 +02001754 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Emeric Brune709e1e2020-05-06 17:23:59 +02001755 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001756 }
1757 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001758 iovec[0].iov_base = hdr_ptr;
1759 iovec[0].iov_len = hdr_max;
1760 iovec[1].iov_base = tag_str;
1761 iovec[1].iov_len = tag_max;
1762 iovec[2].iov_base = pid_sep1;
1763 iovec[2].iov_len = pid_sep1_max;
1764 iovec[3].iov_base = pid_str;
1765 iovec[3].iov_len = pid_max;
1766 iovec[4].iov_base = pid_sep2;
1767 iovec[4].iov_len = pid_sep2_max;
1768 iovec[5].iov_base = sd;
1769 iovec[5].iov_len = sd_max;
1770 iovec[6].iov_base = dataptr;
1771 iovec[6].iov_len = max;
1772 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1773 iovec[7].iov_len = 1;
1774
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001775 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1776 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001777
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001778 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1779 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001780
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001781 if (sent < 0) {
1782 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001783
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001784 if (errno == EAGAIN)
1785 _HA_ATOMIC_ADD(&dropped_logs, 1);
1786 else if (!once) {
1787 once = 1; /* note: no need for atomic ops here */
1788 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1789 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001790 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001791 }
1792}
Dragan Dosen59cee972015-09-19 22:09:02 +02001793
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001794/*
1795 * This function sends a syslog message.
1796 * It doesn't care about errors nor does it report them.
1797 * The arguments <sd> and <sd_size> are used for the structured-data part
1798 * in RFC5424 formatted syslog messages.
1799 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001800void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1801 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001802{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001803 struct logsrv *logsrv;
1804 int nblogger;
1805 static THREAD_LOCAL int curr_pid;
1806 static THREAD_LOCAL char pidstr[100];
1807 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001808
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001809 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001810 if (!LIST_ISEMPTY(&global.logsrvs)) {
1811 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001812 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001813 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001814 if (!tag || !tag->area)
1815 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001816
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001817 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001818 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001819
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001820 if (unlikely(curr_pid != getpid())) {
1821 curr_pid = getpid();
1822 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1823 chunk_initstr(&pid, pidstr);
1824 }
1825
1826 /* Send log messages to syslog server. */
1827 nblogger = 0;
1828 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001829 static THREAD_LOCAL int in_range = 1;
1830
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001831 /* we can filter the level of the messages that are sent to each logger */
1832 if (level > logsrv->level)
1833 continue;
1834
Frédéric Lécailled803e472019-04-25 07:42:09 +02001835 if (logsrv->lb.smp_rgs) {
1836 struct smp_log_range *curr_rg;
1837
1838 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1839 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1840 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1841 if (in_range) {
1842 /* Let's consume this range. */
1843 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1844 if (!curr_rg->curr_idx) {
1845 /* If consumed, let's select the next range. */
1846 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1847 }
1848 }
1849 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1850 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1851 }
1852 if (in_range)
1853 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1854 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001855 }
1856}
1857
1858
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001859const 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 +01001860const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1861 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1862 Set-cookie Updated, unknown, unknown */
1863
William Lallemand1d705562012-03-12 12:46:41 +01001864/*
1865 * try to write a character if there is enough space, or goto out
1866 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001867#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001868 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001869 *(tmplog++) = (x); \
1870 } else { \
1871 goto out; \
1872 } \
1873 } while(0)
1874
Dragan Dosen835b9212016-02-12 13:23:03 +01001875
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001876/* Initializes some log data at boot */
1877static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001878{
1879 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001880 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001881
1882 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1883 * inside PARAM-VALUE should be escaped with '\' as prefix.
1884 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1885 * details.
1886 */
1887 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1888
1889 tmp = "\"\\]";
1890 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001891 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001892 tmp++;
1893 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001894
1895 /* initialize the log header encoding map : '{|}"#' should be encoded with
1896 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1897 * URL encoding only requires '"', '#' to be encoded as well as non-
1898 * printable characters above.
1899 */
1900 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1901 memset(url_encode_map, 0, sizeof(url_encode_map));
1902 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001903 ha_bit_set(i, hdr_encode_map);
1904 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001905 }
1906 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001907 ha_bit_set(i, hdr_encode_map);
1908 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001909 }
1910
1911 tmp = "\"#{|}";
1912 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001913 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001914 tmp++;
1915 }
1916
1917 tmp = "\"#";
1918 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001919 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001920 tmp++;
1921 }
1922
1923 /* initialize the http header encoding map. The draft httpbis define the
1924 * header content as:
1925 *
1926 * HTTP-message = start-line
1927 * *( header-field CRLF )
1928 * CRLF
1929 * [ message-body ]
1930 * header-field = field-name ":" OWS field-value OWS
1931 * field-value = *( field-content / obs-fold )
1932 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1933 * obs-fold = CRLF 1*( SP / HTAB )
1934 * field-vchar = VCHAR / obs-text
1935 * VCHAR = %x21-7E
1936 * obs-text = %x80-FF
1937 *
1938 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1939 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001940 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001941 */
1942 memset(http_encode_map, 0, sizeof(http_encode_map));
1943 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001944 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001945 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001946 ha_bit_set(i, http_encode_map);
1947 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001948}
William Lallemand1d705562012-03-12 12:46:41 +01001949
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001950INITCALL0(STG_PREPARE, init_log);
1951
Christopher Faulet0132d062017-07-26 15:33:35 +02001952/* Initialize log buffers used for syslog messages */
1953int init_log_buffers()
1954{
1955 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001956 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001957 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001958 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001959 logline = my_realloc2(logline, global.max_syslog_len + 1);
1960 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1961 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1962 return 0;
1963 return 1;
1964}
1965
1966/* Deinitialize log buffers used for syslog messages */
1967void deinit_log_buffers()
1968{
1969 free(logheader);
1970 free(logheader_rfc5424);
1971 free(logline);
1972 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001973 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001974 logheader = NULL;
1975 logheader_rfc5424 = NULL;
1976 logline = NULL;
1977 logline_rfc5424 = NULL;
1978}
1979
Willy Tarreaudf974472012-12-28 02:44:01 +01001980/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1981 * <maxsize> characters. Returns the size of the output string in characters,
1982 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001983 * is not zero. It requires a valid session and optionally a stream. If the
1984 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001985 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001986int 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 +02001987{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001988 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001989 struct proxy *be;
1990 struct http_txn *txn;
1991 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001992 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001993 unsigned int s_flags;
1994 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001995 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001996 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001997 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001998 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001999 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02002000 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002001 int t_request;
2002 int hdr;
2003 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002004 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01002005 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01002006 char *ret;
2007 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002008 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002009 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002010 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002011
William Lallemandbddd4fd2012-02-27 11:23:10 +01002012 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002013
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002014 if (likely(s)) {
2015 be = s->be;
2016 txn = s->txn;
2017 be_conn = cs_conn(objt_cs(s->si[1].end));
2018 s_flags = s->flags;
2019 uniq_id = s->uniq_id;
2020 logs = &s->logs;
2021 } else {
2022 /* we have no stream so we first need to initialize a few
2023 * things that are needed later. We do increment the request
2024 * ID so that it's uniquely assigned to this request just as
2025 * if the request had reached the point of being processed.
2026 * A request error is reported as it's the only element we have
2027 * here and which justifies emitting such a log.
2028 */
2029 be = fe;
2030 txn = NULL;
2031 be_conn = NULL;
2032 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002033 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002034
2035 /* prepare a valid log structure */
2036 tmp_strm_log.tv_accept = sess->tv_accept;
2037 tmp_strm_log.accept_date = sess->accept_date;
2038 tmp_strm_log.t_handshake = sess->t_handshake;
2039 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
2040 tv_zero(&tmp_strm_log.tv_request);
2041 tmp_strm_log.t_queue = -1;
2042 tmp_strm_log.t_connect = -1;
2043 tmp_strm_log.t_data = -1;
2044 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2045 tmp_strm_log.bytes_in = 0;
2046 tmp_strm_log.bytes_out = 0;
2047 tmp_strm_log.prx_queue_pos = 0;
2048 tmp_strm_log.srv_queue_pos = 0;
2049
2050 logs = &tmp_strm_log;
2051 }
2052
William Lallemandbddd4fd2012-02-27 11:23:10 +01002053 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002054 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2055 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002056
William Lallemand1d705562012-03-12 12:46:41 +01002057 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002058
William Lallemandbddd4fd2012-02-27 11:23:10 +01002059 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002060 if (LIST_ISEMPTY(list_format))
2061 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002062
William Lallemand1d705562012-03-12 12:46:41 +01002063 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002064 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002065 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002066 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002067 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002068
Willy Tarreauc8368452012-12-21 00:09:23 +01002069 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002070 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002071 if (!last_isspace) {
2072 LOGCHAR(' ');
2073 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002074 }
2075 break;
2076
William Lallemand1d705562012-03-12 12:46:41 +01002077 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002078 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002079 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002080 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002081 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002082 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002083 last_isspace = 0;
2084 break;
2085
Willy Tarreauc8368452012-12-21 00:09:23 +01002086 case LOG_FMT_EXPR: // sample expression, may be request or response
2087 key = NULL;
Christopher Faulet5f940702020-04-06 10:40:02 +02002088 if (tmp->options & LOG_OPT_REQ_CAP)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002089 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 +02002090 if (!key && (tmp->options & LOG_OPT_RES_CAP))
Adis Nezirovic79beb242015-07-06 15:41:02 +02002091 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 +01002092 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002093 ret = lf_encode_chunk(tmplog, dst + maxsize,
2094 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002095 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002096 ret = lf_text_len(tmplog,
2097 key ? key->data.u.str.area : NULL,
2098 key ? key->data.u.str.data : 0,
2099 dst + maxsize - tmplog,
2100 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002101 if (ret == 0)
2102 goto out;
2103 tmplog = ret;
2104 last_isspace = 0;
2105 break;
2106
Willy Tarreau2beef582012-12-20 17:22:52 +01002107 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002108 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002109 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002110 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002111 else
2112 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002113 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002114 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002115 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002116 last_isspace = 0;
2117 break;
2118
Willy Tarreau2beef582012-12-20 17:22:52 +01002119 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002120 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002121 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002122 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002123 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002124 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002125 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002126 dst + maxsize - tmplog, tmp);
2127 }
William Lallemand5f232402012-04-05 18:02:55 +02002128 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002129 else
2130 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2131
William Lallemand5f232402012-04-05 18:02:55 +02002132 if (ret == NULL)
2133 goto out;
2134 tmplog = ret;
2135 last_isspace = 0;
2136 break;
2137
Willy Tarreau2beef582012-12-20 17:22:52 +01002138 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002139 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002140 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002141 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002142 }
2143 else
2144 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2145
William Lallemand1d705562012-03-12 12:46:41 +01002146 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002147 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002148 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002149 last_isspace = 0;
2150 break;
2151
Willy Tarreau2beef582012-12-20 17:22:52 +01002152 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002153 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002154 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002155 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002156 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002157 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002158 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002159 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002160 else
2161 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2162
William Lallemand5f232402012-04-05 18:02:55 +02002163 if (ret == NULL)
2164 goto out;
2165 tmplog = ret;
2166 last_isspace = 0;
2167 break;
2168
Willy Tarreau2beef582012-12-20 17:22:52 +01002169 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002170 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002171 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002172 else
2173 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2174
William Lallemand1d705562012-03-12 12:46:41 +01002175 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002176 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002177 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002178 last_isspace = 0;
2179 break;
2180
Willy Tarreau2beef582012-12-20 17:22:52 +01002181 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002182 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002183 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002184 else
2185 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2186
William Lallemand5f232402012-04-05 18:02:55 +02002187 if (ret == NULL)
2188 goto out;
2189 tmplog = ret;
2190 last_isspace = 0;
2191 break;
2192
Willy Tarreau2beef582012-12-20 17:22:52 +01002193 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002194 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002195 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002196 else
2197 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2198
William Lallemand5f232402012-04-05 18:02:55 +02002199 if (ret == NULL)
2200 goto out;
2201 tmplog = ret;
2202 last_isspace = 0;
2203 break;
2204
Willy Tarreau2beef582012-12-20 17:22:52 +01002205 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002206 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002207 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002208 else
2209 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2210
William Lallemand1d705562012-03-12 12:46:41 +01002211 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002212 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002213 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002214 last_isspace = 0;
2215 break;
2216
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002217 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002218 get_localtime(logs->accept_date.tv_sec, &tm);
2219 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002220 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002221 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002222 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002223 last_isspace = 0;
2224 break;
2225
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002226 case LOG_FMT_tr: // %tr = start of request date
2227 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002228 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 +02002229 get_localtime(tv.tv_sec, &tm);
2230 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2231 if (ret == NULL)
2232 goto out;
2233 tmplog = ret;
2234 last_isspace = 0;
2235 break;
2236
2237 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002238 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002239 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002240 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002241 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002242 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002243 last_isspace = 0;
2244 break;
2245
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002246 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002247 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 +02002248 get_gmtime(tv.tv_sec, &tm);
2249 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2250 if (ret == NULL)
2251 goto out;
2252 tmplog = ret;
2253 last_isspace = 0;
2254 break;
2255
2256 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002257 get_localtime(logs->accept_date.tv_sec, &tm);
2258 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002259 if (ret == NULL)
2260 goto out;
2261 tmplog = ret;
2262 last_isspace = 0;
2263 break;
2264
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002265 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002266 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 +02002267 get_localtime(tv.tv_sec, &tm);
2268 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2269 if (ret == NULL)
2270 goto out;
2271 tmplog = ret;
2272 last_isspace = 0;
2273 break;
2274
William Lallemand5f232402012-04-05 18:02:55 +02002275 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002276 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002277 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002278 if (iret < 0 || iret > dst + maxsize - tmplog)
2279 goto out;
2280 last_isspace = 0;
2281 tmplog += iret;
2282 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002283 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002284 if (ret == NULL)
2285 goto out;
2286 tmplog = ret;
2287 last_isspace = 0;
2288 }
2289 break;
2290
William Lallemand1d705562012-03-12 12:46:41 +01002291 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002292 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002293 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002294 if (iret < 0 || iret > dst + maxsize - tmplog)
2295 goto out;
2296 last_isspace = 0;
2297 tmplog += iret;
2298 } else {
2299 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002300 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002301 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002302 tmplog, 4);
2303 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002304 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002305 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002306 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002307 }
2308 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002309
William Lallemand1d705562012-03-12 12:46:41 +01002310 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002311 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002312 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002313 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002314 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002315 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002316 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002317 break;
2318
Willy Tarreau773d65f2012-10-12 14:56:11 +02002319 case LOG_FMT_FRONTEND_XPRT: // %ft
2320 src = fe->id;
2321 if (tmp->options & LOG_OPT_QUOTE)
2322 LOGCHAR('"');
2323 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2324 if (iret == 0)
2325 goto out;
2326 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002327 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002328 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002329 if (tmp->options & LOG_OPT_QUOTE)
2330 LOGCHAR('"');
2331 last_isspace = 0;
2332 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002333#ifdef USE_OPENSSL
2334 case LOG_FMT_SSL_CIPHER: // %sslc
2335 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002336 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002337 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002338 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002339 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002340 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2341 if (ret == NULL)
2342 goto out;
2343 tmplog = ret;
2344 last_isspace = 0;
2345 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002346
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002347 case LOG_FMT_SSL_VERSION: // %sslv
2348 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002349 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002350 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002351 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002352 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002353 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2354 if (ret == NULL)
2355 goto out;
2356 tmplog = ret;
2357 last_isspace = 0;
2358 break;
2359#endif
William Lallemand1d705562012-03-12 12:46:41 +01002360 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002361 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002362 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002363 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002364 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002365 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002366 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002367 break;
2368
William Lallemand1d705562012-03-12 12:46:41 +01002369 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002370 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002371 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002372 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002373 break;
2374 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002375 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002376 break;
2377 default:
2378 src = "<NOSRV>";
2379 break;
2380 }
William Lallemand5f232402012-04-05 18:02:55 +02002381 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002382 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002383 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002384 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002385 last_isspace = 0;
2386 break;
2387
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002388 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002389 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002390 if (ret == NULL)
2391 goto out;
2392 tmplog = ret;
2393 last_isspace = 0;
2394 break;
2395
2396 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002397 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002398 if (ret == NULL)
2399 goto out;
2400 tmplog = ret;
2401 last_isspace = 0;
2402 break;
2403
2404 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002405 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002406 tmplog, dst + maxsize - tmplog);
2407 if (ret == NULL)
2408 goto out;
2409 tmplog = ret;
2410 last_isspace = 0;
2411 break;
2412
2413 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002414 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002415 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002416 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002417 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002418 last_isspace = 0;
2419 break;
2420
William Lallemand1d705562012-03-12 12:46:41 +01002421 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002422 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002423 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002424 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002425 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002426 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002427 last_isspace = 0;
2428 break;
2429
William Lallemand1d705562012-03-12 12:46:41 +01002430 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002431 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002432 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002433 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002434 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002435 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002436 last_isspace = 0;
2437 break;
2438
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002439 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002440 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002441 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002442 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002443 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002444 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002445 last_isspace = 0;
2446 break;
2447
Willy Tarreau27b639d2016-05-17 17:55:27 +02002448 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002449 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002450 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002451 tmplog, dst + maxsize - tmplog);
2452 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002453 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002454 tmplog, dst + maxsize - tmplog);
2455 if (ret == NULL)
2456 goto out;
2457 tmplog = ret;
2458 last_isspace = 0;
2459 break;
2460
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002461 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2462 if (!(fe->to_log & LW_BYTES))
2463 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002464 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 +02002465 tmplog, dst + maxsize - tmplog);
2466 if (ret == NULL)
2467 goto out;
2468 tmplog = ret;
2469 last_isspace = 0;
2470 break;
2471
2472 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002473 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002474 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002475 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002476 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002477 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002478 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002479 last_isspace = 0;
2480 break;
2481
Damien Claisse57c8eb92020-04-28 12:09:19 +00002482 case LOG_FMT_TU: // %Tu = total time seen by user = Tt - Ti
2483 if (!(fe->to_log & LW_BYTES))
2484 LOGCHAR('+');
2485 ret = ltoa_o(logs->t_close - (logs->t_idle >= 0 ? logs->t_idle : 0),
2486 tmplog, dst + maxsize - tmplog);
2487 if (ret == NULL)
2488 goto out;
2489 tmplog = ret;
2490 last_isspace = 0;
2491 break;
2492
Willy Tarreau2beef582012-12-20 17:22:52 +01002493 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002494 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002495 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002496 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002497 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002498 last_isspace = 0;
2499 break;
2500
William Lallemand1d705562012-03-12 12:46:41 +01002501 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002502 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002503 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002504 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002505 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002506 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002507 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002508 last_isspace = 0;
2509 break;
2510
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002511 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002512 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002513 if (ret == NULL)
2514 goto out;
2515 tmplog = ret;
2516 last_isspace = 0;
2517 break;
2518
Willy Tarreau2beef582012-12-20 17:22:52 +01002519 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002520 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002521 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002522 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002523 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002524 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002525 last_isspace = 0;
2526 break;
2527
Willy Tarreau2beef582012-12-20 17:22:52 +01002528 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002529 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002530 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002531 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002532 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002533 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002534 last_isspace = 0;
2535 break;
2536
William Lallemand1d705562012-03-12 12:46:41 +01002537 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002538 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2539 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002540 *tmplog = '\0';
2541 last_isspace = 0;
2542 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002543
William Lallemand1d705562012-03-12 12:46:41 +01002544 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002545 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2546 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002547 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2548 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 +01002549 last_isspace = 0;
2550 break;
2551
William Lallemand1d705562012-03-12 12:46:41 +01002552 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002553 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002554 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002555 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002556 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002557 last_isspace = 0;
2558 break;
2559
William Lallemand1d705562012-03-12 12:46:41 +01002560 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002561 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002562 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002563 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002564 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002565 last_isspace = 0;
2566 break;
2567
William Lallemand1d705562012-03-12 12:46:41 +01002568 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002569 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002570 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002571 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002572 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002573 last_isspace = 0;
2574 break;
2575
William Lallemand1d705562012-03-12 12:46:41 +01002576 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002577 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002578 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002579 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002580 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002581 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002582 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002583 last_isspace = 0;
2584 break;
2585
William Lallemand1d705562012-03-12 12:46:41 +01002586 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002587 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002588 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002589 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002590 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002591 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002592 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002593 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002594 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002595 last_isspace = 0;
2596 break;
2597
William Lallemand1d705562012-03-12 12:46:41 +01002598 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002599 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002600 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002601 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002602 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002603 last_isspace = 0;
2604 break;
2605
William Lallemand1d705562012-03-12 12:46:41 +01002606 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002607 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002608 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002609 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002610 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002611 last_isspace = 0;
2612 break;
2613
William Lallemand1d705562012-03-12 12:46:41 +01002614 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002615 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002616 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002617 if (tmp->options & LOG_OPT_QUOTE)
2618 LOGCHAR('"');
2619 LOGCHAR('{');
2620 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2621 if (hdr)
2622 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002623 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002624 ret = lf_encode_string(tmplog, dst + maxsize,
2625 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002626 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002627 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002628 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002629 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002630 }
2631 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002632 if (tmp->options & LOG_OPT_QUOTE)
2633 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002634 last_isspace = 0;
2635 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002636 break;
2637
William Lallemand1d705562012-03-12 12:46:41 +01002638 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002639 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002640 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002641 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2642 if (hdr > 0)
2643 LOGCHAR(' ');
2644 if (tmp->options & LOG_OPT_QUOTE)
2645 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002646 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002647 ret = lf_encode_string(tmplog, dst + maxsize,
2648 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002649 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002650 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002651 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002652 } else if (!(tmp->options & LOG_OPT_QUOTE))
2653 LOGCHAR('-');
2654 if (tmp->options & LOG_OPT_QUOTE)
2655 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002656 last_isspace = 0;
2657 }
2658 }
2659 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002660
William Lallemand1d705562012-03-12 12:46:41 +01002661
2662 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002663 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002664 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002665 if (tmp->options & LOG_OPT_QUOTE)
2666 LOGCHAR('"');
2667 LOGCHAR('{');
2668 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2669 if (hdr)
2670 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002671 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002672 ret = lf_encode_string(tmplog, dst + maxsize,
2673 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002674 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002675 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002676 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002677 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002678 }
2679 LOGCHAR('}');
2680 last_isspace = 0;
2681 if (tmp->options & LOG_OPT_QUOTE)
2682 LOGCHAR('"');
2683 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002684 break;
2685
William Lallemand1d705562012-03-12 12:46:41 +01002686 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002687 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002688 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002689 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2690 if (hdr > 0)
2691 LOGCHAR(' ');
2692 if (tmp->options & LOG_OPT_QUOTE)
2693 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002694 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002695 ret = lf_encode_string(tmplog, dst + maxsize,
2696 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002697 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002698 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002699 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002700 } else if (!(tmp->options & LOG_OPT_QUOTE))
2701 LOGCHAR('-');
2702 if (tmp->options & LOG_OPT_QUOTE)
2703 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002704 last_isspace = 0;
2705 }
2706 }
2707 break;
2708
William Lallemand1d705562012-03-12 12:46:41 +01002709 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002710 /* Request */
2711 if (tmp->options & LOG_OPT_QUOTE)
2712 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002713 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002714 ret = lf_encode_string(tmplog, dst + maxsize,
2715 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002716 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002717 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002718 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002719 if (tmp->options & LOG_OPT_QUOTE)
2720 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002721 last_isspace = 0;
2722 break;
William Lallemand5f232402012-04-05 18:02:55 +02002723
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002724 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002725 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002726
Willy Tarreaub7636d12015-06-17 19:58:02 +02002727 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002728 LOGCHAR('"');
2729
2730 end = uri + strlen(uri);
2731 // look for the first whitespace character
2732 while (uri < end && !HTTP_IS_SPHT(*uri))
2733 uri++;
2734
2735 // keep advancing past multiple spaces
2736 while (uri < end && HTTP_IS_SPHT(*uri)) {
2737 uri++; nspaces++;
2738 }
2739
2740 // look for first space or question mark after url
2741 spc = uri;
2742 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2743 spc++;
2744
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002745 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002746 chunk.area = "<BADREQ>";
2747 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002748 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002749 chunk.area = uri;
2750 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002751 }
2752
Dragan Dosen835b9212016-02-12 13:23:03 +01002753 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002754 if (ret == NULL || *ret != '\0')
2755 goto out;
2756
2757 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002758 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002759 LOGCHAR('"');
2760
2761 last_isspace = 0;
2762 break;
2763
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002764 case LOG_FMT_HTTP_QUERY: // %HQ
2765 if (tmp->options & LOG_OPT_QUOTE)
2766 LOGCHAR('"');
2767
Willy Tarreau57bc8912016-04-25 17:09:40 +02002768 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002769 chunk.area = "<BADREQ>";
2770 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002771 } else {
2772 uri = txn->uri;
2773 end = uri + strlen(uri);
2774 // look for the first question mark
2775 while (uri < end && *uri != '?')
2776 uri++;
2777
2778 qmark = uri;
2779 // look for first space or question mark after url
2780 while (uri < end && !HTTP_IS_SPHT(*uri))
2781 uri++;
2782
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002783 chunk.area = qmark;
2784 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002785 }
2786
Dragan Dosen835b9212016-02-12 13:23:03 +01002787 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002788 if (ret == NULL || *ret != '\0')
2789 goto out;
2790
2791 tmplog = ret;
2792 if (tmp->options & LOG_OPT_QUOTE)
2793 LOGCHAR('"');
2794
2795 last_isspace = 0;
2796 break;
2797
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002798 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002799 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002800
Willy Tarreaub7636d12015-06-17 19:58:02 +02002801 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002802 LOGCHAR('"');
2803
2804 end = uri + strlen(uri);
2805 // look for the first whitespace character
2806 while (uri < end && !HTTP_IS_SPHT(*uri))
2807 uri++;
2808
2809 // keep advancing past multiple spaces
2810 while (uri < end && HTTP_IS_SPHT(*uri)) {
2811 uri++; nspaces++;
2812 }
2813
2814 // look for first space after url
2815 spc = uri;
2816 while (spc < end && !HTTP_IS_SPHT(*spc))
2817 spc++;
2818
Willy Tarreau57bc8912016-04-25 17:09:40 +02002819 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002820 chunk.area = "<BADREQ>";
2821 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002822 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002823 chunk.area = uri;
2824 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002825 }
2826
Dragan Dosen835b9212016-02-12 13:23:03 +01002827 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002828 if (ret == NULL || *ret != '\0')
2829 goto out;
2830
2831 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002832 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002833 LOGCHAR('"');
2834
2835 last_isspace = 0;
2836 break;
2837
2838 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002839 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002840 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002841 LOGCHAR('"');
2842
2843 end = uri + strlen(uri);
2844 // look for the first whitespace character
2845 spc = uri;
2846 while (spc < end && !HTTP_IS_SPHT(*spc))
2847 spc++;
2848
2849 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002850 chunk.area = "<BADREQ>";
2851 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002852 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002853 chunk.area = uri;
2854 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002855 }
2856
Dragan Dosen835b9212016-02-12 13:23:03 +01002857 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002858 if (ret == NULL || *ret != '\0')
2859 goto out;
2860
2861 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002862 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002863 LOGCHAR('"');
2864
2865 last_isspace = 0;
2866 break;
2867
2868 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002869 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002870 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002871 LOGCHAR('"');
2872
2873 end = uri + strlen(uri);
2874 // look for the first whitespace character
2875 while (uri < end && !HTTP_IS_SPHT(*uri))
2876 uri++;
2877
2878 // keep advancing past multiple spaces
2879 while (uri < end && HTTP_IS_SPHT(*uri)) {
2880 uri++; nspaces++;
2881 }
2882
2883 // look for the next whitespace character
2884 while (uri < end && !HTTP_IS_SPHT(*uri))
2885 uri++;
2886
2887 // keep advancing past multiple spaces
2888 while (uri < end && HTTP_IS_SPHT(*uri))
2889 uri++;
2890
Willy Tarreau57bc8912016-04-25 17:09:40 +02002891 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002892 chunk.area = "<BADREQ>";
2893 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002894 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002895 chunk.area = "HTTP/0.9";
2896 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002897 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002898 chunk.area = uri;
2899 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002900 }
2901
Dragan Dosen835b9212016-02-12 13:23:03 +01002902 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002903 if (ret == NULL || *ret != '\0')
2904 goto out;
2905
2906 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002907 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002908 LOGCHAR('"');
2909
2910 last_isspace = 0;
2911 break;
2912
William Lallemand5f232402012-04-05 18:02:55 +02002913 case LOG_FMT_COUNTER: // %rt
2914 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002915 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002916 if (iret < 0 || iret > dst + maxsize - tmplog)
2917 goto out;
2918 last_isspace = 0;
2919 tmplog += iret;
2920 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002921 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002922 if (ret == NULL)
2923 goto out;
2924 tmplog = ret;
2925 last_isspace = 0;
2926 }
2927 break;
2928
Willy Tarreau7346acb2014-08-28 15:03:15 +02002929 case LOG_FMT_LOGCNT: // %lc
2930 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002931 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002932 if (iret < 0 || iret > dst + maxsize - tmplog)
2933 goto out;
2934 last_isspace = 0;
2935 tmplog += iret;
2936 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002937 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002938 if (ret == NULL)
2939 goto out;
2940 tmplog = ret;
2941 last_isspace = 0;
2942 }
2943 break;
2944
William Lallemand5f232402012-04-05 18:02:55 +02002945 case LOG_FMT_HOSTNAME: // %H
2946 src = hostname;
2947 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2948 if (ret == NULL)
2949 goto out;
2950 tmplog = ret;
2951 last_isspace = 0;
2952 break;
2953
2954 case LOG_FMT_PID: // %pid
2955 if (tmp->options & LOG_OPT_HEXA) {
2956 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2957 if (iret < 0 || iret > dst + maxsize - tmplog)
2958 goto out;
2959 last_isspace = 0;
2960 tmplog += iret;
2961 } else {
2962 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2963 if (ret == NULL)
2964 goto out;
2965 tmplog = ret;
2966 last_isspace = 0;
2967 }
2968 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002969
2970 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002971 ret = NULL;
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002972 if (s)
2973 ret = lf_text_len(tmplog, s->unique_id.ptr, s->unique_id.len, maxsize - (tmplog - dst), tmp);
2974 else
2975 ret = lf_text_len(tmplog, NULL, 0, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002976 if (ret == NULL)
2977 goto out;
2978 tmplog = ret;
2979 last_isspace = 0;
2980 break;
2981
William Lallemandbddd4fd2012-02-27 11:23:10 +01002982 }
2983 }
2984
2985out:
William Lallemand1d705562012-03-12 12:46:41 +01002986 /* *tmplog is a unused character */
2987 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002988 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002989
Willy Tarreaubaaee002006-06-26 02:48:02 +02002990}
2991
William Lallemand1d705562012-03-12 12:46:41 +01002992/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002993 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002994 * Will not log if the frontend has no log defined.
2995 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002996void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002997{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002998 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002999 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003000 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01003001
3002 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02003003 err = (s->flags & SF_REDISP) ||
3004 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
3005 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01003006 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02003007 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003008
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003009 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01003010 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003011
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003012 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01003013 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003014
Willy Tarreauabcd5142013-06-11 17:18:02 +02003015 if (s->logs.level) { /* loglevel was overridden */
3016 if (s->logs.level == -1) {
3017 s->logs.logwait = 0; /* logs disabled */
3018 return;
3019 }
3020 level = s->logs.level - 1;
3021 }
3022 else {
3023 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003024 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02003025 level = LOG_ERR;
3026 }
William Lallemand1d705562012-03-12 12:46:41 +01003027
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003028 /* if unique-id was not generated */
Tim Duesterhusa17e6622020-03-05 20:19:02 +01003029 if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Tim Duesterhus2825b4b2020-02-28 15:13:34 +01003030 stream_generate_unique_id(s, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003031 }
3032
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003033 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3034 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
3035 &sess->fe->logformat_sd);
3036 }
3037
Dragan Dosen59cee972015-09-19 22:09:02 +02003038 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01003039 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003040 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003041 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3042 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01003043 s->logs.logwait = 0;
3044 }
3045}
William Lallemandbddd4fd2012-02-27 11:23:10 +01003046
Willy Tarreau53839352018-09-05 19:51:10 +02003047/*
3048 * send a minimalist log for the session. Will not log if the frontend has no
3049 * log defined. It is assumed that this is only used to report anomalies that
3050 * cannot lead to the creation of a regular stream. Because of this the log
3051 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
3052 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003053 * function to report unimportant events. It is safe to call this function with
3054 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02003055 */
3056void sess_log(struct session *sess)
3057{
3058 int size, level;
3059 int sd_size = 0;
3060
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003061 if (!sess)
3062 return;
3063
Willy Tarreau53839352018-09-05 19:51:10 +02003064 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3065 return;
3066
3067 level = LOG_INFO;
3068 if (sess->fe->options2 & PR_O2_LOGERRORS)
3069 level = LOG_ERR;
3070
3071 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3072 sd_size = sess_build_logline(sess, NULL,
3073 logline_rfc5424, global.max_syslog_len,
3074 &sess->fe->logformat_sd);
3075 }
3076
3077 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3078 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003079 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003080 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3081 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003082 }
3083}
3084
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003085void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3086{
3087 va_list argp;
3088 int data_len;
3089
3090 if (level < 0 || format == NULL || logline == NULL)
3091 return;
3092
3093 va_start(argp, format);
3094 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3095 if (data_len < 0 || data_len > global.max_syslog_len)
3096 data_len = global.max_syslog_len;
3097 va_end(argp);
3098
3099 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3100}
3101
Willy Tarreau869efd52019-11-15 15:16:57 +01003102/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3103static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003104{
Willy Tarreau869efd52019-11-15 15:16:57 +01003105 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3106 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003107
Willy Tarreau869efd52019-11-15 15:16:57 +01003108 if (!startup_logs)
3109 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3110
3111 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003112}
3113
3114/* register cli keywords */
3115static struct cli_kw_list cli_kws = {{ },{
3116 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003117 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003118 {{},}
3119}};
3120
Willy Tarreau0108d902018-11-25 19:14:37 +01003121INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3122
Willy Tarreau082b6282019-05-22 14:42:12 +02003123REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3124REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003125
Willy Tarreaubaaee002006-06-26 02:48:02 +02003126/*
3127 * Local variables:
3128 * c-indent-level: 8
3129 * c-basic-offset: 8
3130 * End:
3131 */