blob: b4b00cfa14bd7b6c60097f4a355b66c112c0f0ae [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";
Christopher Faulet3b967c12020-05-15 15:47:44 +0200313 case ARGC_HERR:
314 return "http-error";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100315 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200316 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100317 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200318}
319
William Lallemand723b73a2012-02-08 16:37:49 +0100320/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100321 * callback used to configure addr source retrieval
322 */
323int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
324{
325 curproxy->options2 |= PR_O2_SRC_ADDR;
326
327 return 0;
328}
329
330
331/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100332 * Parse args in a logformat_var. Returns 0 in error
333 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100334 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100335int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100336{
337 int i = 0;
338 int end = 0;
339 int flags = 0; // 1 = + 2 = -
340 char *sp = NULL; // start pointer
341
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100342 if (args == NULL) {
343 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100344 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100345 }
William Lallemand723b73a2012-02-08 16:37:49 +0100346
347 while (1) {
348 if (*args == '\0')
349 end = 1;
350
351 if (*args == '+') {
352 // add flag
353 sp = args + 1;
354 flags = 1;
355 }
356 if (*args == '-') {
357 // delete flag
358 sp = args + 1;
359 flags = 2;
360 }
361
362 if (*args == '\0' || *args == ',') {
363 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100364 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100365 if (strcmp(sp, var_args_list[i].name) == 0) {
366 if (flags == 1) {
367 node->options |= var_args_list[i].mask;
368 break;
369 } else if (flags == 2) {
370 node->options &= ~var_args_list[i].mask;
371 break;
372 }
373 }
374 }
375 sp = NULL;
376 if (end)
377 break;
378 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100379 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100380 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100381 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100382}
383
384/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100385 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
386 * must pass the args part in the <arg> pointer with its length in <arg_len>,
387 * and varname with its length in <var> and <var_len> respectively. <arg> is
388 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100389 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100390 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100391int 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 +0100392{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100393 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200394 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100395
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100396 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
397 if (strlen(logformat_keywords[j].name) == var_len &&
398 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
399 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200400 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100401 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100402 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200403 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100404 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100405 node->type = logformat_keywords[j].type;
406 node->options = *defoptions;
407 if (arg_len) {
408 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100409 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200410 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100411 }
412 if (node->type == LOG_FMT_GLOBAL) {
413 *defoptions = node->options;
414 free(node->arg);
415 free(node);
416 } else {
417 if (logformat_keywords[j].config_callback &&
418 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200419 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100420 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100421 curproxy->to_log |= logformat_keywords[j].lw;
422 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100423 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100424 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100425 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
426 curproxy->conf.args.file, curproxy->conf.args.line,
427 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100428 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100429 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100430 memprintf(err, "format variable '%s' is reserved for HTTP mode",
431 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200432 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100433 }
William Lallemand723b73a2012-02-08 16:37:49 +0100434 }
435 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100436
437 j = var[var_len];
438 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100439 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 +0100440 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200441
442 error_free:
443 if (node) {
444 free(node->arg);
445 free(node);
446 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100447 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100448}
449
450/*
451 * push to the logformat linked list
452 *
453 * start: start pointer
454 * end: end text pointer
455 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100456 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100457 *
458 * LOG_TEXT: copy chars from start to end excluding end.
459 *
460*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100461int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100462{
463 char *str;
464
Willy Tarreaua3571662012-12-20 21:59:12 +0100465 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200466 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100467 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100468 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100469 return 0;
470 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200471 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100472 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100473 str[end - start] = '\0';
474 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100475 node->type = LOG_FMT_TEXT; // type string
476 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100477 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200478 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100479 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100480 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100481 return 0;
482 }
William Lallemand1d705562012-03-12 12:46:41 +0100483 node->type = LOG_FMT_SEPARATOR;
484 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100485 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100486 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100487}
488
489/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100490 * Parse the sample fetch expression <text> and add a node to <list_format> upon
491 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100492 * should work. The curpx->conf.args.ctx must be set by the caller. If an end pointer
493 * is passed in <endptr>, it will be updated with the pointer to the first character
494 * not part of the sample expression.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100495 *
496 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100497 */
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100498int 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 +0100499{
500 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200501 struct sample_expr *expr = NULL;
502 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100503 int cmd_arg;
504
505 cmd[0] = text;
506 cmd[1] = "";
507 cmd_arg = 0;
508
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100509 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 +0100510 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100511 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200512 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100513 }
514
Vincent Bernat02779b62016-04-03 13:48:43 +0200515 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100516 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100517 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200518 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100519 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100520 node->type = LOG_FMT_EXPR;
521 node->expr = expr;
522 node->options = options;
523
524 if (arg_len) {
525 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100526 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200527 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100528 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100529 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100530 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
531
Willy Tarreau434c57c2013-01-08 01:10:24 +0100532 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100533 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
534
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100535 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100536 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
537 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200538 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100539 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100540
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200541 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100542 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100543 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100544
William Lallemand65ad6e12014-01-31 15:08:02 +0100545 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
546 * needed with some sample fetches (eg: ssl*). We always set it for
547 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100548 */
549 curpx->to_log |= LW_XPRT;
Christopher Fauletd2236cd2020-04-06 18:29:14 +0200550 if (curpx->http_needed)
551 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100552 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100553 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200554
555 error_free:
556 release_sample_expr(expr);
557 if (node) {
558 free(node->arg);
559 free(node);
560 }
561 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100562}
563
564/*
William Lallemand723b73a2012-02-08 16:37:49 +0100565 * Parse the log_format string and fill a linked list.
566 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200567 * You can set arguments using { } : %{many arguments}varname.
568 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100569 *
Ilya Shipitsinae40dbc2020-04-04 12:59:53 +0500570 * fmt: the string to parse
William Lallemand1d705562012-03-12 12:46:41 +0100571 * curproxy: the proxy affected
572 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100573 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100574 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100575 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100576 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100577 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100578int 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 +0100579{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100580 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100581 char *arg = NULL; /* start pointer for args */
582 char *var = NULL; /* start pointer for vars */
583 int arg_len = 0;
584 int var_len = 0;
585 int cformat; /* current token format */
586 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100587 struct logformat_node *tmplf, *back;
588
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100589 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100590 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100591 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100592 return 0;
593 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200594 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200595
William Lallemand723b73a2012-02-08 16:37:49 +0100596 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100597 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100598 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200599 release_sample_expr(tmplf->expr);
600 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100601 free(tmplf);
602 }
603
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100604 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100605 pformat = cformat;
606
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100607 if (!*str)
608 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100609
Joseph Herlant85b40592018-11-15 12:10:04 -0800610 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100611 * second have all common paths processed at one place. The common paths are the ones
612 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
613 * We use the common LF_INIT state to dispatch to the different final states.
614 */
615 switch (pformat) {
616 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100617 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100618 arg_len = var_len = 0;
619 if (*str == '{') { // optional argument
620 cformat = LF_STARG;
621 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100622 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100623 else if (*str == '[') {
624 cformat = LF_STEXPR;
625 var = str + 1; // store expr in variable name
626 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100627 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100628 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100629 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100630 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100631 else if (*str == '%')
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500632 cformat = LF_TEXT; // convert this character to a literal (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100633 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100634 /* single '%' followed by blank or digit, send them both */
635 cformat = LF_TEXT;
636 pformat = LF_TEXT; /* finally we include the previous char as well */
637 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600638 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 +0100639 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100640 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100641
642 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100643 else
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500644 cformat = LF_INIT; // handle other cases of literals
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100645 break;
646
647 case LF_STARG: // text immediately following '%{'
648 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100649 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100650 arg_len = str - arg;
651 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100652 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100653 break;
654
655 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100656 if (*str == '[') {
657 cformat = LF_STEXPR;
658 var = str + 1; // store expr in variable name
659 break;
660 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100661 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100662 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100663 var = str;
664 break;
665 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100666 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100667 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100668
Willy Tarreauc8368452012-12-21 00:09:23 +0100669 case LF_STEXPR: // text immediately following '%['
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100670 /* the whole sample expression is parsed at once,
671 * returning the pointer to the first character not
672 * part of the expression, which MUST be the trailing
673 * angle bracket.
674 */
675 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str))
676 goto fail;
677
678 if (*str == ']') {
679 // end of arg, go on with next state
680 cformat = pformat = LF_EDEXPR;
681 sp = str;
682 }
683 else {
684 char c = *str;
685 *str = 0;
Willy Tarreau90807112020-02-25 08:16:33 +0100686 if (isprint((unsigned char)c))
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100687 memprintf(err, "expected ']' after '%s', but found '%c'", var, c);
688 else
689 memprintf(err, "missing ']' after '%s'", var);
Willy Tarreauc8368452012-12-21 00:09:23 +0100690 }
691 break;
692
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100693 case LF_VAR: // text part of a variable name
694 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100695 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100696 cformat = LF_INIT; // not variable name anymore
697 break;
698
Willy Tarreauc8368452012-12-21 00:09:23 +0100699 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100700 cformat = LF_INIT;
701 }
702
703 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
704 switch (*str) {
705 case '%': cformat = LF_STARTVAR; break;
706 case ' ': cformat = LF_SEPARATOR; break;
707 case 0 : cformat = LF_END; break;
708 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100709 }
710 }
711
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100712 if (cformat != pformat || pformat == LF_SEPARATOR) {
713 switch (pformat) {
714 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100715 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100716 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100717 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100718 case LF_STEXPR:
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100719 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &sp))
Willy Tarreau51013e82019-12-11 12:05:39 +0100720 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100721 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100722 case LF_TEXT:
723 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100724 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100725 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100726 break;
727 }
728 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100729 }
730 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100731
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100732 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100733 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100734 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100735 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100736 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100737
738 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100739 fail:
740 free(backfmt);
741 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100742}
743
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200744/*
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500745 * 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 +0200746 * ranges of indexes. Note that an index may be considered as a particular range
747 * with a high limit to the low limit.
748 */
749int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
750{
751 char *end, *p;
752
753 *low = *high = 0;
754
755 p = *arg;
756 end = strchr(p, ',');
757 if (!end)
758 end = p + strlen(p);
759
760 *high = *low = read_uint((const char **)&p, end);
761 if (!*low || (p != end && *p != '-'))
762 goto err;
763
764 if (p == end)
765 goto done;
766
767 p++;
768 *high = read_uint((const char **)&p, end);
769 if (!*high || *high <= *low || p != end)
770 goto err;
771
772 done:
773 if (*end == ',')
774 end++;
775 *arg = end;
776 return 1;
777
778 err:
779 memprintf(err, "wrong sample range '%s'", *arg);
780 return 0;
781}
782
783/*
784 * Returns 1 if the range defined by <low> and <high> overlaps
785 * one of them in <rgs> array of ranges with <sz> the size of this
786 * array, 0 if not.
787 */
788int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
789 unsigned int low, unsigned int high, char **err)
790{
791 size_t i;
792
793 for (i = 0; i < sz; i++) {
794 if ((low >= rgs[i].low && low <= rgs[i].high) ||
795 (high >= rgs[i].low && high <= rgs[i].high)) {
796 memprintf(err, "ranges are overlapping");
797 return 1;
798 }
799 }
800
801 return 0;
802}
803
804int smp_log_range_cmp(const void *a, const void *b)
805{
806 const struct smp_log_range *rg_a = a;
807 const struct smp_log_range *rg_b = b;
808
809 if (rg_a->high < rg_b->low)
810 return -1;
811 else if (rg_a->low > rg_b->high)
812 return 1;
813
814 return 0;
815}
816
817/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200818 * Parse "log" keyword and update <logsrvs> list accordingly.
819 *
820 * When <do_del> is set, it means the "no log" line was parsed, so all log
821 * servers in <logsrvs> are released.
822 *
823 * Otherwise, we try to parse the "log" line. First of all, when the list is not
824 * the global one, we look for the parameter "global". If we find it,
825 * global.logsrvs is copied. Else we parse each arguments.
826 *
827 * The function returns 1 in success case, otherwise, it returns 0 and err is
828 * filled.
829 */
830int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
831{
832 struct sockaddr_storage *sk;
833 struct logsrv *logsrv = NULL;
834 int port1, port2;
835 int cur_arg;
836
837 /*
838 * "no log": delete previous herited or defined syslog
839 * servers.
840 */
841 if (do_del) {
842 struct logsrv *back;
843
844 if (*(args[1]) != 0) {
845 memprintf(err, "'no log' does not expect arguments");
846 goto error;
847 }
848
849 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
850 LIST_DEL(&logsrv->list);
851 free(logsrv);
852 }
853 return 1;
854 }
855
856 /*
857 * "log global": copy global.logrsvs linked list to the end of logsrvs
858 * list. But first, we check (logsrvs != global.logsrvs).
859 */
860 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
861 if (logsrvs == &global.logsrvs) {
862 memprintf(err, "'global' is not supported for a global syslog server");
863 goto error;
864 }
865 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200866 struct logsrv *node;
867
868 list_for_each_entry(node, logsrvs, list) {
869 if (node->ref == logsrv)
870 goto skip_logsrv;
871 }
872
873 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200874 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200875 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200876 LIST_INIT(&node->list);
877 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200878
879 skip_logsrv:
880 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200881 }
882 return 1;
883 }
884
885 /*
886 * "log <address> ...: parse a syslog server line
887 */
888 if (*(args[1]) == 0 || *(args[2]) == 0) {
889 memprintf(err, "expects <address> and <facility> %s as arguments",
890 ((logsrvs == &global.logsrvs) ? "" : "or global"));
891 goto error;
892 }
893
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100894 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
895 if (strcmp(args[1], "stdout") == 0)
896 args[1] = "fd@1";
897 else if (strcmp(args[1], "stderr") == 0)
898 args[1] = "fd@2";
899
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200900 logsrv = calloc(1, sizeof(*logsrv));
901 if (!logsrv) {
902 memprintf(err, "out of memory");
903 goto error;
904 }
905
906 /* skip address for now, it will be parsed at the end */
907 cur_arg = 2;
908
909 /* just after the address, a length may be specified */
910 logsrv->maxlen = MAX_SYSLOG_LEN;
911 if (strcmp(args[cur_arg], "len") == 0) {
912 int len = atoi(args[cur_arg+1]);
913 if (len < 80 || len > 65535) {
914 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
915 args[cur_arg+1]);
916 goto error;
917 }
918 logsrv->maxlen = len;
919 cur_arg += 2;
920 }
921 if (logsrv->maxlen > global.max_syslog_len)
922 global.max_syslog_len = logsrv->maxlen;
923
924 /* after the length, a format may be specified */
925 if (strcmp(args[cur_arg], "format") == 0) {
926 logsrv->format = get_log_format(args[cur_arg+1]);
927 if (logsrv->format < 0) {
928 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
929 goto error;
930 }
931 cur_arg += 2;
932 }
933
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200934 if (strcmp(args[cur_arg], "sample") == 0) {
935 unsigned low, high;
936 char *p, *beg, *end, *smp_sz_str;
937 struct smp_log_range *smp_rgs = NULL;
938 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
939
940 p = args[cur_arg+1];
941 smp_sz_str = strchr(p, ':');
942 if (!smp_sz_str) {
943 memprintf(err, "Missing sample size");
944 goto error;
945 }
946
947 *smp_sz_str++ = '\0';
948
949 end = p + strlen(p);
950
951 while (p != end) {
952 if (!get_logsrv_smp_range(&low, &high, &p, err))
953 goto error;
954
955 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
956 goto error;
957
958 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
959 if (!smp_rgs) {
960 memprintf(err, "out of memory error");
961 goto error;
962 }
963
964 smp_rgs[smp_rgs_sz].low = low;
965 smp_rgs[smp_rgs_sz].high = high;
966 smp_rgs[smp_rgs_sz].sz = high - low + 1;
967 smp_rgs[smp_rgs_sz].curr_idx = 0;
968 if (smp_rgs[smp_rgs_sz].high > smp_sz)
969 smp_sz = smp_rgs[smp_rgs_sz].high;
970 smp_rgs_sz++;
971 }
972
Tim Duesterhus21648002019-06-23 22:10:10 +0200973 if (smp_rgs == NULL) {
974 memprintf(err, "no sampling ranges given");
975 goto error;
976 }
977
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200978 beg = smp_sz_str;
979 end = beg + strlen(beg);
980 new_smp_sz = read_uint((const char **)&beg, end);
981 if (!new_smp_sz || beg != end) {
982 memprintf(err, "wrong sample size '%s' for sample range '%s'",
983 smp_sz_str, args[cur_arg+1]);
984 goto error;
985 }
986
987 if (new_smp_sz < smp_sz) {
988 memprintf(err, "sample size %zu should be greater or equal to "
989 "%zu the maximum of the high ranges limits",
990 new_smp_sz, smp_sz);
991 goto error;
992 }
993 smp_sz = new_smp_sz;
994
995 /* Let's order <smp_rgs> array. */
996 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
997
998 logsrv->lb.smp_rgs = smp_rgs;
999 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
1000 logsrv->lb.smp_sz = smp_sz;
1001
1002 cur_arg += 2;
1003 }
Frédéric Lécailled803e472019-04-25 07:42:09 +02001004 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001005 /* parse the facility */
1006 logsrv->facility = get_log_facility(args[cur_arg]);
1007 if (logsrv->facility < 0) {
1008 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
1009 goto error;
1010 }
1011 cur_arg++;
1012
1013 /* parse the max syslog level (default: debug) */
1014 logsrv->level = 7;
1015 if (*(args[cur_arg])) {
1016 logsrv->level = get_log_level(args[cur_arg]);
1017 if (logsrv->level < 0) {
1018 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
1019 goto error;
1020 }
1021 cur_arg++;
1022 }
1023
1024 /* parse the limit syslog level (default: emerg) */
1025 logsrv->minlvl = 0;
1026 if (*(args[cur_arg])) {
1027 logsrv->minlvl = get_log_level(args[cur_arg]);
1028 if (logsrv->minlvl < 0) {
1029 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
1030 goto error;
1031 }
1032 cur_arg++;
1033 }
1034
1035 /* Too many args */
1036 if (*(args[cur_arg])) {
1037 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1038 goto error;
1039 }
1040
1041 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001042 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001043 if (strncmp(args[1], "ring@", 5) == 0) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001044 logsrv->addr.ss_family = AF_UNSPEC;
1045 logsrv->type = LOG_TARGET_BUFFER;
Emeric Brun99c453d2020-05-25 15:01:04 +02001046 logsrv->sink = NULL;
1047 logsrv->ring_name = strdup(args[1] + 5);
Willy Tarreauc046d162019-08-30 15:24:59 +02001048 goto done;
1049 }
1050
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001051 if (strncmp(args[1], "fd@", 3) == 0)
1052 logsrv->type = LOG_TARGET_FD;
1053
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001054 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1055 if (!sk)
1056 goto error;
1057 logsrv->addr = *sk;
1058
1059 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1060 if (port1 != port2) {
1061 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1062 goto error;
1063 }
1064 logsrv->addr = *sk;
1065 if (!port1)
1066 set_host_port(&logsrv->addr, SYSLOG_PORT);
1067 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001068 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001069 LIST_ADDQ(logsrvs, &logsrv->list);
1070 return 1;
1071
1072 error:
1073 free(logsrv);
1074 return 0;
1075}
1076
1077
Christopher Fauletd4696382017-10-24 11:44:05 +02001078/* Generic function to display messages prefixed by a label */
1079static void print_message(const char *label, const char *fmt, va_list argp)
1080{
1081 struct tm tm;
1082 char *head, *msg;
1083
1084 head = msg = NULL;
1085
1086 get_localtime(date.tv_sec, &tm);
1087 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1088 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1089 memvprintf(&msg, fmt, argp);
1090
Willy Tarreau869efd52019-11-15 15:16:57 +01001091 if (global.mode & MODE_STARTING) {
1092 if (unlikely(!startup_logs))
1093 startup_logs = ring_new(STARTUP_LOG_SIZE);
1094
1095 if (likely(startup_logs)) {
1096 struct ist m[2];
1097
1098 m[0] = ist(head);
1099 m[1] = ist(msg);
1100 /* trim the trailing '\n' */
1101 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1102 m[1].len--;
1103 ring_write(startup_logs, ~0, 0, 0, m, 2);
1104 }
1105 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001106
1107 fprintf(stderr, "%s%s", head, msg);
1108 fflush(stderr);
1109
1110 free(head);
1111 free(msg);
1112}
1113
Willy Tarreaubaaee002006-06-26 02:48:02 +02001114/*
1115 * Displays the message on stderr with the date and pid. Overrides the quiet
1116 * mode during startup.
1117 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001118void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001119{
1120 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001121
1122 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Willy Tarreaubb869862020-04-16 10:52:41 +02001123 if (!(warned & WARN_EXEC_PATH)) {
1124 const char *path = get_exec_path();
1125
1126 warned |= WARN_EXEC_PATH;
1127 ha_notice("haproxy version is %s\n", haproxy_version);
1128 if (path)
1129 ha_notice("path to executable is %s\n", path);
1130 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001131 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001132 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001133 va_end(argp);
1134 }
1135}
1136
1137
1138/*
1139 * Displays the message on stderr with the date and pid.
1140 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001141void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001142{
1143 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001144
Willy Tarreaubebd2122020-04-15 16:06:11 +02001145 warned |= WARN_ANY;
1146
Willy Tarreaubaaee002006-06-26 02:48:02 +02001147 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1148 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001149 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001150 va_end(argp);
1151 }
1152}
1153
1154/*
William Lallemand9c56a222018-11-21 18:04:52 +01001155 * Displays the message on stderr with the date and pid.
1156 */
1157void ha_notice(const char *fmt, ...)
1158{
1159 va_list argp;
1160
1161 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1162 va_start(argp, fmt);
1163 print_message("NOTICE", fmt, argp);
1164 va_end(argp);
1165 }
1166}
1167
1168/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001169 * Displays the message on <out> only if quiet mode is not set.
1170 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001171void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001172{
1173 va_list argp;
1174
1175 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1176 va_start(argp, fmt);
1177 vfprintf(out, fmt, argp);
1178 fflush(out);
1179 va_end(argp);
1180 }
1181}
1182
1183/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001184 * returns log format for <fmt> or -1 if not found.
1185 */
1186int get_log_format(const char *fmt)
1187{
1188 int format;
1189
1190 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001191 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001192 format--;
1193
1194 return format;
1195}
1196
1197/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001198 * returns log level for <lev> or -1 if not found.
1199 */
1200int get_log_level(const char *lev)
1201{
1202 int level;
1203
1204 level = NB_LOG_LEVELS - 1;
1205 while (level >= 0 && strcmp(log_levels[level], lev))
1206 level--;
1207
1208 return level;
1209}
1210
Willy Tarreaubaaee002006-06-26 02:48:02 +02001211/*
1212 * returns log facility for <fac> or -1 if not found.
1213 */
1214int get_log_facility(const char *fac)
1215{
1216 int facility;
1217
1218 facility = NB_LOG_FACILITIES - 1;
1219 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1220 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001221
Willy Tarreaubaaee002006-06-26 02:48:02 +02001222 return facility;
1223}
1224
William Lallemanda1cc3812012-02-08 16:38:44 +01001225/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001226 * Encode the string.
1227 *
1228 * When using the +E log format option, it will try to escape '"\]'
1229 * characters with '\' as prefix. The same prefix should not be used as
1230 * <escape>.
1231 */
1232static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001233 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001234 const char *string,
1235 struct logformat_node *node)
1236{
1237 if (node->options & LOG_OPT_ESC) {
1238 if (start < stop) {
1239 stop--; /* reserve one byte for the final '\0' */
1240 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001241 if (!ha_bit_test((unsigned char)(*string), map)) {
1242 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001243 *start++ = *string;
1244 else {
1245 if (start + 2 >= stop)
1246 break;
1247 *start++ = '\\';
1248 *start++ = *string;
1249 }
1250 }
1251 else {
1252 if (start + 3 >= stop)
1253 break;
1254 *start++ = escape;
1255 *start++ = hextab[(*string >> 4) & 15];
1256 *start++ = hextab[*string & 15];
1257 }
1258 string++;
1259 }
1260 *start = '\0';
1261 }
1262 }
1263 else {
1264 return encode_string(start, stop, escape, map, string);
1265 }
1266
1267 return start;
1268}
1269
1270/*
1271 * Encode the chunk.
1272 *
1273 * When using the +E log format option, it will try to escape '"\]'
1274 * characters with '\' as prefix. The same prefix should not be used as
1275 * <escape>.
1276 */
1277static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001278 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001279 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001280 struct logformat_node *node)
1281{
1282 char *str, *end;
1283
1284 if (node->options & LOG_OPT_ESC) {
1285 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001286 str = chunk->area;
1287 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001288
1289 stop--; /* reserve one byte for the final '\0' */
1290 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001291 if (!ha_bit_test((unsigned char)(*str), map)) {
1292 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001293 *start++ = *str;
1294 else {
1295 if (start + 2 >= stop)
1296 break;
1297 *start++ = '\\';
1298 *start++ = *str;
1299 }
1300 }
1301 else {
1302 if (start + 3 >= stop)
1303 break;
1304 *start++ = escape;
1305 *start++ = hextab[(*str >> 4) & 15];
1306 *start++ = hextab[*str & 15];
1307 }
1308 str++;
1309 }
1310 *start = '\0';
1311 }
1312 }
1313 else {
1314 return encode_chunk(start, stop, escape, map, chunk);
1315 }
1316
1317 return start;
1318}
1319
1320/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001321 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001322 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001323 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001324 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001325 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001326char *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 +01001327{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001328 if (size < 2)
1329 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001330
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001331 if (node->options & LOG_OPT_QUOTE) {
1332 *(dst++) = '"';
1333 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001334 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001335
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001336 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001337 if (++len > size)
1338 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001339 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001340 char *ret;
1341
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001342 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001343 if (ret == NULL || *ret != '\0')
1344 return NULL;
1345 len = ret - dst;
1346 }
1347 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001348 len = strlcpy2(dst, src, len);
1349 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001350
1351 size -= len;
1352 dst += len;
1353 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001354 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1355 if (size < 2)
1356 return NULL;
1357 *(dst++) = '-';
1358 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001359
1360 if (node->options & LOG_OPT_QUOTE) {
1361 if (size < 2)
1362 return NULL;
1363 *(dst++) = '"';
1364 }
1365
1366 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001367 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001368}
1369
Willy Tarreau26ffa852018-09-05 15:23:10 +02001370static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001371{
1372 return lf_text_len(dst, src, size, size, node);
1373}
1374
William Lallemand5f232402012-04-05 18:02:55 +02001375/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001376 * Write a IP address to the log string
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001377 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001378 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001379char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001380{
1381 char *ret = dst;
1382 int iret;
1383 char pn[INET6_ADDRSTRLEN];
1384
1385 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001386 unsigned char *addr = NULL;
1387 switch (sockaddr->sa_family) {
1388 case AF_INET:
1389 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1390 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1391 break;
1392 case AF_INET6:
1393 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1394 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1395 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1396 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1397 break;
1398 default:
1399 return NULL;
1400 }
William Lallemand5f232402012-04-05 18:02:55 +02001401 if (iret < 0 || iret > size)
1402 return NULL;
1403 ret += iret;
1404 } else {
1405 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1406 ret = lf_text(dst, pn, size, node);
1407 if (ret == NULL)
1408 return NULL;
1409 }
1410 return ret;
1411}
1412
1413/*
1414 * Write a port to the log
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001415 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001416 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001417char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001418{
1419 char *ret = dst;
1420 int iret;
1421
1422 if (node->options & LOG_OPT_HEXA) {
1423 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1424 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1425 if (iret < 0 || iret > size)
1426 return NULL;
1427 ret += iret;
1428 } else {
1429 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1430 if (ret == NULL)
1431 return NULL;
1432 }
1433 return ret;
1434}
1435
Dragan Dosen1322d092015-09-22 16:05:32 +02001436/* Re-generate time-based part of the syslog header in RFC3164 format at
1437 * the beginning of logheader once a second and return the pointer to the
1438 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001439 */
Emeric Brunbd163812020-05-06 14:33:46 +02001440char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001441{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001442 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001443 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001444 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001445
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001446 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001447 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001448 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001449 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001450
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001451 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001452 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001453
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001454 if (unlikely(global.log_send_hostname != host.area)) {
1455 host.area = global.log_send_hostname;
1456 host.data = host.area ? strlen(host.area) : 0;
1457 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001458 }
1459
Dragan Dosen59cee972015-09-19 22:09:02 +02001460 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001461 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001462 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001463 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001464 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001465 /* WARNING: depending upon implementations, snprintf may return
1466 * either -1 or the number of bytes that would be needed to store
1467 * the total message. In both cases, we must adjust it.
1468 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001469 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1470 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001471
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001472 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001473 }
1474
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001475 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001476
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001477 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001478}
1479
Dragan Dosen1322d092015-09-22 16:05:32 +02001480/* Re-generate time-based part of the syslog header in RFC5424 format at
1481 * the beginning of logheader_rfc5424 once a second and return the pointer
1482 * to the first character after it.
1483 */
Emeric Brunbd163812020-05-06 14:33:46 +02001484char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001485{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001486 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001487 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001488
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001489 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001490 /* this string is rebuild only once a second */
1491 struct tm tm;
1492 int hdr_len;
1493
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001494 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001495 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001496 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001497
1498 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001499 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001500 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001501 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001502 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001503 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001504 /* WARNING: depending upon implementations, snprintf may return
1505 * either -1 or the number of bytes that would be needed to store
1506 * the total message. In both cases, we must adjust it.
1507 */
1508 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1509 hdr_len = global.max_syslog_len;
1510
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001511 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001512 }
1513
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001514 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001515
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001516 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001517}
1518
William Lallemand2a4a44f2012-02-06 16:00:33 +01001519/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001520 * This function sends the syslog message using a printf format string. It
1521 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001522 */
1523void send_log(struct proxy *p, int level, const char *format, ...)
1524{
1525 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001526 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001527
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001528 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001529 return;
1530
William Lallemand2a4a44f2012-02-06 16:00:33 +01001531 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001532 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001533 if (data_len < 0 || data_len > global.max_syslog_len)
1534 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001535 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001536
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001537 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1538 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001539}
1540
1541/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001542 * This function sends a syslog message to <logsrv>.
1543 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1544 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1545 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001546 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001547 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001548 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001549static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1550 int level, char *message, size_t size, char *sd, size_t sd_size,
1551 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001552{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001553 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1554 static THREAD_LOCAL struct msghdr msghdr = {
1555 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001556 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1557 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001558 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1559 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1560 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001561 time_t time = date.tv_sec;
Emeric Brune709e1e2020-05-06 17:23:59 +02001562 char *hdr, *hdr_ptr = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +02001563 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001564 int fac_level;
1565 int *plogfd;
1566 char *pid_sep1 = "", *pid_sep2 = "";
1567 char logheader_short[3];
1568 int sent;
1569 int maxlen;
1570 int hdr_max = 0;
1571 int tag_max = 0;
1572 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001573 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001574 int pid_sep2_max = 0;
1575 int sd_max = 0;
1576 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001577
1578 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001579
1580 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001581
Emeric Brunfa9d7802020-05-28 14:21:33 +02001582 /* historically some messages used to already contain the trailing LF
1583 * or Zero. Let's remove all trailing LF or Zero
1584 */
1585 while (size && ((dataptr[size-1] == '\n' || (dataptr[size-1] == 0))))
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001586 size--;
1587
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001588 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001589 /* the socket's address is a file descriptor */
1590 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001591 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001592 else if (logsrv->type == LOG_TARGET_BUFFER) {
1593 plogfd = NULL;
Emeric Brune709e1e2020-05-06 17:23:59 +02001594 goto send;
Willy Tarreauc046d162019-08-30 15:24:59 +02001595 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001596 else if (logsrv->addr.ss_family == AF_UNIX)
1597 plogfd = &logfdunix;
1598 else
1599 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001600
Willy Tarreauc046d162019-08-30 15:24:59 +02001601 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001602 /* socket not successfully initialized yet */
1603 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1604 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1605 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001606
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001607 if (!once) {
1608 once = 1; /* note: no need for atomic ops here */
1609 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1610 nblogger, strerror(errno), errno);
1611 }
1612 return;
1613 } else {
1614 /* we don't want to receive anything on this socket */
1615 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1616 /* does nothing under Linux, maybe needed for others */
1617 shutdown(*plogfd, SHUT_RD);
1618 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1619 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001620 }
1621
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001622 switch (logsrv->format) {
1623 case LOG_FORMAT_RFC3164:
1624 hdr = logheader;
1625 hdr_ptr = update_log_hdr(time);
1626 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001627
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001628 case LOG_FORMAT_RFC5424:
1629 hdr = logheader_rfc5424;
1630 hdr_ptr = update_log_hdr_rfc5424(time);
1631 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1632 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001633
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001634 case LOG_FORMAT_SHORT:
1635 /* all fields are known, skip the header generation */
1636 hdr = logheader_short;
1637 hdr[0] = '<';
1638 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1639 hdr[2] = '>';
1640 hdr_ptr = hdr;
1641 hdr_max = 3;
1642 maxlen = logsrv->maxlen - hdr_max;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001643 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001644 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001645
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001646 case LOG_FORMAT_RAW:
1647 /* all fields are known, skip the header generation */
1648 hdr_ptr = hdr = "";
1649 hdr_max = 0;
1650 maxlen = logsrv->maxlen;
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001651 max = MIN(size, maxlen - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001652 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001653
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001654 default:
1655 return; /* must never happen */
1656 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001657
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001658 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001659
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001660 /* For each target, we may have a different facility.
1661 * We can also have a different log level for each message.
1662 * This induces variations in the message header length.
1663 * Since we don't want to recompute it each time, nor copy it every
1664 * time, we only change the facility in the pre-computed header,
1665 * and we change the pointer to the header accordingly.
1666 */
1667 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1668 hdr_ptr = hdr + 3; /* last digit of the log level */
1669 do {
1670 *hdr_ptr = '0' + fac_level % 10;
1671 fac_level /= 10;
1672 hdr_ptr--;
1673 } while (fac_level && hdr_ptr > hdr);
1674 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001675
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001676 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001677
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001678 /* time-based header */
1679 if (unlikely(hdr_size >= logsrv->maxlen)) {
1680 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1681 sd_max = 0;
1682 goto send;
1683 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001684
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001685 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001686
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001687 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001688 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001689 if (unlikely(tag_max >= maxlen)) {
1690 tag_max = maxlen - 1;
1691 sd_max = 0;
1692 goto send;
1693 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001694
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001695 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001696
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001697 /* first pid separator */
1698 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1699 if (unlikely(pid_sep1_max >= maxlen)) {
1700 pid_sep1_max = maxlen - 1;
1701 sd_max = 0;
1702 goto send;
1703 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001704
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001705 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1706 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001707
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001708 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001709 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001710 if (unlikely(pid_size >= maxlen)) {
1711 pid_size = maxlen - 1;
1712 sd_max = 0;
1713 goto send;
1714 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001715
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001716 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001717
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001718 /* second pid separator */
1719 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1720 if (unlikely(pid_sep2_max >= maxlen)) {
1721 pid_sep2_max = maxlen - 1;
1722 sd_max = 0;
1723 goto send;
1724 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001725
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001726 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1727 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001728
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001729 /* structured-data */
1730 if (sd_max >= maxlen) {
1731 sd_max = maxlen - 1;
1732 goto send;
1733 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001734
Emeric Brun9e8ea0a2020-05-12 19:33:15 +02001735 max = MIN(size, maxlen - sd_max - 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001736send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001737 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001738 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001739 struct ist msg[7];
1740
Emeric Brune709e1e2020-05-06 17:23:59 +02001741 if (logsrv->type == LOG_TARGET_BUFFER) {
1742 msg[0] = ist2(message, MIN(size, logsrv->maxlen));
1743 msg[1] = ist2(tag_str, tag_size);
1744 msg[2] = ist2(pid_str, pid_size);
1745 msg[3] = ist2(sd, sd_size);
1746 sent = sink_write(logsrv->sink, msg, 1, level, logsrv->facility, &msg[1], &msg[2], &msg[3]);
1747 }
1748 else /* LOG_TARGET_FD */ {
1749 msg[0] = ist2(hdr_ptr, hdr_max);
1750 msg[1] = ist2(tag_str, tag_max);
1751 msg[2] = ist2(pid_sep1, pid_sep1_max);
1752 msg[3] = ist2(pid_str, pid_max);
1753 msg[4] = ist2(pid_sep2, pid_sep2_max);
1754 msg[5] = ist2(sd, sd_max);
1755 msg[6] = ist2(dataptr, max);
Willy Tarreauc046d162019-08-30 15:24:59 +02001756 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Emeric Brune709e1e2020-05-06 17:23:59 +02001757 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001758 }
1759 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001760 iovec[0].iov_base = hdr_ptr;
1761 iovec[0].iov_len = hdr_max;
1762 iovec[1].iov_base = tag_str;
1763 iovec[1].iov_len = tag_max;
1764 iovec[2].iov_base = pid_sep1;
1765 iovec[2].iov_len = pid_sep1_max;
1766 iovec[3].iov_base = pid_str;
1767 iovec[3].iov_len = pid_max;
1768 iovec[4].iov_base = pid_sep2;
1769 iovec[4].iov_len = pid_sep2_max;
1770 iovec[5].iov_base = sd;
1771 iovec[5].iov_len = sd_max;
1772 iovec[6].iov_base = dataptr;
1773 iovec[6].iov_len = max;
1774 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1775 iovec[7].iov_len = 1;
1776
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001777 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1778 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001779
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001780 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1781 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001782
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001783 if (sent < 0) {
1784 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001785
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001786 if (errno == EAGAIN)
1787 _HA_ATOMIC_ADD(&dropped_logs, 1);
1788 else if (!once) {
1789 once = 1; /* note: no need for atomic ops here */
1790 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1791 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001792 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001793 }
1794}
Dragan Dosen59cee972015-09-19 22:09:02 +02001795
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001796/*
1797 * This function sends a syslog message.
1798 * It doesn't care about errors nor does it report them.
1799 * The arguments <sd> and <sd_size> are used for the structured-data part
1800 * in RFC5424 formatted syslog messages.
1801 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001802void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1803 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001804{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001805 struct logsrv *logsrv;
1806 int nblogger;
1807 static THREAD_LOCAL int curr_pid;
1808 static THREAD_LOCAL char pidstr[100];
1809 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001810
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001811 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001812 if (!LIST_ISEMPTY(&global.logsrvs)) {
1813 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001814 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001815 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001816 if (!tag || !tag->area)
1817 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001818
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001819 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001820 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001821
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001822 if (unlikely(curr_pid != getpid())) {
1823 curr_pid = getpid();
1824 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1825 chunk_initstr(&pid, pidstr);
1826 }
1827
1828 /* Send log messages to syslog server. */
1829 nblogger = 0;
1830 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001831 static THREAD_LOCAL int in_range = 1;
1832
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001833 /* we can filter the level of the messages that are sent to each logger */
1834 if (level > logsrv->level)
1835 continue;
1836
Frédéric Lécailled803e472019-04-25 07:42:09 +02001837 if (logsrv->lb.smp_rgs) {
1838 struct smp_log_range *curr_rg;
1839
1840 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1841 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1842 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1843 if (in_range) {
1844 /* Let's consume this range. */
1845 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1846 if (!curr_rg->curr_idx) {
1847 /* If consumed, let's select the next range. */
1848 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1849 }
1850 }
1851 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1852 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1853 }
1854 if (in_range)
1855 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1856 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001857 }
1858}
1859
1860
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001861const 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 +01001862const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1863 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1864 Set-cookie Updated, unknown, unknown */
1865
William Lallemand1d705562012-03-12 12:46:41 +01001866/*
1867 * try to write a character if there is enough space, or goto out
1868 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001869#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001870 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001871 *(tmplog++) = (x); \
1872 } else { \
1873 goto out; \
1874 } \
1875 } while(0)
1876
Dragan Dosen835b9212016-02-12 13:23:03 +01001877
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001878/* Initializes some log data at boot */
1879static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001880{
1881 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001882 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001883
1884 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1885 * inside PARAM-VALUE should be escaped with '\' as prefix.
1886 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1887 * details.
1888 */
1889 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1890
1891 tmp = "\"\\]";
1892 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001893 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001894 tmp++;
1895 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001896
1897 /* initialize the log header encoding map : '{|}"#' should be encoded with
1898 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1899 * URL encoding only requires '"', '#' to be encoded as well as non-
1900 * printable characters above.
1901 */
1902 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1903 memset(url_encode_map, 0, sizeof(url_encode_map));
1904 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001905 ha_bit_set(i, hdr_encode_map);
1906 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001907 }
1908 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001909 ha_bit_set(i, hdr_encode_map);
1910 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001911 }
1912
1913 tmp = "\"#{|}";
1914 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001915 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001916 tmp++;
1917 }
1918
1919 tmp = "\"#";
1920 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001921 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001922 tmp++;
1923 }
1924
1925 /* initialize the http header encoding map. The draft httpbis define the
1926 * header content as:
1927 *
1928 * HTTP-message = start-line
1929 * *( header-field CRLF )
1930 * CRLF
1931 * [ message-body ]
1932 * header-field = field-name ":" OWS field-value OWS
1933 * field-value = *( field-content / obs-fold )
1934 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1935 * obs-fold = CRLF 1*( SP / HTAB )
1936 * field-vchar = VCHAR / obs-text
1937 * VCHAR = %x21-7E
1938 * obs-text = %x80-FF
1939 *
1940 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1941 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001942 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001943 */
1944 memset(http_encode_map, 0, sizeof(http_encode_map));
1945 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001946 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001947 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001948 ha_bit_set(i, http_encode_map);
1949 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001950}
William Lallemand1d705562012-03-12 12:46:41 +01001951
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001952INITCALL0(STG_PREPARE, init_log);
1953
Christopher Faulet0132d062017-07-26 15:33:35 +02001954/* Initialize log buffers used for syslog messages */
1955int init_log_buffers()
1956{
1957 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001958 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001959 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001960 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001961 logline = my_realloc2(logline, global.max_syslog_len + 1);
1962 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1963 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1964 return 0;
1965 return 1;
1966}
1967
1968/* Deinitialize log buffers used for syslog messages */
1969void deinit_log_buffers()
1970{
1971 free(logheader);
1972 free(logheader_rfc5424);
1973 free(logline);
1974 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001975 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001976 logheader = NULL;
1977 logheader_rfc5424 = NULL;
1978 logline = NULL;
1979 logline_rfc5424 = NULL;
1980}
1981
Willy Tarreaudf974472012-12-28 02:44:01 +01001982/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1983 * <maxsize> characters. Returns the size of the output string in characters,
1984 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001985 * is not zero. It requires a valid session and optionally a stream. If the
1986 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001987 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001988int 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 +02001989{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001990 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001991 struct proxy *be;
1992 struct http_txn *txn;
1993 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001994 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001995 unsigned int s_flags;
1996 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001997 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001998 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001999 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002000 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002001 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02002002 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002003 int t_request;
2004 int hdr;
2005 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002006 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01002007 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01002008 char *ret;
2009 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002010 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002011 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002012 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002013
William Lallemandbddd4fd2012-02-27 11:23:10 +01002014 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002015
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002016 if (likely(s)) {
2017 be = s->be;
2018 txn = s->txn;
2019 be_conn = cs_conn(objt_cs(s->si[1].end));
2020 s_flags = s->flags;
2021 uniq_id = s->uniq_id;
2022 logs = &s->logs;
2023 } else {
2024 /* we have no stream so we first need to initialize a few
2025 * things that are needed later. We do increment the request
2026 * ID so that it's uniquely assigned to this request just as
2027 * if the request had reached the point of being processed.
2028 * A request error is reported as it's the only element we have
2029 * here and which justifies emitting such a log.
2030 */
2031 be = fe;
2032 txn = NULL;
2033 be_conn = NULL;
2034 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002035 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002036
2037 /* prepare a valid log structure */
2038 tmp_strm_log.tv_accept = sess->tv_accept;
2039 tmp_strm_log.accept_date = sess->accept_date;
2040 tmp_strm_log.t_handshake = sess->t_handshake;
2041 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
2042 tv_zero(&tmp_strm_log.tv_request);
2043 tmp_strm_log.t_queue = -1;
2044 tmp_strm_log.t_connect = -1;
2045 tmp_strm_log.t_data = -1;
2046 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2047 tmp_strm_log.bytes_in = 0;
2048 tmp_strm_log.bytes_out = 0;
2049 tmp_strm_log.prx_queue_pos = 0;
2050 tmp_strm_log.srv_queue_pos = 0;
2051
2052 logs = &tmp_strm_log;
2053 }
2054
William Lallemandbddd4fd2012-02-27 11:23:10 +01002055 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002056 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2057 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002058
William Lallemand1d705562012-03-12 12:46:41 +01002059 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002060
William Lallemandbddd4fd2012-02-27 11:23:10 +01002061 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002062 if (LIST_ISEMPTY(list_format))
2063 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002064
William Lallemand1d705562012-03-12 12:46:41 +01002065 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002066 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002067 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002068 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002069 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002070
Willy Tarreauc8368452012-12-21 00:09:23 +01002071 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002072 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002073 if (!last_isspace) {
2074 LOGCHAR(' ');
2075 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002076 }
2077 break;
2078
William Lallemand1d705562012-03-12 12:46:41 +01002079 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002080 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002081 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002082 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002083 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002084 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002085 last_isspace = 0;
2086 break;
2087
Willy Tarreauc8368452012-12-21 00:09:23 +01002088 case LOG_FMT_EXPR: // sample expression, may be request or response
2089 key = NULL;
Christopher Faulet5f940702020-04-06 10:40:02 +02002090 if (tmp->options & LOG_OPT_REQ_CAP)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002091 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 +02002092 if (!key && (tmp->options & LOG_OPT_RES_CAP))
Adis Nezirovic79beb242015-07-06 15:41:02 +02002093 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 +01002094 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002095 ret = lf_encode_chunk(tmplog, dst + maxsize,
2096 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002097 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002098 ret = lf_text_len(tmplog,
2099 key ? key->data.u.str.area : NULL,
2100 key ? key->data.u.str.data : 0,
2101 dst + maxsize - tmplog,
2102 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002103 if (ret == 0)
2104 goto out;
2105 tmplog = ret;
2106 last_isspace = 0;
2107 break;
2108
Willy Tarreau2beef582012-12-20 17:22:52 +01002109 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002110 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002111 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002112 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002113 else
2114 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002115 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002116 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002117 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002118 last_isspace = 0;
2119 break;
2120
Willy Tarreau2beef582012-12-20 17:22:52 +01002121 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002122 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002123 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002124 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002125 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002126 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002127 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002128 dst + maxsize - tmplog, tmp);
2129 }
William Lallemand5f232402012-04-05 18:02:55 +02002130 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002131 else
2132 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2133
William Lallemand5f232402012-04-05 18:02:55 +02002134 if (ret == NULL)
2135 goto out;
2136 tmplog = ret;
2137 last_isspace = 0;
2138 break;
2139
Willy Tarreau2beef582012-12-20 17:22:52 +01002140 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002141 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002142 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002143 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002144 }
2145 else
2146 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2147
William Lallemand1d705562012-03-12 12:46:41 +01002148 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002149 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002150 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002151 last_isspace = 0;
2152 break;
2153
Willy Tarreau2beef582012-12-20 17:22:52 +01002154 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002155 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002156 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002157 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002158 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002159 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002160 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002161 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002162 else
2163 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2164
William Lallemand5f232402012-04-05 18:02:55 +02002165 if (ret == NULL)
2166 goto out;
2167 tmplog = ret;
2168 last_isspace = 0;
2169 break;
2170
Willy Tarreau2beef582012-12-20 17:22:52 +01002171 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002172 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002173 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002174 else
2175 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2176
William Lallemand1d705562012-03-12 12:46:41 +01002177 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002178 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002179 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002180 last_isspace = 0;
2181 break;
2182
Willy Tarreau2beef582012-12-20 17:22:52 +01002183 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002184 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002185 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002186 else
2187 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2188
William Lallemand5f232402012-04-05 18:02:55 +02002189 if (ret == NULL)
2190 goto out;
2191 tmplog = ret;
2192 last_isspace = 0;
2193 break;
2194
Willy Tarreau2beef582012-12-20 17:22:52 +01002195 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002196 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002197 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002198 else
2199 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2200
William Lallemand5f232402012-04-05 18:02:55 +02002201 if (ret == NULL)
2202 goto out;
2203 tmplog = ret;
2204 last_isspace = 0;
2205 break;
2206
Willy Tarreau2beef582012-12-20 17:22:52 +01002207 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002208 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002209 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002210 else
2211 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2212
William Lallemand1d705562012-03-12 12:46:41 +01002213 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002214 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002215 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002216 last_isspace = 0;
2217 break;
2218
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002219 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002220 get_localtime(logs->accept_date.tv_sec, &tm);
2221 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002222 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002223 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002224 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002225 last_isspace = 0;
2226 break;
2227
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002228 case LOG_FMT_tr: // %tr = start of request date
2229 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002230 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 +02002231 get_localtime(tv.tv_sec, &tm);
2232 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2233 if (ret == NULL)
2234 goto out;
2235 tmplog = ret;
2236 last_isspace = 0;
2237 break;
2238
2239 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002240 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002241 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002242 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002243 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002244 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002245 last_isspace = 0;
2246 break;
2247
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002248 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002249 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 +02002250 get_gmtime(tv.tv_sec, &tm);
2251 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2252 if (ret == NULL)
2253 goto out;
2254 tmplog = ret;
2255 last_isspace = 0;
2256 break;
2257
2258 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002259 get_localtime(logs->accept_date.tv_sec, &tm);
2260 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002261 if (ret == NULL)
2262 goto out;
2263 tmplog = ret;
2264 last_isspace = 0;
2265 break;
2266
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002267 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002268 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 +02002269 get_localtime(tv.tv_sec, &tm);
2270 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2271 if (ret == NULL)
2272 goto out;
2273 tmplog = ret;
2274 last_isspace = 0;
2275 break;
2276
William Lallemand5f232402012-04-05 18:02:55 +02002277 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002278 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002279 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002280 if (iret < 0 || iret > dst + maxsize - tmplog)
2281 goto out;
2282 last_isspace = 0;
2283 tmplog += iret;
2284 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002285 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002286 if (ret == NULL)
2287 goto out;
2288 tmplog = ret;
2289 last_isspace = 0;
2290 }
2291 break;
2292
William Lallemand1d705562012-03-12 12:46:41 +01002293 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002294 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002295 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002296 if (iret < 0 || iret > dst + maxsize - tmplog)
2297 goto out;
2298 last_isspace = 0;
2299 tmplog += iret;
2300 } else {
2301 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002302 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002303 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002304 tmplog, 4);
2305 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002306 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002307 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002308 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002309 }
2310 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002311
William Lallemand1d705562012-03-12 12:46:41 +01002312 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002313 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002314 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002315 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002316 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002317 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002318 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002319 break;
2320
Willy Tarreau773d65f2012-10-12 14:56:11 +02002321 case LOG_FMT_FRONTEND_XPRT: // %ft
2322 src = fe->id;
2323 if (tmp->options & LOG_OPT_QUOTE)
2324 LOGCHAR('"');
2325 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2326 if (iret == 0)
2327 goto out;
2328 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002329 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002330 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002331 if (tmp->options & LOG_OPT_QUOTE)
2332 LOGCHAR('"');
2333 last_isspace = 0;
2334 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002335#ifdef USE_OPENSSL
2336 case LOG_FMT_SSL_CIPHER: // %sslc
2337 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002338 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002339 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002340 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002341 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002342 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2343 if (ret == NULL)
2344 goto out;
2345 tmplog = ret;
2346 last_isspace = 0;
2347 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002348
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002349 case LOG_FMT_SSL_VERSION: // %sslv
2350 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002351 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002352 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002353 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002354 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002355 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2356 if (ret == NULL)
2357 goto out;
2358 tmplog = ret;
2359 last_isspace = 0;
2360 break;
2361#endif
William Lallemand1d705562012-03-12 12:46:41 +01002362 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002363 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002364 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002365 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002366 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002367 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002368 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002369 break;
2370
William Lallemand1d705562012-03-12 12:46:41 +01002371 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002372 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002373 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002374 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002375 break;
2376 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002377 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002378 break;
2379 default:
2380 src = "<NOSRV>";
2381 break;
2382 }
William Lallemand5f232402012-04-05 18:02:55 +02002383 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002384 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002385 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002386 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002387 last_isspace = 0;
2388 break;
2389
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002390 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002391 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002392 if (ret == NULL)
2393 goto out;
2394 tmplog = ret;
2395 last_isspace = 0;
2396 break;
2397
2398 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002399 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002400 if (ret == NULL)
2401 goto out;
2402 tmplog = ret;
2403 last_isspace = 0;
2404 break;
2405
2406 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002407 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002408 tmplog, dst + maxsize - tmplog);
2409 if (ret == NULL)
2410 goto out;
2411 tmplog = ret;
2412 last_isspace = 0;
2413 break;
2414
2415 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002416 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002417 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002418 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002419 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002420 last_isspace = 0;
2421 break;
2422
William Lallemand1d705562012-03-12 12:46:41 +01002423 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002424 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002425 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002426 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002427 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002428 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002429 last_isspace = 0;
2430 break;
2431
William Lallemand1d705562012-03-12 12:46:41 +01002432 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002433 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002434 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002435 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002436 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002437 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002438 last_isspace = 0;
2439 break;
2440
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002441 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002442 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002443 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002444 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002445 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002446 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002447 last_isspace = 0;
2448 break;
2449
Willy Tarreau27b639d2016-05-17 17:55:27 +02002450 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002451 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002452 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002453 tmplog, dst + maxsize - tmplog);
2454 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002455 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002456 tmplog, dst + maxsize - tmplog);
2457 if (ret == NULL)
2458 goto out;
2459 tmplog = ret;
2460 last_isspace = 0;
2461 break;
2462
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002463 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2464 if (!(fe->to_log & LW_BYTES))
2465 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002466 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 +02002467 tmplog, dst + maxsize - tmplog);
2468 if (ret == NULL)
2469 goto out;
2470 tmplog = ret;
2471 last_isspace = 0;
2472 break;
2473
2474 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002475 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002476 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002477 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002478 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002479 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002480 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002481 last_isspace = 0;
2482 break;
2483
Damien Claisse57c8eb92020-04-28 12:09:19 +00002484 case LOG_FMT_TU: // %Tu = total time seen by user = Tt - Ti
2485 if (!(fe->to_log & LW_BYTES))
2486 LOGCHAR('+');
2487 ret = ltoa_o(logs->t_close - (logs->t_idle >= 0 ? logs->t_idle : 0),
2488 tmplog, dst + maxsize - tmplog);
2489 if (ret == NULL)
2490 goto out;
2491 tmplog = ret;
2492 last_isspace = 0;
2493 break;
2494
Willy Tarreau2beef582012-12-20 17:22:52 +01002495 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002496 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002497 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002498 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002499 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002500 last_isspace = 0;
2501 break;
2502
William Lallemand1d705562012-03-12 12:46:41 +01002503 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002504 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002505 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002506 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002507 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002508 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002509 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002510 last_isspace = 0;
2511 break;
2512
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002513 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002514 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002515 if (ret == NULL)
2516 goto out;
2517 tmplog = ret;
2518 last_isspace = 0;
2519 break;
2520
Willy Tarreau2beef582012-12-20 17:22:52 +01002521 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002522 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002523 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002524 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002525 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002526 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002527 last_isspace = 0;
2528 break;
2529
Willy Tarreau2beef582012-12-20 17:22:52 +01002530 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002531 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002532 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002533 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002534 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002535 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002536 last_isspace = 0;
2537 break;
2538
William Lallemand1d705562012-03-12 12:46:41 +01002539 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002540 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2541 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002542 *tmplog = '\0';
2543 last_isspace = 0;
2544 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002545
William Lallemand1d705562012-03-12 12:46:41 +01002546 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002547 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2548 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002549 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2550 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 +01002551 last_isspace = 0;
2552 break;
2553
William Lallemand1d705562012-03-12 12:46:41 +01002554 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002555 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002556 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002557 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002558 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002559 last_isspace = 0;
2560 break;
2561
William Lallemand1d705562012-03-12 12:46:41 +01002562 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002563 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002564 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002565 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002566 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002567 last_isspace = 0;
2568 break;
2569
William Lallemand1d705562012-03-12 12:46:41 +01002570 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002571 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002572 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002573 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002574 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002575 last_isspace = 0;
2576 break;
2577
William Lallemand1d705562012-03-12 12:46:41 +01002578 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002579 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002580 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002581 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002582 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002583 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002584 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002585 last_isspace = 0;
2586 break;
2587
William Lallemand1d705562012-03-12 12:46:41 +01002588 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002589 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002590 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002591 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002592 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002593 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002594 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002595 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002596 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002597 last_isspace = 0;
2598 break;
2599
William Lallemand1d705562012-03-12 12:46:41 +01002600 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002601 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002602 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002603 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002604 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002605 last_isspace = 0;
2606 break;
2607
William Lallemand1d705562012-03-12 12:46:41 +01002608 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002609 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002610 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002611 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002612 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002613 last_isspace = 0;
2614 break;
2615
William Lallemand1d705562012-03-12 12:46:41 +01002616 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002617 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002618 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002619 if (tmp->options & LOG_OPT_QUOTE)
2620 LOGCHAR('"');
2621 LOGCHAR('{');
2622 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2623 if (hdr)
2624 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002625 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002626 ret = lf_encode_string(tmplog, dst + maxsize,
2627 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002628 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002629 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002630 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002631 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002632 }
2633 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002634 if (tmp->options & LOG_OPT_QUOTE)
2635 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002636 last_isspace = 0;
2637 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002638 break;
2639
William Lallemand1d705562012-03-12 12:46:41 +01002640 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002641 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002642 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002643 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2644 if (hdr > 0)
2645 LOGCHAR(' ');
2646 if (tmp->options & LOG_OPT_QUOTE)
2647 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002648 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002649 ret = lf_encode_string(tmplog, dst + maxsize,
2650 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002651 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002652 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002653 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002654 } else if (!(tmp->options & LOG_OPT_QUOTE))
2655 LOGCHAR('-');
2656 if (tmp->options & LOG_OPT_QUOTE)
2657 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002658 last_isspace = 0;
2659 }
2660 }
2661 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002662
William Lallemand1d705562012-03-12 12:46:41 +01002663
2664 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002665 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002666 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002667 if (tmp->options & LOG_OPT_QUOTE)
2668 LOGCHAR('"');
2669 LOGCHAR('{');
2670 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2671 if (hdr)
2672 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002673 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002674 ret = lf_encode_string(tmplog, dst + maxsize,
2675 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002676 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002677 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002678 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002679 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002680 }
2681 LOGCHAR('}');
2682 last_isspace = 0;
2683 if (tmp->options & LOG_OPT_QUOTE)
2684 LOGCHAR('"');
2685 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002686 break;
2687
William Lallemand1d705562012-03-12 12:46:41 +01002688 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002689 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002690 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002691 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2692 if (hdr > 0)
2693 LOGCHAR(' ');
2694 if (tmp->options & LOG_OPT_QUOTE)
2695 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002696 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002697 ret = lf_encode_string(tmplog, dst + maxsize,
2698 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002699 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002700 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002701 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002702 } else if (!(tmp->options & LOG_OPT_QUOTE))
2703 LOGCHAR('-');
2704 if (tmp->options & LOG_OPT_QUOTE)
2705 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002706 last_isspace = 0;
2707 }
2708 }
2709 break;
2710
William Lallemand1d705562012-03-12 12:46:41 +01002711 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002712 /* Request */
2713 if (tmp->options & LOG_OPT_QUOTE)
2714 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002715 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002716 ret = lf_encode_string(tmplog, dst + maxsize,
2717 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002718 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002719 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002720 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002721 if (tmp->options & LOG_OPT_QUOTE)
2722 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002723 last_isspace = 0;
2724 break;
William Lallemand5f232402012-04-05 18:02:55 +02002725
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002726 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002727 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002728
Willy Tarreaub7636d12015-06-17 19:58:02 +02002729 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002730 LOGCHAR('"');
2731
2732 end = uri + strlen(uri);
2733 // look for the first whitespace character
2734 while (uri < end && !HTTP_IS_SPHT(*uri))
2735 uri++;
2736
2737 // keep advancing past multiple spaces
2738 while (uri < end && HTTP_IS_SPHT(*uri)) {
2739 uri++; nspaces++;
2740 }
2741
2742 // look for first space or question mark after url
2743 spc = uri;
2744 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2745 spc++;
2746
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002747 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002748 chunk.area = "<BADREQ>";
2749 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002750 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002751 chunk.area = uri;
2752 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002753 }
2754
Dragan Dosen835b9212016-02-12 13:23:03 +01002755 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002756 if (ret == NULL || *ret != '\0')
2757 goto out;
2758
2759 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002760 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002761 LOGCHAR('"');
2762
2763 last_isspace = 0;
2764 break;
2765
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002766 case LOG_FMT_HTTP_QUERY: // %HQ
2767 if (tmp->options & LOG_OPT_QUOTE)
2768 LOGCHAR('"');
2769
Willy Tarreau57bc8912016-04-25 17:09:40 +02002770 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002771 chunk.area = "<BADREQ>";
2772 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002773 } else {
2774 uri = txn->uri;
2775 end = uri + strlen(uri);
2776 // look for the first question mark
2777 while (uri < end && *uri != '?')
2778 uri++;
2779
2780 qmark = uri;
2781 // look for first space or question mark after url
2782 while (uri < end && !HTTP_IS_SPHT(*uri))
2783 uri++;
2784
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002785 chunk.area = qmark;
2786 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002787 }
2788
Dragan Dosen835b9212016-02-12 13:23:03 +01002789 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002790 if (ret == NULL || *ret != '\0')
2791 goto out;
2792
2793 tmplog = ret;
2794 if (tmp->options & LOG_OPT_QUOTE)
2795 LOGCHAR('"');
2796
2797 last_isspace = 0;
2798 break;
2799
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002800 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002801 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002802
Willy Tarreaub7636d12015-06-17 19:58:02 +02002803 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002804 LOGCHAR('"');
2805
2806 end = uri + strlen(uri);
2807 // look for the first whitespace character
2808 while (uri < end && !HTTP_IS_SPHT(*uri))
2809 uri++;
2810
2811 // keep advancing past multiple spaces
2812 while (uri < end && HTTP_IS_SPHT(*uri)) {
2813 uri++; nspaces++;
2814 }
2815
2816 // look for first space after url
2817 spc = uri;
2818 while (spc < end && !HTTP_IS_SPHT(*spc))
2819 spc++;
2820
Willy Tarreau57bc8912016-04-25 17:09:40 +02002821 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002822 chunk.area = "<BADREQ>";
2823 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002824 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002825 chunk.area = uri;
2826 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002827 }
2828
Dragan Dosen835b9212016-02-12 13:23:03 +01002829 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002830 if (ret == NULL || *ret != '\0')
2831 goto out;
2832
2833 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002834 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002835 LOGCHAR('"');
2836
2837 last_isspace = 0;
2838 break;
2839
2840 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002841 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002842 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002843 LOGCHAR('"');
2844
2845 end = uri + strlen(uri);
2846 // look for the first whitespace character
2847 spc = uri;
2848 while (spc < end && !HTTP_IS_SPHT(*spc))
2849 spc++;
2850
2851 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002852 chunk.area = "<BADREQ>";
2853 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002854 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002855 chunk.area = uri;
2856 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002857 }
2858
Dragan Dosen835b9212016-02-12 13:23:03 +01002859 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002860 if (ret == NULL || *ret != '\0')
2861 goto out;
2862
2863 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002864 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002865 LOGCHAR('"');
2866
2867 last_isspace = 0;
2868 break;
2869
2870 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002871 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002872 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002873 LOGCHAR('"');
2874
2875 end = uri + strlen(uri);
2876 // look for the first whitespace character
2877 while (uri < end && !HTTP_IS_SPHT(*uri))
2878 uri++;
2879
2880 // keep advancing past multiple spaces
2881 while (uri < end && HTTP_IS_SPHT(*uri)) {
2882 uri++; nspaces++;
2883 }
2884
2885 // look for the next whitespace character
2886 while (uri < end && !HTTP_IS_SPHT(*uri))
2887 uri++;
2888
2889 // keep advancing past multiple spaces
2890 while (uri < end && HTTP_IS_SPHT(*uri))
2891 uri++;
2892
Willy Tarreau57bc8912016-04-25 17:09:40 +02002893 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002894 chunk.area = "<BADREQ>";
2895 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002896 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002897 chunk.area = "HTTP/0.9";
2898 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002899 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002900 chunk.area = uri;
2901 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002902 }
2903
Dragan Dosen835b9212016-02-12 13:23:03 +01002904 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002905 if (ret == NULL || *ret != '\0')
2906 goto out;
2907
2908 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002909 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002910 LOGCHAR('"');
2911
2912 last_isspace = 0;
2913 break;
2914
William Lallemand5f232402012-04-05 18:02:55 +02002915 case LOG_FMT_COUNTER: // %rt
2916 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002917 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002918 if (iret < 0 || iret > dst + maxsize - tmplog)
2919 goto out;
2920 last_isspace = 0;
2921 tmplog += iret;
2922 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002923 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002924 if (ret == NULL)
2925 goto out;
2926 tmplog = ret;
2927 last_isspace = 0;
2928 }
2929 break;
2930
Willy Tarreau7346acb2014-08-28 15:03:15 +02002931 case LOG_FMT_LOGCNT: // %lc
2932 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002933 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002934 if (iret < 0 || iret > dst + maxsize - tmplog)
2935 goto out;
2936 last_isspace = 0;
2937 tmplog += iret;
2938 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002939 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002940 if (ret == NULL)
2941 goto out;
2942 tmplog = ret;
2943 last_isspace = 0;
2944 }
2945 break;
2946
William Lallemand5f232402012-04-05 18:02:55 +02002947 case LOG_FMT_HOSTNAME: // %H
2948 src = hostname;
2949 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2950 if (ret == NULL)
2951 goto out;
2952 tmplog = ret;
2953 last_isspace = 0;
2954 break;
2955
2956 case LOG_FMT_PID: // %pid
2957 if (tmp->options & LOG_OPT_HEXA) {
2958 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2959 if (iret < 0 || iret > dst + maxsize - tmplog)
2960 goto out;
2961 last_isspace = 0;
2962 tmplog += iret;
2963 } else {
2964 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2965 if (ret == NULL)
2966 goto out;
2967 tmplog = ret;
2968 last_isspace = 0;
2969 }
2970 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002971
2972 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002973 ret = NULL;
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002974 if (s)
2975 ret = lf_text_len(tmplog, s->unique_id.ptr, s->unique_id.len, maxsize - (tmplog - dst), tmp);
2976 else
2977 ret = lf_text_len(tmplog, NULL, 0, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002978 if (ret == NULL)
2979 goto out;
2980 tmplog = ret;
2981 last_isspace = 0;
2982 break;
2983
William Lallemandbddd4fd2012-02-27 11:23:10 +01002984 }
2985 }
2986
2987out:
William Lallemand1d705562012-03-12 12:46:41 +01002988 /* *tmplog is a unused character */
2989 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002990 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002991
Willy Tarreaubaaee002006-06-26 02:48:02 +02002992}
2993
William Lallemand1d705562012-03-12 12:46:41 +01002994/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002995 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002996 * Will not log if the frontend has no log defined.
2997 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002998void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002999{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003000 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01003001 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003002 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01003003
3004 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02003005 err = (s->flags & SF_REDISP) ||
3006 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
3007 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01003008 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02003009 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003010
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003011 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01003012 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003013
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003014 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01003015 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01003016
Willy Tarreauabcd5142013-06-11 17:18:02 +02003017 if (s->logs.level) { /* loglevel was overridden */
3018 if (s->logs.level == -1) {
3019 s->logs.logwait = 0; /* logs disabled */
3020 return;
3021 }
3022 level = s->logs.level - 1;
3023 }
3024 else {
3025 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003026 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02003027 level = LOG_ERR;
3028 }
William Lallemand1d705562012-03-12 12:46:41 +01003029
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003030 /* if unique-id was not generated */
Tim Duesterhusa17e6622020-03-05 20:19:02 +01003031 if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Tim Duesterhus2825b4b2020-02-28 15:13:34 +01003032 stream_generate_unique_id(s, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003033 }
3034
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003035 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3036 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
3037 &sess->fe->logformat_sd);
3038 }
3039
Dragan Dosen59cee972015-09-19 22:09:02 +02003040 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01003041 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003042 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003043 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3044 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01003045 s->logs.logwait = 0;
3046 }
3047}
William Lallemandbddd4fd2012-02-27 11:23:10 +01003048
Willy Tarreau53839352018-09-05 19:51:10 +02003049/*
3050 * send a minimalist log for the session. Will not log if the frontend has no
3051 * log defined. It is assumed that this is only used to report anomalies that
3052 * cannot lead to the creation of a regular stream. Because of this the log
3053 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
3054 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003055 * function to report unimportant events. It is safe to call this function with
3056 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02003057 */
3058void sess_log(struct session *sess)
3059{
3060 int size, level;
3061 int sd_size = 0;
3062
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003063 if (!sess)
3064 return;
3065
Willy Tarreau53839352018-09-05 19:51:10 +02003066 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3067 return;
3068
3069 level = LOG_INFO;
3070 if (sess->fe->options2 & PR_O2_LOGERRORS)
3071 level = LOG_ERR;
3072
3073 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3074 sd_size = sess_build_logline(sess, NULL,
3075 logline_rfc5424, global.max_syslog_len,
3076 &sess->fe->logformat_sd);
3077 }
3078
3079 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3080 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003081 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003082 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3083 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003084 }
3085}
3086
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003087void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3088{
3089 va_list argp;
3090 int data_len;
3091
3092 if (level < 0 || format == NULL || logline == NULL)
3093 return;
3094
3095 va_start(argp, format);
3096 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3097 if (data_len < 0 || data_len > global.max_syslog_len)
3098 data_len = global.max_syslog_len;
3099 va_end(argp);
3100
3101 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3102}
3103
Willy Tarreau869efd52019-11-15 15:16:57 +01003104/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3105static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003106{
Willy Tarreau869efd52019-11-15 15:16:57 +01003107 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3108 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003109
Willy Tarreau869efd52019-11-15 15:16:57 +01003110 if (!startup_logs)
3111 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3112
3113 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003114}
3115
3116/* register cli keywords */
3117static struct cli_kw_list cli_kws = {{ },{
3118 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003119 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003120 {{},}
3121}};
3122
Willy Tarreau0108d902018-11-25 19:14:37 +01003123INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3124
Willy Tarreau082b6282019-05-22 14:42:12 +02003125REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3126REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003127
Willy Tarreaubaaee002006-06-26 02:48:02 +02003128/*
3129 * Local variables:
3130 * c-indent-level: 8
3131 * c-basic-offset: 8
3132 * End:
3133 */