blob: 2bc0990c3da340156bf24ac505aa19b722d4b6e3 [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 Tarreau762d7a52020-06-04 11:23:07 +020028#include <haproxy/frontend.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +020029#include <haproxy/http.h>
Willy Tarreau48fbcae2020-06-03 18:09:46 +020030#include <haproxy/tools.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020031#include <haproxy/time.h>
Willy Tarreaud6788052020-05-27 15:59:00 +020032#include <haproxy/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020033
Christopher Fauletc1b730a2017-10-24 12:00:51 +020034#include <types/cli.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020035#include <types/global.h>
William Lallemand723b73a2012-02-08 16:37:49 +010036#include <types/log.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020037
Christopher Fauletc1b730a2017-10-24 12:00:51 +020038#include <proto/applet.h>
39#include <proto/cli.h>
Willy Tarreau0f6ffd62020-06-03 19:33:00 +020040#include <haproxy/fd.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020041#include <proto/log.h>
Willy Tarreaud2ad57c2020-06-03 19:43:35 +020042#include <haproxy/ring.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020043#include <haproxy/sample.h>
Willy Tarreauba2f73d2020-06-03 20:02:28 +020044#include <haproxy/sink.h>
Willy Tarreauc125cef2019-05-10 09:58:43 +020045#include <proto/ssl_sock.h>
Willy Tarreaufb0afa72015-04-03 14:46:27 +020046#include <proto/stream.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010047#include <proto/stream_interface.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020048
Dragan Dosen43885c72015-10-01 13:18:13 +020049struct log_fmt {
50 char *name;
51 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020052 struct buffer sep1; /* first pid separator */
53 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020054 } pid;
55};
56
57static const struct log_fmt log_formats[LOG_FORMATS] = {
58 [LOG_FORMAT_RFC3164] = {
59 .name = "rfc3164",
60 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020061 .sep1 = { .area = "[", .data = 1 },
62 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020063 }
64 },
65 [LOG_FORMAT_RFC5424] = {
66 .name = "rfc5424",
67 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020068 .sep1 = { .area = " ", .data = 1 },
69 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020070 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010071 },
72 [LOG_FORMAT_SHORT] = {
73 .name = "short",
74 .pid = {
75 .sep1 = { .area = "", .data = 0 },
76 .sep2 = { .area = " ", .data = 1 },
77 }
78 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010079 [LOG_FORMAT_RAW] = {
80 .name = "raw",
81 .pid = {
82 .sep1 = { .area = "", .data = 0 },
83 .sep2 = { .area = "", .data = 0 },
84 }
85 },
Dragan Dosen1322d092015-09-22 16:05:32 +020086};
87
Emeric Brunbd163812020-05-06 14:33:46 +020088char *get_format_pid_sep1(int format, size_t *len)
89{
90 *len = log_formats[format].pid.sep1.data;
91 return log_formats[format].pid.sep1.area;
92}
93
94char *get_format_pid_sep2(int format, size_t *len)
95{
96 *len = log_formats[format].pid.sep2.data;
97 return log_formats[format].pid.sep2.area;
98}
99
Dragan Dosen835b9212016-02-12 13:23:03 +0100100/*
101 * This map is used with all the FD_* macros to check whether a particular bit
Willy Tarreau1bfd6022019-06-07 11:10:07 +0200102 * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
103 * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
104 * that the byte should be escaped. Be careful to always pass bytes from 0 to
105 * 255 exclusively to the macros.
Dragan Dosen835b9212016-02-12 13:23:03 +0100106 */
Willy Tarreau1bfd6022019-06-07 11:10:07 +0200107long rfc5424_escape_map[(256/8) / sizeof(long)];
108long hdr_encode_map[(256/8) / sizeof(long)];
109long url_encode_map[(256/8) / sizeof(long)];
110long http_encode_map[(256/8) / sizeof(long)];
Dragan Dosen835b9212016-02-12 13:23:03 +0100111
Dragan Dosen835b9212016-02-12 13:23:03 +0100112
Willy Tarreaubaaee002006-06-26 02:48:02 +0200113const char *log_facilities[NB_LOG_FACILITIES] = {
114 "kern", "user", "mail", "daemon",
115 "auth", "syslog", "lpr", "news",
116 "uucp", "cron", "auth2", "ftp",
117 "ntp", "audit", "alert", "cron2",
118 "local0", "local1", "local2", "local3",
119 "local4", "local5", "local6", "local7"
120};
121
Willy Tarreaubaaee002006-06-26 02:48:02 +0200122const char *log_levels[NB_LOG_LEVELS] = {
123 "emerg", "alert", "crit", "err",
124 "warning", "notice", "info", "debug"
125};
126
Willy Tarreau570f2212013-06-10 16:42:09 +0200127const 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 +0200128const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200129
William Lallemand723b73a2012-02-08 16:37:49 +0100130
131/* log_format */
132struct logformat_type {
133 char *name;
134 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100135 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200136 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100137 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100138 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100139};
140
William Lallemandb7ff6a32012-03-02 14:35:21 +0100141int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
142
William Lallemand723b73a2012-02-08 16:37:49 +0100143/* log_format variable names */
144static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200145 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100146
147 /* please keep these lines sorted ! */
148 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
149 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
150 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
151 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +0100152 { "ID", LOG_FMT_UNIQUEID, PR_MODE_TCP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200153 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200154 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200155 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100156 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200157 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
158 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
159 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
160 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
161 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
162 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200163 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100164 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200165 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Damien Claisse57c8eb92020-04-28 12:09:19 +0000166 { "Tu", LOG_FMT_TU, PR_MODE_TCP, LW_BYTES, NULL }, /* Tu = Tt -Ti */
Willy Tarreau2beef582012-12-20 17:22:52 +0100167 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
168 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200169 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100170 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200171 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100172 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
173 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200174 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200175 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
176 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100177 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
178 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200179 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
180 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100181 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200182 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
183 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
184 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
185 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000186 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
187 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000188 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000189 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
190 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200191 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100192 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200193 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100194 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
195 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100196 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100197 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
198 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
199 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
200 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
201 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200202 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
203 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100204 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200205 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
206 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
207 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100208 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
209 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
210
211 /* The following tags are deprecated and will be removed soon */
212 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
213 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200214 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
215 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
216 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
217 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100218 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
219 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
220 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
221 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
222 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200223 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100224};
225
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200226char 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
227char 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 +0100228char 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 +0100229char *log_format = NULL;
230
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200231/* Default string used for structured-data part in RFC5424 formatted
232 * syslog messages.
233 */
234char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200235
Willy Tarreau13ef7732018-11-12 07:25:28 +0100236/* total number of dropped logs */
237unsigned int dropped_logs = 0;
238
Dragan Dosen1322d092015-09-22 16:05:32 +0200239/* This is a global syslog header, common to all outgoing messages in
240 * RFC3164 format. It begins with time-based part and is updated by
241 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200242 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200243THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200244THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200245
Dragan Dosen1322d092015-09-22 16:05:32 +0200246/* This is a global syslog header for messages in RFC5424 format. It is
247 * updated by update_log_hdr_rfc5424().
248 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200249THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200250THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200251
Dragan Dosen59cee972015-09-19 22:09:02 +0200252/* This is a global syslog message buffer, common to all outgoing
253 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100254 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200255THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100256
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200257/* A global syslog message buffer, common to all RFC5424 syslog messages.
258 * Currently, it is used for generating the structured-data part.
259 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200260THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200261
Christopher Fauletd4696382017-10-24 11:44:05 +0200262/* A global buffer used to store all startup alerts/warnings. It will then be
263 * retrieve on the CLI. */
Willy Tarreau869efd52019-11-15 15:16:57 +0100264static struct ring *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200265
William Lallemand723b73a2012-02-08 16:37:49 +0100266struct logformat_var_args {
267 char *name;
268 int mask;
269};
270
271struct logformat_var_args var_args_list[] = {
272// global
273 { "M", LOG_OPT_MANDATORY },
274 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200275 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100276 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100277 { 0, 0 }
278};
279
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200280/* return the name of the directive used in the current proxy for which we're
281 * currently parsing a header, when it is known.
282 */
283static inline const char *fmt_directive(const struct proxy *curproxy)
284{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100285 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200286 case ARGC_ACL:
287 return "acl";
288 case ARGC_STK:
289 return "stick";
290 case ARGC_TRK:
291 return "track-sc";
292 case ARGC_LOG:
293 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200294 case ARGC_LOGSD:
295 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100296 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100297 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100298 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100299 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200300 case ARGC_UIF:
301 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100302 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200303 return "redirect";
304 case ARGC_CAP:
305 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200306 case ARGC_SRV:
307 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200308 case ARGC_SPOE:
309 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100310 case ARGC_UBK:
311 return "use_backend";
Christopher Faulet3b967c12020-05-15 15:47:44 +0200312 case ARGC_HERR:
313 return "http-error";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100314 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200315 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100316 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200317}
318
William Lallemand723b73a2012-02-08 16:37:49 +0100319/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100320 * callback used to configure addr source retrieval
321 */
322int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
323{
324 curproxy->options2 |= PR_O2_SRC_ADDR;
325
326 return 0;
327}
328
329
330/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100331 * Parse args in a logformat_var. Returns 0 in error
332 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100333 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100334int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100335{
336 int i = 0;
337 int end = 0;
338 int flags = 0; // 1 = + 2 = -
339 char *sp = NULL; // start pointer
340
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100341 if (args == NULL) {
342 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100343 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100344 }
William Lallemand723b73a2012-02-08 16:37:49 +0100345
346 while (1) {
347 if (*args == '\0')
348 end = 1;
349
350 if (*args == '+') {
351 // add flag
352 sp = args + 1;
353 flags = 1;
354 }
355 if (*args == '-') {
356 // delete flag
357 sp = args + 1;
358 flags = 2;
359 }
360
361 if (*args == '\0' || *args == ',') {
362 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100363 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100364 if (strcmp(sp, var_args_list[i].name) == 0) {
365 if (flags == 1) {
366 node->options |= var_args_list[i].mask;
367 break;
368 } else if (flags == 2) {
369 node->options &= ~var_args_list[i].mask;
370 break;
371 }
372 }
373 }
374 sp = NULL;
375 if (end)
376 break;
377 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100378 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100379 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100380 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100381}
382
383/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100384 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
385 * must pass the args part in the <arg> pointer with its length in <arg_len>,
386 * and varname with its length in <var> and <var_len> respectively. <arg> is
387 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100388 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100389 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100390int 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 +0100391{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100392 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200393 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100394
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100395 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
396 if (strlen(logformat_keywords[j].name) == var_len &&
397 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
398 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200399 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100400 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100401 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200402 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100403 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100404 node->type = logformat_keywords[j].type;
405 node->options = *defoptions;
406 if (arg_len) {
407 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100408 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200409 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100410 }
411 if (node->type == LOG_FMT_GLOBAL) {
412 *defoptions = node->options;
413 free(node->arg);
414 free(node);
415 } else {
416 if (logformat_keywords[j].config_callback &&
417 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200418 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100419 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100420 curproxy->to_log |= logformat_keywords[j].lw;
421 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100422 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100423 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100424 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
425 curproxy->conf.args.file, curproxy->conf.args.line,
426 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100427 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100428 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100429 memprintf(err, "format variable '%s' is reserved for HTTP mode",
430 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200431 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100432 }
William Lallemand723b73a2012-02-08 16:37:49 +0100433 }
434 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100435
436 j = var[var_len];
437 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100438 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 +0100439 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200440
441 error_free:
442 if (node) {
443 free(node->arg);
444 free(node);
445 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100446 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100447}
448
449/*
450 * push to the logformat linked list
451 *
452 * start: start pointer
453 * end: end text pointer
454 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100455 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100456 *
457 * LOG_TEXT: copy chars from start to end excluding end.
458 *
459*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100460int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100461{
462 char *str;
463
Willy Tarreaua3571662012-12-20 21:59:12 +0100464 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200465 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100466 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100467 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100468 return 0;
469 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200470 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100471 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100472 str[end - start] = '\0';
473 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100474 node->type = LOG_FMT_TEXT; // type string
475 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100476 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200477 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100478 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100479 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100480 return 0;
481 }
William Lallemand1d705562012-03-12 12:46:41 +0100482 node->type = LOG_FMT_SEPARATOR;
483 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100484 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100485 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100486}
487
488/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100489 * Parse the sample fetch expression <text> and add a node to <list_format> upon
490 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100491 * should work. The curpx->conf.args.ctx must be set by the caller. If an end pointer
492 * is passed in <endptr>, it will be updated with the pointer to the first character
493 * not part of the sample expression.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100494 *
495 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100496 */
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100497int 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 +0100498{
499 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200500 struct sample_expr *expr = NULL;
501 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100502 int cmd_arg;
503
504 cmd[0] = text;
505 cmd[1] = "";
506 cmd_arg = 0;
507
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100508 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 +0100509 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100510 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200511 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100512 }
513
Vincent Bernat02779b62016-04-03 13:48:43 +0200514 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100515 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100516 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200517 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100518 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100519 node->type = LOG_FMT_EXPR;
520 node->expr = expr;
521 node->options = options;
522
523 if (arg_len) {
524 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100525 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200526 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100527 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100528 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100529 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
530
Willy Tarreau434c57c2013-01-08 01:10:24 +0100531 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100532 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
533
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100534 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100535 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
536 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200537 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100538 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100539
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200540 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100541 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100542 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100543
William Lallemand65ad6e12014-01-31 15:08:02 +0100544 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
545 * needed with some sample fetches (eg: ssl*). We always set it for
546 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100547 */
548 curpx->to_log |= LW_XPRT;
Christopher Fauletd2236cd2020-04-06 18:29:14 +0200549 if (curpx->http_needed)
550 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100551 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100552 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200553
554 error_free:
555 release_sample_expr(expr);
556 if (node) {
557 free(node->arg);
558 free(node);
559 }
560 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100561}
562
563/*
William Lallemand723b73a2012-02-08 16:37:49 +0100564 * Parse the log_format string and fill a linked list.
565 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200566 * You can set arguments using { } : %{many arguments}varname.
567 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100568 *
Ilya Shipitsinae40dbc2020-04-04 12:59:53 +0500569 * fmt: the string to parse
William Lallemand1d705562012-03-12 12:46:41 +0100570 * curproxy: the proxy affected
571 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100572 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100573 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100574 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100575 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100576 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100577int 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 +0100578{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100579 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100580 char *arg = NULL; /* start pointer for args */
581 char *var = NULL; /* start pointer for vars */
582 int arg_len = 0;
583 int var_len = 0;
584 int cformat; /* current token format */
585 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100586 struct logformat_node *tmplf, *back;
587
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100588 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100589 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100590 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100591 return 0;
592 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200593 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200594
William Lallemand723b73a2012-02-08 16:37:49 +0100595 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100596 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100597 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200598 release_sample_expr(tmplf->expr);
599 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100600 free(tmplf);
601 }
602
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100603 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100604 pformat = cformat;
605
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100606 if (!*str)
607 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100608
Joseph Herlant85b40592018-11-15 12:10:04 -0800609 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100610 * second have all common paths processed at one place. The common paths are the ones
611 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
612 * We use the common LF_INIT state to dispatch to the different final states.
613 */
614 switch (pformat) {
615 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100616 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100617 arg_len = var_len = 0;
618 if (*str == '{') { // optional argument
619 cformat = LF_STARG;
620 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100621 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100622 else if (*str == '[') {
623 cformat = LF_STEXPR;
624 var = str + 1; // store expr in variable name
625 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100626 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100627 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100628 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100629 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100630 else if (*str == '%')
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500631 cformat = LF_TEXT; // convert this character to a literal (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100632 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100633 /* single '%' followed by blank or digit, send them both */
634 cformat = LF_TEXT;
635 pformat = LF_TEXT; /* finally we include the previous char as well */
636 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600637 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 +0100638 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100639 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100640
641 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100642 else
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500643 cformat = LF_INIT; // handle other cases of literals
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100644 break;
645
646 case LF_STARG: // text immediately following '%{'
647 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100648 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100649 arg_len = str - arg;
650 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100651 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100652 break;
653
654 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100655 if (*str == '[') {
656 cformat = LF_STEXPR;
657 var = str + 1; // store expr in variable name
658 break;
659 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100660 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100661 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100662 var = str;
663 break;
664 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100665 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100666 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100667
Willy Tarreauc8368452012-12-21 00:09:23 +0100668 case LF_STEXPR: // text immediately following '%['
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100669 /* the whole sample expression is parsed at once,
670 * returning the pointer to the first character not
671 * part of the expression, which MUST be the trailing
672 * angle bracket.
673 */
674 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str))
675 goto fail;
676
677 if (*str == ']') {
678 // end of arg, go on with next state
679 cformat = pformat = LF_EDEXPR;
680 sp = str;
681 }
682 else {
683 char c = *str;
684 *str = 0;
Willy Tarreau90807112020-02-25 08:16:33 +0100685 if (isprint((unsigned char)c))
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100686 memprintf(err, "expected ']' after '%s', but found '%c'", var, c);
687 else
688 memprintf(err, "missing ']' after '%s'", var);
Willy Tarreauc8368452012-12-21 00:09:23 +0100689 }
690 break;
691
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100692 case LF_VAR: // text part of a variable name
693 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100694 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100695 cformat = LF_INIT; // not variable name anymore
696 break;
697
Willy Tarreauc8368452012-12-21 00:09:23 +0100698 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100699 cformat = LF_INIT;
700 }
701
702 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
703 switch (*str) {
704 case '%': cformat = LF_STARTVAR; break;
705 case ' ': cformat = LF_SEPARATOR; break;
706 case 0 : cformat = LF_END; break;
707 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100708 }
709 }
710
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100711 if (cformat != pformat || pformat == LF_SEPARATOR) {
712 switch (pformat) {
713 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100714 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100715 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100716 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100717 case LF_STEXPR:
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100718 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &sp))
Willy Tarreau51013e82019-12-11 12:05:39 +0100719 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100720 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100721 case LF_TEXT:
722 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100723 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100724 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100725 break;
726 }
727 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100728 }
729 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100730
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100731 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100732 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100733 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100734 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100735 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100736
737 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100738 fail:
739 free(backfmt);
740 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100741}
742
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200743/*
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500744 * 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 +0200745 * ranges of indexes. Note that an index may be considered as a particular range
746 * with a high limit to the low limit.
747 */
748int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
749{
750 char *end, *p;
751
752 *low = *high = 0;
753
754 p = *arg;
755 end = strchr(p, ',');
756 if (!end)
757 end = p + strlen(p);
758
759 *high = *low = read_uint((const char **)&p, end);
760 if (!*low || (p != end && *p != '-'))
761 goto err;
762
763 if (p == end)
764 goto done;
765
766 p++;
767 *high = read_uint((const char **)&p, end);
768 if (!*high || *high <= *low || p != end)
769 goto err;
770
771 done:
772 if (*end == ',')
773 end++;
774 *arg = end;
775 return 1;
776
777 err:
778 memprintf(err, "wrong sample range '%s'", *arg);
779 return 0;
780}
781
782/*
783 * Returns 1 if the range defined by <low> and <high> overlaps
784 * one of them in <rgs> array of ranges with <sz> the size of this
785 * array, 0 if not.
786 */
787int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
788 unsigned int low, unsigned int high, char **err)
789{
790 size_t i;
791
792 for (i = 0; i < sz; i++) {
793 if ((low >= rgs[i].low && low <= rgs[i].high) ||
794 (high >= rgs[i].low && high <= rgs[i].high)) {
795 memprintf(err, "ranges are overlapping");
796 return 1;
797 }
798 }
799
800 return 0;
801}
802
803int smp_log_range_cmp(const void *a, const void *b)
804{
805 const struct smp_log_range *rg_a = a;
806 const struct smp_log_range *rg_b = b;
807
808 if (rg_a->high < rg_b->low)
809 return -1;
810 else if (rg_a->low > rg_b->high)
811 return 1;
812
813 return 0;
814}
815
816/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200817 * Parse "log" keyword and update <logsrvs> list accordingly.
818 *
819 * When <do_del> is set, it means the "no log" line was parsed, so all log
820 * servers in <logsrvs> are released.
821 *
822 * Otherwise, we try to parse the "log" line. First of all, when the list is not
823 * the global one, we look for the parameter "global". If we find it,
824 * global.logsrvs is copied. Else we parse each arguments.
825 *
826 * The function returns 1 in success case, otherwise, it returns 0 and err is
827 * filled.
828 */
829int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
830{
831 struct sockaddr_storage *sk;
832 struct logsrv *logsrv = NULL;
833 int port1, port2;
834 int cur_arg;
835
836 /*
837 * "no log": delete previous herited or defined syslog
838 * servers.
839 */
840 if (do_del) {
841 struct logsrv *back;
842
843 if (*(args[1]) != 0) {
844 memprintf(err, "'no log' does not expect arguments");
845 goto error;
846 }
847
848 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
849 LIST_DEL(&logsrv->list);
850 free(logsrv);
851 }
852 return 1;
853 }
854
855 /*
856 * "log global": copy global.logrsvs linked list to the end of logsrvs
857 * list. But first, we check (logsrvs != global.logsrvs).
858 */
859 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
860 if (logsrvs == &global.logsrvs) {
861 memprintf(err, "'global' is not supported for a global syslog server");
862 goto error;
863 }
864 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200865 struct logsrv *node;
866
867 list_for_each_entry(node, logsrvs, list) {
868 if (node->ref == logsrv)
869 goto skip_logsrv;
870 }
871
872 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200873 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200874 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200875 LIST_INIT(&node->list);
876 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200877
878 skip_logsrv:
879 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200880 }
881 return 1;
882 }
883
884 /*
885 * "log <address> ...: parse a syslog server line
886 */
887 if (*(args[1]) == 0 || *(args[2]) == 0) {
888 memprintf(err, "expects <address> and <facility> %s as arguments",
889 ((logsrvs == &global.logsrvs) ? "" : "or global"));
890 goto error;
891 }
892
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100893 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
894 if (strcmp(args[1], "stdout") == 0)
895 args[1] = "fd@1";
896 else if (strcmp(args[1], "stderr") == 0)
897 args[1] = "fd@2";
898
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200899 logsrv = calloc(1, sizeof(*logsrv));
900 if (!logsrv) {
901 memprintf(err, "out of memory");
902 goto error;
903 }
904
905 /* skip address for now, it will be parsed at the end */
906 cur_arg = 2;
907
908 /* just after the address, a length may be specified */
909 logsrv->maxlen = MAX_SYSLOG_LEN;
910 if (strcmp(args[cur_arg], "len") == 0) {
911 int len = atoi(args[cur_arg+1]);
912 if (len < 80 || len > 65535) {
913 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
914 args[cur_arg+1]);
915 goto error;
916 }
917 logsrv->maxlen = len;
918 cur_arg += 2;
919 }
920 if (logsrv->maxlen > global.max_syslog_len)
921 global.max_syslog_len = logsrv->maxlen;
922
923 /* after the length, a format may be specified */
924 if (strcmp(args[cur_arg], "format") == 0) {
925 logsrv->format = get_log_format(args[cur_arg+1]);
926 if (logsrv->format < 0) {
927 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
928 goto error;
929 }
930 cur_arg += 2;
931 }
932
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200933 if (strcmp(args[cur_arg], "sample") == 0) {
934 unsigned low, high;
935 char *p, *beg, *end, *smp_sz_str;
936 struct smp_log_range *smp_rgs = NULL;
937 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
938
939 p = args[cur_arg+1];
940 smp_sz_str = strchr(p, ':');
941 if (!smp_sz_str) {
942 memprintf(err, "Missing sample size");
943 goto error;
944 }
945
946 *smp_sz_str++ = '\0';
947
948 end = p + strlen(p);
949
950 while (p != end) {
951 if (!get_logsrv_smp_range(&low, &high, &p, err))
952 goto error;
953
954 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
955 goto error;
956
957 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
958 if (!smp_rgs) {
959 memprintf(err, "out of memory error");
960 goto error;
961 }
962
963 smp_rgs[smp_rgs_sz].low = low;
964 smp_rgs[smp_rgs_sz].high = high;
965 smp_rgs[smp_rgs_sz].sz = high - low + 1;
966 smp_rgs[smp_rgs_sz].curr_idx = 0;
967 if (smp_rgs[smp_rgs_sz].high > smp_sz)
968 smp_sz = smp_rgs[smp_rgs_sz].high;
969 smp_rgs_sz++;
970 }
971
Tim Duesterhus21648002019-06-23 22:10:10 +0200972 if (smp_rgs == NULL) {
973 memprintf(err, "no sampling ranges given");
974 goto error;
975 }
976
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200977 beg = smp_sz_str;
978 end = beg + strlen(beg);
979 new_smp_sz = read_uint((const char **)&beg, end);
980 if (!new_smp_sz || beg != end) {
981 memprintf(err, "wrong sample size '%s' for sample range '%s'",
982 smp_sz_str, args[cur_arg+1]);
983 goto error;
984 }
985
986 if (new_smp_sz < smp_sz) {
987 memprintf(err, "sample size %zu should be greater or equal to "
988 "%zu the maximum of the high ranges limits",
989 new_smp_sz, smp_sz);
990 goto error;
991 }
992 smp_sz = new_smp_sz;
993
994 /* Let's order <smp_rgs> array. */
995 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
996
997 logsrv->lb.smp_rgs = smp_rgs;
998 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
999 logsrv->lb.smp_sz = smp_sz;
1000
1001 cur_arg += 2;
1002 }
Frédéric Lécailled803e472019-04-25 07:42:09 +02001003 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001004 /* parse the facility */
1005 logsrv->facility = get_log_facility(args[cur_arg]);
1006 if (logsrv->facility < 0) {
1007 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
1008 goto error;
1009 }
1010 cur_arg++;
1011
1012 /* parse the max syslog level (default: debug) */
1013 logsrv->level = 7;
1014 if (*(args[cur_arg])) {
1015 logsrv->level = get_log_level(args[cur_arg]);
1016 if (logsrv->level < 0) {
1017 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
1018 goto error;
1019 }
1020 cur_arg++;
1021 }
1022
1023 /* parse the limit syslog level (default: emerg) */
1024 logsrv->minlvl = 0;
1025 if (*(args[cur_arg])) {
1026 logsrv->minlvl = get_log_level(args[cur_arg]);
1027 if (logsrv->minlvl < 0) {
1028 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
1029 goto error;
1030 }
1031 cur_arg++;
1032 }
1033
1034 /* Too many args */
1035 if (*(args[cur_arg])) {
1036 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1037 goto error;
1038 }
1039
1040 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001041 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001042 if (strncmp(args[1], "ring@", 5) == 0) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001043 logsrv->addr.ss_family = AF_UNSPEC;
1044 logsrv->type = LOG_TARGET_BUFFER;
Emeric Brun99c453d2020-05-25 15:01:04 +02001045 logsrv->sink = NULL;
1046 logsrv->ring_name = strdup(args[1] + 5);
Willy Tarreauc046d162019-08-30 15:24:59 +02001047 goto done;
1048 }
1049
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001050 if (strncmp(args[1], "fd@", 3) == 0)
1051 logsrv->type = LOG_TARGET_FD;
1052
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001053 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1054 if (!sk)
1055 goto error;
1056 logsrv->addr = *sk;
1057
1058 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1059 if (port1 != port2) {
1060 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1061 goto error;
1062 }
1063 logsrv->addr = *sk;
1064 if (!port1)
1065 set_host_port(&logsrv->addr, SYSLOG_PORT);
1066 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001067 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001068 LIST_ADDQ(logsrvs, &logsrv->list);
1069 return 1;
1070
1071 error:
1072 free(logsrv);
1073 return 0;
1074}
1075
1076
Christopher Fauletd4696382017-10-24 11:44:05 +02001077/* Generic function to display messages prefixed by a label */
1078static void print_message(const char *label, const char *fmt, va_list argp)
1079{
1080 struct tm tm;
1081 char *head, *msg;
1082
1083 head = msg = NULL;
1084
1085 get_localtime(date.tv_sec, &tm);
1086 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1087 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1088 memvprintf(&msg, fmt, argp);
1089
Willy Tarreau869efd52019-11-15 15:16:57 +01001090 if (global.mode & MODE_STARTING) {
1091 if (unlikely(!startup_logs))
1092 startup_logs = ring_new(STARTUP_LOG_SIZE);
1093
1094 if (likely(startup_logs)) {
1095 struct ist m[2];
1096
1097 m[0] = ist(head);
1098 m[1] = ist(msg);
1099 /* trim the trailing '\n' */
1100 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1101 m[1].len--;
1102 ring_write(startup_logs, ~0, 0, 0, m, 2);
1103 }
1104 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001105
1106 fprintf(stderr, "%s%s", head, msg);
1107 fflush(stderr);
1108
1109 free(head);
1110 free(msg);
1111}
1112
Willy Tarreaubaaee002006-06-26 02:48:02 +02001113/*
1114 * Displays the message on stderr with the date and pid. Overrides the quiet
1115 * mode during startup.
1116 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001117void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001118{
1119 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001120
1121 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Willy Tarreaubb869862020-04-16 10:52:41 +02001122 if (!(warned & WARN_EXEC_PATH)) {
1123 const char *path = get_exec_path();
1124
1125 warned |= WARN_EXEC_PATH;
1126 ha_notice("haproxy version is %s\n", haproxy_version);
1127 if (path)
1128 ha_notice("path to executable is %s\n", path);
1129 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001130 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001131 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001132 va_end(argp);
1133 }
1134}
1135
1136
1137/*
1138 * Displays the message on stderr with the date and pid.
1139 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001140void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001141{
1142 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001143
Willy Tarreaubebd2122020-04-15 16:06:11 +02001144 warned |= WARN_ANY;
1145
Willy Tarreaubaaee002006-06-26 02:48:02 +02001146 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1147 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001148 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001149 va_end(argp);
1150 }
1151}
1152
1153/*
William Lallemand9c56a222018-11-21 18:04:52 +01001154 * Displays the message on stderr with the date and pid.
1155 */
1156void ha_notice(const char *fmt, ...)
1157{
1158 va_list argp;
1159
1160 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1161 va_start(argp, fmt);
1162 print_message("NOTICE", fmt, argp);
1163 va_end(argp);
1164 }
1165}
1166
1167/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001168 * Displays the message on <out> only if quiet mode is not set.
1169 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001170void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001171{
1172 va_list argp;
1173
1174 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1175 va_start(argp, fmt);
1176 vfprintf(out, fmt, argp);
1177 fflush(out);
1178 va_end(argp);
1179 }
1180}
1181
1182/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001183 * returns log format for <fmt> or -1 if not found.
1184 */
1185int get_log_format(const char *fmt)
1186{
1187 int format;
1188
1189 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001190 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001191 format--;
1192
1193 return format;
1194}
1195
1196/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001197 * returns log level for <lev> or -1 if not found.
1198 */
1199int get_log_level(const char *lev)
1200{
1201 int level;
1202
1203 level = NB_LOG_LEVELS - 1;
1204 while (level >= 0 && strcmp(log_levels[level], lev))
1205 level--;
1206
1207 return level;
1208}
1209
Willy Tarreaubaaee002006-06-26 02:48:02 +02001210/*
1211 * returns log facility for <fac> or -1 if not found.
1212 */
1213int get_log_facility(const char *fac)
1214{
1215 int facility;
1216
1217 facility = NB_LOG_FACILITIES - 1;
1218 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1219 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001220
Willy Tarreaubaaee002006-06-26 02:48:02 +02001221 return facility;
1222}
1223
William Lallemanda1cc3812012-02-08 16:38:44 +01001224/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001225 * Encode the string.
1226 *
1227 * When using the +E log format option, it will try to escape '"\]'
1228 * characters with '\' as prefix. The same prefix should not be used as
1229 * <escape>.
1230 */
1231static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001232 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001233 const char *string,
1234 struct logformat_node *node)
1235{
1236 if (node->options & LOG_OPT_ESC) {
1237 if (start < stop) {
1238 stop--; /* reserve one byte for the final '\0' */
1239 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001240 if (!ha_bit_test((unsigned char)(*string), map)) {
1241 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001242 *start++ = *string;
1243 else {
1244 if (start + 2 >= stop)
1245 break;
1246 *start++ = '\\';
1247 *start++ = *string;
1248 }
1249 }
1250 else {
1251 if (start + 3 >= stop)
1252 break;
1253 *start++ = escape;
1254 *start++ = hextab[(*string >> 4) & 15];
1255 *start++ = hextab[*string & 15];
1256 }
1257 string++;
1258 }
1259 *start = '\0';
1260 }
1261 }
1262 else {
1263 return encode_string(start, stop, escape, map, string);
1264 }
1265
1266 return start;
1267}
1268
1269/*
1270 * Encode the chunk.
1271 *
1272 * When using the +E log format option, it will try to escape '"\]'
1273 * characters with '\' as prefix. The same prefix should not be used as
1274 * <escape>.
1275 */
1276static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001277 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001278 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001279 struct logformat_node *node)
1280{
1281 char *str, *end;
1282
1283 if (node->options & LOG_OPT_ESC) {
1284 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001285 str = chunk->area;
1286 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001287
1288 stop--; /* reserve one byte for the final '\0' */
1289 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001290 if (!ha_bit_test((unsigned char)(*str), map)) {
1291 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001292 *start++ = *str;
1293 else {
1294 if (start + 2 >= stop)
1295 break;
1296 *start++ = '\\';
1297 *start++ = *str;
1298 }
1299 }
1300 else {
1301 if (start + 3 >= stop)
1302 break;
1303 *start++ = escape;
1304 *start++ = hextab[(*str >> 4) & 15];
1305 *start++ = hextab[*str & 15];
1306 }
1307 str++;
1308 }
1309 *start = '\0';
1310 }
1311 }
1312 else {
1313 return encode_chunk(start, stop, escape, map, chunk);
1314 }
1315
1316 return start;
1317}
1318
1319/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001320 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001321 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001322 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001323 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001324 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001325char *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 +01001326{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001327 if (size < 2)
1328 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001329
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001330 if (node->options & LOG_OPT_QUOTE) {
1331 *(dst++) = '"';
1332 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001333 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001334
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001335 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001336 if (++len > size)
1337 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001338 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001339 char *ret;
1340
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001341 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001342 if (ret == NULL || *ret != '\0')
1343 return NULL;
1344 len = ret - dst;
1345 }
1346 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001347 len = strlcpy2(dst, src, len);
1348 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001349
1350 size -= len;
1351 dst += len;
1352 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001353 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1354 if (size < 2)
1355 return NULL;
1356 *(dst++) = '-';
1357 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001358
1359 if (node->options & LOG_OPT_QUOTE) {
1360 if (size < 2)
1361 return NULL;
1362 *(dst++) = '"';
1363 }
1364
1365 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001366 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001367}
1368
Willy Tarreau26ffa852018-09-05 15:23:10 +02001369static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001370{
1371 return lf_text_len(dst, src, size, size, node);
1372}
1373
William Lallemand5f232402012-04-05 18:02:55 +02001374/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001375 * Write a IP address to the log string
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001376 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001377 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001378char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001379{
1380 char *ret = dst;
1381 int iret;
1382 char pn[INET6_ADDRSTRLEN];
1383
1384 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001385 unsigned char *addr = NULL;
1386 switch (sockaddr->sa_family) {
1387 case AF_INET:
1388 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1389 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1390 break;
1391 case AF_INET6:
1392 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1393 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1394 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1395 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1396 break;
1397 default:
1398 return NULL;
1399 }
William Lallemand5f232402012-04-05 18:02:55 +02001400 if (iret < 0 || iret > size)
1401 return NULL;
1402 ret += iret;
1403 } else {
1404 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1405 ret = lf_text(dst, pn, size, node);
1406 if (ret == NULL)
1407 return NULL;
1408 }
1409 return ret;
1410}
1411
1412/*
1413 * Write a port to the log
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001414 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001415 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001416char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001417{
1418 char *ret = dst;
1419 int iret;
1420
1421 if (node->options & LOG_OPT_HEXA) {
1422 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1423 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1424 if (iret < 0 || iret > size)
1425 return NULL;
1426 ret += iret;
1427 } else {
1428 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1429 if (ret == NULL)
1430 return NULL;
1431 }
1432 return ret;
1433}
1434
Dragan Dosen1322d092015-09-22 16:05:32 +02001435/* Re-generate time-based part of the syslog header in RFC3164 format at
1436 * the beginning of logheader once a second and return the pointer to the
1437 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001438 */
Emeric Brunbd163812020-05-06 14:33:46 +02001439char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001440{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001441 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001442 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001443 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001444
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001445 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001446 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001447 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001448 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001449
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001450 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001451 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001452
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001453 if (unlikely(global.log_send_hostname != host.area)) {
1454 host.area = global.log_send_hostname;
1455 host.data = host.area ? strlen(host.area) : 0;
1456 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001457 }
1458
Dragan Dosen59cee972015-09-19 22:09:02 +02001459 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001460 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001461 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001462 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001463 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001464 /* WARNING: depending upon implementations, snprintf may return
1465 * either -1 or the number of bytes that would be needed to store
1466 * the total message. In both cases, we must adjust it.
1467 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001468 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1469 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001470
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001471 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001472 }
1473
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001474 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001475
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001476 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001477}
1478
Dragan Dosen1322d092015-09-22 16:05:32 +02001479/* Re-generate time-based part of the syslog header in RFC5424 format at
1480 * the beginning of logheader_rfc5424 once a second and return the pointer
1481 * to the first character after it.
1482 */
Emeric Brunbd163812020-05-06 14:33:46 +02001483char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001484{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001485 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001486 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001487
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001488 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001489 /* this string is rebuild only once a second */
1490 struct tm tm;
1491 int hdr_len;
1492
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001493 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001494 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001495 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001496
1497 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001498 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001499 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001500 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001501 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001502 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001503 /* WARNING: depending upon implementations, snprintf may return
1504 * either -1 or the number of bytes that would be needed to store
1505 * the total message. In both cases, we must adjust it.
1506 */
1507 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1508 hdr_len = global.max_syslog_len;
1509
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001510 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001511 }
1512
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001513 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001514
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001515 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001516}
1517
William Lallemand2a4a44f2012-02-06 16:00:33 +01001518/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001519 * This function sends the syslog message using a printf format string. It
1520 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001521 */
1522void send_log(struct proxy *p, int level, const char *format, ...)
1523{
1524 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001525 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001526
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001527 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001528 return;
1529
William Lallemand2a4a44f2012-02-06 16:00:33 +01001530 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001531 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001532 if (data_len < 0 || data_len > global.max_syslog_len)
1533 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001534 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001535
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001536 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1537 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001538}
1539
1540/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001541 * This function sends a syslog message to <logsrv>.
1542 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1543 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1544 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001545 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001546 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001547 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001548static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1549 int level, char *message, size_t size, char *sd, size_t sd_size,
1550 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001551{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001552 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1553 static THREAD_LOCAL struct msghdr msghdr = {
1554 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001555 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1556 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001557 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1558 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1559 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001560 time_t time = date.tv_sec;
Emeric Brune709e1e2020-05-06 17:23:59 +02001561 char *hdr, *hdr_ptr = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +02001562 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001563 int fac_level;
1564 int *plogfd;
1565 char *pid_sep1 = "", *pid_sep2 = "";
1566 char logheader_short[3];
1567 int sent;
1568 int maxlen;
1569 int hdr_max = 0;
1570 int tag_max = 0;
1571 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001572 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001573 int pid_sep2_max = 0;
1574 int sd_max = 0;
1575 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001576
1577 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001578
1579 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001580
Emeric Brunfa9d7802020-05-28 14:21:33 +02001581 /* historically some messages used to already contain the trailing LF
1582 * or Zero. Let's remove all trailing LF or Zero
1583 */
1584 while (size && ((dataptr[size-1] == '\n' || (dataptr[size-1] == 0))))
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001585 size--;
1586
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001587 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001588 /* the socket's address is a file descriptor */
1589 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001590 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001591 else if (logsrv->type == LOG_TARGET_BUFFER) {
1592 plogfd = NULL;
Emeric Brune709e1e2020-05-06 17:23:59 +02001593 goto send;
Willy Tarreauc046d162019-08-30 15:24:59 +02001594 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001595 else if (logsrv->addr.ss_family == AF_UNIX)
1596 plogfd = &logfdunix;
1597 else
1598 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001599
Willy Tarreauc046d162019-08-30 15:24:59 +02001600 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001601 /* socket not successfully initialized yet */
1602 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1603 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1604 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001605
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001606 if (!once) {
1607 once = 1; /* note: no need for atomic ops here */
1608 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1609 nblogger, strerror(errno), errno);
1610 }
1611 return;
1612 } else {
1613 /* we don't want to receive anything on this socket */
1614 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1615 /* does nothing under Linux, maybe needed for others */
1616 shutdown(*plogfd, SHUT_RD);
1617 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1618 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001619 }
1620
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001621 switch (logsrv->format) {
1622 case LOG_FORMAT_RFC3164:
1623 hdr = logheader;
1624 hdr_ptr = update_log_hdr(time);
1625 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001626
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001627 case LOG_FORMAT_RFC5424:
1628 hdr = logheader_rfc5424;
1629 hdr_ptr = update_log_hdr_rfc5424(time);
1630 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1631 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001632
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001633 case LOG_FORMAT_SHORT:
1634 /* all fields are known, skip the header generation */
1635 hdr = logheader_short;
1636 hdr[0] = '<';
1637 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1638 hdr[2] = '>';
1639 hdr_ptr = hdr;
1640 hdr_max = 3;
1641 maxlen = logsrv->maxlen - hdr_max;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001642 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001643 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001644
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001645 case LOG_FORMAT_RAW:
1646 /* all fields are known, skip the header generation */
1647 hdr_ptr = hdr = "";
1648 hdr_max = 0;
1649 maxlen = logsrv->maxlen;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001650 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001651 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001652
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001653 default:
1654 return; /* must never happen */
1655 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001656
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001657 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001658
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001659 /* For each target, we may have a different facility.
1660 * We can also have a different log level for each message.
1661 * This induces variations in the message header length.
1662 * Since we don't want to recompute it each time, nor copy it every
1663 * time, we only change the facility in the pre-computed header,
1664 * and we change the pointer to the header accordingly.
1665 */
1666 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1667 hdr_ptr = hdr + 3; /* last digit of the log level */
1668 do {
1669 *hdr_ptr = '0' + fac_level % 10;
1670 fac_level /= 10;
1671 hdr_ptr--;
1672 } while (fac_level && hdr_ptr > hdr);
1673 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001674
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001675 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001676
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001677 /* time-based header */
1678 if (unlikely(hdr_size >= logsrv->maxlen)) {
1679 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1680 sd_max = 0;
1681 goto send;
1682 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001683
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001684 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001685
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001686 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001687 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001688 if (unlikely(tag_max >= maxlen)) {
1689 tag_max = maxlen - 1;
1690 sd_max = 0;
1691 goto send;
1692 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001693
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001694 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001695
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001696 /* first pid separator */
1697 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1698 if (unlikely(pid_sep1_max >= maxlen)) {
1699 pid_sep1_max = maxlen - 1;
1700 sd_max = 0;
1701 goto send;
1702 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001703
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001704 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1705 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001706
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001707 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001708 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001709 if (unlikely(pid_size >= maxlen)) {
1710 pid_size = maxlen - 1;
1711 sd_max = 0;
1712 goto send;
1713 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001714
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001715 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001716
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001717 /* second pid separator */
1718 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1719 if (unlikely(pid_sep2_max >= maxlen)) {
1720 pid_sep2_max = maxlen - 1;
1721 sd_max = 0;
1722 goto send;
1723 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001724
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001725 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1726 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001727
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001728 /* structured-data */
1729 if (sd_max >= maxlen) {
1730 sd_max = maxlen - 1;
1731 goto send;
1732 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001733
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001734 max = MIN(size, maxlen - sd_max - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001735send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001736 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001737 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001738 struct ist msg[7];
1739
Emeric Brune709e1e2020-05-06 17:23:59 +02001740 if (logsrv->type == LOG_TARGET_BUFFER) {
1741 msg[0] = ist2(message, MIN(size, logsrv->maxlen));
1742 msg[1] = ist2(tag_str, tag_size);
1743 msg[2] = ist2(pid_str, pid_size);
1744 msg[3] = ist2(sd, sd_size);
1745 sent = sink_write(logsrv->sink, msg, 1, level, logsrv->facility, &msg[1], &msg[2], &msg[3]);
1746 }
1747 else /* LOG_TARGET_FD */ {
1748 msg[0] = ist2(hdr_ptr, hdr_max);
1749 msg[1] = ist2(tag_str, tag_max);
1750 msg[2] = ist2(pid_sep1, pid_sep1_max);
1751 msg[3] = ist2(pid_str, pid_max);
1752 msg[4] = ist2(pid_sep2, pid_sep2_max);
1753 msg[5] = ist2(sd, sd_max);
1754 msg[6] = ist2(dataptr, max);
Willy Tarreauc046d162019-08-30 15:24:59 +02001755 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Emeric Brune709e1e2020-05-06 17:23:59 +02001756 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001757 }
1758 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001759 iovec[0].iov_base = hdr_ptr;
1760 iovec[0].iov_len = hdr_max;
1761 iovec[1].iov_base = tag_str;
1762 iovec[1].iov_len = tag_max;
1763 iovec[2].iov_base = pid_sep1;
1764 iovec[2].iov_len = pid_sep1_max;
1765 iovec[3].iov_base = pid_str;
1766 iovec[3].iov_len = pid_max;
1767 iovec[4].iov_base = pid_sep2;
1768 iovec[4].iov_len = pid_sep2_max;
1769 iovec[5].iov_base = sd;
1770 iovec[5].iov_len = sd_max;
1771 iovec[6].iov_base = dataptr;
1772 iovec[6].iov_len = max;
1773 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1774 iovec[7].iov_len = 1;
1775
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001776 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1777 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001778
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001779 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1780 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001781
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001782 if (sent < 0) {
1783 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001784
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001785 if (errno == EAGAIN)
1786 _HA_ATOMIC_ADD(&dropped_logs, 1);
1787 else if (!once) {
1788 once = 1; /* note: no need for atomic ops here */
1789 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1790 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001791 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001792 }
1793}
Dragan Dosen59cee972015-09-19 22:09:02 +02001794
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001795/*
1796 * This function sends a syslog message.
1797 * It doesn't care about errors nor does it report them.
1798 * The arguments <sd> and <sd_size> are used for the structured-data part
1799 * in RFC5424 formatted syslog messages.
1800 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001801void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1802 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001803{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001804 struct logsrv *logsrv;
1805 int nblogger;
1806 static THREAD_LOCAL int curr_pid;
1807 static THREAD_LOCAL char pidstr[100];
1808 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001809
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001810 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001811 if (!LIST_ISEMPTY(&global.logsrvs)) {
1812 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001813 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001814 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001815 if (!tag || !tag->area)
1816 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001817
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001818 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001819 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001820
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001821 if (unlikely(curr_pid != getpid())) {
1822 curr_pid = getpid();
1823 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1824 chunk_initstr(&pid, pidstr);
1825 }
1826
1827 /* Send log messages to syslog server. */
1828 nblogger = 0;
1829 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001830 static THREAD_LOCAL int in_range = 1;
1831
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001832 /* we can filter the level of the messages that are sent to each logger */
1833 if (level > logsrv->level)
1834 continue;
1835
Frédéric Lécailled803e472019-04-25 07:42:09 +02001836 if (logsrv->lb.smp_rgs) {
1837 struct smp_log_range *curr_rg;
1838
1839 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1840 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1841 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1842 if (in_range) {
1843 /* Let's consume this range. */
1844 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1845 if (!curr_rg->curr_idx) {
1846 /* If consumed, let's select the next range. */
1847 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1848 }
1849 }
1850 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1851 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1852 }
1853 if (in_range)
1854 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1855 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001856 }
1857}
1858
1859
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001860const 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 +01001861const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1862 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1863 Set-cookie Updated, unknown, unknown */
1864
William Lallemand1d705562012-03-12 12:46:41 +01001865/*
1866 * try to write a character if there is enough space, or goto out
1867 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001868#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001869 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001870 *(tmplog++) = (x); \
1871 } else { \
1872 goto out; \
1873 } \
1874 } while(0)
1875
Dragan Dosen835b9212016-02-12 13:23:03 +01001876
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001877/* Initializes some log data at boot */
1878static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001879{
1880 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001881 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001882
1883 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1884 * inside PARAM-VALUE should be escaped with '\' as prefix.
1885 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1886 * details.
1887 */
1888 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1889
1890 tmp = "\"\\]";
1891 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001892 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001893 tmp++;
1894 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001895
1896 /* initialize the log header encoding map : '{|}"#' should be encoded with
1897 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1898 * URL encoding only requires '"', '#' to be encoded as well as non-
1899 * printable characters above.
1900 */
1901 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1902 memset(url_encode_map, 0, sizeof(url_encode_map));
1903 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001904 ha_bit_set(i, hdr_encode_map);
1905 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001906 }
1907 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001908 ha_bit_set(i, hdr_encode_map);
1909 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001910 }
1911
1912 tmp = "\"#{|}";
1913 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001914 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001915 tmp++;
1916 }
1917
1918 tmp = "\"#";
1919 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001920 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001921 tmp++;
1922 }
1923
1924 /* initialize the http header encoding map. The draft httpbis define the
1925 * header content as:
1926 *
1927 * HTTP-message = start-line
1928 * *( header-field CRLF )
1929 * CRLF
1930 * [ message-body ]
1931 * header-field = field-name ":" OWS field-value OWS
1932 * field-value = *( field-content / obs-fold )
1933 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1934 * obs-fold = CRLF 1*( SP / HTAB )
1935 * field-vchar = VCHAR / obs-text
1936 * VCHAR = %x21-7E
1937 * obs-text = %x80-FF
1938 *
1939 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1940 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001941 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001942 */
1943 memset(http_encode_map, 0, sizeof(http_encode_map));
1944 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001945 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001946 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001947 ha_bit_set(i, http_encode_map);
1948 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001949}
William Lallemand1d705562012-03-12 12:46:41 +01001950
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001951INITCALL0(STG_PREPARE, init_log);
1952
Christopher Faulet0132d062017-07-26 15:33:35 +02001953/* Initialize log buffers used for syslog messages */
1954int init_log_buffers()
1955{
1956 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001957 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001958 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001959 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001960 logline = my_realloc2(logline, global.max_syslog_len + 1);
1961 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1962 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1963 return 0;
1964 return 1;
1965}
1966
1967/* Deinitialize log buffers used for syslog messages */
1968void deinit_log_buffers()
1969{
1970 free(logheader);
1971 free(logheader_rfc5424);
1972 free(logline);
1973 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001974 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001975 logheader = NULL;
1976 logheader_rfc5424 = NULL;
1977 logline = NULL;
1978 logline_rfc5424 = NULL;
1979}
1980
Willy Tarreaudf974472012-12-28 02:44:01 +01001981/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1982 * <maxsize> characters. Returns the size of the output string in characters,
1983 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001984 * is not zero. It requires a valid session and optionally a stream. If the
1985 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001986 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001987int 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 +02001988{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001989 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001990 struct proxy *be;
1991 struct http_txn *txn;
1992 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001993 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001994 unsigned int s_flags;
1995 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001996 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001997 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001998 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001999 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002000 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02002001 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002002 int t_request;
2003 int hdr;
2004 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002005 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01002006 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01002007 char *ret;
2008 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002009 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002010 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002011 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002012
William Lallemandbddd4fd2012-02-27 11:23:10 +01002013 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002014
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002015 if (likely(s)) {
2016 be = s->be;
2017 txn = s->txn;
2018 be_conn = cs_conn(objt_cs(s->si[1].end));
2019 s_flags = s->flags;
2020 uniq_id = s->uniq_id;
2021 logs = &s->logs;
2022 } else {
2023 /* we have no stream so we first need to initialize a few
2024 * things that are needed later. We do increment the request
2025 * ID so that it's uniquely assigned to this request just as
2026 * if the request had reached the point of being processed.
2027 * A request error is reported as it's the only element we have
2028 * here and which justifies emitting such a log.
2029 */
2030 be = fe;
2031 txn = NULL;
2032 be_conn = NULL;
2033 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002034 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002035
2036 /* prepare a valid log structure */
2037 tmp_strm_log.tv_accept = sess->tv_accept;
2038 tmp_strm_log.accept_date = sess->accept_date;
2039 tmp_strm_log.t_handshake = sess->t_handshake;
2040 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
2041 tv_zero(&tmp_strm_log.tv_request);
2042 tmp_strm_log.t_queue = -1;
2043 tmp_strm_log.t_connect = -1;
2044 tmp_strm_log.t_data = -1;
2045 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2046 tmp_strm_log.bytes_in = 0;
2047 tmp_strm_log.bytes_out = 0;
2048 tmp_strm_log.prx_queue_pos = 0;
2049 tmp_strm_log.srv_queue_pos = 0;
2050
2051 logs = &tmp_strm_log;
2052 }
2053
William Lallemandbddd4fd2012-02-27 11:23:10 +01002054 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002055 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2056 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002057
William Lallemand1d705562012-03-12 12:46:41 +01002058 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002059
William Lallemandbddd4fd2012-02-27 11:23:10 +01002060 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002061 if (LIST_ISEMPTY(list_format))
2062 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002063
William Lallemand1d705562012-03-12 12:46:41 +01002064 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002065 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002066 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002067 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002068 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002069
Willy Tarreauc8368452012-12-21 00:09:23 +01002070 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002071 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002072 if (!last_isspace) {
2073 LOGCHAR(' ');
2074 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002075 }
2076 break;
2077
William Lallemand1d705562012-03-12 12:46:41 +01002078 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002079 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002080 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002081 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002082 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002083 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002084 last_isspace = 0;
2085 break;
2086
Willy Tarreauc8368452012-12-21 00:09:23 +01002087 case LOG_FMT_EXPR: // sample expression, may be request or response
2088 key = NULL;
Christopher Faulet5f940702020-04-06 10:40:02 +02002089 if (tmp->options & LOG_OPT_REQ_CAP)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002090 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 +02002091 if (!key && (tmp->options & LOG_OPT_RES_CAP))
Adis Nezirovic79beb242015-07-06 15:41:02 +02002092 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 +01002093 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002094 ret = lf_encode_chunk(tmplog, dst + maxsize,
2095 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002096 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002097 ret = lf_text_len(tmplog,
2098 key ? key->data.u.str.area : NULL,
2099 key ? key->data.u.str.data : 0,
2100 dst + maxsize - tmplog,
2101 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002102 if (ret == 0)
2103 goto out;
2104 tmplog = ret;
2105 last_isspace = 0;
2106 break;
2107
Willy Tarreau2beef582012-12-20 17:22:52 +01002108 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002109 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002110 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002111 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002112 else
2113 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002114 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002115 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002116 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002117 last_isspace = 0;
2118 break;
2119
Willy Tarreau2beef582012-12-20 17:22:52 +01002120 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002121 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002122 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002123 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002124 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002125 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002126 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002127 dst + maxsize - tmplog, tmp);
2128 }
William Lallemand5f232402012-04-05 18:02:55 +02002129 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002130 else
2131 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2132
William Lallemand5f232402012-04-05 18:02:55 +02002133 if (ret == NULL)
2134 goto out;
2135 tmplog = ret;
2136 last_isspace = 0;
2137 break;
2138
Willy Tarreau2beef582012-12-20 17:22:52 +01002139 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002140 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002141 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002142 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002143 }
2144 else
2145 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2146
William Lallemand1d705562012-03-12 12:46:41 +01002147 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002148 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002149 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002150 last_isspace = 0;
2151 break;
2152
Willy Tarreau2beef582012-12-20 17:22:52 +01002153 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002154 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002155 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002156 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002157 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002158 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002159 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002160 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002161 else
2162 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2163
William Lallemand5f232402012-04-05 18:02:55 +02002164 if (ret == NULL)
2165 goto out;
2166 tmplog = ret;
2167 last_isspace = 0;
2168 break;
2169
Willy Tarreau2beef582012-12-20 17:22:52 +01002170 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002171 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002172 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002173 else
2174 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2175
William Lallemand1d705562012-03-12 12:46:41 +01002176 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002177 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002178 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002179 last_isspace = 0;
2180 break;
2181
Willy Tarreau2beef582012-12-20 17:22:52 +01002182 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002183 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002184 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002185 else
2186 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2187
William Lallemand5f232402012-04-05 18:02:55 +02002188 if (ret == NULL)
2189 goto out;
2190 tmplog = ret;
2191 last_isspace = 0;
2192 break;
2193
Willy Tarreau2beef582012-12-20 17:22:52 +01002194 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002195 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002196 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002197 else
2198 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2199
William Lallemand5f232402012-04-05 18:02:55 +02002200 if (ret == NULL)
2201 goto out;
2202 tmplog = ret;
2203 last_isspace = 0;
2204 break;
2205
Willy Tarreau2beef582012-12-20 17:22:52 +01002206 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002207 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002208 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002209 else
2210 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2211
William Lallemand1d705562012-03-12 12:46:41 +01002212 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002213 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002214 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002215 last_isspace = 0;
2216 break;
2217
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002218 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002219 get_localtime(logs->accept_date.tv_sec, &tm);
2220 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002221 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002222 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002223 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002224 last_isspace = 0;
2225 break;
2226
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002227 case LOG_FMT_tr: // %tr = start of request date
2228 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002229 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 +02002230 get_localtime(tv.tv_sec, &tm);
2231 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2232 if (ret == NULL)
2233 goto out;
2234 tmplog = ret;
2235 last_isspace = 0;
2236 break;
2237
2238 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002239 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002240 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002241 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002242 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002243 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002244 last_isspace = 0;
2245 break;
2246
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002247 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002248 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 +02002249 get_gmtime(tv.tv_sec, &tm);
2250 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2251 if (ret == NULL)
2252 goto out;
2253 tmplog = ret;
2254 last_isspace = 0;
2255 break;
2256
2257 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002258 get_localtime(logs->accept_date.tv_sec, &tm);
2259 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002260 if (ret == NULL)
2261 goto out;
2262 tmplog = ret;
2263 last_isspace = 0;
2264 break;
2265
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002266 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002267 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 +02002268 get_localtime(tv.tv_sec, &tm);
2269 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2270 if (ret == NULL)
2271 goto out;
2272 tmplog = ret;
2273 last_isspace = 0;
2274 break;
2275
William Lallemand5f232402012-04-05 18:02:55 +02002276 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002277 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002278 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002279 if (iret < 0 || iret > dst + maxsize - tmplog)
2280 goto out;
2281 last_isspace = 0;
2282 tmplog += iret;
2283 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002284 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002285 if (ret == NULL)
2286 goto out;
2287 tmplog = ret;
2288 last_isspace = 0;
2289 }
2290 break;
2291
William Lallemand1d705562012-03-12 12:46:41 +01002292 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002293 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002294 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002295 if (iret < 0 || iret > dst + maxsize - tmplog)
2296 goto out;
2297 last_isspace = 0;
2298 tmplog += iret;
2299 } else {
2300 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002301 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002302 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002303 tmplog, 4);
2304 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002305 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002306 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002307 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002308 }
2309 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002310
William Lallemand1d705562012-03-12 12:46:41 +01002311 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002312 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002313 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002314 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002315 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002316 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002317 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002318 break;
2319
Willy Tarreau773d65f2012-10-12 14:56:11 +02002320 case LOG_FMT_FRONTEND_XPRT: // %ft
2321 src = fe->id;
2322 if (tmp->options & LOG_OPT_QUOTE)
2323 LOGCHAR('"');
2324 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2325 if (iret == 0)
2326 goto out;
2327 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002328 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002329 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002330 if (tmp->options & LOG_OPT_QUOTE)
2331 LOGCHAR('"');
2332 last_isspace = 0;
2333 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002334#ifdef USE_OPENSSL
2335 case LOG_FMT_SSL_CIPHER: // %sslc
2336 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002337 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002338 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002339 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002340 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002341 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2342 if (ret == NULL)
2343 goto out;
2344 tmplog = ret;
2345 last_isspace = 0;
2346 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002347
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002348 case LOG_FMT_SSL_VERSION: // %sslv
2349 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002350 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002351 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002352 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002353 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002354 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2355 if (ret == NULL)
2356 goto out;
2357 tmplog = ret;
2358 last_isspace = 0;
2359 break;
2360#endif
William Lallemand1d705562012-03-12 12:46:41 +01002361 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002362 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002363 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002364 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002365 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002366 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002367 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002368 break;
2369
William Lallemand1d705562012-03-12 12:46:41 +01002370 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002371 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002372 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002373 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002374 break;
2375 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002376 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002377 break;
2378 default:
2379 src = "<NOSRV>";
2380 break;
2381 }
William Lallemand5f232402012-04-05 18:02:55 +02002382 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002383 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002384 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002385 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002386 last_isspace = 0;
2387 break;
2388
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002389 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002390 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002391 if (ret == NULL)
2392 goto out;
2393 tmplog = ret;
2394 last_isspace = 0;
2395 break;
2396
2397 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002398 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002399 if (ret == NULL)
2400 goto out;
2401 tmplog = ret;
2402 last_isspace = 0;
2403 break;
2404
2405 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002406 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002407 tmplog, dst + maxsize - tmplog);
2408 if (ret == NULL)
2409 goto out;
2410 tmplog = ret;
2411 last_isspace = 0;
2412 break;
2413
2414 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002415 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002416 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002417 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002418 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002419 last_isspace = 0;
2420 break;
2421
William Lallemand1d705562012-03-12 12:46:41 +01002422 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002423 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002424 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002425 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002426 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002427 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002428 last_isspace = 0;
2429 break;
2430
William Lallemand1d705562012-03-12 12:46:41 +01002431 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002432 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002433 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002434 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002435 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002436 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002437 last_isspace = 0;
2438 break;
2439
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002440 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002441 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002442 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002443 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002444 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002445 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002446 last_isspace = 0;
2447 break;
2448
Willy Tarreau27b639d2016-05-17 17:55:27 +02002449 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002450 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002451 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002452 tmplog, dst + maxsize - tmplog);
2453 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002454 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002455 tmplog, dst + maxsize - tmplog);
2456 if (ret == NULL)
2457 goto out;
2458 tmplog = ret;
2459 last_isspace = 0;
2460 break;
2461
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002462 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2463 if (!(fe->to_log & LW_BYTES))
2464 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002465 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 +02002466 tmplog, dst + maxsize - tmplog);
2467 if (ret == NULL)
2468 goto out;
2469 tmplog = ret;
2470 last_isspace = 0;
2471 break;
2472
2473 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002474 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002475 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002476 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002477 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002478 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002479 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002480 last_isspace = 0;
2481 break;
2482
Damien Claisse57c8eb92020-04-28 12:09:19 +00002483 case LOG_FMT_TU: // %Tu = total time seen by user = Tt - Ti
2484 if (!(fe->to_log & LW_BYTES))
2485 LOGCHAR('+');
2486 ret = ltoa_o(logs->t_close - (logs->t_idle >= 0 ? logs->t_idle : 0),
2487 tmplog, dst + maxsize - tmplog);
2488 if (ret == NULL)
2489 goto out;
2490 tmplog = ret;
2491 last_isspace = 0;
2492 break;
2493
Willy Tarreau2beef582012-12-20 17:22:52 +01002494 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002495 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002496 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002497 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002498 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002499 last_isspace = 0;
2500 break;
2501
William Lallemand1d705562012-03-12 12:46:41 +01002502 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002503 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002504 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002505 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002506 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002507 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002508 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002509 last_isspace = 0;
2510 break;
2511
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002512 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002513 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002514 if (ret == NULL)
2515 goto out;
2516 tmplog = ret;
2517 last_isspace = 0;
2518 break;
2519
Willy Tarreau2beef582012-12-20 17:22:52 +01002520 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002521 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002522 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002523 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002524 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002525 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002526 last_isspace = 0;
2527 break;
2528
Willy Tarreau2beef582012-12-20 17:22:52 +01002529 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002530 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002531 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002532 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002533 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002534 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002535 last_isspace = 0;
2536 break;
2537
William Lallemand1d705562012-03-12 12:46:41 +01002538 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002539 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2540 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002541 *tmplog = '\0';
2542 last_isspace = 0;
2543 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002544
William Lallemand1d705562012-03-12 12:46:41 +01002545 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002546 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2547 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002548 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2549 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 +01002550 last_isspace = 0;
2551 break;
2552
William Lallemand1d705562012-03-12 12:46:41 +01002553 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002554 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002555 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002556 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002557 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002558 last_isspace = 0;
2559 break;
2560
William Lallemand1d705562012-03-12 12:46:41 +01002561 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002562 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002563 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002564 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002565 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002566 last_isspace = 0;
2567 break;
2568
William Lallemand1d705562012-03-12 12:46:41 +01002569 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002570 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002571 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002572 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002573 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002574 last_isspace = 0;
2575 break;
2576
William Lallemand1d705562012-03-12 12:46:41 +01002577 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002578 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002579 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002580 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002581 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002582 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002583 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002584 last_isspace = 0;
2585 break;
2586
William Lallemand1d705562012-03-12 12:46:41 +01002587 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002588 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002589 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002590 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002591 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002592 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002593 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002594 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002595 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002596 last_isspace = 0;
2597 break;
2598
William Lallemand1d705562012-03-12 12:46:41 +01002599 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002600 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002601 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002602 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002603 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002604 last_isspace = 0;
2605 break;
2606
William Lallemand1d705562012-03-12 12:46:41 +01002607 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002608 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002609 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002610 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002611 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002612 last_isspace = 0;
2613 break;
2614
William Lallemand1d705562012-03-12 12:46:41 +01002615 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002616 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002617 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002618 if (tmp->options & LOG_OPT_QUOTE)
2619 LOGCHAR('"');
2620 LOGCHAR('{');
2621 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2622 if (hdr)
2623 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002624 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002625 ret = lf_encode_string(tmplog, dst + maxsize,
2626 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002627 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002628 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002629 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002630 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002631 }
2632 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002633 if (tmp->options & LOG_OPT_QUOTE)
2634 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002635 last_isspace = 0;
2636 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002637 break;
2638
William Lallemand1d705562012-03-12 12:46:41 +01002639 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002640 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002641 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002642 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2643 if (hdr > 0)
2644 LOGCHAR(' ');
2645 if (tmp->options & LOG_OPT_QUOTE)
2646 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002647 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002648 ret = lf_encode_string(tmplog, dst + maxsize,
2649 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002650 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002651 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002652 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002653 } else if (!(tmp->options & LOG_OPT_QUOTE))
2654 LOGCHAR('-');
2655 if (tmp->options & LOG_OPT_QUOTE)
2656 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002657 last_isspace = 0;
2658 }
2659 }
2660 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002661
William Lallemand1d705562012-03-12 12:46:41 +01002662
2663 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002664 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002665 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002666 if (tmp->options & LOG_OPT_QUOTE)
2667 LOGCHAR('"');
2668 LOGCHAR('{');
2669 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2670 if (hdr)
2671 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002672 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002673 ret = lf_encode_string(tmplog, dst + maxsize,
2674 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002675 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002676 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002677 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002678 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002679 }
2680 LOGCHAR('}');
2681 last_isspace = 0;
2682 if (tmp->options & LOG_OPT_QUOTE)
2683 LOGCHAR('"');
2684 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002685 break;
2686
William Lallemand1d705562012-03-12 12:46:41 +01002687 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002688 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002689 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002690 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2691 if (hdr > 0)
2692 LOGCHAR(' ');
2693 if (tmp->options & LOG_OPT_QUOTE)
2694 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002695 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002696 ret = lf_encode_string(tmplog, dst + maxsize,
2697 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002698 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002699 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002700 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002701 } else if (!(tmp->options & LOG_OPT_QUOTE))
2702 LOGCHAR('-');
2703 if (tmp->options & LOG_OPT_QUOTE)
2704 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002705 last_isspace = 0;
2706 }
2707 }
2708 break;
2709
William Lallemand1d705562012-03-12 12:46:41 +01002710 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002711 /* Request */
2712 if (tmp->options & LOG_OPT_QUOTE)
2713 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002714 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002715 ret = lf_encode_string(tmplog, dst + maxsize,
2716 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002717 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002718 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002719 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002720 if (tmp->options & LOG_OPT_QUOTE)
2721 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002722 last_isspace = 0;
2723 break;
William Lallemand5f232402012-04-05 18:02:55 +02002724
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002725 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002726 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002727
Willy Tarreaub7636d12015-06-17 19:58:02 +02002728 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002729 LOGCHAR('"');
2730
2731 end = uri + strlen(uri);
2732 // look for the first whitespace character
2733 while (uri < end && !HTTP_IS_SPHT(*uri))
2734 uri++;
2735
2736 // keep advancing past multiple spaces
2737 while (uri < end && HTTP_IS_SPHT(*uri)) {
2738 uri++; nspaces++;
2739 }
2740
2741 // look for first space or question mark after url
2742 spc = uri;
2743 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2744 spc++;
2745
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002746 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002747 chunk.area = "<BADREQ>";
2748 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002749 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002750 chunk.area = uri;
2751 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002752 }
2753
Dragan Dosen835b9212016-02-12 13:23:03 +01002754 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002755 if (ret == NULL || *ret != '\0')
2756 goto out;
2757
2758 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002759 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002760 LOGCHAR('"');
2761
2762 last_isspace = 0;
2763 break;
2764
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002765 case LOG_FMT_HTTP_QUERY: // %HQ
2766 if (tmp->options & LOG_OPT_QUOTE)
2767 LOGCHAR('"');
2768
Willy Tarreau57bc8912016-04-25 17:09:40 +02002769 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002770 chunk.area = "<BADREQ>";
2771 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002772 } else {
2773 uri = txn->uri;
2774 end = uri + strlen(uri);
2775 // look for the first question mark
2776 while (uri < end && *uri != '?')
2777 uri++;
2778
2779 qmark = uri;
2780 // look for first space or question mark after url
2781 while (uri < end && !HTTP_IS_SPHT(*uri))
2782 uri++;
2783
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002784 chunk.area = qmark;
2785 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002786 }
2787
Dragan Dosen835b9212016-02-12 13:23:03 +01002788 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002789 if (ret == NULL || *ret != '\0')
2790 goto out;
2791
2792 tmplog = ret;
2793 if (tmp->options & LOG_OPT_QUOTE)
2794 LOGCHAR('"');
2795
2796 last_isspace = 0;
2797 break;
2798
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002799 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002800 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002801
Willy Tarreaub7636d12015-06-17 19:58:02 +02002802 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002803 LOGCHAR('"');
2804
2805 end = uri + strlen(uri);
2806 // look for the first whitespace character
2807 while (uri < end && !HTTP_IS_SPHT(*uri))
2808 uri++;
2809
2810 // keep advancing past multiple spaces
2811 while (uri < end && HTTP_IS_SPHT(*uri)) {
2812 uri++; nspaces++;
2813 }
2814
2815 // look for first space after url
2816 spc = uri;
2817 while (spc < end && !HTTP_IS_SPHT(*spc))
2818 spc++;
2819
Willy Tarreau57bc8912016-04-25 17:09:40 +02002820 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002821 chunk.area = "<BADREQ>";
2822 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002823 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002824 chunk.area = uri;
2825 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002826 }
2827
Dragan Dosen835b9212016-02-12 13:23:03 +01002828 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002829 if (ret == NULL || *ret != '\0')
2830 goto out;
2831
2832 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002833 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002834 LOGCHAR('"');
2835
2836 last_isspace = 0;
2837 break;
2838
2839 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002840 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002841 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002842 LOGCHAR('"');
2843
2844 end = uri + strlen(uri);
2845 // look for the first whitespace character
2846 spc = uri;
2847 while (spc < end && !HTTP_IS_SPHT(*spc))
2848 spc++;
2849
2850 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002851 chunk.area = "<BADREQ>";
2852 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002853 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002854 chunk.area = uri;
2855 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002856 }
2857
Dragan Dosen835b9212016-02-12 13:23:03 +01002858 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002859 if (ret == NULL || *ret != '\0')
2860 goto out;
2861
2862 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002863 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002864 LOGCHAR('"');
2865
2866 last_isspace = 0;
2867 break;
2868
2869 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002870 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002871 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002872 LOGCHAR('"');
2873
2874 end = uri + strlen(uri);
2875 // look for the first whitespace character
2876 while (uri < end && !HTTP_IS_SPHT(*uri))
2877 uri++;
2878
2879 // keep advancing past multiple spaces
2880 while (uri < end && HTTP_IS_SPHT(*uri)) {
2881 uri++; nspaces++;
2882 }
2883
2884 // look for the next whitespace character
2885 while (uri < end && !HTTP_IS_SPHT(*uri))
2886 uri++;
2887
2888 // keep advancing past multiple spaces
2889 while (uri < end && HTTP_IS_SPHT(*uri))
2890 uri++;
2891
Willy Tarreau57bc8912016-04-25 17:09:40 +02002892 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002893 chunk.area = "<BADREQ>";
2894 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002895 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002896 chunk.area = "HTTP/0.9";
2897 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002898 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002899 chunk.area = uri;
2900 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002901 }
2902
Dragan Dosen835b9212016-02-12 13:23:03 +01002903 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002904 if (ret == NULL || *ret != '\0')
2905 goto out;
2906
2907 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002908 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002909 LOGCHAR('"');
2910
2911 last_isspace = 0;
2912 break;
2913
William Lallemand5f232402012-04-05 18:02:55 +02002914 case LOG_FMT_COUNTER: // %rt
2915 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002916 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002917 if (iret < 0 || iret > dst + maxsize - tmplog)
2918 goto out;
2919 last_isspace = 0;
2920 tmplog += iret;
2921 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002922 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002923 if (ret == NULL)
2924 goto out;
2925 tmplog = ret;
2926 last_isspace = 0;
2927 }
2928 break;
2929
Willy Tarreau7346acb2014-08-28 15:03:15 +02002930 case LOG_FMT_LOGCNT: // %lc
2931 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002932 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002933 if (iret < 0 || iret > dst + maxsize - tmplog)
2934 goto out;
2935 last_isspace = 0;
2936 tmplog += iret;
2937 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002938 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002939 if (ret == NULL)
2940 goto out;
2941 tmplog = ret;
2942 last_isspace = 0;
2943 }
2944 break;
2945
William Lallemand5f232402012-04-05 18:02:55 +02002946 case LOG_FMT_HOSTNAME: // %H
2947 src = hostname;
2948 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2949 if (ret == NULL)
2950 goto out;
2951 tmplog = ret;
2952 last_isspace = 0;
2953 break;
2954
2955 case LOG_FMT_PID: // %pid
2956 if (tmp->options & LOG_OPT_HEXA) {
2957 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2958 if (iret < 0 || iret > dst + maxsize - tmplog)
2959 goto out;
2960 last_isspace = 0;
2961 tmplog += iret;
2962 } else {
2963 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2964 if (ret == NULL)
2965 goto out;
2966 tmplog = ret;
2967 last_isspace = 0;
2968 }
2969 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002970
2971 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002972 ret = NULL;
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002973 if (s)
2974 ret = lf_text_len(tmplog, s->unique_id.ptr, s->unique_id.len, maxsize - (tmplog - dst), tmp);
2975 else
2976 ret = lf_text_len(tmplog, NULL, 0, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002977 if (ret == NULL)
2978 goto out;
2979 tmplog = ret;
2980 last_isspace = 0;
2981 break;
2982
William Lallemandbddd4fd2012-02-27 11:23:10 +01002983 }
2984 }
2985
2986out:
William Lallemand1d705562012-03-12 12:46:41 +01002987 /* *tmplog is a unused character */
2988 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002989 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002990
Willy Tarreaubaaee002006-06-26 02:48:02 +02002991}
2992
William Lallemand1d705562012-03-12 12:46:41 +01002993/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002994 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002995 * Will not log if the frontend has no log defined.
2996 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002997void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002998{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002999 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01003000 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003001 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01003002
3003 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02003004 err = (s->flags & SF_REDISP) ||
3005 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
3006 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01003007 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02003008 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003009
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003010 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01003011 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003012
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003013 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01003014 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003015
Willy Tarreauabcd5142013-06-11 17:18:02 +02003016 if (s->logs.level) { /* loglevel was overridden */
3017 if (s->logs.level == -1) {
3018 s->logs.logwait = 0; /* logs disabled */
3019 return;
3020 }
3021 level = s->logs.level - 1;
3022 }
3023 else {
3024 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003025 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02003026 level = LOG_ERR;
3027 }
William Lallemand1d705562012-03-12 12:46:41 +01003028
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003029 /* if unique-id was not generated */
Tim Duesterhusa17e6622020-03-05 20:19:02 +01003030 if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Tim Duesterhus2825b4b2020-02-28 15:13:34 +01003031 stream_generate_unique_id(s, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003032 }
3033
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003034 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3035 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
3036 &sess->fe->logformat_sd);
3037 }
3038
Dragan Dosen59cee972015-09-19 22:09:02 +02003039 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01003040 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003041 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003042 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3043 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01003044 s->logs.logwait = 0;
3045 }
3046}
William Lallemandbddd4fd2012-02-27 11:23:10 +01003047
Willy Tarreau53839352018-09-05 19:51:10 +02003048/*
3049 * send a minimalist log for the session. Will not log if the frontend has no
3050 * log defined. It is assumed that this is only used to report anomalies that
3051 * cannot lead to the creation of a regular stream. Because of this the log
3052 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
3053 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003054 * function to report unimportant events. It is safe to call this function with
3055 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02003056 */
3057void sess_log(struct session *sess)
3058{
3059 int size, level;
3060 int sd_size = 0;
3061
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003062 if (!sess)
3063 return;
3064
Willy Tarreau53839352018-09-05 19:51:10 +02003065 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3066 return;
3067
3068 level = LOG_INFO;
3069 if (sess->fe->options2 & PR_O2_LOGERRORS)
3070 level = LOG_ERR;
3071
3072 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3073 sd_size = sess_build_logline(sess, NULL,
3074 logline_rfc5424, global.max_syslog_len,
3075 &sess->fe->logformat_sd);
3076 }
3077
3078 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3079 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003080 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003081 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3082 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003083 }
3084}
3085
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003086void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3087{
3088 va_list argp;
3089 int data_len;
3090
3091 if (level < 0 || format == NULL || logline == NULL)
3092 return;
3093
3094 va_start(argp, format);
3095 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3096 if (data_len < 0 || data_len > global.max_syslog_len)
3097 data_len = global.max_syslog_len;
3098 va_end(argp);
3099
3100 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3101}
3102
Willy Tarreau869efd52019-11-15 15:16:57 +01003103/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3104static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003105{
Willy Tarreau869efd52019-11-15 15:16:57 +01003106 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3107 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003108
Willy Tarreau869efd52019-11-15 15:16:57 +01003109 if (!startup_logs)
3110 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3111
3112 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003113}
3114
3115/* register cli keywords */
3116static struct cli_kw_list cli_kws = {{ },{
3117 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003118 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003119 {{},}
3120}};
3121
Willy Tarreau0108d902018-11-25 19:14:37 +01003122INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3123
Willy Tarreau082b6282019-05-22 14:42:12 +02003124REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3125REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003126
Willy Tarreaubaaee002006-06-26 02:48:02 +02003127/*
3128 * Local variables:
3129 * c-indent-level: 8
3130 * c-basic-offset: 8
3131 * End:
3132 */