blob: bacc04ed56c1255346f12e61f510272283456399 [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
Dragan Dosen835b9212016-02-12 13:23:03 +010089/*
90 * This map is used with all the FD_* macros to check whether a particular bit
Willy Tarreau1bfd6022019-06-07 11:10:07 +020091 * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
92 * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
93 * that the byte should be escaped. Be careful to always pass bytes from 0 to
94 * 255 exclusively to the macros.
Dragan Dosen835b9212016-02-12 13:23:03 +010095 */
Willy Tarreau1bfd6022019-06-07 11:10:07 +020096long rfc5424_escape_map[(256/8) / sizeof(long)];
97long hdr_encode_map[(256/8) / sizeof(long)];
98long url_encode_map[(256/8) / sizeof(long)];
99long http_encode_map[(256/8) / sizeof(long)];
Dragan Dosen835b9212016-02-12 13:23:03 +0100100
Dragan Dosen835b9212016-02-12 13:23:03 +0100101
Willy Tarreaubaaee002006-06-26 02:48:02 +0200102const char *log_facilities[NB_LOG_FACILITIES] = {
103 "kern", "user", "mail", "daemon",
104 "auth", "syslog", "lpr", "news",
105 "uucp", "cron", "auth2", "ftp",
106 "ntp", "audit", "alert", "cron2",
107 "local0", "local1", "local2", "local3",
108 "local4", "local5", "local6", "local7"
109};
110
Willy Tarreaubaaee002006-06-26 02:48:02 +0200111const char *log_levels[NB_LOG_LEVELS] = {
112 "emerg", "alert", "crit", "err",
113 "warning", "notice", "info", "debug"
114};
115
Willy Tarreau570f2212013-06-10 16:42:09 +0200116const 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 +0200117const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200118
William Lallemand723b73a2012-02-08 16:37:49 +0100119
120/* log_format */
121struct logformat_type {
122 char *name;
123 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100124 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200125 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100126 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100127 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100128};
129
William Lallemandb7ff6a32012-03-02 14:35:21 +0100130int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
131
William Lallemand723b73a2012-02-08 16:37:49 +0100132/* log_format variable names */
133static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200134 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100135
136 /* please keep these lines sorted ! */
137 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
138 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
139 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
140 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +0100141 { "ID", LOG_FMT_UNIQUEID, PR_MODE_TCP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200142 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200143 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200144 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100145 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200146 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
147 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
148 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
149 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
150 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
151 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200152 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100153 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200154 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Willy Tarreau2beef582012-12-20 17:22:52 +0100155 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
156 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200157 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100158 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200159 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100160 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
161 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200162 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200163 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
164 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100165 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
166 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200167 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
168 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100169 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200170 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
171 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
172 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
173 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000174 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
175 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000176 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000177 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
178 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200179 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100180 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200181 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100182 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
183 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100184 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100185 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
186 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
187 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
188 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
189 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200190 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
191 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100192 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200193 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
194 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
195 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100196 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
197 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
198
199 /* The following tags are deprecated and will be removed soon */
200 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
201 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200202 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
203 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
204 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
205 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100206 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
207 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
208 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
209 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
210 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200211 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100212};
213
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200214char 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
215char 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 +0100216char 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 +0100217char *log_format = NULL;
218
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200219/* Default string used for structured-data part in RFC5424 formatted
220 * syslog messages.
221 */
222char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200223
Willy Tarreau13ef7732018-11-12 07:25:28 +0100224/* total number of dropped logs */
225unsigned int dropped_logs = 0;
226
Dragan Dosen1322d092015-09-22 16:05:32 +0200227/* This is a global syslog header, common to all outgoing messages in
228 * RFC3164 format. It begins with time-based part and is updated by
229 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200230 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200231THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200232THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200233
Dragan Dosen1322d092015-09-22 16:05:32 +0200234/* This is a global syslog header for messages in RFC5424 format. It is
235 * updated by update_log_hdr_rfc5424().
236 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200237THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200238THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200239
Dragan Dosen59cee972015-09-19 22:09:02 +0200240/* This is a global syslog message buffer, common to all outgoing
241 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100242 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200243THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100244
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200245/* A global syslog message buffer, common to all RFC5424 syslog messages.
246 * Currently, it is used for generating the structured-data part.
247 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200248THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200249
Christopher Fauletd4696382017-10-24 11:44:05 +0200250/* A global buffer used to store all startup alerts/warnings. It will then be
251 * retrieve on the CLI. */
Willy Tarreau869efd52019-11-15 15:16:57 +0100252static struct ring *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200253
William Lallemand723b73a2012-02-08 16:37:49 +0100254struct logformat_var_args {
255 char *name;
256 int mask;
257};
258
259struct logformat_var_args var_args_list[] = {
260// global
261 { "M", LOG_OPT_MANDATORY },
262 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200263 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100264 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100265 { 0, 0 }
266};
267
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200268/* return the name of the directive used in the current proxy for which we're
269 * currently parsing a header, when it is known.
270 */
271static inline const char *fmt_directive(const struct proxy *curproxy)
272{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100273 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200274 case ARGC_ACL:
275 return "acl";
276 case ARGC_STK:
277 return "stick";
278 case ARGC_TRK:
279 return "track-sc";
280 case ARGC_LOG:
281 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200282 case ARGC_LOGSD:
283 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100284 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100285 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100286 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100287 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200288 case ARGC_UIF:
289 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100290 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200291 return "redirect";
292 case ARGC_CAP:
293 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200294 case ARGC_SRV:
295 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200296 case ARGC_SPOE:
297 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100298 case ARGC_UBK:
299 return "use_backend";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100300 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200301 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100302 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200303}
304
William Lallemand723b73a2012-02-08 16:37:49 +0100305/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100306 * callback used to configure addr source retrieval
307 */
308int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
309{
310 curproxy->options2 |= PR_O2_SRC_ADDR;
311
312 return 0;
313}
314
315
316/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100317 * Parse args in a logformat_var. Returns 0 in error
318 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100319 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100320int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100321{
322 int i = 0;
323 int end = 0;
324 int flags = 0; // 1 = + 2 = -
325 char *sp = NULL; // start pointer
326
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100327 if (args == NULL) {
328 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100329 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100330 }
William Lallemand723b73a2012-02-08 16:37:49 +0100331
332 while (1) {
333 if (*args == '\0')
334 end = 1;
335
336 if (*args == '+') {
337 // add flag
338 sp = args + 1;
339 flags = 1;
340 }
341 if (*args == '-') {
342 // delete flag
343 sp = args + 1;
344 flags = 2;
345 }
346
347 if (*args == '\0' || *args == ',') {
348 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100349 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100350 if (strcmp(sp, var_args_list[i].name) == 0) {
351 if (flags == 1) {
352 node->options |= var_args_list[i].mask;
353 break;
354 } else if (flags == 2) {
355 node->options &= ~var_args_list[i].mask;
356 break;
357 }
358 }
359 }
360 sp = NULL;
361 if (end)
362 break;
363 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100364 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100365 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100366 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100367}
368
369/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100370 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
371 * must pass the args part in the <arg> pointer with its length in <arg_len>,
372 * and varname with its length in <var> and <var_len> respectively. <arg> is
373 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100374 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100375 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100376int 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 +0100377{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100378 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200379 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100380
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100381 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
382 if (strlen(logformat_keywords[j].name) == var_len &&
383 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
384 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200385 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100386 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100387 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200388 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100389 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100390 node->type = logformat_keywords[j].type;
391 node->options = *defoptions;
392 if (arg_len) {
393 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100394 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200395 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100396 }
397 if (node->type == LOG_FMT_GLOBAL) {
398 *defoptions = node->options;
399 free(node->arg);
400 free(node);
401 } else {
402 if (logformat_keywords[j].config_callback &&
403 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200404 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100405 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100406 curproxy->to_log |= logformat_keywords[j].lw;
407 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100408 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100409 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100410 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
411 curproxy->conf.args.file, curproxy->conf.args.line,
412 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100413 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100414 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100415 memprintf(err, "format variable '%s' is reserved for HTTP mode",
416 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200417 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100418 }
William Lallemand723b73a2012-02-08 16:37:49 +0100419 }
420 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100421
422 j = var[var_len];
423 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100424 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 +0100425 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200426
427 error_free:
428 if (node) {
429 free(node->arg);
430 free(node);
431 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100432 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100433}
434
435/*
436 * push to the logformat linked list
437 *
438 * start: start pointer
439 * end: end text pointer
440 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100441 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100442 *
443 * LOG_TEXT: copy chars from start to end excluding end.
444 *
445*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100446int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100447{
448 char *str;
449
Willy Tarreaua3571662012-12-20 21:59:12 +0100450 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200451 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100452 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100453 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100454 return 0;
455 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200456 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100457 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100458 str[end - start] = '\0';
459 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100460 node->type = LOG_FMT_TEXT; // type string
461 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100462 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200463 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100464 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100465 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100466 return 0;
467 }
William Lallemand1d705562012-03-12 12:46:41 +0100468 node->type = LOG_FMT_SEPARATOR;
469 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100470 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100471 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100472}
473
474/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100475 * Parse the sample fetch expression <text> and add a node to <list_format> upon
476 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100477 * should work. The curpx->conf.args.ctx must be set by the caller. If an end pointer
478 * is passed in <endptr>, it will be updated with the pointer to the first character
479 * not part of the sample expression.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100480 *
481 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100482 */
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100483int 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 +0100484{
485 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200486 struct sample_expr *expr = NULL;
487 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100488 int cmd_arg;
489
490 cmd[0] = text;
491 cmd[1] = "";
492 cmd_arg = 0;
493
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100494 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 +0100495 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100496 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200497 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100498 }
499
Vincent Bernat02779b62016-04-03 13:48:43 +0200500 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100501 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100502 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200503 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100504 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100505 node->type = LOG_FMT_EXPR;
506 node->expr = expr;
507 node->options = options;
508
509 if (arg_len) {
510 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100511 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200512 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100513 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100514 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100515 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
516
Willy Tarreau434c57c2013-01-08 01:10:24 +0100517 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100518 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
519
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100520 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100521 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
522 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200523 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100524 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100525
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200526 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100527 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100528 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100529
William Lallemand65ad6e12014-01-31 15:08:02 +0100530 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
531 * needed with some sample fetches (eg: ssl*). We always set it for
532 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100533 */
534 curpx->to_log |= LW_XPRT;
Christopher Fauletd2236cd2020-04-06 18:29:14 +0200535 if (curpx->http_needed)
536 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100537 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100538 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200539
540 error_free:
541 release_sample_expr(expr);
542 if (node) {
543 free(node->arg);
544 free(node);
545 }
546 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100547}
548
549/*
William Lallemand723b73a2012-02-08 16:37:49 +0100550 * Parse the log_format string and fill a linked list.
551 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200552 * You can set arguments using { } : %{many arguments}varname.
553 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100554 *
Ilya Shipitsinae40dbc2020-04-04 12:59:53 +0500555 * fmt: the string to parse
William Lallemand1d705562012-03-12 12:46:41 +0100556 * curproxy: the proxy affected
557 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100558 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100559 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100560 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100561 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100562 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100563int 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 +0100564{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100565 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100566 char *arg = NULL; /* start pointer for args */
567 char *var = NULL; /* start pointer for vars */
568 int arg_len = 0;
569 int var_len = 0;
570 int cformat; /* current token format */
571 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100572 struct logformat_node *tmplf, *back;
573
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100574 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100575 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100576 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100577 return 0;
578 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200579 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200580
William Lallemand723b73a2012-02-08 16:37:49 +0100581 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100582 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100583 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200584 release_sample_expr(tmplf->expr);
585 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100586 free(tmplf);
587 }
588
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100589 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100590 pformat = cformat;
591
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100592 if (!*str)
593 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100594
Joseph Herlant85b40592018-11-15 12:10:04 -0800595 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100596 * second have all common paths processed at one place. The common paths are the ones
597 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
598 * We use the common LF_INIT state to dispatch to the different final states.
599 */
600 switch (pformat) {
601 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100602 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100603 arg_len = var_len = 0;
604 if (*str == '{') { // optional argument
605 cformat = LF_STARG;
606 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100607 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100608 else if (*str == '[') {
609 cformat = LF_STEXPR;
610 var = str + 1; // store expr in variable name
611 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100612 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100613 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100614 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100615 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100616 else if (*str == '%')
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500617 cformat = LF_TEXT; // convert this character to a literal (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100618 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100619 /* single '%' followed by blank or digit, send them both */
620 cformat = LF_TEXT;
621 pformat = LF_TEXT; /* finally we include the previous char as well */
622 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600623 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 +0100624 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100625 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100626
627 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100628 else
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500629 cformat = LF_INIT; // handle other cases of literals
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100630 break;
631
632 case LF_STARG: // text immediately following '%{'
633 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100634 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100635 arg_len = str - arg;
636 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100637 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100638 break;
639
640 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100641 if (*str == '[') {
642 cformat = LF_STEXPR;
643 var = str + 1; // store expr in variable name
644 break;
645 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100646 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100647 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100648 var = str;
649 break;
650 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100651 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100652 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100653
Willy Tarreauc8368452012-12-21 00:09:23 +0100654 case LF_STEXPR: // text immediately following '%['
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100655 /* the whole sample expression is parsed at once,
656 * returning the pointer to the first character not
657 * part of the expression, which MUST be the trailing
658 * angle bracket.
659 */
660 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str))
661 goto fail;
662
663 if (*str == ']') {
664 // end of arg, go on with next state
665 cformat = pformat = LF_EDEXPR;
666 sp = str;
667 }
668 else {
669 char c = *str;
670 *str = 0;
Willy Tarreau90807112020-02-25 08:16:33 +0100671 if (isprint((unsigned char)c))
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100672 memprintf(err, "expected ']' after '%s', but found '%c'", var, c);
673 else
674 memprintf(err, "missing ']' after '%s'", var);
Willy Tarreauc8368452012-12-21 00:09:23 +0100675 }
676 break;
677
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100678 case LF_VAR: // text part of a variable name
679 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100680 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100681 cformat = LF_INIT; // not variable name anymore
682 break;
683
Willy Tarreauc8368452012-12-21 00:09:23 +0100684 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100685 cformat = LF_INIT;
686 }
687
688 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
689 switch (*str) {
690 case '%': cformat = LF_STARTVAR; break;
691 case ' ': cformat = LF_SEPARATOR; break;
692 case 0 : cformat = LF_END; break;
693 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100694 }
695 }
696
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100697 if (cformat != pformat || pformat == LF_SEPARATOR) {
698 switch (pformat) {
699 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100700 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100701 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100702 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100703 case LF_STEXPR:
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100704 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &sp))
Willy Tarreau51013e82019-12-11 12:05:39 +0100705 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100706 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100707 case LF_TEXT:
708 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100709 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100710 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100711 break;
712 }
713 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100714 }
715 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100716
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100717 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100718 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100719 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100720 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100721 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100722
723 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100724 fail:
725 free(backfmt);
726 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100727}
728
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200729/*
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500730 * 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 +0200731 * ranges of indexes. Note that an index may be considered as a particular range
732 * with a high limit to the low limit.
733 */
734int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
735{
736 char *end, *p;
737
738 *low = *high = 0;
739
740 p = *arg;
741 end = strchr(p, ',');
742 if (!end)
743 end = p + strlen(p);
744
745 *high = *low = read_uint((const char **)&p, end);
746 if (!*low || (p != end && *p != '-'))
747 goto err;
748
749 if (p == end)
750 goto done;
751
752 p++;
753 *high = read_uint((const char **)&p, end);
754 if (!*high || *high <= *low || p != end)
755 goto err;
756
757 done:
758 if (*end == ',')
759 end++;
760 *arg = end;
761 return 1;
762
763 err:
764 memprintf(err, "wrong sample range '%s'", *arg);
765 return 0;
766}
767
768/*
769 * Returns 1 if the range defined by <low> and <high> overlaps
770 * one of them in <rgs> array of ranges with <sz> the size of this
771 * array, 0 if not.
772 */
773int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
774 unsigned int low, unsigned int high, char **err)
775{
776 size_t i;
777
778 for (i = 0; i < sz; i++) {
779 if ((low >= rgs[i].low && low <= rgs[i].high) ||
780 (high >= rgs[i].low && high <= rgs[i].high)) {
781 memprintf(err, "ranges are overlapping");
782 return 1;
783 }
784 }
785
786 return 0;
787}
788
789int smp_log_range_cmp(const void *a, const void *b)
790{
791 const struct smp_log_range *rg_a = a;
792 const struct smp_log_range *rg_b = b;
793
794 if (rg_a->high < rg_b->low)
795 return -1;
796 else if (rg_a->low > rg_b->high)
797 return 1;
798
799 return 0;
800}
801
802/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200803 * Parse "log" keyword and update <logsrvs> list accordingly.
804 *
805 * When <do_del> is set, it means the "no log" line was parsed, so all log
806 * servers in <logsrvs> are released.
807 *
808 * Otherwise, we try to parse the "log" line. First of all, when the list is not
809 * the global one, we look for the parameter "global". If we find it,
810 * global.logsrvs is copied. Else we parse each arguments.
811 *
812 * The function returns 1 in success case, otherwise, it returns 0 and err is
813 * filled.
814 */
815int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
816{
817 struct sockaddr_storage *sk;
818 struct logsrv *logsrv = NULL;
819 int port1, port2;
820 int cur_arg;
821
822 /*
823 * "no log": delete previous herited or defined syslog
824 * servers.
825 */
826 if (do_del) {
827 struct logsrv *back;
828
829 if (*(args[1]) != 0) {
830 memprintf(err, "'no log' does not expect arguments");
831 goto error;
832 }
833
834 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
835 LIST_DEL(&logsrv->list);
836 free(logsrv);
837 }
838 return 1;
839 }
840
841 /*
842 * "log global": copy global.logrsvs linked list to the end of logsrvs
843 * list. But first, we check (logsrvs != global.logsrvs).
844 */
845 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
846 if (logsrvs == &global.logsrvs) {
847 memprintf(err, "'global' is not supported for a global syslog server");
848 goto error;
849 }
850 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200851 struct logsrv *node;
852
853 list_for_each_entry(node, logsrvs, list) {
854 if (node->ref == logsrv)
855 goto skip_logsrv;
856 }
857
858 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200859 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200860 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200861 LIST_INIT(&node->list);
862 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200863
864 skip_logsrv:
865 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200866 }
867 return 1;
868 }
869
870 /*
871 * "log <address> ...: parse a syslog server line
872 */
873 if (*(args[1]) == 0 || *(args[2]) == 0) {
874 memprintf(err, "expects <address> and <facility> %s as arguments",
875 ((logsrvs == &global.logsrvs) ? "" : "or global"));
876 goto error;
877 }
878
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100879 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
880 if (strcmp(args[1], "stdout") == 0)
881 args[1] = "fd@1";
882 else if (strcmp(args[1], "stderr") == 0)
883 args[1] = "fd@2";
884
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200885 logsrv = calloc(1, sizeof(*logsrv));
886 if (!logsrv) {
887 memprintf(err, "out of memory");
888 goto error;
889 }
890
891 /* skip address for now, it will be parsed at the end */
892 cur_arg = 2;
893
894 /* just after the address, a length may be specified */
895 logsrv->maxlen = MAX_SYSLOG_LEN;
896 if (strcmp(args[cur_arg], "len") == 0) {
897 int len = atoi(args[cur_arg+1]);
898 if (len < 80 || len > 65535) {
899 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
900 args[cur_arg+1]);
901 goto error;
902 }
903 logsrv->maxlen = len;
904 cur_arg += 2;
905 }
906 if (logsrv->maxlen > global.max_syslog_len)
907 global.max_syslog_len = logsrv->maxlen;
908
909 /* after the length, a format may be specified */
910 if (strcmp(args[cur_arg], "format") == 0) {
911 logsrv->format = get_log_format(args[cur_arg+1]);
912 if (logsrv->format < 0) {
913 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
914 goto error;
915 }
916 cur_arg += 2;
917 }
918
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200919 if (strcmp(args[cur_arg], "sample") == 0) {
920 unsigned low, high;
921 char *p, *beg, *end, *smp_sz_str;
922 struct smp_log_range *smp_rgs = NULL;
923 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
924
925 p = args[cur_arg+1];
926 smp_sz_str = strchr(p, ':');
927 if (!smp_sz_str) {
928 memprintf(err, "Missing sample size");
929 goto error;
930 }
931
932 *smp_sz_str++ = '\0';
933
934 end = p + strlen(p);
935
936 while (p != end) {
937 if (!get_logsrv_smp_range(&low, &high, &p, err))
938 goto error;
939
940 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
941 goto error;
942
943 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
944 if (!smp_rgs) {
945 memprintf(err, "out of memory error");
946 goto error;
947 }
948
949 smp_rgs[smp_rgs_sz].low = low;
950 smp_rgs[smp_rgs_sz].high = high;
951 smp_rgs[smp_rgs_sz].sz = high - low + 1;
952 smp_rgs[smp_rgs_sz].curr_idx = 0;
953 if (smp_rgs[smp_rgs_sz].high > smp_sz)
954 smp_sz = smp_rgs[smp_rgs_sz].high;
955 smp_rgs_sz++;
956 }
957
Tim Duesterhus21648002019-06-23 22:10:10 +0200958 if (smp_rgs == NULL) {
959 memprintf(err, "no sampling ranges given");
960 goto error;
961 }
962
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200963 beg = smp_sz_str;
964 end = beg + strlen(beg);
965 new_smp_sz = read_uint((const char **)&beg, end);
966 if (!new_smp_sz || beg != end) {
967 memprintf(err, "wrong sample size '%s' for sample range '%s'",
968 smp_sz_str, args[cur_arg+1]);
969 goto error;
970 }
971
972 if (new_smp_sz < smp_sz) {
973 memprintf(err, "sample size %zu should be greater or equal to "
974 "%zu the maximum of the high ranges limits",
975 new_smp_sz, smp_sz);
976 goto error;
977 }
978 smp_sz = new_smp_sz;
979
980 /* Let's order <smp_rgs> array. */
981 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
982
983 logsrv->lb.smp_rgs = smp_rgs;
984 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
985 logsrv->lb.smp_sz = smp_sz;
986
987 cur_arg += 2;
988 }
Frédéric Lécailled803e472019-04-25 07:42:09 +0200989 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200990 /* parse the facility */
991 logsrv->facility = get_log_facility(args[cur_arg]);
992 if (logsrv->facility < 0) {
993 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
994 goto error;
995 }
996 cur_arg++;
997
998 /* parse the max syslog level (default: debug) */
999 logsrv->level = 7;
1000 if (*(args[cur_arg])) {
1001 logsrv->level = get_log_level(args[cur_arg]);
1002 if (logsrv->level < 0) {
1003 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
1004 goto error;
1005 }
1006 cur_arg++;
1007 }
1008
1009 /* parse the limit syslog level (default: emerg) */
1010 logsrv->minlvl = 0;
1011 if (*(args[cur_arg])) {
1012 logsrv->minlvl = get_log_level(args[cur_arg]);
1013 if (logsrv->minlvl < 0) {
1014 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
1015 goto error;
1016 }
1017 cur_arg++;
1018 }
1019
1020 /* Too many args */
1021 if (*(args[cur_arg])) {
1022 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1023 goto error;
1024 }
1025
1026 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001027 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001028 if (strncmp(args[1], "ring@", 5) == 0) {
1029 struct sink *sink = sink_find(args[1] + 5);
1030
1031 if (!sink || sink->type != SINK_TYPE_BUFFER) {
1032 memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
1033 goto error;
1034 }
1035
1036 logsrv->addr.ss_family = AF_UNSPEC;
1037 logsrv->type = LOG_TARGET_BUFFER;
1038 logsrv->ring = sink->ctx.ring;
1039 goto done;
1040 }
1041
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001042 if (strncmp(args[1], "fd@", 3) == 0)
1043 logsrv->type = LOG_TARGET_FD;
1044
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001045 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1046 if (!sk)
1047 goto error;
1048 logsrv->addr = *sk;
1049
1050 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1051 if (port1 != port2) {
1052 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1053 goto error;
1054 }
1055 logsrv->addr = *sk;
1056 if (!port1)
1057 set_host_port(&logsrv->addr, SYSLOG_PORT);
1058 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001059 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001060 LIST_ADDQ(logsrvs, &logsrv->list);
1061 return 1;
1062
1063 error:
1064 free(logsrv);
1065 return 0;
1066}
1067
1068
Christopher Fauletd4696382017-10-24 11:44:05 +02001069/* Generic function to display messages prefixed by a label */
1070static void print_message(const char *label, const char *fmt, va_list argp)
1071{
1072 struct tm tm;
1073 char *head, *msg;
1074
1075 head = msg = NULL;
1076
1077 get_localtime(date.tv_sec, &tm);
1078 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1079 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1080 memvprintf(&msg, fmt, argp);
1081
Willy Tarreau869efd52019-11-15 15:16:57 +01001082 if (global.mode & MODE_STARTING) {
1083 if (unlikely(!startup_logs))
1084 startup_logs = ring_new(STARTUP_LOG_SIZE);
1085
1086 if (likely(startup_logs)) {
1087 struct ist m[2];
1088
1089 m[0] = ist(head);
1090 m[1] = ist(msg);
1091 /* trim the trailing '\n' */
1092 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1093 m[1].len--;
1094 ring_write(startup_logs, ~0, 0, 0, m, 2);
1095 }
1096 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001097
1098 fprintf(stderr, "%s%s", head, msg);
1099 fflush(stderr);
1100
1101 free(head);
1102 free(msg);
1103}
1104
Willy Tarreaubaaee002006-06-26 02:48:02 +02001105/*
1106 * Displays the message on stderr with the date and pid. Overrides the quiet
1107 * mode during startup.
1108 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001109void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001110{
1111 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001112
1113 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Willy Tarreaubb869862020-04-16 10:52:41 +02001114 if (!(warned & WARN_EXEC_PATH)) {
1115 const char *path = get_exec_path();
1116
1117 warned |= WARN_EXEC_PATH;
1118 ha_notice("haproxy version is %s\n", haproxy_version);
1119 if (path)
1120 ha_notice("path to executable is %s\n", path);
1121 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001122 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001123 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001124 va_end(argp);
1125 }
1126}
1127
1128
1129/*
1130 * Displays the message on stderr with the date and pid.
1131 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001132void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001133{
1134 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001135
Willy Tarreaubebd2122020-04-15 16:06:11 +02001136 warned |= WARN_ANY;
1137
Willy Tarreaubaaee002006-06-26 02:48:02 +02001138 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1139 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001140 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001141 va_end(argp);
1142 }
1143}
1144
1145/*
William Lallemand9c56a222018-11-21 18:04:52 +01001146 * Displays the message on stderr with the date and pid.
1147 */
1148void ha_notice(const char *fmt, ...)
1149{
1150 va_list argp;
1151
1152 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1153 va_start(argp, fmt);
1154 print_message("NOTICE", fmt, argp);
1155 va_end(argp);
1156 }
1157}
1158
1159/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001160 * Displays the message on <out> only if quiet mode is not set.
1161 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001162void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001163{
1164 va_list argp;
1165
1166 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1167 va_start(argp, fmt);
1168 vfprintf(out, fmt, argp);
1169 fflush(out);
1170 va_end(argp);
1171 }
1172}
1173
1174/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001175 * returns log format for <fmt> or -1 if not found.
1176 */
1177int get_log_format(const char *fmt)
1178{
1179 int format;
1180
1181 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001182 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001183 format--;
1184
1185 return format;
1186}
1187
1188/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001189 * returns log level for <lev> or -1 if not found.
1190 */
1191int get_log_level(const char *lev)
1192{
1193 int level;
1194
1195 level = NB_LOG_LEVELS - 1;
1196 while (level >= 0 && strcmp(log_levels[level], lev))
1197 level--;
1198
1199 return level;
1200}
1201
Willy Tarreaubaaee002006-06-26 02:48:02 +02001202/*
1203 * returns log facility for <fac> or -1 if not found.
1204 */
1205int get_log_facility(const char *fac)
1206{
1207 int facility;
1208
1209 facility = NB_LOG_FACILITIES - 1;
1210 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1211 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001212
Willy Tarreaubaaee002006-06-26 02:48:02 +02001213 return facility;
1214}
1215
William Lallemanda1cc3812012-02-08 16:38:44 +01001216/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001217 * Encode the string.
1218 *
1219 * When using the +E log format option, it will try to escape '"\]'
1220 * characters with '\' as prefix. The same prefix should not be used as
1221 * <escape>.
1222 */
1223static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001224 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001225 const char *string,
1226 struct logformat_node *node)
1227{
1228 if (node->options & LOG_OPT_ESC) {
1229 if (start < stop) {
1230 stop--; /* reserve one byte for the final '\0' */
1231 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001232 if (!ha_bit_test((unsigned char)(*string), map)) {
1233 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001234 *start++ = *string;
1235 else {
1236 if (start + 2 >= stop)
1237 break;
1238 *start++ = '\\';
1239 *start++ = *string;
1240 }
1241 }
1242 else {
1243 if (start + 3 >= stop)
1244 break;
1245 *start++ = escape;
1246 *start++ = hextab[(*string >> 4) & 15];
1247 *start++ = hextab[*string & 15];
1248 }
1249 string++;
1250 }
1251 *start = '\0';
1252 }
1253 }
1254 else {
1255 return encode_string(start, stop, escape, map, string);
1256 }
1257
1258 return start;
1259}
1260
1261/*
1262 * Encode the chunk.
1263 *
1264 * When using the +E log format option, it will try to escape '"\]'
1265 * characters with '\' as prefix. The same prefix should not be used as
1266 * <escape>.
1267 */
1268static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001269 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001270 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001271 struct logformat_node *node)
1272{
1273 char *str, *end;
1274
1275 if (node->options & LOG_OPT_ESC) {
1276 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001277 str = chunk->area;
1278 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001279
1280 stop--; /* reserve one byte for the final '\0' */
1281 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001282 if (!ha_bit_test((unsigned char)(*str), map)) {
1283 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001284 *start++ = *str;
1285 else {
1286 if (start + 2 >= stop)
1287 break;
1288 *start++ = '\\';
1289 *start++ = *str;
1290 }
1291 }
1292 else {
1293 if (start + 3 >= stop)
1294 break;
1295 *start++ = escape;
1296 *start++ = hextab[(*str >> 4) & 15];
1297 *start++ = hextab[*str & 15];
1298 }
1299 str++;
1300 }
1301 *start = '\0';
1302 }
1303 }
1304 else {
1305 return encode_chunk(start, stop, escape, map, chunk);
1306 }
1307
1308 return start;
1309}
1310
1311/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001312 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001313 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001314 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001315 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001316 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001317char *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 +01001318{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001319 if (size < 2)
1320 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001321
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001322 if (node->options & LOG_OPT_QUOTE) {
1323 *(dst++) = '"';
1324 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001325 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001326
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001327 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001328 if (++len > size)
1329 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001330 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001331 char *ret;
1332
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001333 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001334 if (ret == NULL || *ret != '\0')
1335 return NULL;
1336 len = ret - dst;
1337 }
1338 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001339 len = strlcpy2(dst, src, len);
1340 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001341
1342 size -= len;
1343 dst += len;
1344 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001345 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1346 if (size < 2)
1347 return NULL;
1348 *(dst++) = '-';
1349 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001350
1351 if (node->options & LOG_OPT_QUOTE) {
1352 if (size < 2)
1353 return NULL;
1354 *(dst++) = '"';
1355 }
1356
1357 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001358 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001359}
1360
Willy Tarreau26ffa852018-09-05 15:23:10 +02001361static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001362{
1363 return lf_text_len(dst, src, size, size, node);
1364}
1365
William Lallemand5f232402012-04-05 18:02:55 +02001366/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001367 * Write a IP address to the log string
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001368 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001369 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001370char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001371{
1372 char *ret = dst;
1373 int iret;
1374 char pn[INET6_ADDRSTRLEN];
1375
1376 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001377 unsigned char *addr = NULL;
1378 switch (sockaddr->sa_family) {
1379 case AF_INET:
1380 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1381 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1382 break;
1383 case AF_INET6:
1384 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1385 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1386 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1387 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1388 break;
1389 default:
1390 return NULL;
1391 }
William Lallemand5f232402012-04-05 18:02:55 +02001392 if (iret < 0 || iret > size)
1393 return NULL;
1394 ret += iret;
1395 } else {
1396 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1397 ret = lf_text(dst, pn, size, node);
1398 if (ret == NULL)
1399 return NULL;
1400 }
1401 return ret;
1402}
1403
1404/*
1405 * Write a port to the log
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001406 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001407 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001408char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001409{
1410 char *ret = dst;
1411 int iret;
1412
1413 if (node->options & LOG_OPT_HEXA) {
1414 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1415 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1416 if (iret < 0 || iret > size)
1417 return NULL;
1418 ret += iret;
1419 } else {
1420 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1421 if (ret == NULL)
1422 return NULL;
1423 }
1424 return ret;
1425}
1426
Dragan Dosen1322d092015-09-22 16:05:32 +02001427/* Re-generate time-based part of the syslog header in RFC3164 format at
1428 * the beginning of logheader once a second and return the pointer to the
1429 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001430 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001431static char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001432{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001433 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001434 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001435 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001436
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001437 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001438 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001439 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001440 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001441
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001442 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001443 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001444
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001445 if (unlikely(global.log_send_hostname != host.area)) {
1446 host.area = global.log_send_hostname;
1447 host.data = host.area ? strlen(host.area) : 0;
1448 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001449 }
1450
Dragan Dosen59cee972015-09-19 22:09:02 +02001451 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001452 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001453 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001454 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001455 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001456 /* WARNING: depending upon implementations, snprintf may return
1457 * either -1 or the number of bytes that would be needed to store
1458 * the total message. In both cases, we must adjust it.
1459 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001460 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1461 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001462
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001463 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001464 }
1465
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001466 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001467
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001468 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001469}
1470
Dragan Dosen1322d092015-09-22 16:05:32 +02001471/* Re-generate time-based part of the syslog header in RFC5424 format at
1472 * the beginning of logheader_rfc5424 once a second and return the pointer
1473 * to the first character after it.
1474 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001475static char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001476{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001477 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001478 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001479
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001480 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001481 /* this string is rebuild only once a second */
1482 struct tm tm;
1483 int hdr_len;
1484
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001485 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001486 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001487 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001488
1489 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001490 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001491 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001492 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001493 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001494 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001495 /* WARNING: depending upon implementations, snprintf may return
1496 * either -1 or the number of bytes that would be needed to store
1497 * the total message. In both cases, we must adjust it.
1498 */
1499 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1500 hdr_len = global.max_syslog_len;
1501
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001502 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001503 }
1504
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001505 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001506
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001507 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001508}
1509
William Lallemand2a4a44f2012-02-06 16:00:33 +01001510/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001511 * This function sends the syslog message using a printf format string. It
1512 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001513 */
1514void send_log(struct proxy *p, int level, const char *format, ...)
1515{
1516 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001517 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001518
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001519 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001520 return;
1521
William Lallemand2a4a44f2012-02-06 16:00:33 +01001522 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001523 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001524 if (data_len < 0 || data_len > global.max_syslog_len)
1525 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001526 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001527
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001528 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1529 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001530}
1531
1532/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001533 * This function sends a syslog message to <logsrv>.
1534 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1535 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1536 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001537 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001538 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001539 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001540static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1541 int level, char *message, size_t size, char *sd, size_t sd_size,
1542 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001543{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001544 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1545 static THREAD_LOCAL struct msghdr msghdr = {
1546 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001547 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1548 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001549 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1550 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1551 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001552 time_t time = date.tv_sec;
Dragan Dosen1322d092015-09-22 16:05:32 +02001553 char *hdr, *hdr_ptr;
Dragan Dosen59cee972015-09-19 22:09:02 +02001554 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001555 int fac_level;
1556 int *plogfd;
1557 char *pid_sep1 = "", *pid_sep2 = "";
1558 char logheader_short[3];
1559 int sent;
1560 int maxlen;
1561 int hdr_max = 0;
1562 int tag_max = 0;
1563 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001564 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001565 int pid_sep2_max = 0;
1566 int sd_max = 0;
1567 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001568
1569 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001570
1571 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001572
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001573 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001574 /* the socket's address is a file descriptor */
1575 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001576 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001577 else if (logsrv->type == LOG_TARGET_BUFFER) {
1578 plogfd = NULL;
1579 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001580 else if (logsrv->addr.ss_family == AF_UNIX)
1581 plogfd = &logfdunix;
1582 else
1583 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001584
Willy Tarreauc046d162019-08-30 15:24:59 +02001585 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001586 /* socket not successfully initialized yet */
1587 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1588 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1589 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001590
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001591 if (!once) {
1592 once = 1; /* note: no need for atomic ops here */
1593 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1594 nblogger, strerror(errno), errno);
1595 }
1596 return;
1597 } else {
1598 /* we don't want to receive anything on this socket */
1599 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1600 /* does nothing under Linux, maybe needed for others */
1601 shutdown(*plogfd, SHUT_RD);
1602 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1603 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001604 }
1605
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001606 switch (logsrv->format) {
1607 case LOG_FORMAT_RFC3164:
1608 hdr = logheader;
1609 hdr_ptr = update_log_hdr(time);
1610 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001611
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001612 case LOG_FORMAT_RFC5424:
1613 hdr = logheader_rfc5424;
1614 hdr_ptr = update_log_hdr_rfc5424(time);
1615 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1616 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001617
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001618 case LOG_FORMAT_SHORT:
1619 /* all fields are known, skip the header generation */
1620 hdr = logheader_short;
1621 hdr[0] = '<';
1622 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1623 hdr[2] = '>';
1624 hdr_ptr = hdr;
1625 hdr_max = 3;
1626 maxlen = logsrv->maxlen - hdr_max;
1627 max = MIN(size, maxlen) - 1;
1628 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001629
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001630 case LOG_FORMAT_RAW:
1631 /* all fields are known, skip the header generation */
1632 hdr_ptr = hdr = "";
1633 hdr_max = 0;
1634 maxlen = logsrv->maxlen;
1635 max = MIN(size, maxlen) - 1;
1636 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001637
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001638 default:
1639 return; /* must never happen */
1640 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001641
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001642 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001643
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001644 /* For each target, we may have a different facility.
1645 * We can also have a different log level for each message.
1646 * This induces variations in the message header length.
1647 * Since we don't want to recompute it each time, nor copy it every
1648 * time, we only change the facility in the pre-computed header,
1649 * and we change the pointer to the header accordingly.
1650 */
1651 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1652 hdr_ptr = hdr + 3; /* last digit of the log level */
1653 do {
1654 *hdr_ptr = '0' + fac_level % 10;
1655 fac_level /= 10;
1656 hdr_ptr--;
1657 } while (fac_level && hdr_ptr > hdr);
1658 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001659
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001660 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001661
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001662 /* time-based header */
1663 if (unlikely(hdr_size >= logsrv->maxlen)) {
1664 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1665 sd_max = 0;
1666 goto send;
1667 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001668
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001669 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001670
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001671 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001672 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001673 if (unlikely(tag_max >= maxlen)) {
1674 tag_max = maxlen - 1;
1675 sd_max = 0;
1676 goto send;
1677 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001678
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001679 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001680
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001681 /* first pid separator */
1682 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1683 if (unlikely(pid_sep1_max >= maxlen)) {
1684 pid_sep1_max = maxlen - 1;
1685 sd_max = 0;
1686 goto send;
1687 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001688
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001689 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1690 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001691
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001692 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001693 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001694 if (unlikely(pid_size >= maxlen)) {
1695 pid_size = maxlen - 1;
1696 sd_max = 0;
1697 goto send;
1698 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001699
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001700 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001701
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001702 /* second pid separator */
1703 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1704 if (unlikely(pid_sep2_max >= maxlen)) {
1705 pid_sep2_max = maxlen - 1;
1706 sd_max = 0;
1707 goto send;
1708 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001709
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001710 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1711 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001712
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001713 /* structured-data */
1714 if (sd_max >= maxlen) {
1715 sd_max = maxlen - 1;
1716 goto send;
1717 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001718
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001719 max = MIN(size, maxlen - sd_max) - 1;
1720send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001721 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001722 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001723 struct ist msg[7];
1724
1725 msg[0].ptr = hdr_ptr; msg[0].len = hdr_max;
1726 msg[1].ptr = tag_str; msg[1].len = tag_max;
1727 msg[2].ptr = pid_sep1; msg[2].len = pid_sep1_max;
1728 msg[3].ptr = pid_str; msg[3].len = pid_max;
1729 msg[4].ptr = pid_sep2; msg[4].len = pid_sep2_max;
1730 msg[5].ptr = sd; msg[5].len = sd_max;
1731 msg[6].ptr = dataptr; msg[6].len = max;
1732
Willy Tarreauc046d162019-08-30 15:24:59 +02001733 if (logsrv->type == LOG_TARGET_BUFFER)
1734 sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
1735 else /* LOG_TARGET_FD */
1736 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001737 }
1738 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001739 iovec[0].iov_base = hdr_ptr;
1740 iovec[0].iov_len = hdr_max;
1741 iovec[1].iov_base = tag_str;
1742 iovec[1].iov_len = tag_max;
1743 iovec[2].iov_base = pid_sep1;
1744 iovec[2].iov_len = pid_sep1_max;
1745 iovec[3].iov_base = pid_str;
1746 iovec[3].iov_len = pid_max;
1747 iovec[4].iov_base = pid_sep2;
1748 iovec[4].iov_len = pid_sep2_max;
1749 iovec[5].iov_base = sd;
1750 iovec[5].iov_len = sd_max;
1751 iovec[6].iov_base = dataptr;
1752 iovec[6].iov_len = max;
1753 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1754 iovec[7].iov_len = 1;
1755
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001756 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1757 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001758
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001759 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1760 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001761
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001762 if (sent < 0) {
1763 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001764
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001765 if (errno == EAGAIN)
1766 _HA_ATOMIC_ADD(&dropped_logs, 1);
1767 else if (!once) {
1768 once = 1; /* note: no need for atomic ops here */
1769 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1770 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001771 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001772 }
1773}
Dragan Dosen59cee972015-09-19 22:09:02 +02001774
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001775/*
1776 * This function sends a syslog message.
1777 * It doesn't care about errors nor does it report them.
1778 * The arguments <sd> and <sd_size> are used for the structured-data part
1779 * in RFC5424 formatted syslog messages.
1780 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001781void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1782 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001783{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001784 struct logsrv *logsrv;
1785 int nblogger;
1786 static THREAD_LOCAL int curr_pid;
1787 static THREAD_LOCAL char pidstr[100];
1788 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001789
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001790 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001791 if (!LIST_ISEMPTY(&global.logsrvs)) {
1792 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001793 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001794 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001795 if (!tag || !tag->area)
1796 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001797
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001798 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001799 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001800
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001801 if (unlikely(curr_pid != getpid())) {
1802 curr_pid = getpid();
1803 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1804 chunk_initstr(&pid, pidstr);
1805 }
1806
1807 /* Send log messages to syslog server. */
1808 nblogger = 0;
1809 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001810 static THREAD_LOCAL int in_range = 1;
1811
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001812 /* we can filter the level of the messages that are sent to each logger */
1813 if (level > logsrv->level)
1814 continue;
1815
Frédéric Lécailled803e472019-04-25 07:42:09 +02001816 if (logsrv->lb.smp_rgs) {
1817 struct smp_log_range *curr_rg;
1818
1819 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1820 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1821 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1822 if (in_range) {
1823 /* Let's consume this range. */
1824 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1825 if (!curr_rg->curr_idx) {
1826 /* If consumed, let's select the next range. */
1827 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1828 }
1829 }
1830 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1831 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1832 }
1833 if (in_range)
1834 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1835 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001836 }
1837}
1838
1839
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001840const 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 +01001841const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1842 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1843 Set-cookie Updated, unknown, unknown */
1844
William Lallemand1d705562012-03-12 12:46:41 +01001845/*
1846 * try to write a character if there is enough space, or goto out
1847 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001848#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001849 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001850 *(tmplog++) = (x); \
1851 } else { \
1852 goto out; \
1853 } \
1854 } while(0)
1855
Dragan Dosen835b9212016-02-12 13:23:03 +01001856
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001857/* Initializes some log data at boot */
1858static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001859{
1860 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001861 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001862
1863 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1864 * inside PARAM-VALUE should be escaped with '\' as prefix.
1865 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1866 * details.
1867 */
1868 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1869
1870 tmp = "\"\\]";
1871 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001872 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001873 tmp++;
1874 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001875
1876 /* initialize the log header encoding map : '{|}"#' should be encoded with
1877 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1878 * URL encoding only requires '"', '#' to be encoded as well as non-
1879 * printable characters above.
1880 */
1881 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1882 memset(url_encode_map, 0, sizeof(url_encode_map));
1883 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001884 ha_bit_set(i, hdr_encode_map);
1885 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001886 }
1887 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001888 ha_bit_set(i, hdr_encode_map);
1889 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001890 }
1891
1892 tmp = "\"#{|}";
1893 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001894 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001895 tmp++;
1896 }
1897
1898 tmp = "\"#";
1899 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001900 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001901 tmp++;
1902 }
1903
1904 /* initialize the http header encoding map. The draft httpbis define the
1905 * header content as:
1906 *
1907 * HTTP-message = start-line
1908 * *( header-field CRLF )
1909 * CRLF
1910 * [ message-body ]
1911 * header-field = field-name ":" OWS field-value OWS
1912 * field-value = *( field-content / obs-fold )
1913 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1914 * obs-fold = CRLF 1*( SP / HTAB )
1915 * field-vchar = VCHAR / obs-text
1916 * VCHAR = %x21-7E
1917 * obs-text = %x80-FF
1918 *
1919 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1920 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001921 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001922 */
1923 memset(http_encode_map, 0, sizeof(http_encode_map));
1924 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001925 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001926 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001927 ha_bit_set(i, http_encode_map);
1928 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001929}
William Lallemand1d705562012-03-12 12:46:41 +01001930
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001931INITCALL0(STG_PREPARE, init_log);
1932
Christopher Faulet0132d062017-07-26 15:33:35 +02001933/* Initialize log buffers used for syslog messages */
1934int init_log_buffers()
1935{
1936 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001937 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001938 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001939 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001940 logline = my_realloc2(logline, global.max_syslog_len + 1);
1941 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1942 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1943 return 0;
1944 return 1;
1945}
1946
1947/* Deinitialize log buffers used for syslog messages */
1948void deinit_log_buffers()
1949{
1950 free(logheader);
1951 free(logheader_rfc5424);
1952 free(logline);
1953 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001954 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001955 logheader = NULL;
1956 logheader_rfc5424 = NULL;
1957 logline = NULL;
1958 logline_rfc5424 = NULL;
1959}
1960
Willy Tarreaudf974472012-12-28 02:44:01 +01001961/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1962 * <maxsize> characters. Returns the size of the output string in characters,
1963 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001964 * is not zero. It requires a valid session and optionally a stream. If the
1965 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001966 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001967int 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 +02001968{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001969 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001970 struct proxy *be;
1971 struct http_txn *txn;
1972 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001973 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001974 unsigned int s_flags;
1975 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001976 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001977 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001978 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001979 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001980 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001981 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001982 int t_request;
1983 int hdr;
1984 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001985 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001986 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01001987 char *ret;
1988 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001989 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001990 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001991 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001992
William Lallemandbddd4fd2012-02-27 11:23:10 +01001993 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001994
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001995 if (likely(s)) {
1996 be = s->be;
1997 txn = s->txn;
1998 be_conn = cs_conn(objt_cs(s->si[1].end));
1999 s_flags = s->flags;
2000 uniq_id = s->uniq_id;
2001 logs = &s->logs;
2002 } else {
2003 /* we have no stream so we first need to initialize a few
2004 * things that are needed later. We do increment the request
2005 * ID so that it's uniquely assigned to this request just as
2006 * if the request had reached the point of being processed.
2007 * A request error is reported as it's the only element we have
2008 * here and which justifies emitting such a log.
2009 */
2010 be = fe;
2011 txn = NULL;
2012 be_conn = NULL;
2013 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002014 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002015
2016 /* prepare a valid log structure */
2017 tmp_strm_log.tv_accept = sess->tv_accept;
2018 tmp_strm_log.accept_date = sess->accept_date;
2019 tmp_strm_log.t_handshake = sess->t_handshake;
2020 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
2021 tv_zero(&tmp_strm_log.tv_request);
2022 tmp_strm_log.t_queue = -1;
2023 tmp_strm_log.t_connect = -1;
2024 tmp_strm_log.t_data = -1;
2025 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2026 tmp_strm_log.bytes_in = 0;
2027 tmp_strm_log.bytes_out = 0;
2028 tmp_strm_log.prx_queue_pos = 0;
2029 tmp_strm_log.srv_queue_pos = 0;
2030
2031 logs = &tmp_strm_log;
2032 }
2033
William Lallemandbddd4fd2012-02-27 11:23:10 +01002034 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002035 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2036 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002037
William Lallemand1d705562012-03-12 12:46:41 +01002038 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002039
William Lallemandbddd4fd2012-02-27 11:23:10 +01002040 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002041 if (LIST_ISEMPTY(list_format))
2042 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002043
William Lallemand1d705562012-03-12 12:46:41 +01002044 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002045 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002046 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002047 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002048 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002049
Willy Tarreauc8368452012-12-21 00:09:23 +01002050 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002051 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002052 if (!last_isspace) {
2053 LOGCHAR(' ');
2054 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002055 }
2056 break;
2057
William Lallemand1d705562012-03-12 12:46:41 +01002058 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002059 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002060 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002061 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002062 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002063 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002064 last_isspace = 0;
2065 break;
2066
Willy Tarreauc8368452012-12-21 00:09:23 +01002067 case LOG_FMT_EXPR: // sample expression, may be request or response
2068 key = NULL;
Christopher Faulet5f940702020-04-06 10:40:02 +02002069 if (tmp->options & LOG_OPT_REQ_CAP)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002070 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 +02002071 if (!key && (tmp->options & LOG_OPT_RES_CAP))
Adis Nezirovic79beb242015-07-06 15:41:02 +02002072 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 +01002073 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002074 ret = lf_encode_chunk(tmplog, dst + maxsize,
2075 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002076 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002077 ret = lf_text_len(tmplog,
2078 key ? key->data.u.str.area : NULL,
2079 key ? key->data.u.str.data : 0,
2080 dst + maxsize - tmplog,
2081 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002082 if (ret == 0)
2083 goto out;
2084 tmplog = ret;
2085 last_isspace = 0;
2086 break;
2087
Willy Tarreau2beef582012-12-20 17:22:52 +01002088 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002089 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002090 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002091 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002092 else
2093 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002094 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002095 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002096 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002097 last_isspace = 0;
2098 break;
2099
Willy Tarreau2beef582012-12-20 17:22:52 +01002100 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002101 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002102 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002103 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002104 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002105 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002106 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002107 dst + maxsize - tmplog, tmp);
2108 }
William Lallemand5f232402012-04-05 18:02:55 +02002109 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002110 else
2111 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2112
William Lallemand5f232402012-04-05 18:02:55 +02002113 if (ret == NULL)
2114 goto out;
2115 tmplog = ret;
2116 last_isspace = 0;
2117 break;
2118
Willy Tarreau2beef582012-12-20 17:22:52 +01002119 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002120 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002121 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002122 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002123 }
2124 else
2125 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2126
William Lallemand1d705562012-03-12 12:46:41 +01002127 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002128 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002129 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002130 last_isspace = 0;
2131 break;
2132
Willy Tarreau2beef582012-12-20 17:22:52 +01002133 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002134 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002135 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002136 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002137 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002138 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002139 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002140 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002141 else
2142 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2143
William Lallemand5f232402012-04-05 18:02:55 +02002144 if (ret == NULL)
2145 goto out;
2146 tmplog = ret;
2147 last_isspace = 0;
2148 break;
2149
Willy Tarreau2beef582012-12-20 17:22:52 +01002150 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002151 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002152 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002153 else
2154 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2155
William Lallemand1d705562012-03-12 12:46:41 +01002156 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002157 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002158 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002159 last_isspace = 0;
2160 break;
2161
Willy Tarreau2beef582012-12-20 17:22:52 +01002162 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002163 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002164 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002165 else
2166 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2167
William Lallemand5f232402012-04-05 18:02:55 +02002168 if (ret == NULL)
2169 goto out;
2170 tmplog = ret;
2171 last_isspace = 0;
2172 break;
2173
Willy Tarreau2beef582012-12-20 17:22:52 +01002174 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002175 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002176 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002177 else
2178 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2179
William Lallemand5f232402012-04-05 18:02:55 +02002180 if (ret == NULL)
2181 goto out;
2182 tmplog = ret;
2183 last_isspace = 0;
2184 break;
2185
Willy Tarreau2beef582012-12-20 17:22:52 +01002186 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002187 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002188 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002189 else
2190 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2191
William Lallemand1d705562012-03-12 12:46:41 +01002192 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002193 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002194 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002195 last_isspace = 0;
2196 break;
2197
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002198 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002199 get_localtime(logs->accept_date.tv_sec, &tm);
2200 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002201 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002202 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002203 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002204 last_isspace = 0;
2205 break;
2206
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002207 case LOG_FMT_tr: // %tr = start of request date
2208 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002209 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 +02002210 get_localtime(tv.tv_sec, &tm);
2211 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2212 if (ret == NULL)
2213 goto out;
2214 tmplog = ret;
2215 last_isspace = 0;
2216 break;
2217
2218 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002219 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002220 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002221 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002222 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002223 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002224 last_isspace = 0;
2225 break;
2226
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002227 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002228 tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002229 get_gmtime(tv.tv_sec, &tm);
2230 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2231 if (ret == NULL)
2232 goto out;
2233 tmplog = ret;
2234 last_isspace = 0;
2235 break;
2236
2237 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002238 get_localtime(logs->accept_date.tv_sec, &tm);
2239 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002240 if (ret == NULL)
2241 goto out;
2242 tmplog = ret;
2243 last_isspace = 0;
2244 break;
2245
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002246 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002247 tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002248 get_localtime(tv.tv_sec, &tm);
2249 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2250 if (ret == NULL)
2251 goto out;
2252 tmplog = ret;
2253 last_isspace = 0;
2254 break;
2255
William Lallemand5f232402012-04-05 18:02:55 +02002256 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002257 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002258 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002259 if (iret < 0 || iret > dst + maxsize - tmplog)
2260 goto out;
2261 last_isspace = 0;
2262 tmplog += iret;
2263 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002264 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002265 if (ret == NULL)
2266 goto out;
2267 tmplog = ret;
2268 last_isspace = 0;
2269 }
2270 break;
2271
William Lallemand1d705562012-03-12 12:46:41 +01002272 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002273 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002274 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002275 if (iret < 0 || iret > dst + maxsize - tmplog)
2276 goto out;
2277 last_isspace = 0;
2278 tmplog += iret;
2279 } else {
2280 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002281 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002282 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002283 tmplog, 4);
2284 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002285 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002286 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002287 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002288 }
2289 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002290
William Lallemand1d705562012-03-12 12:46:41 +01002291 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002292 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002293 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002294 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002295 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002296 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002297 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002298 break;
2299
Willy Tarreau773d65f2012-10-12 14:56:11 +02002300 case LOG_FMT_FRONTEND_XPRT: // %ft
2301 src = fe->id;
2302 if (tmp->options & LOG_OPT_QUOTE)
2303 LOGCHAR('"');
2304 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2305 if (iret == 0)
2306 goto out;
2307 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002308 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002309 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002310 if (tmp->options & LOG_OPT_QUOTE)
2311 LOGCHAR('"');
2312 last_isspace = 0;
2313 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002314#ifdef USE_OPENSSL
2315 case LOG_FMT_SSL_CIPHER: // %sslc
2316 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002317 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002318 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002319 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002320 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002321 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2322 if (ret == NULL)
2323 goto out;
2324 tmplog = ret;
2325 last_isspace = 0;
2326 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002327
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002328 case LOG_FMT_SSL_VERSION: // %sslv
2329 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002330 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002331 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002332 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002333 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002334 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2335 if (ret == NULL)
2336 goto out;
2337 tmplog = ret;
2338 last_isspace = 0;
2339 break;
2340#endif
William Lallemand1d705562012-03-12 12:46:41 +01002341 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002342 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002343 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002344 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002345 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002346 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002347 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002348 break;
2349
William Lallemand1d705562012-03-12 12:46:41 +01002350 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002351 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002352 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002353 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002354 break;
2355 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002356 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002357 break;
2358 default:
2359 src = "<NOSRV>";
2360 break;
2361 }
William Lallemand5f232402012-04-05 18:02:55 +02002362 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002363 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002364 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002365 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002366 last_isspace = 0;
2367 break;
2368
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002369 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002370 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002371 if (ret == NULL)
2372 goto out;
2373 tmplog = ret;
2374 last_isspace = 0;
2375 break;
2376
2377 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002378 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002379 if (ret == NULL)
2380 goto out;
2381 tmplog = ret;
2382 last_isspace = 0;
2383 break;
2384
2385 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002386 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002387 tmplog, dst + maxsize - tmplog);
2388 if (ret == NULL)
2389 goto out;
2390 tmplog = ret;
2391 last_isspace = 0;
2392 break;
2393
2394 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002395 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002396 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002397 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002398 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002399 last_isspace = 0;
2400 break;
2401
William Lallemand1d705562012-03-12 12:46:41 +01002402 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002403 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002404 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002405 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002406 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002407 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002408 last_isspace = 0;
2409 break;
2410
William Lallemand1d705562012-03-12 12:46:41 +01002411 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002412 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002413 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002414 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002415 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002416 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002417 last_isspace = 0;
2418 break;
2419
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002420 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002421 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002422 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002423 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002424 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002425 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002426 last_isspace = 0;
2427 break;
2428
Willy Tarreau27b639d2016-05-17 17:55:27 +02002429 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002430 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002431 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002432 tmplog, dst + maxsize - tmplog);
2433 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002434 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002435 tmplog, dst + maxsize - tmplog);
2436 if (ret == NULL)
2437 goto out;
2438 tmplog = ret;
2439 last_isspace = 0;
2440 break;
2441
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002442 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2443 if (!(fe->to_log & LW_BYTES))
2444 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002445 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 +02002446 tmplog, dst + maxsize - tmplog);
2447 if (ret == NULL)
2448 goto out;
2449 tmplog = ret;
2450 last_isspace = 0;
2451 break;
2452
2453 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002454 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002455 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002456 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002457 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002458 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002459 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002460 last_isspace = 0;
2461 break;
2462
Willy Tarreau2beef582012-12-20 17:22:52 +01002463 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002464 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002465 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002466 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002467 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002468 last_isspace = 0;
2469 break;
2470
William Lallemand1d705562012-03-12 12:46:41 +01002471 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002472 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002473 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002474 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002475 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002476 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002477 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002478 last_isspace = 0;
2479 break;
2480
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002481 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002482 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002483 if (ret == NULL)
2484 goto out;
2485 tmplog = ret;
2486 last_isspace = 0;
2487 break;
2488
Willy Tarreau2beef582012-12-20 17:22:52 +01002489 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002490 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002491 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002492 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002493 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002494 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002495 last_isspace = 0;
2496 break;
2497
Willy Tarreau2beef582012-12-20 17:22:52 +01002498 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002499 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002500 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002501 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002502 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002503 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002504 last_isspace = 0;
2505 break;
2506
William Lallemand1d705562012-03-12 12:46:41 +01002507 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002508 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2509 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002510 *tmplog = '\0';
2511 last_isspace = 0;
2512 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002513
William Lallemand1d705562012-03-12 12:46:41 +01002514 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002515 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2516 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002517 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2518 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 +01002519 last_isspace = 0;
2520 break;
2521
William Lallemand1d705562012-03-12 12:46:41 +01002522 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002523 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002524 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002525 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
William Lallemand1d705562012-03-12 12:46:41 +01002530 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002531 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002532 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002533 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002534 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002535 last_isspace = 0;
2536 break;
2537
William Lallemand1d705562012-03-12 12:46:41 +01002538 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002539 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002540 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002541 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002542 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002543 last_isspace = 0;
2544 break;
2545
William Lallemand1d705562012-03-12 12:46:41 +01002546 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002547 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002548 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002549 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002550 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002551 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002552 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002553 last_isspace = 0;
2554 break;
2555
William Lallemand1d705562012-03-12 12:46:41 +01002556 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002557 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002558 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002559 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002560 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002561 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002562 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002563 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002564 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002565 last_isspace = 0;
2566 break;
2567
William Lallemand1d705562012-03-12 12:46:41 +01002568 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002569 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002570 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002571 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002572 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002573 last_isspace = 0;
2574 break;
2575
William Lallemand1d705562012-03-12 12:46:41 +01002576 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002577 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002578 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002579 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002580 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002581 last_isspace = 0;
2582 break;
2583
William Lallemand1d705562012-03-12 12:46:41 +01002584 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002585 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002586 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002587 if (tmp->options & LOG_OPT_QUOTE)
2588 LOGCHAR('"');
2589 LOGCHAR('{');
2590 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2591 if (hdr)
2592 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002593 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002594 ret = lf_encode_string(tmplog, dst + maxsize,
2595 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002596 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002597 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002598 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002599 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002600 }
2601 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002602 if (tmp->options & LOG_OPT_QUOTE)
2603 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002604 last_isspace = 0;
2605 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002606 break;
2607
William Lallemand1d705562012-03-12 12:46:41 +01002608 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002609 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002610 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002611 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2612 if (hdr > 0)
2613 LOGCHAR(' ');
2614 if (tmp->options & LOG_OPT_QUOTE)
2615 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002616 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002617 ret = lf_encode_string(tmplog, dst + maxsize,
2618 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002619 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002620 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002621 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002622 } else if (!(tmp->options & LOG_OPT_QUOTE))
2623 LOGCHAR('-');
2624 if (tmp->options & LOG_OPT_QUOTE)
2625 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002626 last_isspace = 0;
2627 }
2628 }
2629 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002630
William Lallemand1d705562012-03-12 12:46:41 +01002631
2632 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002633 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002634 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002635 if (tmp->options & LOG_OPT_QUOTE)
2636 LOGCHAR('"');
2637 LOGCHAR('{');
2638 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2639 if (hdr)
2640 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002641 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002642 ret = lf_encode_string(tmplog, dst + maxsize,
2643 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002644 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002645 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002646 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002647 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002648 }
2649 LOGCHAR('}');
2650 last_isspace = 0;
2651 if (tmp->options & LOG_OPT_QUOTE)
2652 LOGCHAR('"');
2653 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002654 break;
2655
William Lallemand1d705562012-03-12 12:46:41 +01002656 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002657 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002658 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002659 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2660 if (hdr > 0)
2661 LOGCHAR(' ');
2662 if (tmp->options & LOG_OPT_QUOTE)
2663 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002664 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002665 ret = lf_encode_string(tmplog, dst + maxsize,
2666 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002667 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002668 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002669 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002670 } else if (!(tmp->options & LOG_OPT_QUOTE))
2671 LOGCHAR('-');
2672 if (tmp->options & LOG_OPT_QUOTE)
2673 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002674 last_isspace = 0;
2675 }
2676 }
2677 break;
2678
William Lallemand1d705562012-03-12 12:46:41 +01002679 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002680 /* Request */
2681 if (tmp->options & LOG_OPT_QUOTE)
2682 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002683 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002684 ret = lf_encode_string(tmplog, dst + maxsize,
2685 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002686 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002687 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002688 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002689 if (tmp->options & LOG_OPT_QUOTE)
2690 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002691 last_isspace = 0;
2692 break;
William Lallemand5f232402012-04-05 18:02:55 +02002693
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002694 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002695 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002696
Willy Tarreaub7636d12015-06-17 19:58:02 +02002697 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002698 LOGCHAR('"');
2699
2700 end = uri + strlen(uri);
2701 // look for the first whitespace character
2702 while (uri < end && !HTTP_IS_SPHT(*uri))
2703 uri++;
2704
2705 // keep advancing past multiple spaces
2706 while (uri < end && HTTP_IS_SPHT(*uri)) {
2707 uri++; nspaces++;
2708 }
2709
2710 // look for first space or question mark after url
2711 spc = uri;
2712 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2713 spc++;
2714
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002715 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002716 chunk.area = "<BADREQ>";
2717 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002718 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002719 chunk.area = uri;
2720 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002721 }
2722
Dragan Dosen835b9212016-02-12 13:23:03 +01002723 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002724 if (ret == NULL || *ret != '\0')
2725 goto out;
2726
2727 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002728 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002729 LOGCHAR('"');
2730
2731 last_isspace = 0;
2732 break;
2733
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002734 case LOG_FMT_HTTP_QUERY: // %HQ
2735 if (tmp->options & LOG_OPT_QUOTE)
2736 LOGCHAR('"');
2737
Willy Tarreau57bc8912016-04-25 17:09:40 +02002738 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002739 chunk.area = "<BADREQ>";
2740 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002741 } else {
2742 uri = txn->uri;
2743 end = uri + strlen(uri);
2744 // look for the first question mark
2745 while (uri < end && *uri != '?')
2746 uri++;
2747
2748 qmark = uri;
2749 // look for first space or question mark after url
2750 while (uri < end && !HTTP_IS_SPHT(*uri))
2751 uri++;
2752
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002753 chunk.area = qmark;
2754 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002755 }
2756
Dragan Dosen835b9212016-02-12 13:23:03 +01002757 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002758 if (ret == NULL || *ret != '\0')
2759 goto out;
2760
2761 tmplog = ret;
2762 if (tmp->options & LOG_OPT_QUOTE)
2763 LOGCHAR('"');
2764
2765 last_isspace = 0;
2766 break;
2767
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002768 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002769 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002770
Willy Tarreaub7636d12015-06-17 19:58:02 +02002771 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002772 LOGCHAR('"');
2773
2774 end = uri + strlen(uri);
2775 // look for the first whitespace character
2776 while (uri < end && !HTTP_IS_SPHT(*uri))
2777 uri++;
2778
2779 // keep advancing past multiple spaces
2780 while (uri < end && HTTP_IS_SPHT(*uri)) {
2781 uri++; nspaces++;
2782 }
2783
2784 // look for first space after url
2785 spc = uri;
2786 while (spc < end && !HTTP_IS_SPHT(*spc))
2787 spc++;
2788
Willy Tarreau57bc8912016-04-25 17:09:40 +02002789 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002790 chunk.area = "<BADREQ>";
2791 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002792 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002793 chunk.area = uri;
2794 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002795 }
2796
Dragan Dosen835b9212016-02-12 13:23:03 +01002797 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002798 if (ret == NULL || *ret != '\0')
2799 goto out;
2800
2801 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002802 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002803 LOGCHAR('"');
2804
2805 last_isspace = 0;
2806 break;
2807
2808 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002809 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002810 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002811 LOGCHAR('"');
2812
2813 end = uri + strlen(uri);
2814 // look for the first whitespace character
2815 spc = uri;
2816 while (spc < end && !HTTP_IS_SPHT(*spc))
2817 spc++;
2818
2819 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002820 chunk.area = "<BADREQ>";
2821 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002822 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002823 chunk.area = uri;
2824 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002825 }
2826
Dragan Dosen835b9212016-02-12 13:23:03 +01002827 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002828 if (ret == NULL || *ret != '\0')
2829 goto out;
2830
2831 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002832 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002833 LOGCHAR('"');
2834
2835 last_isspace = 0;
2836 break;
2837
2838 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002839 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002840 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002841 LOGCHAR('"');
2842
2843 end = uri + strlen(uri);
2844 // look for the first whitespace character
2845 while (uri < end && !HTTP_IS_SPHT(*uri))
2846 uri++;
2847
2848 // keep advancing past multiple spaces
2849 while (uri < end && HTTP_IS_SPHT(*uri)) {
2850 uri++; nspaces++;
2851 }
2852
2853 // look for the next whitespace character
2854 while (uri < end && !HTTP_IS_SPHT(*uri))
2855 uri++;
2856
2857 // keep advancing past multiple spaces
2858 while (uri < end && HTTP_IS_SPHT(*uri))
2859 uri++;
2860
Willy Tarreau57bc8912016-04-25 17:09:40 +02002861 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002862 chunk.area = "<BADREQ>";
2863 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002864 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002865 chunk.area = "HTTP/0.9";
2866 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002867 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002868 chunk.area = uri;
2869 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002870 }
2871
Dragan Dosen835b9212016-02-12 13:23:03 +01002872 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002873 if (ret == NULL || *ret != '\0')
2874 goto out;
2875
2876 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002877 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002878 LOGCHAR('"');
2879
2880 last_isspace = 0;
2881 break;
2882
William Lallemand5f232402012-04-05 18:02:55 +02002883 case LOG_FMT_COUNTER: // %rt
2884 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002885 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002886 if (iret < 0 || iret > dst + maxsize - tmplog)
2887 goto out;
2888 last_isspace = 0;
2889 tmplog += iret;
2890 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002891 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002892 if (ret == NULL)
2893 goto out;
2894 tmplog = ret;
2895 last_isspace = 0;
2896 }
2897 break;
2898
Willy Tarreau7346acb2014-08-28 15:03:15 +02002899 case LOG_FMT_LOGCNT: // %lc
2900 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002901 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002902 if (iret < 0 || iret > dst + maxsize - tmplog)
2903 goto out;
2904 last_isspace = 0;
2905 tmplog += iret;
2906 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002907 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002908 if (ret == NULL)
2909 goto out;
2910 tmplog = ret;
2911 last_isspace = 0;
2912 }
2913 break;
2914
William Lallemand5f232402012-04-05 18:02:55 +02002915 case LOG_FMT_HOSTNAME: // %H
2916 src = hostname;
2917 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2918 if (ret == NULL)
2919 goto out;
2920 tmplog = ret;
2921 last_isspace = 0;
2922 break;
2923
2924 case LOG_FMT_PID: // %pid
2925 if (tmp->options & LOG_OPT_HEXA) {
2926 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2927 if (iret < 0 || iret > dst + maxsize - tmplog)
2928 goto out;
2929 last_isspace = 0;
2930 tmplog += iret;
2931 } else {
2932 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2933 if (ret == NULL)
2934 goto out;
2935 tmplog = ret;
2936 last_isspace = 0;
2937 }
2938 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002939
2940 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002941 ret = NULL;
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002942 if (s)
2943 ret = lf_text_len(tmplog, s->unique_id.ptr, s->unique_id.len, maxsize - (tmplog - dst), tmp);
2944 else
2945 ret = lf_text_len(tmplog, NULL, 0, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002946 if (ret == NULL)
2947 goto out;
2948 tmplog = ret;
2949 last_isspace = 0;
2950 break;
2951
William Lallemandbddd4fd2012-02-27 11:23:10 +01002952 }
2953 }
2954
2955out:
William Lallemand1d705562012-03-12 12:46:41 +01002956 /* *tmplog is a unused character */
2957 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002958 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002959
Willy Tarreaubaaee002006-06-26 02:48:02 +02002960}
2961
William Lallemand1d705562012-03-12 12:46:41 +01002962/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002963 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002964 * Will not log if the frontend has no log defined.
2965 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002966void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002967{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002968 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002969 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002970 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01002971
2972 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02002973 err = (s->flags & SF_REDISP) ||
2974 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2975 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01002976 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02002977 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002978
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002979 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01002980 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002981
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002982 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01002983 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002984
Willy Tarreauabcd5142013-06-11 17:18:02 +02002985 if (s->logs.level) { /* loglevel was overridden */
2986 if (s->logs.level == -1) {
2987 s->logs.logwait = 0; /* logs disabled */
2988 return;
2989 }
2990 level = s->logs.level - 1;
2991 }
2992 else {
2993 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002994 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02002995 level = LOG_ERR;
2996 }
William Lallemand1d705562012-03-12 12:46:41 +01002997
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002998 /* if unique-id was not generated */
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002999 if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Tim Duesterhus2825b4b2020-02-28 15:13:34 +01003000 stream_generate_unique_id(s, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003001 }
3002
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003003 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3004 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
3005 &sess->fe->logformat_sd);
3006 }
3007
Dragan Dosen59cee972015-09-19 22:09:02 +02003008 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01003009 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003010 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003011 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3012 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01003013 s->logs.logwait = 0;
3014 }
3015}
William Lallemandbddd4fd2012-02-27 11:23:10 +01003016
Willy Tarreau53839352018-09-05 19:51:10 +02003017/*
3018 * send a minimalist log for the session. Will not log if the frontend has no
3019 * log defined. It is assumed that this is only used to report anomalies that
3020 * cannot lead to the creation of a regular stream. Because of this the log
3021 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
3022 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003023 * function to report unimportant events. It is safe to call this function with
3024 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02003025 */
3026void sess_log(struct session *sess)
3027{
3028 int size, level;
3029 int sd_size = 0;
3030
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003031 if (!sess)
3032 return;
3033
Willy Tarreau53839352018-09-05 19:51:10 +02003034 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3035 return;
3036
3037 level = LOG_INFO;
3038 if (sess->fe->options2 & PR_O2_LOGERRORS)
3039 level = LOG_ERR;
3040
3041 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3042 sd_size = sess_build_logline(sess, NULL,
3043 logline_rfc5424, global.max_syslog_len,
3044 &sess->fe->logformat_sd);
3045 }
3046
3047 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3048 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003049 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003050 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3051 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003052 }
3053}
3054
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003055void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3056{
3057 va_list argp;
3058 int data_len;
3059
3060 if (level < 0 || format == NULL || logline == NULL)
3061 return;
3062
3063 va_start(argp, format);
3064 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3065 if (data_len < 0 || data_len > global.max_syslog_len)
3066 data_len = global.max_syslog_len;
3067 va_end(argp);
3068
3069 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3070}
3071
Willy Tarreau869efd52019-11-15 15:16:57 +01003072/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3073static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003074{
Willy Tarreau869efd52019-11-15 15:16:57 +01003075 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3076 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003077
Willy Tarreau869efd52019-11-15 15:16:57 +01003078 if (!startup_logs)
3079 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3080
3081 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003082}
3083
3084/* register cli keywords */
3085static struct cli_kw_list cli_kws = {{ },{
3086 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003087 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003088 {{},}
3089}};
3090
Willy Tarreau0108d902018-11-25 19:14:37 +01003091INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3092
Willy Tarreau082b6282019-05-22 14:42:12 +02003093REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3094REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003095
Willy Tarreaubaaee002006-06-26 02:48:02 +02003096/*
3097 * Local variables:
3098 * c-indent-level: 8
3099 * c-basic-offset: 8
3100 * End:
3101 */