blob: 0aa043f255b51e3b4602fe594b9cbf0dc6bf1efa [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 Tarreaue3ba5f02006-06-29 18:54:54 +020027#include <common/config.h>
Willy Tarreaud6d06902009-08-19 11:22:33 +020028#include <common/compat.h>
Willy Tarreau0108d902018-11-25 19:14:37 +010029#include <common/initcall.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020030#include <common/standard.h>
Willy Tarreaufb278672006-10-15 15:38:50 +020031#include <common/time.h>
Willy Tarreaubb869862020-04-16 10:52:41 +020032#include <common/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 Tarreaud52a7f82019-08-30 14:05:35 +020040#include <proto/fd.h>
William Lallemand5f232402012-04-05 18:02:55 +020041#include <proto/frontend.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020042#include <proto/log.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020043#include <proto/ring.h>
Willy Tarreauc8368452012-12-21 00:09:23 +010044#include <proto/sample.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020045#include <proto/sink.h>
Willy Tarreauc125cef2019-05-10 09:58:43 +020046#include <proto/ssl_sock.h>
Willy Tarreaufb0afa72015-04-03 14:46:27 +020047#include <proto/stream.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010048#include <proto/stream_interface.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020049
Dragan Dosen43885c72015-10-01 13:18:13 +020050struct log_fmt {
51 char *name;
52 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020053 struct buffer sep1; /* first pid separator */
54 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020055 } pid;
56};
57
58static const struct log_fmt log_formats[LOG_FORMATS] = {
59 [LOG_FORMAT_RFC3164] = {
60 .name = "rfc3164",
61 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020062 .sep1 = { .area = "[", .data = 1 },
63 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020064 }
65 },
66 [LOG_FORMAT_RFC5424] = {
67 .name = "rfc5424",
68 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020069 .sep1 = { .area = " ", .data = 1 },
70 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020071 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010072 },
73 [LOG_FORMAT_SHORT] = {
74 .name = "short",
75 .pid = {
76 .sep1 = { .area = "", .data = 0 },
77 .sep2 = { .area = " ", .data = 1 },
78 }
79 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010080 [LOG_FORMAT_RAW] = {
81 .name = "raw",
82 .pid = {
83 .sep1 = { .area = "", .data = 0 },
84 .sep2 = { .area = "", .data = 0 },
85 }
86 },
Dragan Dosen1322d092015-09-22 16:05:32 +020087};
88
Emeric Brunbd163812020-05-06 14:33:46 +020089char *get_format_pid_sep1(int format, size_t *len)
90{
91 *len = log_formats[format].pid.sep1.data;
92 return log_formats[format].pid.sep1.area;
93}
94
95char *get_format_pid_sep2(int format, size_t *len)
96{
97 *len = log_formats[format].pid.sep2.data;
98 return log_formats[format].pid.sep2.area;
99}
100
Dragan Dosen835b9212016-02-12 13:23:03 +0100101/*
102 * This map is used with all the FD_* macros to check whether a particular bit
Willy Tarreau1bfd6022019-06-07 11:10:07 +0200103 * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
104 * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
105 * that the byte should be escaped. Be careful to always pass bytes from 0 to
106 * 255 exclusively to the macros.
Dragan Dosen835b9212016-02-12 13:23:03 +0100107 */
Willy Tarreau1bfd6022019-06-07 11:10:07 +0200108long rfc5424_escape_map[(256/8) / sizeof(long)];
109long hdr_encode_map[(256/8) / sizeof(long)];
110long url_encode_map[(256/8) / sizeof(long)];
111long http_encode_map[(256/8) / sizeof(long)];
Dragan Dosen835b9212016-02-12 13:23:03 +0100112
Dragan Dosen835b9212016-02-12 13:23:03 +0100113
Willy Tarreaubaaee002006-06-26 02:48:02 +0200114const char *log_facilities[NB_LOG_FACILITIES] = {
115 "kern", "user", "mail", "daemon",
116 "auth", "syslog", "lpr", "news",
117 "uucp", "cron", "auth2", "ftp",
118 "ntp", "audit", "alert", "cron2",
119 "local0", "local1", "local2", "local3",
120 "local4", "local5", "local6", "local7"
121};
122
Willy Tarreaubaaee002006-06-26 02:48:02 +0200123const char *log_levels[NB_LOG_LEVELS] = {
124 "emerg", "alert", "crit", "err",
125 "warning", "notice", "info", "debug"
126};
127
Willy Tarreau570f2212013-06-10 16:42:09 +0200128const 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 +0200129const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200130
William Lallemand723b73a2012-02-08 16:37:49 +0100131
132/* log_format */
133struct logformat_type {
134 char *name;
135 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100136 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200137 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100138 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100139 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100140};
141
William Lallemandb7ff6a32012-03-02 14:35:21 +0100142int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
143
William Lallemand723b73a2012-02-08 16:37:49 +0100144/* log_format variable names */
145static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200146 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100147
148 /* please keep these lines sorted ! */
149 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
150 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
151 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
152 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +0100153 { "ID", LOG_FMT_UNIQUEID, PR_MODE_TCP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200154 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200155 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200156 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100157 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200158 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
159 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
160 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
161 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
162 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
163 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200164 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100165 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200166 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Damien Claisse57c8eb92020-04-28 12:09:19 +0000167 { "Tu", LOG_FMT_TU, PR_MODE_TCP, LW_BYTES, NULL }, /* Tu = Tt -Ti */
Willy Tarreau2beef582012-12-20 17:22:52 +0100168 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
169 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200170 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100171 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200172 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100173 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
174 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200175 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200176 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
177 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100178 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
179 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200180 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
181 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100182 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200183 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
184 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
185 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
186 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000187 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
188 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000189 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000190 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
191 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200192 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100193 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200194 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100195 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
196 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100197 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100198 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
199 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
200 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
201 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
202 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200203 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
204 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100205 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200206 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
207 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
208 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100209 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
210 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
211
212 /* The following tags are deprecated and will be removed soon */
213 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
214 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200215 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
216 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
217 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
218 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100219 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
220 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
221 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
222 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
223 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200224 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100225};
226
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200227char 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
228char 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 +0100229char 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 +0100230char *log_format = NULL;
231
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200232/* Default string used for structured-data part in RFC5424 formatted
233 * syslog messages.
234 */
235char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200236
Willy Tarreau13ef7732018-11-12 07:25:28 +0100237/* total number of dropped logs */
238unsigned int dropped_logs = 0;
239
Dragan Dosen1322d092015-09-22 16:05:32 +0200240/* This is a global syslog header, common to all outgoing messages in
241 * RFC3164 format. It begins with time-based part and is updated by
242 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200243 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200244THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200245THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200246
Dragan Dosen1322d092015-09-22 16:05:32 +0200247/* This is a global syslog header for messages in RFC5424 format. It is
248 * updated by update_log_hdr_rfc5424().
249 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200250THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200251THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200252
Dragan Dosen59cee972015-09-19 22:09:02 +0200253/* This is a global syslog message buffer, common to all outgoing
254 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100255 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200256THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100257
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200258/* A global syslog message buffer, common to all RFC5424 syslog messages.
259 * Currently, it is used for generating the structured-data part.
260 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200261THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200262
Christopher Fauletd4696382017-10-24 11:44:05 +0200263/* A global buffer used to store all startup alerts/warnings. It will then be
264 * retrieve on the CLI. */
Willy Tarreau869efd52019-11-15 15:16:57 +0100265static struct ring *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200266
William Lallemand723b73a2012-02-08 16:37:49 +0100267struct logformat_var_args {
268 char *name;
269 int mask;
270};
271
272struct logformat_var_args var_args_list[] = {
273// global
274 { "M", LOG_OPT_MANDATORY },
275 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200276 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100277 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100278 { 0, 0 }
279};
280
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200281/* return the name of the directive used in the current proxy for which we're
282 * currently parsing a header, when it is known.
283 */
284static inline const char *fmt_directive(const struct proxy *curproxy)
285{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100286 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200287 case ARGC_ACL:
288 return "acl";
289 case ARGC_STK:
290 return "stick";
291 case ARGC_TRK:
292 return "track-sc";
293 case ARGC_LOG:
294 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200295 case ARGC_LOGSD:
296 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100297 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100298 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100299 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100300 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200301 case ARGC_UIF:
302 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100303 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200304 return "redirect";
305 case ARGC_CAP:
306 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200307 case ARGC_SRV:
308 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200309 case ARGC_SPOE:
310 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100311 case ARGC_UBK:
312 return "use_backend";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100313 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200314 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100315 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200316}
317
William Lallemand723b73a2012-02-08 16:37:49 +0100318/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100319 * callback used to configure addr source retrieval
320 */
321int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
322{
323 curproxy->options2 |= PR_O2_SRC_ADDR;
324
325 return 0;
326}
327
328
329/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100330 * Parse args in a logformat_var. Returns 0 in error
331 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100332 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100333int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100334{
335 int i = 0;
336 int end = 0;
337 int flags = 0; // 1 = + 2 = -
338 char *sp = NULL; // start pointer
339
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100340 if (args == NULL) {
341 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100342 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100343 }
William Lallemand723b73a2012-02-08 16:37:49 +0100344
345 while (1) {
346 if (*args == '\0')
347 end = 1;
348
349 if (*args == '+') {
350 // add flag
351 sp = args + 1;
352 flags = 1;
353 }
354 if (*args == '-') {
355 // delete flag
356 sp = args + 1;
357 flags = 2;
358 }
359
360 if (*args == '\0' || *args == ',') {
361 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100362 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100363 if (strcmp(sp, var_args_list[i].name) == 0) {
364 if (flags == 1) {
365 node->options |= var_args_list[i].mask;
366 break;
367 } else if (flags == 2) {
368 node->options &= ~var_args_list[i].mask;
369 break;
370 }
371 }
372 }
373 sp = NULL;
374 if (end)
375 break;
376 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100377 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100378 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100379 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100380}
381
382/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100383 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
384 * must pass the args part in the <arg> pointer with its length in <arg_len>,
385 * and varname with its length in <var> and <var_len> respectively. <arg> is
386 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100387 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100388 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100389int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100390{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100391 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200392 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100393
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100394 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
395 if (strlen(logformat_keywords[j].name) == var_len &&
396 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
397 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200398 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100399 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100400 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200401 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100402 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100403 node->type = logformat_keywords[j].type;
404 node->options = *defoptions;
405 if (arg_len) {
406 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100407 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200408 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100409 }
410 if (node->type == LOG_FMT_GLOBAL) {
411 *defoptions = node->options;
412 free(node->arg);
413 free(node);
414 } else {
415 if (logformat_keywords[j].config_callback &&
416 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200417 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100418 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100419 curproxy->to_log |= logformat_keywords[j].lw;
420 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100421 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100422 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100423 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
424 curproxy->conf.args.file, curproxy->conf.args.line,
425 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100426 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100427 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100428 memprintf(err, "format variable '%s' is reserved for HTTP mode",
429 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200430 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100431 }
William Lallemand723b73a2012-02-08 16:37:49 +0100432 }
433 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100434
435 j = var[var_len];
436 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100437 memprintf(err, "no such format variable '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%'", var);
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100438 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200439
440 error_free:
441 if (node) {
442 free(node->arg);
443 free(node);
444 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100445 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100446}
447
448/*
449 * push to the logformat linked list
450 *
451 * start: start pointer
452 * end: end text pointer
453 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100454 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100455 *
456 * LOG_TEXT: copy chars from start to end excluding end.
457 *
458*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100459int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100460{
461 char *str;
462
Willy Tarreaua3571662012-12-20 21:59:12 +0100463 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200464 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100465 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100466 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100467 return 0;
468 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200469 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100470 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100471 str[end - start] = '\0';
472 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100473 node->type = LOG_FMT_TEXT; // type string
474 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100475 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200476 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100477 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100478 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100479 return 0;
480 }
William Lallemand1d705562012-03-12 12:46:41 +0100481 node->type = LOG_FMT_SEPARATOR;
482 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100483 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100484 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100485}
486
487/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100488 * Parse the sample fetch expression <text> and add a node to <list_format> upon
489 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100490 * should work. The curpx->conf.args.ctx must be set by the caller. If an end pointer
491 * is passed in <endptr>, it will be updated with the pointer to the first character
492 * not part of the sample expression.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100493 *
494 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100495 */
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100496int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err, char **endptr)
Willy Tarreauc8368452012-12-21 00:09:23 +0100497{
498 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200499 struct sample_expr *expr = NULL;
500 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100501 int cmd_arg;
502
503 cmd[0] = text;
504 cmd[1] = "";
505 cmd_arg = 0;
506
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100507 expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args, endptr);
Willy Tarreauc8368452012-12-21 00:09:23 +0100508 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100509 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200510 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100511 }
512
Vincent Bernat02779b62016-04-03 13:48:43 +0200513 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100514 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100515 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200516 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100517 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100518 node->type = LOG_FMT_EXPR;
519 node->expr = expr;
520 node->options = options;
521
522 if (arg_len) {
523 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100524 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200525 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100526 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100527 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100528 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
529
Willy Tarreau434c57c2013-01-08 01:10:24 +0100530 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100531 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
532
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100533 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100534 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
535 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200536 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100537 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100538
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200539 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100540 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100541 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100542
William Lallemand65ad6e12014-01-31 15:08:02 +0100543 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
544 * needed with some sample fetches (eg: ssl*). We always set it for
545 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100546 */
547 curpx->to_log |= LW_XPRT;
Christopher Fauletd2236cd2020-04-06 18:29:14 +0200548 if (curpx->http_needed)
549 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100550 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100551 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200552
553 error_free:
554 release_sample_expr(expr);
555 if (node) {
556 free(node->arg);
557 free(node);
558 }
559 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100560}
561
562/*
William Lallemand723b73a2012-02-08 16:37:49 +0100563 * Parse the log_format string and fill a linked list.
564 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200565 * You can set arguments using { } : %{many arguments}varname.
566 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100567 *
Ilya Shipitsinae40dbc2020-04-04 12:59:53 +0500568 * fmt: the string to parse
William Lallemand1d705562012-03-12 12:46:41 +0100569 * curproxy: the proxy affected
570 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100571 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100572 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100573 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100574 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100575 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100576int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100577{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100578 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100579 char *arg = NULL; /* start pointer for args */
580 char *var = NULL; /* start pointer for vars */
581 int arg_len = 0;
582 int var_len = 0;
583 int cformat; /* current token format */
584 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100585 struct logformat_node *tmplf, *back;
586
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100587 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100588 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100589 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100590 return 0;
591 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200592 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200593
William Lallemand723b73a2012-02-08 16:37:49 +0100594 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100595 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100596 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200597 release_sample_expr(tmplf->expr);
598 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100599 free(tmplf);
600 }
601
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100602 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100603 pformat = cformat;
604
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100605 if (!*str)
606 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100607
Joseph Herlant85b40592018-11-15 12:10:04 -0800608 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100609 * second have all common paths processed at one place. The common paths are the ones
610 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
611 * We use the common LF_INIT state to dispatch to the different final states.
612 */
613 switch (pformat) {
614 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100615 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100616 arg_len = var_len = 0;
617 if (*str == '{') { // optional argument
618 cformat = LF_STARG;
619 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100620 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100621 else if (*str == '[') {
622 cformat = LF_STEXPR;
623 var = str + 1; // store expr in variable name
624 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100625 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100626 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100627 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100628 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100629 else if (*str == '%')
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500630 cformat = LF_TEXT; // convert this character to a literal (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100631 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100632 /* single '%' followed by blank or digit, send them both */
633 cformat = LF_TEXT;
634 pformat = LF_TEXT; /* finally we include the previous char as well */
635 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600636 memprintf(err, "unexpected variable name near '%c' at position %d line : '%s'. Maybe you want to write a single '%%', use the syntax '%%%%'",
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100637 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100638 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100639
640 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100641 else
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500642 cformat = LF_INIT; // handle other cases of literals
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100643 break;
644
645 case LF_STARG: // text immediately following '%{'
646 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100647 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100648 arg_len = str - arg;
649 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100650 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100651 break;
652
653 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100654 if (*str == '[') {
655 cformat = LF_STEXPR;
656 var = str + 1; // store expr in variable name
657 break;
658 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100659 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100660 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100661 var = str;
662 break;
663 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100664 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100665 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100666
Willy Tarreauc8368452012-12-21 00:09:23 +0100667 case LF_STEXPR: // text immediately following '%['
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100668 /* the whole sample expression is parsed at once,
669 * returning the pointer to the first character not
670 * part of the expression, which MUST be the trailing
671 * angle bracket.
672 */
673 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str))
674 goto fail;
675
676 if (*str == ']') {
677 // end of arg, go on with next state
678 cformat = pformat = LF_EDEXPR;
679 sp = str;
680 }
681 else {
682 char c = *str;
683 *str = 0;
Willy Tarreau90807112020-02-25 08:16:33 +0100684 if (isprint((unsigned char)c))
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100685 memprintf(err, "expected ']' after '%s', but found '%c'", var, c);
686 else
687 memprintf(err, "missing ']' after '%s'", var);
Willy Tarreauc8368452012-12-21 00:09:23 +0100688 }
689 break;
690
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100691 case LF_VAR: // text part of a variable name
692 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100693 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100694 cformat = LF_INIT; // not variable name anymore
695 break;
696
Willy Tarreauc8368452012-12-21 00:09:23 +0100697 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100698 cformat = LF_INIT;
699 }
700
701 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
702 switch (*str) {
703 case '%': cformat = LF_STARTVAR; break;
704 case ' ': cformat = LF_SEPARATOR; break;
705 case 0 : cformat = LF_END; break;
706 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100707 }
708 }
709
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100710 if (cformat != pformat || pformat == LF_SEPARATOR) {
711 switch (pformat) {
712 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100713 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100714 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100715 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100716 case LF_STEXPR:
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100717 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &sp))
Willy Tarreau51013e82019-12-11 12:05:39 +0100718 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100719 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100720 case LF_TEXT:
721 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100722 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100723 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100724 break;
725 }
726 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100727 }
728 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100729
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100730 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100731 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100732 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100733 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100734 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100735
736 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100737 fail:
738 free(backfmt);
739 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100740}
741
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200742/*
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500743 * Parse the first range of indexes from a string made of a list of comma separated
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200744 * ranges of indexes. Note that an index may be considered as a particular range
745 * with a high limit to the low limit.
746 */
747int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
748{
749 char *end, *p;
750
751 *low = *high = 0;
752
753 p = *arg;
754 end = strchr(p, ',');
755 if (!end)
756 end = p + strlen(p);
757
758 *high = *low = read_uint((const char **)&p, end);
759 if (!*low || (p != end && *p != '-'))
760 goto err;
761
762 if (p == end)
763 goto done;
764
765 p++;
766 *high = read_uint((const char **)&p, end);
767 if (!*high || *high <= *low || p != end)
768 goto err;
769
770 done:
771 if (*end == ',')
772 end++;
773 *arg = end;
774 return 1;
775
776 err:
777 memprintf(err, "wrong sample range '%s'", *arg);
778 return 0;
779}
780
781/*
782 * Returns 1 if the range defined by <low> and <high> overlaps
783 * one of them in <rgs> array of ranges with <sz> the size of this
784 * array, 0 if not.
785 */
786int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
787 unsigned int low, unsigned int high, char **err)
788{
789 size_t i;
790
791 for (i = 0; i < sz; i++) {
792 if ((low >= rgs[i].low && low <= rgs[i].high) ||
793 (high >= rgs[i].low && high <= rgs[i].high)) {
794 memprintf(err, "ranges are overlapping");
795 return 1;
796 }
797 }
798
799 return 0;
800}
801
802int smp_log_range_cmp(const void *a, const void *b)
803{
804 const struct smp_log_range *rg_a = a;
805 const struct smp_log_range *rg_b = b;
806
807 if (rg_a->high < rg_b->low)
808 return -1;
809 else if (rg_a->low > rg_b->high)
810 return 1;
811
812 return 0;
813}
814
815/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200816 * Parse "log" keyword and update <logsrvs> list accordingly.
817 *
818 * When <do_del> is set, it means the "no log" line was parsed, so all log
819 * servers in <logsrvs> are released.
820 *
821 * Otherwise, we try to parse the "log" line. First of all, when the list is not
822 * the global one, we look for the parameter "global". If we find it,
823 * global.logsrvs is copied. Else we parse each arguments.
824 *
825 * The function returns 1 in success case, otherwise, it returns 0 and err is
826 * filled.
827 */
828int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
829{
830 struct sockaddr_storage *sk;
831 struct logsrv *logsrv = NULL;
832 int port1, port2;
833 int cur_arg;
834
835 /*
836 * "no log": delete previous herited or defined syslog
837 * servers.
838 */
839 if (do_del) {
840 struct logsrv *back;
841
842 if (*(args[1]) != 0) {
843 memprintf(err, "'no log' does not expect arguments");
844 goto error;
845 }
846
847 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
848 LIST_DEL(&logsrv->list);
849 free(logsrv);
850 }
851 return 1;
852 }
853
854 /*
855 * "log global": copy global.logrsvs linked list to the end of logsrvs
856 * list. But first, we check (logsrvs != global.logsrvs).
857 */
858 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
859 if (logsrvs == &global.logsrvs) {
860 memprintf(err, "'global' is not supported for a global syslog server");
861 goto error;
862 }
863 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200864 struct logsrv *node;
865
866 list_for_each_entry(node, logsrvs, list) {
867 if (node->ref == logsrv)
868 goto skip_logsrv;
869 }
870
871 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200872 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200873 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200874 LIST_INIT(&node->list);
875 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200876
877 skip_logsrv:
878 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200879 }
880 return 1;
881 }
882
883 /*
884 * "log <address> ...: parse a syslog server line
885 */
886 if (*(args[1]) == 0 || *(args[2]) == 0) {
887 memprintf(err, "expects <address> and <facility> %s as arguments",
888 ((logsrvs == &global.logsrvs) ? "" : "or global"));
889 goto error;
890 }
891
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100892 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
893 if (strcmp(args[1], "stdout") == 0)
894 args[1] = "fd@1";
895 else if (strcmp(args[1], "stderr") == 0)
896 args[1] = "fd@2";
897
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200898 logsrv = calloc(1, sizeof(*logsrv));
899 if (!logsrv) {
900 memprintf(err, "out of memory");
901 goto error;
902 }
903
904 /* skip address for now, it will be parsed at the end */
905 cur_arg = 2;
906
907 /* just after the address, a length may be specified */
908 logsrv->maxlen = MAX_SYSLOG_LEN;
909 if (strcmp(args[cur_arg], "len") == 0) {
910 int len = atoi(args[cur_arg+1]);
911 if (len < 80 || len > 65535) {
912 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
913 args[cur_arg+1]);
914 goto error;
915 }
916 logsrv->maxlen = len;
917 cur_arg += 2;
918 }
919 if (logsrv->maxlen > global.max_syslog_len)
920 global.max_syslog_len = logsrv->maxlen;
921
922 /* after the length, a format may be specified */
923 if (strcmp(args[cur_arg], "format") == 0) {
924 logsrv->format = get_log_format(args[cur_arg+1]);
925 if (logsrv->format < 0) {
926 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
927 goto error;
928 }
929 cur_arg += 2;
930 }
931
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200932 if (strcmp(args[cur_arg], "sample") == 0) {
933 unsigned low, high;
934 char *p, *beg, *end, *smp_sz_str;
935 struct smp_log_range *smp_rgs = NULL;
936 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
937
938 p = args[cur_arg+1];
939 smp_sz_str = strchr(p, ':');
940 if (!smp_sz_str) {
941 memprintf(err, "Missing sample size");
942 goto error;
943 }
944
945 *smp_sz_str++ = '\0';
946
947 end = p + strlen(p);
948
949 while (p != end) {
950 if (!get_logsrv_smp_range(&low, &high, &p, err))
951 goto error;
952
953 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
954 goto error;
955
956 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
957 if (!smp_rgs) {
958 memprintf(err, "out of memory error");
959 goto error;
960 }
961
962 smp_rgs[smp_rgs_sz].low = low;
963 smp_rgs[smp_rgs_sz].high = high;
964 smp_rgs[smp_rgs_sz].sz = high - low + 1;
965 smp_rgs[smp_rgs_sz].curr_idx = 0;
966 if (smp_rgs[smp_rgs_sz].high > smp_sz)
967 smp_sz = smp_rgs[smp_rgs_sz].high;
968 smp_rgs_sz++;
969 }
970
Tim Duesterhus21648002019-06-23 22:10:10 +0200971 if (smp_rgs == NULL) {
972 memprintf(err, "no sampling ranges given");
973 goto error;
974 }
975
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200976 beg = smp_sz_str;
977 end = beg + strlen(beg);
978 new_smp_sz = read_uint((const char **)&beg, end);
979 if (!new_smp_sz || beg != end) {
980 memprintf(err, "wrong sample size '%s' for sample range '%s'",
981 smp_sz_str, args[cur_arg+1]);
982 goto error;
983 }
984
985 if (new_smp_sz < smp_sz) {
986 memprintf(err, "sample size %zu should be greater or equal to "
987 "%zu the maximum of the high ranges limits",
988 new_smp_sz, smp_sz);
989 goto error;
990 }
991 smp_sz = new_smp_sz;
992
993 /* Let's order <smp_rgs> array. */
994 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
995
996 logsrv->lb.smp_rgs = smp_rgs;
997 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
998 logsrv->lb.smp_sz = smp_sz;
999
1000 cur_arg += 2;
1001 }
Frédéric Lécailled803e472019-04-25 07:42:09 +02001002 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001003 /* parse the facility */
1004 logsrv->facility = get_log_facility(args[cur_arg]);
1005 if (logsrv->facility < 0) {
1006 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
1007 goto error;
1008 }
1009 cur_arg++;
1010
1011 /* parse the max syslog level (default: debug) */
1012 logsrv->level = 7;
1013 if (*(args[cur_arg])) {
1014 logsrv->level = get_log_level(args[cur_arg]);
1015 if (logsrv->level < 0) {
1016 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
1017 goto error;
1018 }
1019 cur_arg++;
1020 }
1021
1022 /* parse the limit syslog level (default: emerg) */
1023 logsrv->minlvl = 0;
1024 if (*(args[cur_arg])) {
1025 logsrv->minlvl = get_log_level(args[cur_arg]);
1026 if (logsrv->minlvl < 0) {
1027 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
1028 goto error;
1029 }
1030 cur_arg++;
1031 }
1032
1033 /* Too many args */
1034 if (*(args[cur_arg])) {
1035 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1036 goto error;
1037 }
1038
1039 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001040 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001041 if (strncmp(args[1], "ring@", 5) == 0) {
1042 struct sink *sink = sink_find(args[1] + 5);
1043
1044 if (!sink || sink->type != SINK_TYPE_BUFFER) {
1045 memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
1046 goto error;
1047 }
1048
1049 logsrv->addr.ss_family = AF_UNSPEC;
1050 logsrv->type = LOG_TARGET_BUFFER;
Emeric Brune709e1e2020-05-06 17:23:59 +02001051 logsrv->sink = sink;
Willy Tarreauc046d162019-08-30 15:24:59 +02001052 goto done;
1053 }
1054
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001055 if (strncmp(args[1], "fd@", 3) == 0)
1056 logsrv->type = LOG_TARGET_FD;
1057
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001058 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1059 if (!sk)
1060 goto error;
1061 logsrv->addr = *sk;
1062
1063 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1064 if (port1 != port2) {
1065 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1066 goto error;
1067 }
1068 logsrv->addr = *sk;
1069 if (!port1)
1070 set_host_port(&logsrv->addr, SYSLOG_PORT);
1071 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001072 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001073 LIST_ADDQ(logsrvs, &logsrv->list);
1074 return 1;
1075
1076 error:
1077 free(logsrv);
1078 return 0;
1079}
1080
1081
Christopher Fauletd4696382017-10-24 11:44:05 +02001082/* Generic function to display messages prefixed by a label */
1083static void print_message(const char *label, const char *fmt, va_list argp)
1084{
1085 struct tm tm;
1086 char *head, *msg;
1087
1088 head = msg = NULL;
1089
1090 get_localtime(date.tv_sec, &tm);
1091 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1092 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1093 memvprintf(&msg, fmt, argp);
1094
Willy Tarreau869efd52019-11-15 15:16:57 +01001095 if (global.mode & MODE_STARTING) {
1096 if (unlikely(!startup_logs))
1097 startup_logs = ring_new(STARTUP_LOG_SIZE);
1098
1099 if (likely(startup_logs)) {
1100 struct ist m[2];
1101
1102 m[0] = ist(head);
1103 m[1] = ist(msg);
1104 /* trim the trailing '\n' */
1105 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1106 m[1].len--;
1107 ring_write(startup_logs, ~0, 0, 0, m, 2);
1108 }
1109 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001110
1111 fprintf(stderr, "%s%s", head, msg);
1112 fflush(stderr);
1113
1114 free(head);
1115 free(msg);
1116}
1117
Willy Tarreaubaaee002006-06-26 02:48:02 +02001118/*
1119 * Displays the message on stderr with the date and pid. Overrides the quiet
1120 * mode during startup.
1121 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001122void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001123{
1124 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001125
1126 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Willy Tarreaubb869862020-04-16 10:52:41 +02001127 if (!(warned & WARN_EXEC_PATH)) {
1128 const char *path = get_exec_path();
1129
1130 warned |= WARN_EXEC_PATH;
1131 ha_notice("haproxy version is %s\n", haproxy_version);
1132 if (path)
1133 ha_notice("path to executable is %s\n", path);
1134 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001135 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001136 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001137 va_end(argp);
1138 }
1139}
1140
1141
1142/*
1143 * Displays the message on stderr with the date and pid.
1144 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001145void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001146{
1147 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001148
Willy Tarreaubebd2122020-04-15 16:06:11 +02001149 warned |= WARN_ANY;
1150
Willy Tarreaubaaee002006-06-26 02:48:02 +02001151 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1152 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001153 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001154 va_end(argp);
1155 }
1156}
1157
1158/*
William Lallemand9c56a222018-11-21 18:04:52 +01001159 * Displays the message on stderr with the date and pid.
1160 */
1161void ha_notice(const char *fmt, ...)
1162{
1163 va_list argp;
1164
1165 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1166 va_start(argp, fmt);
1167 print_message("NOTICE", fmt, argp);
1168 va_end(argp);
1169 }
1170}
1171
1172/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001173 * Displays the message on <out> only if quiet mode is not set.
1174 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001175void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001176{
1177 va_list argp;
1178
1179 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1180 va_start(argp, fmt);
1181 vfprintf(out, fmt, argp);
1182 fflush(out);
1183 va_end(argp);
1184 }
1185}
1186
1187/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001188 * returns log format for <fmt> or -1 if not found.
1189 */
1190int get_log_format(const char *fmt)
1191{
1192 int format;
1193
1194 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001195 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001196 format--;
1197
1198 return format;
1199}
1200
1201/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001202 * returns log level for <lev> or -1 if not found.
1203 */
1204int get_log_level(const char *lev)
1205{
1206 int level;
1207
1208 level = NB_LOG_LEVELS - 1;
1209 while (level >= 0 && strcmp(log_levels[level], lev))
1210 level--;
1211
1212 return level;
1213}
1214
Willy Tarreaubaaee002006-06-26 02:48:02 +02001215/*
1216 * returns log facility for <fac> or -1 if not found.
1217 */
1218int get_log_facility(const char *fac)
1219{
1220 int facility;
1221
1222 facility = NB_LOG_FACILITIES - 1;
1223 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1224 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001225
Willy Tarreaubaaee002006-06-26 02:48:02 +02001226 return facility;
1227}
1228
William Lallemanda1cc3812012-02-08 16:38:44 +01001229/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001230 * Encode the string.
1231 *
1232 * When using the +E log format option, it will try to escape '"\]'
1233 * characters with '\' as prefix. The same prefix should not be used as
1234 * <escape>.
1235 */
1236static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001237 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001238 const char *string,
1239 struct logformat_node *node)
1240{
1241 if (node->options & LOG_OPT_ESC) {
1242 if (start < stop) {
1243 stop--; /* reserve one byte for the final '\0' */
1244 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001245 if (!ha_bit_test((unsigned char)(*string), map)) {
1246 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001247 *start++ = *string;
1248 else {
1249 if (start + 2 >= stop)
1250 break;
1251 *start++ = '\\';
1252 *start++ = *string;
1253 }
1254 }
1255 else {
1256 if (start + 3 >= stop)
1257 break;
1258 *start++ = escape;
1259 *start++ = hextab[(*string >> 4) & 15];
1260 *start++ = hextab[*string & 15];
1261 }
1262 string++;
1263 }
1264 *start = '\0';
1265 }
1266 }
1267 else {
1268 return encode_string(start, stop, escape, map, string);
1269 }
1270
1271 return start;
1272}
1273
1274/*
1275 * Encode the chunk.
1276 *
1277 * When using the +E log format option, it will try to escape '"\]'
1278 * characters with '\' as prefix. The same prefix should not be used as
1279 * <escape>.
1280 */
1281static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001282 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001283 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001284 struct logformat_node *node)
1285{
1286 char *str, *end;
1287
1288 if (node->options & LOG_OPT_ESC) {
1289 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001290 str = chunk->area;
1291 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001292
1293 stop--; /* reserve one byte for the final '\0' */
1294 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001295 if (!ha_bit_test((unsigned char)(*str), map)) {
1296 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001297 *start++ = *str;
1298 else {
1299 if (start + 2 >= stop)
1300 break;
1301 *start++ = '\\';
1302 *start++ = *str;
1303 }
1304 }
1305 else {
1306 if (start + 3 >= stop)
1307 break;
1308 *start++ = escape;
1309 *start++ = hextab[(*str >> 4) & 15];
1310 *start++ = hextab[*str & 15];
1311 }
1312 str++;
1313 }
1314 *start = '\0';
1315 }
1316 }
1317 else {
1318 return encode_chunk(start, stop, escape, map, chunk);
1319 }
1320
1321 return start;
1322}
1323
1324/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001325 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001326 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001327 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001328 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001329 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001330char *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 +01001331{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001332 if (size < 2)
1333 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001334
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001335 if (node->options & LOG_OPT_QUOTE) {
1336 *(dst++) = '"';
1337 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001338 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001339
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001340 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001341 if (++len > size)
1342 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001343 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001344 char *ret;
1345
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001346 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001347 if (ret == NULL || *ret != '\0')
1348 return NULL;
1349 len = ret - dst;
1350 }
1351 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001352 len = strlcpy2(dst, src, len);
1353 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001354
1355 size -= len;
1356 dst += len;
1357 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001358 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1359 if (size < 2)
1360 return NULL;
1361 *(dst++) = '-';
1362 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001363
1364 if (node->options & LOG_OPT_QUOTE) {
1365 if (size < 2)
1366 return NULL;
1367 *(dst++) = '"';
1368 }
1369
1370 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001371 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001372}
1373
Willy Tarreau26ffa852018-09-05 15:23:10 +02001374static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001375{
1376 return lf_text_len(dst, src, size, size, node);
1377}
1378
William Lallemand5f232402012-04-05 18:02:55 +02001379/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001380 * Write a IP address to the log string
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001381 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001382 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001383char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001384{
1385 char *ret = dst;
1386 int iret;
1387 char pn[INET6_ADDRSTRLEN];
1388
1389 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001390 unsigned char *addr = NULL;
1391 switch (sockaddr->sa_family) {
1392 case AF_INET:
1393 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1394 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1395 break;
1396 case AF_INET6:
1397 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1398 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1399 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1400 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1401 break;
1402 default:
1403 return NULL;
1404 }
William Lallemand5f232402012-04-05 18:02:55 +02001405 if (iret < 0 || iret > size)
1406 return NULL;
1407 ret += iret;
1408 } else {
1409 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1410 ret = lf_text(dst, pn, size, node);
1411 if (ret == NULL)
1412 return NULL;
1413 }
1414 return ret;
1415}
1416
1417/*
1418 * Write a port to the log
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001419 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001420 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001421char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001422{
1423 char *ret = dst;
1424 int iret;
1425
1426 if (node->options & LOG_OPT_HEXA) {
1427 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1428 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1429 if (iret < 0 || iret > size)
1430 return NULL;
1431 ret += iret;
1432 } else {
1433 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1434 if (ret == NULL)
1435 return NULL;
1436 }
1437 return ret;
1438}
1439
Dragan Dosen1322d092015-09-22 16:05:32 +02001440/* Re-generate time-based part of the syslog header in RFC3164 format at
1441 * the beginning of logheader once a second and return the pointer to the
1442 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001443 */
Emeric Brunbd163812020-05-06 14:33:46 +02001444char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001445{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001446 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001447 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001448 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001449
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001450 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001451 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001452 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001453 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001454
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001455 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001456 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001457
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001458 if (unlikely(global.log_send_hostname != host.area)) {
1459 host.area = global.log_send_hostname;
1460 host.data = host.area ? strlen(host.area) : 0;
1461 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001462 }
1463
Dragan Dosen59cee972015-09-19 22:09:02 +02001464 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001465 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001466 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001467 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001468 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001469 /* WARNING: depending upon implementations, snprintf may return
1470 * either -1 or the number of bytes that would be needed to store
1471 * the total message. In both cases, we must adjust it.
1472 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001473 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1474 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001475
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001476 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001477 }
1478
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001479 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001480
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001481 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001482}
1483
Dragan Dosen1322d092015-09-22 16:05:32 +02001484/* Re-generate time-based part of the syslog header in RFC5424 format at
1485 * the beginning of logheader_rfc5424 once a second and return the pointer
1486 * to the first character after it.
1487 */
Emeric Brunbd163812020-05-06 14:33:46 +02001488char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001489{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001490 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001491 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001492
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001493 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001494 /* this string is rebuild only once a second */
1495 struct tm tm;
1496 int hdr_len;
1497
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001498 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001499 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001500 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001501
1502 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001503 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001504 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001505 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001506 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001507 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001508 /* WARNING: depending upon implementations, snprintf may return
1509 * either -1 or the number of bytes that would be needed to store
1510 * the total message. In both cases, we must adjust it.
1511 */
1512 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1513 hdr_len = global.max_syslog_len;
1514
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001515 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001516 }
1517
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001518 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001519
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001520 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001521}
1522
William Lallemand2a4a44f2012-02-06 16:00:33 +01001523/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001524 * This function sends the syslog message using a printf format string. It
1525 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001526 */
1527void send_log(struct proxy *p, int level, const char *format, ...)
1528{
1529 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001530 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001531
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001532 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001533 return;
1534
William Lallemand2a4a44f2012-02-06 16:00:33 +01001535 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001536 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001537 if (data_len < 0 || data_len > global.max_syslog_len)
1538 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001539 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001540
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001541 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1542 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001543}
1544
1545/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001546 * This function sends a syslog message to <logsrv>.
1547 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1548 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1549 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001550 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001551 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001552 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001553static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1554 int level, char *message, size_t size, char *sd, size_t sd_size,
1555 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001556{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001557 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1558 static THREAD_LOCAL struct msghdr msghdr = {
1559 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001560 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1561 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001562 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1563 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1564 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001565 time_t time = date.tv_sec;
Emeric Brune709e1e2020-05-06 17:23:59 +02001566 char *hdr, *hdr_ptr = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +02001567 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001568 int fac_level;
1569 int *plogfd;
1570 char *pid_sep1 = "", *pid_sep2 = "";
1571 char logheader_short[3];
1572 int sent;
1573 int maxlen;
1574 int hdr_max = 0;
1575 int tag_max = 0;
1576 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001577 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001578 int pid_sep2_max = 0;
1579 int sd_max = 0;
1580 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001581
1582 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001583
1584 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001585
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001586 /* historically some messages used to already contain the trailing LF */
1587 if (size && (dataptr[size-1] == '\n'))
1588 size--;
1589
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001590 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001591 /* the socket's address is a file descriptor */
1592 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001593 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001594 else if (logsrv->type == LOG_TARGET_BUFFER) {
1595 plogfd = NULL;
Emeric Brune709e1e2020-05-06 17:23:59 +02001596 goto send;
Willy Tarreauc046d162019-08-30 15:24:59 +02001597 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001598 else if (logsrv->addr.ss_family == AF_UNIX)
1599 plogfd = &logfdunix;
1600 else
1601 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001602
Willy Tarreauc046d162019-08-30 15:24:59 +02001603 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001604 /* socket not successfully initialized yet */
1605 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1606 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1607 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001608
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001609 if (!once) {
1610 once = 1; /* note: no need for atomic ops here */
1611 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1612 nblogger, strerror(errno), errno);
1613 }
1614 return;
1615 } else {
1616 /* we don't want to receive anything on this socket */
1617 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1618 /* does nothing under Linux, maybe needed for others */
1619 shutdown(*plogfd, SHUT_RD);
1620 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1621 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001622 }
1623
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001624 switch (logsrv->format) {
1625 case LOG_FORMAT_RFC3164:
1626 hdr = logheader;
1627 hdr_ptr = update_log_hdr(time);
1628 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001629
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001630 case LOG_FORMAT_RFC5424:
1631 hdr = logheader_rfc5424;
1632 hdr_ptr = update_log_hdr_rfc5424(time);
1633 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1634 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001635
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001636 case LOG_FORMAT_SHORT:
1637 /* all fields are known, skip the header generation */
1638 hdr = logheader_short;
1639 hdr[0] = '<';
1640 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1641 hdr[2] = '>';
1642 hdr_ptr = hdr;
1643 hdr_max = 3;
1644 maxlen = logsrv->maxlen - hdr_max;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001645 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001646 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001647
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001648 case LOG_FORMAT_RAW:
1649 /* all fields are known, skip the header generation */
1650 hdr_ptr = hdr = "";
1651 hdr_max = 0;
1652 maxlen = logsrv->maxlen;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001653 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001654 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001655
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001656 default:
1657 return; /* must never happen */
1658 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001659
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001660 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001661
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001662 /* For each target, we may have a different facility.
1663 * We can also have a different log level for each message.
1664 * This induces variations in the message header length.
1665 * Since we don't want to recompute it each time, nor copy it every
1666 * time, we only change the facility in the pre-computed header,
1667 * and we change the pointer to the header accordingly.
1668 */
1669 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1670 hdr_ptr = hdr + 3; /* last digit of the log level */
1671 do {
1672 *hdr_ptr = '0' + fac_level % 10;
1673 fac_level /= 10;
1674 hdr_ptr--;
1675 } while (fac_level && hdr_ptr > hdr);
1676 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001677
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001678 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001679
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001680 /* time-based header */
1681 if (unlikely(hdr_size >= logsrv->maxlen)) {
1682 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1683 sd_max = 0;
1684 goto send;
1685 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001686
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001687 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001688
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001689 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001690 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001691 if (unlikely(tag_max >= maxlen)) {
1692 tag_max = maxlen - 1;
1693 sd_max = 0;
1694 goto send;
1695 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001696
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001697 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001698
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001699 /* first pid separator */
1700 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1701 if (unlikely(pid_sep1_max >= maxlen)) {
1702 pid_sep1_max = maxlen - 1;
1703 sd_max = 0;
1704 goto send;
1705 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001706
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001707 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1708 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001709
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001710 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001711 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001712 if (unlikely(pid_size >= maxlen)) {
1713 pid_size = maxlen - 1;
1714 sd_max = 0;
1715 goto send;
1716 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001717
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001718 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001719
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001720 /* second pid separator */
1721 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1722 if (unlikely(pid_sep2_max >= maxlen)) {
1723 pid_sep2_max = maxlen - 1;
1724 sd_max = 0;
1725 goto send;
1726 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001727
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001728 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1729 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001730
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001731 /* structured-data */
1732 if (sd_max >= maxlen) {
1733 sd_max = maxlen - 1;
1734 goto send;
1735 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001736
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001737 max = MIN(size, maxlen - sd_max - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001738send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001739 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001740 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001741 struct ist msg[7];
1742
Emeric Brune709e1e2020-05-06 17:23:59 +02001743 if (logsrv->type == LOG_TARGET_BUFFER) {
1744 msg[0] = ist2(message, MIN(size, logsrv->maxlen));
1745 msg[1] = ist2(tag_str, tag_size);
1746 msg[2] = ist2(pid_str, pid_size);
1747 msg[3] = ist2(sd, sd_size);
1748 sent = sink_write(logsrv->sink, msg, 1, level, logsrv->facility, &msg[1], &msg[2], &msg[3]);
1749 }
1750 else /* LOG_TARGET_FD */ {
1751 msg[0] = ist2(hdr_ptr, hdr_max);
1752 msg[1] = ist2(tag_str, tag_max);
1753 msg[2] = ist2(pid_sep1, pid_sep1_max);
1754 msg[3] = ist2(pid_str, pid_max);
1755 msg[4] = ist2(pid_sep2, pid_sep2_max);
1756 msg[5] = ist2(sd, sd_max);
1757 msg[6] = ist2(dataptr, max);
Willy Tarreauc046d162019-08-30 15:24:59 +02001758 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Emeric Brune709e1e2020-05-06 17:23:59 +02001759 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001760 }
1761 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001762 iovec[0].iov_base = hdr_ptr;
1763 iovec[0].iov_len = hdr_max;
1764 iovec[1].iov_base = tag_str;
1765 iovec[1].iov_len = tag_max;
1766 iovec[2].iov_base = pid_sep1;
1767 iovec[2].iov_len = pid_sep1_max;
1768 iovec[3].iov_base = pid_str;
1769 iovec[3].iov_len = pid_max;
1770 iovec[4].iov_base = pid_sep2;
1771 iovec[4].iov_len = pid_sep2_max;
1772 iovec[5].iov_base = sd;
1773 iovec[5].iov_len = sd_max;
1774 iovec[6].iov_base = dataptr;
1775 iovec[6].iov_len = max;
1776 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1777 iovec[7].iov_len = 1;
1778
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001779 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1780 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001781
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001782 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1783 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001784
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001785 if (sent < 0) {
1786 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001787
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001788 if (errno == EAGAIN)
1789 _HA_ATOMIC_ADD(&dropped_logs, 1);
1790 else if (!once) {
1791 once = 1; /* note: no need for atomic ops here */
1792 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1793 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001794 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001795 }
1796}
Dragan Dosen59cee972015-09-19 22:09:02 +02001797
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001798/*
1799 * This function sends a syslog message.
1800 * It doesn't care about errors nor does it report them.
1801 * The arguments <sd> and <sd_size> are used for the structured-data part
1802 * in RFC5424 formatted syslog messages.
1803 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001804void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1805 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001806{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001807 struct logsrv *logsrv;
1808 int nblogger;
1809 static THREAD_LOCAL int curr_pid;
1810 static THREAD_LOCAL char pidstr[100];
1811 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001812
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001813 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001814 if (!LIST_ISEMPTY(&global.logsrvs)) {
1815 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001816 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001817 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001818 if (!tag || !tag->area)
1819 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001820
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001821 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001822 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001823
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001824 if (unlikely(curr_pid != getpid())) {
1825 curr_pid = getpid();
1826 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1827 chunk_initstr(&pid, pidstr);
1828 }
1829
1830 /* Send log messages to syslog server. */
1831 nblogger = 0;
1832 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001833 static THREAD_LOCAL int in_range = 1;
1834
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001835 /* we can filter the level of the messages that are sent to each logger */
1836 if (level > logsrv->level)
1837 continue;
1838
Frédéric Lécailled803e472019-04-25 07:42:09 +02001839 if (logsrv->lb.smp_rgs) {
1840 struct smp_log_range *curr_rg;
1841
1842 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1843 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1844 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1845 if (in_range) {
1846 /* Let's consume this range. */
1847 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1848 if (!curr_rg->curr_idx) {
1849 /* If consumed, let's select the next range. */
1850 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1851 }
1852 }
1853 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1854 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1855 }
1856 if (in_range)
1857 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1858 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001859 }
1860}
1861
1862
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001863const 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 +01001864const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1865 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1866 Set-cookie Updated, unknown, unknown */
1867
William Lallemand1d705562012-03-12 12:46:41 +01001868/*
1869 * try to write a character if there is enough space, or goto out
1870 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001871#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001872 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001873 *(tmplog++) = (x); \
1874 } else { \
1875 goto out; \
1876 } \
1877 } while(0)
1878
Dragan Dosen835b9212016-02-12 13:23:03 +01001879
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001880/* Initializes some log data at boot */
1881static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001882{
1883 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001884 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001885
1886 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1887 * inside PARAM-VALUE should be escaped with '\' as prefix.
1888 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1889 * details.
1890 */
1891 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1892
1893 tmp = "\"\\]";
1894 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001895 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001896 tmp++;
1897 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001898
1899 /* initialize the log header encoding map : '{|}"#' should be encoded with
1900 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1901 * URL encoding only requires '"', '#' to be encoded as well as non-
1902 * printable characters above.
1903 */
1904 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1905 memset(url_encode_map, 0, sizeof(url_encode_map));
1906 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001907 ha_bit_set(i, hdr_encode_map);
1908 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001909 }
1910 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001911 ha_bit_set(i, hdr_encode_map);
1912 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001913 }
1914
1915 tmp = "\"#{|}";
1916 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001917 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001918 tmp++;
1919 }
1920
1921 tmp = "\"#";
1922 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001923 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001924 tmp++;
1925 }
1926
1927 /* initialize the http header encoding map. The draft httpbis define the
1928 * header content as:
1929 *
1930 * HTTP-message = start-line
1931 * *( header-field CRLF )
1932 * CRLF
1933 * [ message-body ]
1934 * header-field = field-name ":" OWS field-value OWS
1935 * field-value = *( field-content / obs-fold )
1936 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1937 * obs-fold = CRLF 1*( SP / HTAB )
1938 * field-vchar = VCHAR / obs-text
1939 * VCHAR = %x21-7E
1940 * obs-text = %x80-FF
1941 *
1942 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1943 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001944 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001945 */
1946 memset(http_encode_map, 0, sizeof(http_encode_map));
1947 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001948 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001949 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001950 ha_bit_set(i, http_encode_map);
1951 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001952}
William Lallemand1d705562012-03-12 12:46:41 +01001953
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001954INITCALL0(STG_PREPARE, init_log);
1955
Christopher Faulet0132d062017-07-26 15:33:35 +02001956/* Initialize log buffers used for syslog messages */
1957int init_log_buffers()
1958{
1959 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001960 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001961 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001962 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001963 logline = my_realloc2(logline, global.max_syslog_len + 1);
1964 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1965 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1966 return 0;
1967 return 1;
1968}
1969
1970/* Deinitialize log buffers used for syslog messages */
1971void deinit_log_buffers()
1972{
1973 free(logheader);
1974 free(logheader_rfc5424);
1975 free(logline);
1976 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001977 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001978 logheader = NULL;
1979 logheader_rfc5424 = NULL;
1980 logline = NULL;
1981 logline_rfc5424 = NULL;
1982}
1983
Willy Tarreaudf974472012-12-28 02:44:01 +01001984/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1985 * <maxsize> characters. Returns the size of the output string in characters,
1986 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001987 * is not zero. It requires a valid session and optionally a stream. If the
1988 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001989 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001990int 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 +02001991{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001992 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001993 struct proxy *be;
1994 struct http_txn *txn;
1995 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001996 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001997 unsigned int s_flags;
1998 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001999 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002000 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002001 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002002 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002003 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02002004 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002005 int t_request;
2006 int hdr;
2007 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002008 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01002009 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01002010 char *ret;
2011 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002012 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002013 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002014 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002015
William Lallemandbddd4fd2012-02-27 11:23:10 +01002016 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002017
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002018 if (likely(s)) {
2019 be = s->be;
2020 txn = s->txn;
2021 be_conn = cs_conn(objt_cs(s->si[1].end));
2022 s_flags = s->flags;
2023 uniq_id = s->uniq_id;
2024 logs = &s->logs;
2025 } else {
2026 /* we have no stream so we first need to initialize a few
2027 * things that are needed later. We do increment the request
2028 * ID so that it's uniquely assigned to this request just as
2029 * if the request had reached the point of being processed.
2030 * A request error is reported as it's the only element we have
2031 * here and which justifies emitting such a log.
2032 */
2033 be = fe;
2034 txn = NULL;
2035 be_conn = NULL;
2036 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002037 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002038
2039 /* prepare a valid log structure */
2040 tmp_strm_log.tv_accept = sess->tv_accept;
2041 tmp_strm_log.accept_date = sess->accept_date;
2042 tmp_strm_log.t_handshake = sess->t_handshake;
2043 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
2044 tv_zero(&tmp_strm_log.tv_request);
2045 tmp_strm_log.t_queue = -1;
2046 tmp_strm_log.t_connect = -1;
2047 tmp_strm_log.t_data = -1;
2048 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2049 tmp_strm_log.bytes_in = 0;
2050 tmp_strm_log.bytes_out = 0;
2051 tmp_strm_log.prx_queue_pos = 0;
2052 tmp_strm_log.srv_queue_pos = 0;
2053
2054 logs = &tmp_strm_log;
2055 }
2056
William Lallemandbddd4fd2012-02-27 11:23:10 +01002057 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002058 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2059 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002060
William Lallemand1d705562012-03-12 12:46:41 +01002061 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002062
William Lallemandbddd4fd2012-02-27 11:23:10 +01002063 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002064 if (LIST_ISEMPTY(list_format))
2065 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002066
William Lallemand1d705562012-03-12 12:46:41 +01002067 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002068 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002069 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002070 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002071 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002072
Willy Tarreauc8368452012-12-21 00:09:23 +01002073 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002074 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002075 if (!last_isspace) {
2076 LOGCHAR(' ');
2077 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002078 }
2079 break;
2080
William Lallemand1d705562012-03-12 12:46:41 +01002081 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002082 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002083 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002084 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002085 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002086 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002087 last_isspace = 0;
2088 break;
2089
Willy Tarreauc8368452012-12-21 00:09:23 +01002090 case LOG_FMT_EXPR: // sample expression, may be request or response
2091 key = NULL;
Christopher Faulet5f940702020-04-06 10:40:02 +02002092 if (tmp->options & LOG_OPT_REQ_CAP)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002093 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 +02002094 if (!key && (tmp->options & LOG_OPT_RES_CAP))
Adis Nezirovic79beb242015-07-06 15:41:02 +02002095 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 +01002096 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002097 ret = lf_encode_chunk(tmplog, dst + maxsize,
2098 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002099 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002100 ret = lf_text_len(tmplog,
2101 key ? key->data.u.str.area : NULL,
2102 key ? key->data.u.str.data : 0,
2103 dst + maxsize - tmplog,
2104 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002105 if (ret == 0)
2106 goto out;
2107 tmplog = ret;
2108 last_isspace = 0;
2109 break;
2110
Willy Tarreau2beef582012-12-20 17:22:52 +01002111 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002112 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002113 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002114 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002115 else
2116 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002117 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002118 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002119 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002120 last_isspace = 0;
2121 break;
2122
Willy Tarreau2beef582012-12-20 17:22:52 +01002123 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002124 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002125 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002126 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002127 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002128 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002129 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002130 dst + maxsize - tmplog, tmp);
2131 }
William Lallemand5f232402012-04-05 18:02:55 +02002132 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002133 else
2134 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2135
William Lallemand5f232402012-04-05 18:02:55 +02002136 if (ret == NULL)
2137 goto out;
2138 tmplog = ret;
2139 last_isspace = 0;
2140 break;
2141
Willy Tarreau2beef582012-12-20 17:22:52 +01002142 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002143 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002144 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002145 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002146 }
2147 else
2148 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2149
William Lallemand1d705562012-03-12 12:46:41 +01002150 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002151 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002152 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002153 last_isspace = 0;
2154 break;
2155
Willy Tarreau2beef582012-12-20 17:22:52 +01002156 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002157 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002158 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002159 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002160 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002161 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002162 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002163 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002164 else
2165 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2166
William Lallemand5f232402012-04-05 18:02:55 +02002167 if (ret == NULL)
2168 goto out;
2169 tmplog = ret;
2170 last_isspace = 0;
2171 break;
2172
Willy Tarreau2beef582012-12-20 17:22:52 +01002173 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002174 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002175 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002176 else
2177 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2178
William Lallemand1d705562012-03-12 12:46:41 +01002179 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002180 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002181 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002182 last_isspace = 0;
2183 break;
2184
Willy Tarreau2beef582012-12-20 17:22:52 +01002185 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002186 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002187 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002188 else
2189 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2190
William Lallemand5f232402012-04-05 18:02:55 +02002191 if (ret == NULL)
2192 goto out;
2193 tmplog = ret;
2194 last_isspace = 0;
2195 break;
2196
Willy Tarreau2beef582012-12-20 17:22:52 +01002197 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002198 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002199 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002200 else
2201 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2202
William Lallemand5f232402012-04-05 18:02:55 +02002203 if (ret == NULL)
2204 goto out;
2205 tmplog = ret;
2206 last_isspace = 0;
2207 break;
2208
Willy Tarreau2beef582012-12-20 17:22:52 +01002209 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002210 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002211 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002212 else
2213 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2214
William Lallemand1d705562012-03-12 12:46:41 +01002215 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002216 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002217 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002218 last_isspace = 0;
2219 break;
2220
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002221 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002222 get_localtime(logs->accept_date.tv_sec, &tm);
2223 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002224 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002225 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002226 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002227 last_isspace = 0;
2228 break;
2229
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002230 case LOG_FMT_tr: // %tr = start of request date
2231 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002232 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 +02002233 get_localtime(tv.tv_sec, &tm);
2234 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2235 if (ret == NULL)
2236 goto out;
2237 tmplog = ret;
2238 last_isspace = 0;
2239 break;
2240
2241 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002242 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002243 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002244 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002245 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002246 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002247 last_isspace = 0;
2248 break;
2249
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002250 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002251 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 +02002252 get_gmtime(tv.tv_sec, &tm);
2253 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2254 if (ret == NULL)
2255 goto out;
2256 tmplog = ret;
2257 last_isspace = 0;
2258 break;
2259
2260 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002261 get_localtime(logs->accept_date.tv_sec, &tm);
2262 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002263 if (ret == NULL)
2264 goto out;
2265 tmplog = ret;
2266 last_isspace = 0;
2267 break;
2268
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002269 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002270 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 +02002271 get_localtime(tv.tv_sec, &tm);
2272 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2273 if (ret == NULL)
2274 goto out;
2275 tmplog = ret;
2276 last_isspace = 0;
2277 break;
2278
William Lallemand5f232402012-04-05 18:02:55 +02002279 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002280 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002281 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002282 if (iret < 0 || iret > dst + maxsize - tmplog)
2283 goto out;
2284 last_isspace = 0;
2285 tmplog += iret;
2286 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002287 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002288 if (ret == NULL)
2289 goto out;
2290 tmplog = ret;
2291 last_isspace = 0;
2292 }
2293 break;
2294
William Lallemand1d705562012-03-12 12:46:41 +01002295 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002296 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002297 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002298 if (iret < 0 || iret > dst + maxsize - tmplog)
2299 goto out;
2300 last_isspace = 0;
2301 tmplog += iret;
2302 } else {
2303 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002304 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002305 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002306 tmplog, 4);
2307 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002308 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002309 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002310 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002311 }
2312 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002313
William Lallemand1d705562012-03-12 12:46:41 +01002314 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002315 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002316 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002317 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002318 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002319 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002320 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002321 break;
2322
Willy Tarreau773d65f2012-10-12 14:56:11 +02002323 case LOG_FMT_FRONTEND_XPRT: // %ft
2324 src = fe->id;
2325 if (tmp->options & LOG_OPT_QUOTE)
2326 LOGCHAR('"');
2327 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2328 if (iret == 0)
2329 goto out;
2330 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002331 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002332 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002333 if (tmp->options & LOG_OPT_QUOTE)
2334 LOGCHAR('"');
2335 last_isspace = 0;
2336 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002337#ifdef USE_OPENSSL
2338 case LOG_FMT_SSL_CIPHER: // %sslc
2339 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002340 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002341 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002342 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002343 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002344 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2345 if (ret == NULL)
2346 goto out;
2347 tmplog = ret;
2348 last_isspace = 0;
2349 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002350
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002351 case LOG_FMT_SSL_VERSION: // %sslv
2352 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002353 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002354 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002355 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002356 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002357 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2358 if (ret == NULL)
2359 goto out;
2360 tmplog = ret;
2361 last_isspace = 0;
2362 break;
2363#endif
William Lallemand1d705562012-03-12 12:46:41 +01002364 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002365 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002366 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002367 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002368 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002369 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002370 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002371 break;
2372
William Lallemand1d705562012-03-12 12:46:41 +01002373 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002374 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002375 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002376 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002377 break;
2378 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002379 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002380 break;
2381 default:
2382 src = "<NOSRV>";
2383 break;
2384 }
William Lallemand5f232402012-04-05 18:02:55 +02002385 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002386 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002387 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002388 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002389 last_isspace = 0;
2390 break;
2391
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002392 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002393 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002394 if (ret == NULL)
2395 goto out;
2396 tmplog = ret;
2397 last_isspace = 0;
2398 break;
2399
2400 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002401 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002402 if (ret == NULL)
2403 goto out;
2404 tmplog = ret;
2405 last_isspace = 0;
2406 break;
2407
2408 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002409 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002410 tmplog, dst + maxsize - tmplog);
2411 if (ret == NULL)
2412 goto out;
2413 tmplog = ret;
2414 last_isspace = 0;
2415 break;
2416
2417 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002418 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002419 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002420 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002421 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002422 last_isspace = 0;
2423 break;
2424
William Lallemand1d705562012-03-12 12:46:41 +01002425 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002426 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002427 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002428 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002429 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002430 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002431 last_isspace = 0;
2432 break;
2433
William Lallemand1d705562012-03-12 12:46:41 +01002434 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002435 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002436 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002437 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002438 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002439 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002440 last_isspace = 0;
2441 break;
2442
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002443 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002444 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002445 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002446 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002447 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002448 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002449 last_isspace = 0;
2450 break;
2451
Willy Tarreau27b639d2016-05-17 17:55:27 +02002452 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002453 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002454 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002455 tmplog, dst + maxsize - tmplog);
2456 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002457 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002458 tmplog, dst + maxsize - tmplog);
2459 if (ret == NULL)
2460 goto out;
2461 tmplog = ret;
2462 last_isspace = 0;
2463 break;
2464
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002465 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2466 if (!(fe->to_log & LW_BYTES))
2467 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002468 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 +02002469 tmplog, dst + maxsize - tmplog);
2470 if (ret == NULL)
2471 goto out;
2472 tmplog = ret;
2473 last_isspace = 0;
2474 break;
2475
2476 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002477 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002478 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002479 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002480 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002481 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002482 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002483 last_isspace = 0;
2484 break;
2485
Damien Claisse57c8eb92020-04-28 12:09:19 +00002486 case LOG_FMT_TU: // %Tu = total time seen by user = Tt - Ti
2487 if (!(fe->to_log & LW_BYTES))
2488 LOGCHAR('+');
2489 ret = ltoa_o(logs->t_close - (logs->t_idle >= 0 ? logs->t_idle : 0),
2490 tmplog, dst + maxsize - tmplog);
2491 if (ret == NULL)
2492 goto out;
2493 tmplog = ret;
2494 last_isspace = 0;
2495 break;
2496
Willy Tarreau2beef582012-12-20 17:22:52 +01002497 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002498 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002499 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002500 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002501 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002502 last_isspace = 0;
2503 break;
2504
William Lallemand1d705562012-03-12 12:46:41 +01002505 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002506 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002507 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002508 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002509 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002510 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002511 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002512 last_isspace = 0;
2513 break;
2514
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002515 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002516 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002517 if (ret == NULL)
2518 goto out;
2519 tmplog = ret;
2520 last_isspace = 0;
2521 break;
2522
Willy Tarreau2beef582012-12-20 17:22:52 +01002523 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002524 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002525 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002526 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002527 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002528 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002529 last_isspace = 0;
2530 break;
2531
Willy Tarreau2beef582012-12-20 17:22:52 +01002532 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002533 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002534 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002535 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002536 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002537 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002538 last_isspace = 0;
2539 break;
2540
William Lallemand1d705562012-03-12 12:46:41 +01002541 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002542 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2543 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002544 *tmplog = '\0';
2545 last_isspace = 0;
2546 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002547
William Lallemand1d705562012-03-12 12:46:41 +01002548 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002549 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2550 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002551 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2552 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 +01002553 last_isspace = 0;
2554 break;
2555
William Lallemand1d705562012-03-12 12:46:41 +01002556 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002557 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002558 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002559 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002560 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002561 last_isspace = 0;
2562 break;
2563
William Lallemand1d705562012-03-12 12:46:41 +01002564 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002565 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002566 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002567 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002568 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002569 last_isspace = 0;
2570 break;
2571
William Lallemand1d705562012-03-12 12:46:41 +01002572 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002573 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002574 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002575 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002576 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002577 last_isspace = 0;
2578 break;
2579
William Lallemand1d705562012-03-12 12:46:41 +01002580 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002581 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002582 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002583 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002584 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002585 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002586 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002587 last_isspace = 0;
2588 break;
2589
William Lallemand1d705562012-03-12 12:46:41 +01002590 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002591 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002592 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002593 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002594 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002595 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002596 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002597 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002598 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002599 last_isspace = 0;
2600 break;
2601
William Lallemand1d705562012-03-12 12:46:41 +01002602 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002603 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002604 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002605 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002606 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002607 last_isspace = 0;
2608 break;
2609
William Lallemand1d705562012-03-12 12:46:41 +01002610 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002611 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002612 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002613 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002614 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002615 last_isspace = 0;
2616 break;
2617
William Lallemand1d705562012-03-12 12:46:41 +01002618 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002619 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002620 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002621 if (tmp->options & LOG_OPT_QUOTE)
2622 LOGCHAR('"');
2623 LOGCHAR('{');
2624 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2625 if (hdr)
2626 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002627 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002628 ret = lf_encode_string(tmplog, dst + maxsize,
2629 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002630 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002631 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002632 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002633 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002634 }
2635 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002636 if (tmp->options & LOG_OPT_QUOTE)
2637 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002638 last_isspace = 0;
2639 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002640 break;
2641
William Lallemand1d705562012-03-12 12:46:41 +01002642 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002643 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002644 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002645 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2646 if (hdr > 0)
2647 LOGCHAR(' ');
2648 if (tmp->options & LOG_OPT_QUOTE)
2649 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002650 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002651 ret = lf_encode_string(tmplog, dst + maxsize,
2652 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002653 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002654 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002655 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002656 } else if (!(tmp->options & LOG_OPT_QUOTE))
2657 LOGCHAR('-');
2658 if (tmp->options & LOG_OPT_QUOTE)
2659 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002660 last_isspace = 0;
2661 }
2662 }
2663 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002664
William Lallemand1d705562012-03-12 12:46:41 +01002665
2666 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002667 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002668 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002669 if (tmp->options & LOG_OPT_QUOTE)
2670 LOGCHAR('"');
2671 LOGCHAR('{');
2672 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2673 if (hdr)
2674 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002675 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002676 ret = lf_encode_string(tmplog, dst + maxsize,
2677 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002678 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002679 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002680 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002681 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002682 }
2683 LOGCHAR('}');
2684 last_isspace = 0;
2685 if (tmp->options & LOG_OPT_QUOTE)
2686 LOGCHAR('"');
2687 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002688 break;
2689
William Lallemand1d705562012-03-12 12:46:41 +01002690 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002691 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002692 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002693 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2694 if (hdr > 0)
2695 LOGCHAR(' ');
2696 if (tmp->options & LOG_OPT_QUOTE)
2697 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002698 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002699 ret = lf_encode_string(tmplog, dst + maxsize,
2700 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002701 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002702 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002703 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002704 } else if (!(tmp->options & LOG_OPT_QUOTE))
2705 LOGCHAR('-');
2706 if (tmp->options & LOG_OPT_QUOTE)
2707 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002708 last_isspace = 0;
2709 }
2710 }
2711 break;
2712
William Lallemand1d705562012-03-12 12:46:41 +01002713 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002714 /* Request */
2715 if (tmp->options & LOG_OPT_QUOTE)
2716 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002717 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002718 ret = lf_encode_string(tmplog, dst + maxsize,
2719 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002720 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002721 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002722 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002723 if (tmp->options & LOG_OPT_QUOTE)
2724 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002725 last_isspace = 0;
2726 break;
William Lallemand5f232402012-04-05 18:02:55 +02002727
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002728 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002729 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002730
Willy Tarreaub7636d12015-06-17 19:58:02 +02002731 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002732 LOGCHAR('"');
2733
2734 end = uri + strlen(uri);
2735 // look for the first whitespace character
2736 while (uri < end && !HTTP_IS_SPHT(*uri))
2737 uri++;
2738
2739 // keep advancing past multiple spaces
2740 while (uri < end && HTTP_IS_SPHT(*uri)) {
2741 uri++; nspaces++;
2742 }
2743
2744 // look for first space or question mark after url
2745 spc = uri;
2746 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2747 spc++;
2748
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002749 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002750 chunk.area = "<BADREQ>";
2751 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002752 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002753 chunk.area = uri;
2754 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002755 }
2756
Dragan Dosen835b9212016-02-12 13:23:03 +01002757 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002758 if (ret == NULL || *ret != '\0')
2759 goto out;
2760
2761 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002762 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002763 LOGCHAR('"');
2764
2765 last_isspace = 0;
2766 break;
2767
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002768 case LOG_FMT_HTTP_QUERY: // %HQ
2769 if (tmp->options & LOG_OPT_QUOTE)
2770 LOGCHAR('"');
2771
Willy Tarreau57bc8912016-04-25 17:09:40 +02002772 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002773 chunk.area = "<BADREQ>";
2774 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002775 } else {
2776 uri = txn->uri;
2777 end = uri + strlen(uri);
2778 // look for the first question mark
2779 while (uri < end && *uri != '?')
2780 uri++;
2781
2782 qmark = uri;
2783 // look for first space or question mark after url
2784 while (uri < end && !HTTP_IS_SPHT(*uri))
2785 uri++;
2786
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002787 chunk.area = qmark;
2788 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002789 }
2790
Dragan Dosen835b9212016-02-12 13:23:03 +01002791 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002792 if (ret == NULL || *ret != '\0')
2793 goto out;
2794
2795 tmplog = ret;
2796 if (tmp->options & LOG_OPT_QUOTE)
2797 LOGCHAR('"');
2798
2799 last_isspace = 0;
2800 break;
2801
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002802 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002803 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002804
Willy Tarreaub7636d12015-06-17 19:58:02 +02002805 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002806 LOGCHAR('"');
2807
2808 end = uri + strlen(uri);
2809 // look for the first whitespace character
2810 while (uri < end && !HTTP_IS_SPHT(*uri))
2811 uri++;
2812
2813 // keep advancing past multiple spaces
2814 while (uri < end && HTTP_IS_SPHT(*uri)) {
2815 uri++; nspaces++;
2816 }
2817
2818 // look for first space after url
2819 spc = uri;
2820 while (spc < end && !HTTP_IS_SPHT(*spc))
2821 spc++;
2822
Willy Tarreau57bc8912016-04-25 17:09:40 +02002823 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002824 chunk.area = "<BADREQ>";
2825 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002826 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002827 chunk.area = uri;
2828 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002829 }
2830
Dragan Dosen835b9212016-02-12 13:23:03 +01002831 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002832 if (ret == NULL || *ret != '\0')
2833 goto out;
2834
2835 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002836 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002837 LOGCHAR('"');
2838
2839 last_isspace = 0;
2840 break;
2841
2842 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002843 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002844 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002845 LOGCHAR('"');
2846
2847 end = uri + strlen(uri);
2848 // look for the first whitespace character
2849 spc = uri;
2850 while (spc < end && !HTTP_IS_SPHT(*spc))
2851 spc++;
2852
2853 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002854 chunk.area = "<BADREQ>";
2855 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002856 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002857 chunk.area = uri;
2858 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002859 }
2860
Dragan Dosen835b9212016-02-12 13:23:03 +01002861 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002862 if (ret == NULL || *ret != '\0')
2863 goto out;
2864
2865 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002866 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002867 LOGCHAR('"');
2868
2869 last_isspace = 0;
2870 break;
2871
2872 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002873 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002874 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002875 LOGCHAR('"');
2876
2877 end = uri + strlen(uri);
2878 // look for the first whitespace character
2879 while (uri < end && !HTTP_IS_SPHT(*uri))
2880 uri++;
2881
2882 // keep advancing past multiple spaces
2883 while (uri < end && HTTP_IS_SPHT(*uri)) {
2884 uri++; nspaces++;
2885 }
2886
2887 // look for the next whitespace character
2888 while (uri < end && !HTTP_IS_SPHT(*uri))
2889 uri++;
2890
2891 // keep advancing past multiple spaces
2892 while (uri < end && HTTP_IS_SPHT(*uri))
2893 uri++;
2894
Willy Tarreau57bc8912016-04-25 17:09:40 +02002895 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002896 chunk.area = "<BADREQ>";
2897 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002898 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002899 chunk.area = "HTTP/0.9";
2900 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002901 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002902 chunk.area = uri;
2903 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002904 }
2905
Dragan Dosen835b9212016-02-12 13:23:03 +01002906 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002907 if (ret == NULL || *ret != '\0')
2908 goto out;
2909
2910 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002911 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002912 LOGCHAR('"');
2913
2914 last_isspace = 0;
2915 break;
2916
William Lallemand5f232402012-04-05 18:02:55 +02002917 case LOG_FMT_COUNTER: // %rt
2918 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002919 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002920 if (iret < 0 || iret > dst + maxsize - tmplog)
2921 goto out;
2922 last_isspace = 0;
2923 tmplog += iret;
2924 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002925 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002926 if (ret == NULL)
2927 goto out;
2928 tmplog = ret;
2929 last_isspace = 0;
2930 }
2931 break;
2932
Willy Tarreau7346acb2014-08-28 15:03:15 +02002933 case LOG_FMT_LOGCNT: // %lc
2934 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002935 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002936 if (iret < 0 || iret > dst + maxsize - tmplog)
2937 goto out;
2938 last_isspace = 0;
2939 tmplog += iret;
2940 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002941 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002942 if (ret == NULL)
2943 goto out;
2944 tmplog = ret;
2945 last_isspace = 0;
2946 }
2947 break;
2948
William Lallemand5f232402012-04-05 18:02:55 +02002949 case LOG_FMT_HOSTNAME: // %H
2950 src = hostname;
2951 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2952 if (ret == NULL)
2953 goto out;
2954 tmplog = ret;
2955 last_isspace = 0;
2956 break;
2957
2958 case LOG_FMT_PID: // %pid
2959 if (tmp->options & LOG_OPT_HEXA) {
2960 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2961 if (iret < 0 || iret > dst + maxsize - tmplog)
2962 goto out;
2963 last_isspace = 0;
2964 tmplog += iret;
2965 } else {
2966 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2967 if (ret == NULL)
2968 goto out;
2969 tmplog = ret;
2970 last_isspace = 0;
2971 }
2972 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002973
2974 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002975 ret = NULL;
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002976 if (s)
2977 ret = lf_text_len(tmplog, s->unique_id.ptr, s->unique_id.len, maxsize - (tmplog - dst), tmp);
2978 else
2979 ret = lf_text_len(tmplog, NULL, 0, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002980 if (ret == NULL)
2981 goto out;
2982 tmplog = ret;
2983 last_isspace = 0;
2984 break;
2985
William Lallemandbddd4fd2012-02-27 11:23:10 +01002986 }
2987 }
2988
2989out:
William Lallemand1d705562012-03-12 12:46:41 +01002990 /* *tmplog is a unused character */
2991 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002992 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002993
Willy Tarreaubaaee002006-06-26 02:48:02 +02002994}
2995
William Lallemand1d705562012-03-12 12:46:41 +01002996/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002997 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002998 * Will not log if the frontend has no log defined.
2999 */
Willy Tarreau87b09662015-04-03 00:22:06 +02003000void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01003001{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003002 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01003003 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003004 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01003005
3006 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02003007 err = (s->flags & SF_REDISP) ||
3008 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
3009 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01003010 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02003011 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003012
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003013 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01003014 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003015
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003016 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01003017 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003018
Willy Tarreauabcd5142013-06-11 17:18:02 +02003019 if (s->logs.level) { /* loglevel was overridden */
3020 if (s->logs.level == -1) {
3021 s->logs.logwait = 0; /* logs disabled */
3022 return;
3023 }
3024 level = s->logs.level - 1;
3025 }
3026 else {
3027 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003028 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02003029 level = LOG_ERR;
3030 }
William Lallemand1d705562012-03-12 12:46:41 +01003031
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003032 /* if unique-id was not generated */
Tim Duesterhusa17e6622020-03-05 20:19:02 +01003033 if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Tim Duesterhus2825b4b2020-02-28 15:13:34 +01003034 stream_generate_unique_id(s, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003035 }
3036
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003037 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3038 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
3039 &sess->fe->logformat_sd);
3040 }
3041
Dragan Dosen59cee972015-09-19 22:09:02 +02003042 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01003043 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003044 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003045 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3046 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01003047 s->logs.logwait = 0;
3048 }
3049}
William Lallemandbddd4fd2012-02-27 11:23:10 +01003050
Willy Tarreau53839352018-09-05 19:51:10 +02003051/*
3052 * send a minimalist log for the session. Will not log if the frontend has no
3053 * log defined. It is assumed that this is only used to report anomalies that
3054 * cannot lead to the creation of a regular stream. Because of this the log
3055 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
3056 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003057 * function to report unimportant events. It is safe to call this function with
3058 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02003059 */
3060void sess_log(struct session *sess)
3061{
3062 int size, level;
3063 int sd_size = 0;
3064
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003065 if (!sess)
3066 return;
3067
Willy Tarreau53839352018-09-05 19:51:10 +02003068 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3069 return;
3070
3071 level = LOG_INFO;
3072 if (sess->fe->options2 & PR_O2_LOGERRORS)
3073 level = LOG_ERR;
3074
3075 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3076 sd_size = sess_build_logline(sess, NULL,
3077 logline_rfc5424, global.max_syslog_len,
3078 &sess->fe->logformat_sd);
3079 }
3080
3081 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3082 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003083 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003084 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3085 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003086 }
3087}
3088
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003089void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3090{
3091 va_list argp;
3092 int data_len;
3093
3094 if (level < 0 || format == NULL || logline == NULL)
3095 return;
3096
3097 va_start(argp, format);
3098 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3099 if (data_len < 0 || data_len > global.max_syslog_len)
3100 data_len = global.max_syslog_len;
3101 va_end(argp);
3102
3103 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3104}
3105
Willy Tarreau869efd52019-11-15 15:16:57 +01003106/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3107static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003108{
Willy Tarreau869efd52019-11-15 15:16:57 +01003109 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3110 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003111
Willy Tarreau869efd52019-11-15 15:16:57 +01003112 if (!startup_logs)
3113 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3114
3115 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003116}
3117
3118/* register cli keywords */
3119static struct cli_kw_list cli_kws = {{ },{
3120 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003121 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003122 {{},}
3123}};
3124
Willy Tarreau0108d902018-11-25 19:14:37 +01003125INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3126
Willy Tarreau082b6282019-05-22 14:42:12 +02003127REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3128REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003129
Willy Tarreaubaaee002006-06-26 02:48:02 +02003130/*
3131 * Local variables:
3132 * c-indent-level: 8
3133 * c-basic-offset: 8
3134 * End:
3135 */