blob: c4e0082860f40e2e2337064147d58d4ad86ea95c [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 Tarreaubaaee002006-06-26 02:48:02 +020032
Christopher Fauletc1b730a2017-10-24 12:00:51 +020033#include <types/cli.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020034#include <types/global.h>
William Lallemand723b73a2012-02-08 16:37:49 +010035#include <types/log.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020036
Christopher Fauletc1b730a2017-10-24 12:00:51 +020037#include <proto/applet.h>
38#include <proto/cli.h>
Willy Tarreaud52a7f82019-08-30 14:05:35 +020039#include <proto/fd.h>
William Lallemand5f232402012-04-05 18:02:55 +020040#include <proto/frontend.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020041#include <proto/log.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020042#include <proto/ring.h>
Willy Tarreauc8368452012-12-21 00:09:23 +010043#include <proto/sample.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020044#include <proto/sink.h>
Willy Tarreauc125cef2019-05-10 09:58:43 +020045#include <proto/ssl_sock.h>
Willy Tarreaufb0afa72015-04-03 14:46:27 +020046#include <proto/stream.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010047#include <proto/stream_interface.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020048
Dragan Dosen43885c72015-10-01 13:18:13 +020049struct log_fmt {
50 char *name;
51 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020052 struct buffer sep1; /* first pid separator */
53 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020054 } pid;
55};
56
57static const struct log_fmt log_formats[LOG_FORMATS] = {
58 [LOG_FORMAT_RFC3164] = {
59 .name = "rfc3164",
60 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020061 .sep1 = { .area = "[", .data = 1 },
62 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020063 }
64 },
65 [LOG_FORMAT_RFC5424] = {
66 .name = "rfc5424",
67 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020068 .sep1 = { .area = " ", .data = 1 },
69 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020070 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010071 },
72 [LOG_FORMAT_SHORT] = {
73 .name = "short",
74 .pid = {
75 .sep1 = { .area = "", .data = 0 },
76 .sep2 = { .area = " ", .data = 1 },
77 }
78 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010079 [LOG_FORMAT_RAW] = {
80 .name = "raw",
81 .pid = {
82 .sep1 = { .area = "", .data = 0 },
83 .sep2 = { .area = "", .data = 0 },
84 }
85 },
Dragan Dosen1322d092015-09-22 16:05:32 +020086};
87
Dragan Dosen835b9212016-02-12 13:23:03 +010088/*
89 * This map is used with all the FD_* macros to check whether a particular bit
Willy Tarreau1bfd6022019-06-07 11:10:07 +020090 * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
91 * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
92 * that the byte should be escaped. Be careful to always pass bytes from 0 to
93 * 255 exclusively to the macros.
Dragan Dosen835b9212016-02-12 13:23:03 +010094 */
Willy Tarreau1bfd6022019-06-07 11:10:07 +020095long rfc5424_escape_map[(256/8) / sizeof(long)];
96long hdr_encode_map[(256/8) / sizeof(long)];
97long url_encode_map[(256/8) / sizeof(long)];
98long http_encode_map[(256/8) / sizeof(long)];
Dragan Dosen835b9212016-02-12 13:23:03 +010099
Dragan Dosen835b9212016-02-12 13:23:03 +0100100
Willy Tarreaubaaee002006-06-26 02:48:02 +0200101const char *log_facilities[NB_LOG_FACILITIES] = {
102 "kern", "user", "mail", "daemon",
103 "auth", "syslog", "lpr", "news",
104 "uucp", "cron", "auth2", "ftp",
105 "ntp", "audit", "alert", "cron2",
106 "local0", "local1", "local2", "local3",
107 "local4", "local5", "local6", "local7"
108};
109
Willy Tarreaubaaee002006-06-26 02:48:02 +0200110const char *log_levels[NB_LOG_LEVELS] = {
111 "emerg", "alert", "crit", "err",
112 "warning", "notice", "info", "debug"
113};
114
Willy Tarreau570f2212013-06-10 16:42:09 +0200115const 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 +0200116const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200117
William Lallemand723b73a2012-02-08 16:37:49 +0100118
119/* log_format */
120struct logformat_type {
121 char *name;
122 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100123 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200124 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100125 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100126 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100127};
128
William Lallemandb7ff6a32012-03-02 14:35:21 +0100129int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
130
William Lallemand723b73a2012-02-08 16:37:49 +0100131/* log_format variable names */
132static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200133 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100134
135 /* please keep these lines sorted ! */
136 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
137 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
138 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
139 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
140 { "ID", LOG_FMT_UNIQUEID, PR_MODE_HTTP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200141 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200142 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200143 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100144 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200145 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
146 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
147 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
148 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
149 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
150 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200151 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100152 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200153 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Willy Tarreau2beef582012-12-20 17:22:52 +0100154 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
155 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200156 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100157 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200158 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100159 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
160 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200161 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200162 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
163 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100164 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
165 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200166 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
167 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100168 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200169 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
170 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
171 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
172 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000173 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
174 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000175 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000176 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
177 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200178 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100179 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200180 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100181 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
182 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100183 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100184 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
185 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
186 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
187 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
188 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200189 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
190 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100191 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200192 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
193 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
194 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100195 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
196 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
197
198 /* The following tags are deprecated and will be removed soon */
199 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
200 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200201 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
202 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
203 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
204 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100205 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
206 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
207 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
208 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
209 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200210 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100211};
212
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200213char 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
214char 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 +0100215char 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 +0100216char *log_format = NULL;
217
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200218/* Default string used for structured-data part in RFC5424 formatted
219 * syslog messages.
220 */
221char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200222
Willy Tarreau13ef7732018-11-12 07:25:28 +0100223/* total number of dropped logs */
224unsigned int dropped_logs = 0;
225
Dragan Dosen1322d092015-09-22 16:05:32 +0200226/* This is a global syslog header, common to all outgoing messages in
227 * RFC3164 format. It begins with time-based part and is updated by
228 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200229 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200230THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200231THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200232
Dragan Dosen1322d092015-09-22 16:05:32 +0200233/* This is a global syslog header for messages in RFC5424 format. It is
234 * updated by update_log_hdr_rfc5424().
235 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200236THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200237THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200238
Dragan Dosen59cee972015-09-19 22:09:02 +0200239/* This is a global syslog message buffer, common to all outgoing
240 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100241 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200242THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100243
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200244/* A global syslog message buffer, common to all RFC5424 syslog messages.
245 * Currently, it is used for generating the structured-data part.
246 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200247THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200248
Christopher Fauletd4696382017-10-24 11:44:05 +0200249/* A global buffer used to store all startup alerts/warnings. It will then be
250 * retrieve on the CLI. */
Willy Tarreau869efd52019-11-15 15:16:57 +0100251static struct ring *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200252
William Lallemand723b73a2012-02-08 16:37:49 +0100253struct logformat_var_args {
254 char *name;
255 int mask;
256};
257
258struct logformat_var_args var_args_list[] = {
259// global
260 { "M", LOG_OPT_MANDATORY },
261 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200262 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100263 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100264 { 0, 0 }
265};
266
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200267/* return the name of the directive used in the current proxy for which we're
268 * currently parsing a header, when it is known.
269 */
270static inline const char *fmt_directive(const struct proxy *curproxy)
271{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100272 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200273 case ARGC_ACL:
274 return "acl";
275 case ARGC_STK:
276 return "stick";
277 case ARGC_TRK:
278 return "track-sc";
279 case ARGC_LOG:
280 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200281 case ARGC_LOGSD:
282 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100283 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100284 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100285 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100286 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200287 case ARGC_UIF:
288 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100289 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200290 return "redirect";
291 case ARGC_CAP:
292 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200293 case ARGC_SRV:
294 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200295 case ARGC_SPOE:
296 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100297 case ARGC_UBK:
298 return "use_backend";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100299 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200300 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100301 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200302}
303
William Lallemand723b73a2012-02-08 16:37:49 +0100304/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100305 * callback used to configure addr source retrieval
306 */
307int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
308{
309 curproxy->options2 |= PR_O2_SRC_ADDR;
310
311 return 0;
312}
313
314
315/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100316 * Parse args in a logformat_var. Returns 0 in error
317 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100318 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100319int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100320{
321 int i = 0;
322 int end = 0;
323 int flags = 0; // 1 = + 2 = -
324 char *sp = NULL; // start pointer
325
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100326 if (args == NULL) {
327 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100328 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100329 }
William Lallemand723b73a2012-02-08 16:37:49 +0100330
331 while (1) {
332 if (*args == '\0')
333 end = 1;
334
335 if (*args == '+') {
336 // add flag
337 sp = args + 1;
338 flags = 1;
339 }
340 if (*args == '-') {
341 // delete flag
342 sp = args + 1;
343 flags = 2;
344 }
345
346 if (*args == '\0' || *args == ',') {
347 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100348 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100349 if (strcmp(sp, var_args_list[i].name) == 0) {
350 if (flags == 1) {
351 node->options |= var_args_list[i].mask;
352 break;
353 } else if (flags == 2) {
354 node->options &= ~var_args_list[i].mask;
355 break;
356 }
357 }
358 }
359 sp = NULL;
360 if (end)
361 break;
362 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100363 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100364 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100365 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100366}
367
368/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100369 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
370 * must pass the args part in the <arg> pointer with its length in <arg_len>,
371 * and varname with its length in <var> and <var_len> respectively. <arg> is
372 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100373 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100374 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100375int 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 +0100376{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100377 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200378 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100379
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100380 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
381 if (strlen(logformat_keywords[j].name) == var_len &&
382 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
383 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200384 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100385 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100386 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200387 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100388 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100389 node->type = logformat_keywords[j].type;
390 node->options = *defoptions;
391 if (arg_len) {
392 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100393 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200394 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100395 }
396 if (node->type == LOG_FMT_GLOBAL) {
397 *defoptions = node->options;
398 free(node->arg);
399 free(node);
400 } else {
401 if (logformat_keywords[j].config_callback &&
402 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200403 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100404 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100405 curproxy->to_log |= logformat_keywords[j].lw;
406 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100407 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100408 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100409 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
410 curproxy->conf.args.file, curproxy->conf.args.line,
411 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100412 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100413 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100414 memprintf(err, "format variable '%s' is reserved for HTTP mode",
415 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200416 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100417 }
William Lallemand723b73a2012-02-08 16:37:49 +0100418 }
419 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100420
421 j = var[var_len];
422 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100423 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 +0100424 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200425
426 error_free:
427 if (node) {
428 free(node->arg);
429 free(node);
430 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100431 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100432}
433
434/*
435 * push to the logformat linked list
436 *
437 * start: start pointer
438 * end: end text pointer
439 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100440 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100441 *
442 * LOG_TEXT: copy chars from start to end excluding end.
443 *
444*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100445int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100446{
447 char *str;
448
Willy Tarreaua3571662012-12-20 21:59:12 +0100449 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200450 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100451 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100452 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100453 return 0;
454 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200455 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100456 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100457 str[end - start] = '\0';
458 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100459 node->type = LOG_FMT_TEXT; // type string
460 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100461 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200462 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100463 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100464 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100465 return 0;
466 }
William Lallemand1d705562012-03-12 12:46:41 +0100467 node->type = LOG_FMT_SEPARATOR;
468 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100469 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100470 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100471}
472
473/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100474 * Parse the sample fetch expression <text> and add a node to <list_format> upon
475 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200476 * should work. The curpx->conf.args.ctx must be set by the caller.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100477 *
478 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100479 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100480int 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)
Willy Tarreauc8368452012-12-21 00:09:23 +0100481{
482 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200483 struct sample_expr *expr = NULL;
484 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100485 int cmd_arg;
486
487 cmd[0] = text;
488 cmd[1] = "";
489 cmd_arg = 0;
490
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100491 expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args);
Willy Tarreauc8368452012-12-21 00:09:23 +0100492 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100493 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200494 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100495 }
496
Vincent Bernat02779b62016-04-03 13:48:43 +0200497 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100498 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100499 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200500 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100501 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100502 node->type = LOG_FMT_EXPR;
503 node->expr = expr;
504 node->options = options;
505
506 if (arg_len) {
507 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100508 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200509 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100510 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100511 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100512 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
513
Willy Tarreau434c57c2013-01-08 01:10:24 +0100514 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100515 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
516
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100517 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100518 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
519 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200520 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100521 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100522
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200523 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100524 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100525 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100526
William Lallemand65ad6e12014-01-31 15:08:02 +0100527 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
528 * needed with some sample fetches (eg: ssl*). We always set it for
529 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100530 */
531 curpx->to_log |= LW_XPRT;
William Lallemand65ad6e12014-01-31 15:08:02 +0100532 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100533 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100534 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200535
536 error_free:
537 release_sample_expr(expr);
538 if (node) {
539 free(node->arg);
540 free(node);
541 }
542 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100543}
544
545/*
William Lallemand723b73a2012-02-08 16:37:49 +0100546 * Parse the log_format string and fill a linked list.
547 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200548 * You can set arguments using { } : %{many arguments}varname.
549 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100550 *
551 * str: the string to parse
552 * curproxy: the proxy affected
553 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100554 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100555 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100556 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100557 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100558 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100559int 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 +0100560{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100561 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100562 char *arg = NULL; /* start pointer for args */
563 char *var = NULL; /* start pointer for vars */
564 int arg_len = 0;
565 int var_len = 0;
566 int cformat; /* current token format */
567 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100568 struct logformat_node *tmplf, *back;
569
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100570 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100571 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100572 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100573 return 0;
574 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200575 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200576
William Lallemand723b73a2012-02-08 16:37:49 +0100577 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100578 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100579 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200580 release_sample_expr(tmplf->expr);
581 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100582 free(tmplf);
583 }
584
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100585 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100586 pformat = cformat;
587
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100588 if (!*str)
589 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100590
Joseph Herlant85b40592018-11-15 12:10:04 -0800591 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100592 * second have all common paths processed at one place. The common paths are the ones
593 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
594 * We use the common LF_INIT state to dispatch to the different final states.
595 */
596 switch (pformat) {
597 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100598 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100599 arg_len = var_len = 0;
600 if (*str == '{') { // optional argument
601 cformat = LF_STARG;
602 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100603 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100604 else if (*str == '[') {
605 cformat = LF_STEXPR;
606 var = str + 1; // store expr in variable name
607 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100608 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100609 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100610 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100611 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100612 else if (*str == '%')
613 cformat = LF_TEXT; // convert this character to a litteral (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100614 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100615 /* single '%' followed by blank or digit, send them both */
616 cformat = LF_TEXT;
617 pformat = LF_TEXT; /* finally we include the previous char as well */
618 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600619 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 +0100620 *str, (int)(str - backfmt), fmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100621 return 0;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100622
623 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100624 else
625 cformat = LF_INIT; // handle other cases of litterals
626 break;
627
628 case LF_STARG: // text immediately following '%{'
629 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100630 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100631 arg_len = str - arg;
632 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100633 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100634 break;
635
636 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100637 if (*str == '[') {
638 cformat = LF_STEXPR;
639 var = str + 1; // store expr in variable name
640 break;
641 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100642 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100643 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100644 var = str;
645 break;
646 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100647 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100648 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100649
Willy Tarreauc8368452012-12-21 00:09:23 +0100650 case LF_STEXPR: // text immediately following '%['
651 if (*str == ']') { // end of arg
652 cformat = LF_EDEXPR;
653 var_len = str - var;
654 *str = 0; // needed for parsing the expression
655 }
656 break;
657
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100658 case LF_VAR: // text part of a variable name
659 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100660 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100661 cformat = LF_INIT; // not variable name anymore
662 break;
663
Willy Tarreauc8368452012-12-21 00:09:23 +0100664 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100665 cformat = LF_INIT;
666 }
667
668 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
669 switch (*str) {
670 case '%': cformat = LF_STARTVAR; break;
671 case ' ': cformat = LF_SEPARATOR; break;
672 case 0 : cformat = LF_END; break;
673 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100674 }
675 }
676
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100677 if (cformat != pformat || pformat == LF_SEPARATOR) {
678 switch (pformat) {
679 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100680 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100681 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100682 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100683 case LF_STEXPR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100684 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100685 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100686 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100687 case LF_TEXT:
688 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100689 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100690 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100691 break;
692 }
693 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100694 }
695 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100696
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100697 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100698 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100699 return 0;
700 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100701 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100702
703 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100704}
705
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200706/*
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200707 * Parse the first range of indexes from a string made of a list of comma seperated
708 * ranges of indexes. Note that an index may be considered as a particular range
709 * with a high limit to the low limit.
710 */
711int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
712{
713 char *end, *p;
714
715 *low = *high = 0;
716
717 p = *arg;
718 end = strchr(p, ',');
719 if (!end)
720 end = p + strlen(p);
721
722 *high = *low = read_uint((const char **)&p, end);
723 if (!*low || (p != end && *p != '-'))
724 goto err;
725
726 if (p == end)
727 goto done;
728
729 p++;
730 *high = read_uint((const char **)&p, end);
731 if (!*high || *high <= *low || p != end)
732 goto err;
733
734 done:
735 if (*end == ',')
736 end++;
737 *arg = end;
738 return 1;
739
740 err:
741 memprintf(err, "wrong sample range '%s'", *arg);
742 return 0;
743}
744
745/*
746 * Returns 1 if the range defined by <low> and <high> overlaps
747 * one of them in <rgs> array of ranges with <sz> the size of this
748 * array, 0 if not.
749 */
750int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
751 unsigned int low, unsigned int high, char **err)
752{
753 size_t i;
754
755 for (i = 0; i < sz; i++) {
756 if ((low >= rgs[i].low && low <= rgs[i].high) ||
757 (high >= rgs[i].low && high <= rgs[i].high)) {
758 memprintf(err, "ranges are overlapping");
759 return 1;
760 }
761 }
762
763 return 0;
764}
765
766int smp_log_range_cmp(const void *a, const void *b)
767{
768 const struct smp_log_range *rg_a = a;
769 const struct smp_log_range *rg_b = b;
770
771 if (rg_a->high < rg_b->low)
772 return -1;
773 else if (rg_a->low > rg_b->high)
774 return 1;
775
776 return 0;
777}
778
779/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200780 * Parse "log" keyword and update <logsrvs> list accordingly.
781 *
782 * When <do_del> is set, it means the "no log" line was parsed, so all log
783 * servers in <logsrvs> are released.
784 *
785 * Otherwise, we try to parse the "log" line. First of all, when the list is not
786 * the global one, we look for the parameter "global". If we find it,
787 * global.logsrvs is copied. Else we parse each arguments.
788 *
789 * The function returns 1 in success case, otherwise, it returns 0 and err is
790 * filled.
791 */
792int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
793{
794 struct sockaddr_storage *sk;
795 struct logsrv *logsrv = NULL;
796 int port1, port2;
797 int cur_arg;
798
799 /*
800 * "no log": delete previous herited or defined syslog
801 * servers.
802 */
803 if (do_del) {
804 struct logsrv *back;
805
806 if (*(args[1]) != 0) {
807 memprintf(err, "'no log' does not expect arguments");
808 goto error;
809 }
810
811 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
812 LIST_DEL(&logsrv->list);
813 free(logsrv);
814 }
815 return 1;
816 }
817
818 /*
819 * "log global": copy global.logrsvs linked list to the end of logsrvs
820 * list. But first, we check (logsrvs != global.logsrvs).
821 */
822 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
823 if (logsrvs == &global.logsrvs) {
824 memprintf(err, "'global' is not supported for a global syslog server");
825 goto error;
826 }
827 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200828 struct logsrv *node;
829
830 list_for_each_entry(node, logsrvs, list) {
831 if (node->ref == logsrv)
832 goto skip_logsrv;
833 }
834
835 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200836 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200837 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200838 LIST_INIT(&node->list);
839 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200840
841 skip_logsrv:
842 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200843 }
844 return 1;
845 }
846
847 /*
848 * "log <address> ...: parse a syslog server line
849 */
850 if (*(args[1]) == 0 || *(args[2]) == 0) {
851 memprintf(err, "expects <address> and <facility> %s as arguments",
852 ((logsrvs == &global.logsrvs) ? "" : "or global"));
853 goto error;
854 }
855
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100856 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
857 if (strcmp(args[1], "stdout") == 0)
858 args[1] = "fd@1";
859 else if (strcmp(args[1], "stderr") == 0)
860 args[1] = "fd@2";
861
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200862 logsrv = calloc(1, sizeof(*logsrv));
863 if (!logsrv) {
864 memprintf(err, "out of memory");
865 goto error;
866 }
867
868 /* skip address for now, it will be parsed at the end */
869 cur_arg = 2;
870
871 /* just after the address, a length may be specified */
872 logsrv->maxlen = MAX_SYSLOG_LEN;
873 if (strcmp(args[cur_arg], "len") == 0) {
874 int len = atoi(args[cur_arg+1]);
875 if (len < 80 || len > 65535) {
876 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
877 args[cur_arg+1]);
878 goto error;
879 }
880 logsrv->maxlen = len;
881 cur_arg += 2;
882 }
883 if (logsrv->maxlen > global.max_syslog_len)
884 global.max_syslog_len = logsrv->maxlen;
885
886 /* after the length, a format may be specified */
887 if (strcmp(args[cur_arg], "format") == 0) {
888 logsrv->format = get_log_format(args[cur_arg+1]);
889 if (logsrv->format < 0) {
890 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
891 goto error;
892 }
893 cur_arg += 2;
894 }
895
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200896 if (strcmp(args[cur_arg], "sample") == 0) {
897 unsigned low, high;
898 char *p, *beg, *end, *smp_sz_str;
899 struct smp_log_range *smp_rgs = NULL;
900 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
901
902 p = args[cur_arg+1];
903 smp_sz_str = strchr(p, ':');
904 if (!smp_sz_str) {
905 memprintf(err, "Missing sample size");
906 goto error;
907 }
908
909 *smp_sz_str++ = '\0';
910
911 end = p + strlen(p);
912
913 while (p != end) {
914 if (!get_logsrv_smp_range(&low, &high, &p, err))
915 goto error;
916
917 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
918 goto error;
919
920 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
921 if (!smp_rgs) {
922 memprintf(err, "out of memory error");
923 goto error;
924 }
925
926 smp_rgs[smp_rgs_sz].low = low;
927 smp_rgs[smp_rgs_sz].high = high;
928 smp_rgs[smp_rgs_sz].sz = high - low + 1;
929 smp_rgs[smp_rgs_sz].curr_idx = 0;
930 if (smp_rgs[smp_rgs_sz].high > smp_sz)
931 smp_sz = smp_rgs[smp_rgs_sz].high;
932 smp_rgs_sz++;
933 }
934
Tim Duesterhus21648002019-06-23 22:10:10 +0200935 if (smp_rgs == NULL) {
936 memprintf(err, "no sampling ranges given");
937 goto error;
938 }
939
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200940 beg = smp_sz_str;
941 end = beg + strlen(beg);
942 new_smp_sz = read_uint((const char **)&beg, end);
943 if (!new_smp_sz || beg != end) {
944 memprintf(err, "wrong sample size '%s' for sample range '%s'",
945 smp_sz_str, args[cur_arg+1]);
946 goto error;
947 }
948
949 if (new_smp_sz < smp_sz) {
950 memprintf(err, "sample size %zu should be greater or equal to "
951 "%zu the maximum of the high ranges limits",
952 new_smp_sz, smp_sz);
953 goto error;
954 }
955 smp_sz = new_smp_sz;
956
957 /* Let's order <smp_rgs> array. */
958 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
959
960 logsrv->lb.smp_rgs = smp_rgs;
961 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
962 logsrv->lb.smp_sz = smp_sz;
963
964 cur_arg += 2;
965 }
Frédéric Lécailled803e472019-04-25 07:42:09 +0200966 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200967 /* parse the facility */
968 logsrv->facility = get_log_facility(args[cur_arg]);
969 if (logsrv->facility < 0) {
970 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
971 goto error;
972 }
973 cur_arg++;
974
975 /* parse the max syslog level (default: debug) */
976 logsrv->level = 7;
977 if (*(args[cur_arg])) {
978 logsrv->level = get_log_level(args[cur_arg]);
979 if (logsrv->level < 0) {
980 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
981 goto error;
982 }
983 cur_arg++;
984 }
985
986 /* parse the limit syslog level (default: emerg) */
987 logsrv->minlvl = 0;
988 if (*(args[cur_arg])) {
989 logsrv->minlvl = get_log_level(args[cur_arg]);
990 if (logsrv->minlvl < 0) {
991 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
992 goto error;
993 }
994 cur_arg++;
995 }
996
997 /* Too many args */
998 if (*(args[cur_arg])) {
999 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1000 goto error;
1001 }
1002
1003 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001004 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001005 if (strncmp(args[1], "ring@", 5) == 0) {
1006 struct sink *sink = sink_find(args[1] + 5);
1007
1008 if (!sink || sink->type != SINK_TYPE_BUFFER) {
1009 memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
1010 goto error;
1011 }
1012
1013 logsrv->addr.ss_family = AF_UNSPEC;
1014 logsrv->type = LOG_TARGET_BUFFER;
1015 logsrv->ring = sink->ctx.ring;
1016 goto done;
1017 }
1018
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001019 if (strncmp(args[1], "fd@", 3) == 0)
1020 logsrv->type = LOG_TARGET_FD;
1021
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001022 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1023 if (!sk)
1024 goto error;
1025 logsrv->addr = *sk;
1026
1027 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1028 if (port1 != port2) {
1029 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1030 goto error;
1031 }
1032 logsrv->addr = *sk;
1033 if (!port1)
1034 set_host_port(&logsrv->addr, SYSLOG_PORT);
1035 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001036 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001037 LIST_ADDQ(logsrvs, &logsrv->list);
1038 return 1;
1039
1040 error:
1041 free(logsrv);
1042 return 0;
1043}
1044
1045
Christopher Fauletd4696382017-10-24 11:44:05 +02001046/* Generic function to display messages prefixed by a label */
1047static void print_message(const char *label, const char *fmt, va_list argp)
1048{
1049 struct tm tm;
1050 char *head, *msg;
1051
1052 head = msg = NULL;
1053
1054 get_localtime(date.tv_sec, &tm);
1055 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1056 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1057 memvprintf(&msg, fmt, argp);
1058
Willy Tarreau869efd52019-11-15 15:16:57 +01001059 if (global.mode & MODE_STARTING) {
1060 if (unlikely(!startup_logs))
1061 startup_logs = ring_new(STARTUP_LOG_SIZE);
1062
1063 if (likely(startup_logs)) {
1064 struct ist m[2];
1065
1066 m[0] = ist(head);
1067 m[1] = ist(msg);
1068 /* trim the trailing '\n' */
1069 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1070 m[1].len--;
1071 ring_write(startup_logs, ~0, 0, 0, m, 2);
1072 }
1073 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001074
1075 fprintf(stderr, "%s%s", head, msg);
1076 fflush(stderr);
1077
1078 free(head);
1079 free(msg);
1080}
1081
Willy Tarreaubaaee002006-06-26 02:48:02 +02001082/*
1083 * Displays the message on stderr with the date and pid. Overrides the quiet
1084 * mode during startup.
1085 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001086void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001087{
1088 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001089
1090 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
1091 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001092 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001093 va_end(argp);
1094 }
1095}
1096
1097
1098/*
1099 * Displays the message on stderr with the date and pid.
1100 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001101void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001102{
1103 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001104
1105 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1106 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001107 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001108 va_end(argp);
1109 }
1110}
1111
1112/*
William Lallemand9c56a222018-11-21 18:04:52 +01001113 * Displays the message on stderr with the date and pid.
1114 */
1115void ha_notice(const char *fmt, ...)
1116{
1117 va_list argp;
1118
1119 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1120 va_start(argp, fmt);
1121 print_message("NOTICE", fmt, argp);
1122 va_end(argp);
1123 }
1124}
1125
1126/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001127 * Displays the message on <out> only if quiet mode is not set.
1128 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001129void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001130{
1131 va_list argp;
1132
1133 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1134 va_start(argp, fmt);
1135 vfprintf(out, fmt, argp);
1136 fflush(out);
1137 va_end(argp);
1138 }
1139}
1140
1141/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001142 * returns log format for <fmt> or -1 if not found.
1143 */
1144int get_log_format(const char *fmt)
1145{
1146 int format;
1147
1148 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001149 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001150 format--;
1151
1152 return format;
1153}
1154
1155/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001156 * returns log level for <lev> or -1 if not found.
1157 */
1158int get_log_level(const char *lev)
1159{
1160 int level;
1161
1162 level = NB_LOG_LEVELS - 1;
1163 while (level >= 0 && strcmp(log_levels[level], lev))
1164 level--;
1165
1166 return level;
1167}
1168
Willy Tarreaubaaee002006-06-26 02:48:02 +02001169/*
1170 * returns log facility for <fac> or -1 if not found.
1171 */
1172int get_log_facility(const char *fac)
1173{
1174 int facility;
1175
1176 facility = NB_LOG_FACILITIES - 1;
1177 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1178 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001179
Willy Tarreaubaaee002006-06-26 02:48:02 +02001180 return facility;
1181}
1182
William Lallemanda1cc3812012-02-08 16:38:44 +01001183/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001184 * Encode the string.
1185 *
1186 * When using the +E log format option, it will try to escape '"\]'
1187 * characters with '\' as prefix. The same prefix should not be used as
1188 * <escape>.
1189 */
1190static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001191 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001192 const char *string,
1193 struct logformat_node *node)
1194{
1195 if (node->options & LOG_OPT_ESC) {
1196 if (start < stop) {
1197 stop--; /* reserve one byte for the final '\0' */
1198 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001199 if (!ha_bit_test((unsigned char)(*string), map)) {
1200 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001201 *start++ = *string;
1202 else {
1203 if (start + 2 >= stop)
1204 break;
1205 *start++ = '\\';
1206 *start++ = *string;
1207 }
1208 }
1209 else {
1210 if (start + 3 >= stop)
1211 break;
1212 *start++ = escape;
1213 *start++ = hextab[(*string >> 4) & 15];
1214 *start++ = hextab[*string & 15];
1215 }
1216 string++;
1217 }
1218 *start = '\0';
1219 }
1220 }
1221 else {
1222 return encode_string(start, stop, escape, map, string);
1223 }
1224
1225 return start;
1226}
1227
1228/*
1229 * Encode the chunk.
1230 *
1231 * When using the +E log format option, it will try to escape '"\]'
1232 * characters with '\' as prefix. The same prefix should not be used as
1233 * <escape>.
1234 */
1235static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001236 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001237 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001238 struct logformat_node *node)
1239{
1240 char *str, *end;
1241
1242 if (node->options & LOG_OPT_ESC) {
1243 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001244 str = chunk->area;
1245 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001246
1247 stop--; /* reserve one byte for the final '\0' */
1248 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001249 if (!ha_bit_test((unsigned char)(*str), map)) {
1250 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001251 *start++ = *str;
1252 else {
1253 if (start + 2 >= stop)
1254 break;
1255 *start++ = '\\';
1256 *start++ = *str;
1257 }
1258 }
1259 else {
1260 if (start + 3 >= stop)
1261 break;
1262 *start++ = escape;
1263 *start++ = hextab[(*str >> 4) & 15];
1264 *start++ = hextab[*str & 15];
1265 }
1266 str++;
1267 }
1268 *start = '\0';
1269 }
1270 }
1271 else {
1272 return encode_chunk(start, stop, escape, map, chunk);
1273 }
1274
1275 return start;
1276}
1277
1278/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001279 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001280 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001281 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001282 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001283 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001284char *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 +01001285{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001286 if (size < 2)
1287 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001288
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001289 if (node->options & LOG_OPT_QUOTE) {
1290 *(dst++) = '"';
1291 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001292 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001293
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001294 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001295 if (++len > size)
1296 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001297 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001298 char *ret;
1299
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001300 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001301 if (ret == NULL || *ret != '\0')
1302 return NULL;
1303 len = ret - dst;
1304 }
1305 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001306 len = strlcpy2(dst, src, len);
1307 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001308
1309 size -= len;
1310 dst += len;
1311 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001312 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1313 if (size < 2)
1314 return NULL;
1315 *(dst++) = '-';
1316 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001317
1318 if (node->options & LOG_OPT_QUOTE) {
1319 if (size < 2)
1320 return NULL;
1321 *(dst++) = '"';
1322 }
1323
1324 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001325 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001326}
1327
Willy Tarreau26ffa852018-09-05 15:23:10 +02001328static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001329{
1330 return lf_text_len(dst, src, size, size, node);
1331}
1332
William Lallemand5f232402012-04-05 18:02:55 +02001333/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001334 * Write a IP address to the log string
William Lallemand5f232402012-04-05 18:02:55 +02001335 * +X option write in hexadecimal notation, most signifant byte on the left
1336 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001337char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001338{
1339 char *ret = dst;
1340 int iret;
1341 char pn[INET6_ADDRSTRLEN];
1342
1343 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001344 unsigned char *addr = NULL;
1345 switch (sockaddr->sa_family) {
1346 case AF_INET:
1347 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1348 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1349 break;
1350 case AF_INET6:
1351 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1352 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1353 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1354 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1355 break;
1356 default:
1357 return NULL;
1358 }
William Lallemand5f232402012-04-05 18:02:55 +02001359 if (iret < 0 || iret > size)
1360 return NULL;
1361 ret += iret;
1362 } else {
1363 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1364 ret = lf_text(dst, pn, size, node);
1365 if (ret == NULL)
1366 return NULL;
1367 }
1368 return ret;
1369}
1370
1371/*
1372 * Write a port to the log
1373 * +X option write in hexadecimal notation, most signifant byte on the left
1374 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001375char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001376{
1377 char *ret = dst;
1378 int iret;
1379
1380 if (node->options & LOG_OPT_HEXA) {
1381 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1382 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1383 if (iret < 0 || iret > size)
1384 return NULL;
1385 ret += iret;
1386 } else {
1387 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1388 if (ret == NULL)
1389 return NULL;
1390 }
1391 return ret;
1392}
1393
Dragan Dosen1322d092015-09-22 16:05:32 +02001394/* Re-generate time-based part of the syslog header in RFC3164 format at
1395 * the beginning of logheader once a second and return the pointer to the
1396 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001397 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001398static char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001399{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001400 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001401 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001402 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001403
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001404 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001405 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001406 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001407 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001408
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001409 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001410 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001411
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001412 if (unlikely(global.log_send_hostname != host.area)) {
1413 host.area = global.log_send_hostname;
1414 host.data = host.area ? strlen(host.area) : 0;
1415 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001416 }
1417
Dragan Dosen59cee972015-09-19 22:09:02 +02001418 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001419 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001420 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001421 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001422 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001423 /* WARNING: depending upon implementations, snprintf may return
1424 * either -1 or the number of bytes that would be needed to store
1425 * the total message. In both cases, we must adjust it.
1426 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001427 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1428 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001429
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001430 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001431 }
1432
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001433 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001434
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001435 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001436}
1437
Dragan Dosen1322d092015-09-22 16:05:32 +02001438/* Re-generate time-based part of the syslog header in RFC5424 format at
1439 * the beginning of logheader_rfc5424 once a second and return the pointer
1440 * to the first character after it.
1441 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001442static char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001443{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001444 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001445 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001446
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001447 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001448 /* this string is rebuild only once a second */
1449 struct tm tm;
1450 int hdr_len;
1451
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001452 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001453 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001454 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001455
1456 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001457 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001458 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001459 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001460 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001461 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001462 /* WARNING: depending upon implementations, snprintf may return
1463 * either -1 or the number of bytes that would be needed to store
1464 * the total message. In both cases, we must adjust it.
1465 */
1466 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1467 hdr_len = global.max_syslog_len;
1468
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001469 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001470 }
1471
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001472 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001473
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001474 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001475}
1476
William Lallemand2a4a44f2012-02-06 16:00:33 +01001477/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001478 * This function sends the syslog message using a printf format string. It
1479 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001480 */
1481void send_log(struct proxy *p, int level, const char *format, ...)
1482{
1483 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001484 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001485
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001486 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001487 return;
1488
William Lallemand2a4a44f2012-02-06 16:00:33 +01001489 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001490 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001491 if (data_len < 0 || data_len > global.max_syslog_len)
1492 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001493 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001494
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001495 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1496 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001497}
1498
1499/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001500 * This function sends a syslog message to <logsrv>.
1501 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1502 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1503 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001504 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001505 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001506 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001507static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1508 int level, char *message, size_t size, char *sd, size_t sd_size,
1509 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001510{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001511 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1512 static THREAD_LOCAL struct msghdr msghdr = {
1513 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001514 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1515 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001516 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1517 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1518 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001519 time_t time = date.tv_sec;
Dragan Dosen1322d092015-09-22 16:05:32 +02001520 char *hdr, *hdr_ptr;
Dragan Dosen59cee972015-09-19 22:09:02 +02001521 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001522 int fac_level;
1523 int *plogfd;
1524 char *pid_sep1 = "", *pid_sep2 = "";
1525 char logheader_short[3];
1526 int sent;
1527 int maxlen;
1528 int hdr_max = 0;
1529 int tag_max = 0;
1530 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001531 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001532 int pid_sep2_max = 0;
1533 int sd_max = 0;
1534 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001535
1536 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001537
1538 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001539
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001540 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001541 /* the socket's address is a file descriptor */
1542 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001543 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001544 else if (logsrv->type == LOG_TARGET_BUFFER) {
1545 plogfd = NULL;
1546 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001547 else if (logsrv->addr.ss_family == AF_UNIX)
1548 plogfd = &logfdunix;
1549 else
1550 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001551
Willy Tarreauc046d162019-08-30 15:24:59 +02001552 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001553 /* socket not successfully initialized yet */
1554 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1555 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1556 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001557
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001558 if (!once) {
1559 once = 1; /* note: no need for atomic ops here */
1560 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1561 nblogger, strerror(errno), errno);
1562 }
1563 return;
1564 } else {
1565 /* we don't want to receive anything on this socket */
1566 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1567 /* does nothing under Linux, maybe needed for others */
1568 shutdown(*plogfd, SHUT_RD);
1569 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1570 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001571 }
1572
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001573 switch (logsrv->format) {
1574 case LOG_FORMAT_RFC3164:
1575 hdr = logheader;
1576 hdr_ptr = update_log_hdr(time);
1577 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001578
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001579 case LOG_FORMAT_RFC5424:
1580 hdr = logheader_rfc5424;
1581 hdr_ptr = update_log_hdr_rfc5424(time);
1582 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1583 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001584
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001585 case LOG_FORMAT_SHORT:
1586 /* all fields are known, skip the header generation */
1587 hdr = logheader_short;
1588 hdr[0] = '<';
1589 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1590 hdr[2] = '>';
1591 hdr_ptr = hdr;
1592 hdr_max = 3;
1593 maxlen = logsrv->maxlen - hdr_max;
1594 max = MIN(size, maxlen) - 1;
1595 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001596
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001597 case LOG_FORMAT_RAW:
1598 /* all fields are known, skip the header generation */
1599 hdr_ptr = hdr = "";
1600 hdr_max = 0;
1601 maxlen = logsrv->maxlen;
1602 max = MIN(size, maxlen) - 1;
1603 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001604
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001605 default:
1606 return; /* must never happen */
1607 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001608
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001609 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001610
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001611 /* For each target, we may have a different facility.
1612 * We can also have a different log level for each message.
1613 * This induces variations in the message header length.
1614 * Since we don't want to recompute it each time, nor copy it every
1615 * time, we only change the facility in the pre-computed header,
1616 * and we change the pointer to the header accordingly.
1617 */
1618 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1619 hdr_ptr = hdr + 3; /* last digit of the log level */
1620 do {
1621 *hdr_ptr = '0' + fac_level % 10;
1622 fac_level /= 10;
1623 hdr_ptr--;
1624 } while (fac_level && hdr_ptr > hdr);
1625 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001626
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001627 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001628
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001629 /* time-based header */
1630 if (unlikely(hdr_size >= logsrv->maxlen)) {
1631 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1632 sd_max = 0;
1633 goto send;
1634 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001635
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001636 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001637
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001638 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001639 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001640 if (unlikely(tag_max >= maxlen)) {
1641 tag_max = maxlen - 1;
1642 sd_max = 0;
1643 goto send;
1644 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001645
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001646 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001647
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001648 /* first pid separator */
1649 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1650 if (unlikely(pid_sep1_max >= maxlen)) {
1651 pid_sep1_max = maxlen - 1;
1652 sd_max = 0;
1653 goto send;
1654 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001655
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001656 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1657 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001658
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001659 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001660 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001661 if (unlikely(pid_size >= maxlen)) {
1662 pid_size = maxlen - 1;
1663 sd_max = 0;
1664 goto send;
1665 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001666
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001667 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001668
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001669 /* second pid separator */
1670 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1671 if (unlikely(pid_sep2_max >= maxlen)) {
1672 pid_sep2_max = maxlen - 1;
1673 sd_max = 0;
1674 goto send;
1675 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001676
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001677 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1678 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001679
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001680 /* structured-data */
1681 if (sd_max >= maxlen) {
1682 sd_max = maxlen - 1;
1683 goto send;
1684 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001685
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001686 max = MIN(size, maxlen - sd_max) - 1;
1687send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001688 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001689 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001690 struct ist msg[7];
1691
1692 msg[0].ptr = hdr_ptr; msg[0].len = hdr_max;
1693 msg[1].ptr = tag_str; msg[1].len = tag_max;
1694 msg[2].ptr = pid_sep1; msg[2].len = pid_sep1_max;
1695 msg[3].ptr = pid_str; msg[3].len = pid_max;
1696 msg[4].ptr = pid_sep2; msg[4].len = pid_sep2_max;
1697 msg[5].ptr = sd; msg[5].len = sd_max;
1698 msg[6].ptr = dataptr; msg[6].len = max;
1699
Willy Tarreauc046d162019-08-30 15:24:59 +02001700 if (logsrv->type == LOG_TARGET_BUFFER)
1701 sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
1702 else /* LOG_TARGET_FD */
1703 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001704 }
1705 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001706 iovec[0].iov_base = hdr_ptr;
1707 iovec[0].iov_len = hdr_max;
1708 iovec[1].iov_base = tag_str;
1709 iovec[1].iov_len = tag_max;
1710 iovec[2].iov_base = pid_sep1;
1711 iovec[2].iov_len = pid_sep1_max;
1712 iovec[3].iov_base = pid_str;
1713 iovec[3].iov_len = pid_max;
1714 iovec[4].iov_base = pid_sep2;
1715 iovec[4].iov_len = pid_sep2_max;
1716 iovec[5].iov_base = sd;
1717 iovec[5].iov_len = sd_max;
1718 iovec[6].iov_base = dataptr;
1719 iovec[6].iov_len = max;
1720 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1721 iovec[7].iov_len = 1;
1722
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001723 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1724 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001725
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001726 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1727 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001728
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001729 if (sent < 0) {
1730 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001731
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001732 if (errno == EAGAIN)
1733 _HA_ATOMIC_ADD(&dropped_logs, 1);
1734 else if (!once) {
1735 once = 1; /* note: no need for atomic ops here */
1736 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1737 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001738 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001739 }
1740}
Dragan Dosen59cee972015-09-19 22:09:02 +02001741
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001742/*
1743 * This function sends a syslog message.
1744 * It doesn't care about errors nor does it report them.
1745 * The arguments <sd> and <sd_size> are used for the structured-data part
1746 * in RFC5424 formatted syslog messages.
1747 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001748void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1749 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001750{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001751 struct logsrv *logsrv;
1752 int nblogger;
1753 static THREAD_LOCAL int curr_pid;
1754 static THREAD_LOCAL char pidstr[100];
1755 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001756
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001757 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001758 if (!LIST_ISEMPTY(&global.logsrvs)) {
1759 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001760 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001761 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001762 if (!tag || !tag->area)
1763 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001764
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001765 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001766 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001767
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001768 if (unlikely(curr_pid != getpid())) {
1769 curr_pid = getpid();
1770 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1771 chunk_initstr(&pid, pidstr);
1772 }
1773
1774 /* Send log messages to syslog server. */
1775 nblogger = 0;
1776 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001777 static THREAD_LOCAL int in_range = 1;
1778
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001779 /* we can filter the level of the messages that are sent to each logger */
1780 if (level > logsrv->level)
1781 continue;
1782
Frédéric Lécailled803e472019-04-25 07:42:09 +02001783 if (logsrv->lb.smp_rgs) {
1784 struct smp_log_range *curr_rg;
1785
1786 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1787 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1788 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1789 if (in_range) {
1790 /* Let's consume this range. */
1791 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1792 if (!curr_rg->curr_idx) {
1793 /* If consumed, let's select the next range. */
1794 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1795 }
1796 }
1797 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1798 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1799 }
1800 if (in_range)
1801 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1802 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001803 }
1804}
1805
1806
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001807const 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 +01001808const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1809 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1810 Set-cookie Updated, unknown, unknown */
1811
William Lallemand1d705562012-03-12 12:46:41 +01001812/*
1813 * try to write a character if there is enough space, or goto out
1814 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001815#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001816 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001817 *(tmplog++) = (x); \
1818 } else { \
1819 goto out; \
1820 } \
1821 } while(0)
1822
Dragan Dosen835b9212016-02-12 13:23:03 +01001823
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001824/* Initializes some log data at boot */
1825static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001826{
1827 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001828 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001829
1830 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1831 * inside PARAM-VALUE should be escaped with '\' as prefix.
1832 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1833 * details.
1834 */
1835 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1836
1837 tmp = "\"\\]";
1838 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001839 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001840 tmp++;
1841 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001842
1843 /* initialize the log header encoding map : '{|}"#' should be encoded with
1844 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1845 * URL encoding only requires '"', '#' to be encoded as well as non-
1846 * printable characters above.
1847 */
1848 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1849 memset(url_encode_map, 0, sizeof(url_encode_map));
1850 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001851 ha_bit_set(i, hdr_encode_map);
1852 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001853 }
1854 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001855 ha_bit_set(i, hdr_encode_map);
1856 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001857 }
1858
1859 tmp = "\"#{|}";
1860 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001861 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001862 tmp++;
1863 }
1864
1865 tmp = "\"#";
1866 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001867 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001868 tmp++;
1869 }
1870
1871 /* initialize the http header encoding map. The draft httpbis define the
1872 * header content as:
1873 *
1874 * HTTP-message = start-line
1875 * *( header-field CRLF )
1876 * CRLF
1877 * [ message-body ]
1878 * header-field = field-name ":" OWS field-value OWS
1879 * field-value = *( field-content / obs-fold )
1880 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1881 * obs-fold = CRLF 1*( SP / HTAB )
1882 * field-vchar = VCHAR / obs-text
1883 * VCHAR = %x21-7E
1884 * obs-text = %x80-FF
1885 *
1886 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1887 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001888 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001889 */
1890 memset(http_encode_map, 0, sizeof(http_encode_map));
1891 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001892 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001893 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001894 ha_bit_set(i, http_encode_map);
1895 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001896}
William Lallemand1d705562012-03-12 12:46:41 +01001897
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001898INITCALL0(STG_PREPARE, init_log);
1899
Christopher Faulet0132d062017-07-26 15:33:35 +02001900/* Initialize log buffers used for syslog messages */
1901int init_log_buffers()
1902{
1903 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001904 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001905 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001906 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001907 logline = my_realloc2(logline, global.max_syslog_len + 1);
1908 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1909 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1910 return 0;
1911 return 1;
1912}
1913
1914/* Deinitialize log buffers used for syslog messages */
1915void deinit_log_buffers()
1916{
1917 free(logheader);
1918 free(logheader_rfc5424);
1919 free(logline);
1920 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001921 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001922 logheader = NULL;
1923 logheader_rfc5424 = NULL;
1924 logline = NULL;
1925 logline_rfc5424 = NULL;
1926}
1927
Willy Tarreaudf974472012-12-28 02:44:01 +01001928/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1929 * <maxsize> characters. Returns the size of the output string in characters,
1930 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001931 * is not zero. It requires a valid session and optionally a stream. If the
1932 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001933 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001934int 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 +02001935{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001936 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001937 struct proxy *be;
1938 struct http_txn *txn;
1939 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001940 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001941 unsigned int s_flags;
1942 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001943 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001944 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001945 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001946 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001947 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001948 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001949 int t_request;
1950 int hdr;
1951 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001952 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001953 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01001954 char *ret;
1955 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001956 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001957 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001958 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001959
William Lallemandbddd4fd2012-02-27 11:23:10 +01001960 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001961
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001962 if (likely(s)) {
1963 be = s->be;
1964 txn = s->txn;
1965 be_conn = cs_conn(objt_cs(s->si[1].end));
1966 s_flags = s->flags;
1967 uniq_id = s->uniq_id;
1968 logs = &s->logs;
1969 } else {
1970 /* we have no stream so we first need to initialize a few
1971 * things that are needed later. We do increment the request
1972 * ID so that it's uniquely assigned to this request just as
1973 * if the request had reached the point of being processed.
1974 * A request error is reported as it's the only element we have
1975 * here and which justifies emitting such a log.
1976 */
1977 be = fe;
1978 txn = NULL;
1979 be_conn = NULL;
1980 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01001981 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001982
1983 /* prepare a valid log structure */
1984 tmp_strm_log.tv_accept = sess->tv_accept;
1985 tmp_strm_log.accept_date = sess->accept_date;
1986 tmp_strm_log.t_handshake = sess->t_handshake;
1987 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
1988 tv_zero(&tmp_strm_log.tv_request);
1989 tmp_strm_log.t_queue = -1;
1990 tmp_strm_log.t_connect = -1;
1991 tmp_strm_log.t_data = -1;
1992 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
1993 tmp_strm_log.bytes_in = 0;
1994 tmp_strm_log.bytes_out = 0;
1995 tmp_strm_log.prx_queue_pos = 0;
1996 tmp_strm_log.srv_queue_pos = 0;
1997
1998 logs = &tmp_strm_log;
1999 }
2000
William Lallemandbddd4fd2012-02-27 11:23:10 +01002001 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002002 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2003 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002004
William Lallemand1d705562012-03-12 12:46:41 +01002005 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002006
William Lallemandbddd4fd2012-02-27 11:23:10 +01002007 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002008 if (LIST_ISEMPTY(list_format))
2009 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002010
William Lallemand1d705562012-03-12 12:46:41 +01002011 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002012 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002013 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002014 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002015 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002016
Willy Tarreauc8368452012-12-21 00:09:23 +01002017 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002018 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002019 if (!last_isspace) {
2020 LOGCHAR(' ');
2021 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002022 }
2023 break;
2024
William Lallemand1d705562012-03-12 12:46:41 +01002025 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002026 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002027 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002028 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002029 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002030 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002031 last_isspace = 0;
2032 break;
2033
Willy Tarreauc8368452012-12-21 00:09:23 +01002034 case LOG_FMT_EXPR: // sample expression, may be request or response
2035 key = NULL;
Olivier Houchardf90db442018-12-15 14:00:06 +01002036 if (tmp->options & LOG_OPT_REQ_CAP && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002037 key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
Olivier Houchardf90db442018-12-15 14:00:06 +01002038 if (!key && (tmp->options & LOG_OPT_RES_CAP) && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002039 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 +01002040 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002041 ret = lf_encode_chunk(tmplog, dst + maxsize,
2042 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002043 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002044 ret = lf_text_len(tmplog,
2045 key ? key->data.u.str.area : NULL,
2046 key ? key->data.u.str.data : 0,
2047 dst + maxsize - tmplog,
2048 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002049 if (ret == 0)
2050 goto out;
2051 tmplog = ret;
2052 last_isspace = 0;
2053 break;
2054
Willy Tarreau2beef582012-12-20 17:22:52 +01002055 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002056 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002057 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002058 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002059 else
2060 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002061 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002062 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002063 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002064 last_isspace = 0;
2065 break;
2066
Willy Tarreau2beef582012-12-20 17:22:52 +01002067 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002068 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002069 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002070 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002071 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002072 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002073 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002074 dst + maxsize - tmplog, tmp);
2075 }
William Lallemand5f232402012-04-05 18:02:55 +02002076 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002077 else
2078 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2079
William Lallemand5f232402012-04-05 18:02:55 +02002080 if (ret == NULL)
2081 goto out;
2082 tmplog = ret;
2083 last_isspace = 0;
2084 break;
2085
Willy Tarreau2beef582012-12-20 17:22:52 +01002086 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002087 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002088 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002089 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002090 }
2091 else
2092 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2093
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_FRONTENDPORT: // %fp
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_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002103 if (conn->dst->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->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002107 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002108 else
2109 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2110
William Lallemand5f232402012-04-05 18:02:55 +02002111 if (ret == NULL)
2112 goto out;
2113 tmplog = ret;
2114 last_isspace = 0;
2115 break;
2116
Willy Tarreau2beef582012-12-20 17:22:52 +01002117 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002118 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002119 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002120 else
2121 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2122
William Lallemand1d705562012-03-12 12:46:41 +01002123 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002124 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002125 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002126 last_isspace = 0;
2127 break;
2128
Willy Tarreau2beef582012-12-20 17:22:52 +01002129 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002130 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002131 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002132 else
2133 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2134
William Lallemand5f232402012-04-05 18:02:55 +02002135 if (ret == NULL)
2136 goto out;
2137 tmplog = ret;
2138 last_isspace = 0;
2139 break;
2140
Willy Tarreau2beef582012-12-20 17:22:52 +01002141 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002142 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002143 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002144 else
2145 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2146
William Lallemand5f232402012-04-05 18:02:55 +02002147 if (ret == NULL)
2148 goto out;
2149 tmplog = ret;
2150 last_isspace = 0;
2151 break;
2152
Willy Tarreau2beef582012-12-20 17:22:52 +01002153 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002154 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002155 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002156 else
2157 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2158
William Lallemand1d705562012-03-12 12:46:41 +01002159 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002160 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002161 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002162 last_isspace = 0;
2163 break;
2164
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002165 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002166 get_localtime(logs->accept_date.tv_sec, &tm);
2167 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002168 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002169 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002170 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002171 last_isspace = 0;
2172 break;
2173
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002174 case LOG_FMT_tr: // %tr = start of request date
2175 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002176 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 +02002177 get_localtime(tv.tv_sec, &tm);
2178 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2179 if (ret == NULL)
2180 goto out;
2181 tmplog = ret;
2182 last_isspace = 0;
2183 break;
2184
2185 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002186 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002187 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002188 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002189 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002190 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002191 last_isspace = 0;
2192 break;
2193
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002194 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002195 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 +02002196 get_gmtime(tv.tv_sec, &tm);
2197 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2198 if (ret == NULL)
2199 goto out;
2200 tmplog = ret;
2201 last_isspace = 0;
2202 break;
2203
2204 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002205 get_localtime(logs->accept_date.tv_sec, &tm);
2206 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002207 if (ret == NULL)
2208 goto out;
2209 tmplog = ret;
2210 last_isspace = 0;
2211 break;
2212
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002213 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002214 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 +02002215 get_localtime(tv.tv_sec, &tm);
2216 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2217 if (ret == NULL)
2218 goto out;
2219 tmplog = ret;
2220 last_isspace = 0;
2221 break;
2222
William Lallemand5f232402012-04-05 18:02:55 +02002223 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002224 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002225 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002226 if (iret < 0 || iret > dst + maxsize - tmplog)
2227 goto out;
2228 last_isspace = 0;
2229 tmplog += iret;
2230 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002231 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002232 if (ret == NULL)
2233 goto out;
2234 tmplog = ret;
2235 last_isspace = 0;
2236 }
2237 break;
2238
William Lallemand1d705562012-03-12 12:46:41 +01002239 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002240 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002241 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002242 if (iret < 0 || iret > dst + maxsize - tmplog)
2243 goto out;
2244 last_isspace = 0;
2245 tmplog += iret;
2246 } else {
2247 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002248 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002249 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002250 tmplog, 4);
2251 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002252 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002253 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002254 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002255 }
2256 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002257
William Lallemand1d705562012-03-12 12:46:41 +01002258 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002259 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002260 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002261 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002262 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002263 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002264 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002265 break;
2266
Willy Tarreau773d65f2012-10-12 14:56:11 +02002267 case LOG_FMT_FRONTEND_XPRT: // %ft
2268 src = fe->id;
2269 if (tmp->options & LOG_OPT_QUOTE)
2270 LOGCHAR('"');
2271 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2272 if (iret == 0)
2273 goto out;
2274 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002275 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002276 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002277 if (tmp->options & LOG_OPT_QUOTE)
2278 LOGCHAR('"');
2279 last_isspace = 0;
2280 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002281#ifdef USE_OPENSSL
2282 case LOG_FMT_SSL_CIPHER: // %sslc
2283 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002284 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002285 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002286 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002287 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002288 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2289 if (ret == NULL)
2290 goto out;
2291 tmplog = ret;
2292 last_isspace = 0;
2293 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002294
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002295 case LOG_FMT_SSL_VERSION: // %sslv
2296 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002297 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002298 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002299 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002300 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002301 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2302 if (ret == NULL)
2303 goto out;
2304 tmplog = ret;
2305 last_isspace = 0;
2306 break;
2307#endif
William Lallemand1d705562012-03-12 12:46:41 +01002308 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002309 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002310 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002311 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002312 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002313 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002314 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002315 break;
2316
William Lallemand1d705562012-03-12 12:46:41 +01002317 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002318 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002319 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002320 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002321 break;
2322 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002323 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002324 break;
2325 default:
2326 src = "<NOSRV>";
2327 break;
2328 }
William Lallemand5f232402012-04-05 18:02:55 +02002329 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002330 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002331 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002332 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002333 last_isspace = 0;
2334 break;
2335
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002336 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002337 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002338 if (ret == NULL)
2339 goto out;
2340 tmplog = ret;
2341 last_isspace = 0;
2342 break;
2343
2344 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002345 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002346 if (ret == NULL)
2347 goto out;
2348 tmplog = ret;
2349 last_isspace = 0;
2350 break;
2351
2352 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002353 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002354 tmplog, dst + maxsize - tmplog);
2355 if (ret == NULL)
2356 goto out;
2357 tmplog = ret;
2358 last_isspace = 0;
2359 break;
2360
2361 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002362 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
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
William Lallemand1d705562012-03-12 12:46:41 +01002369 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002370 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002371 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002372 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002373 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002374 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002375 last_isspace = 0;
2376 break;
2377
William Lallemand1d705562012-03-12 12:46:41 +01002378 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002379 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002380 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002381 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002382 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002383 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002384 last_isspace = 0;
2385 break;
2386
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002387 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002388 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002389 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002390 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002391 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002392 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002393 last_isspace = 0;
2394 break;
2395
Willy Tarreau27b639d2016-05-17 17:55:27 +02002396 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002397 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002398 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002399 tmplog, dst + maxsize - tmplog);
2400 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002401 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002402 tmplog, dst + maxsize - tmplog);
2403 if (ret == NULL)
2404 goto out;
2405 tmplog = ret;
2406 last_isspace = 0;
2407 break;
2408
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002409 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2410 if (!(fe->to_log & LW_BYTES))
2411 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002412 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 +02002413 tmplog, dst + maxsize - tmplog);
2414 if (ret == NULL)
2415 goto out;
2416 tmplog = ret;
2417 last_isspace = 0;
2418 break;
2419
2420 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002421 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002422 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002423 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002424 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002425 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002426 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002427 last_isspace = 0;
2428 break;
2429
Willy Tarreau2beef582012-12-20 17:22:52 +01002430 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002431 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002432 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002433 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002434 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002435 last_isspace = 0;
2436 break;
2437
William Lallemand1d705562012-03-12 12:46:41 +01002438 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002439 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002440 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002441 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002442 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002443 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002444 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002445 last_isspace = 0;
2446 break;
2447
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002448 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002449 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002450 if (ret == NULL)
2451 goto out;
2452 tmplog = ret;
2453 last_isspace = 0;
2454 break;
2455
Willy Tarreau2beef582012-12-20 17:22:52 +01002456 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002457 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002458 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002459 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002460 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002461 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002462 last_isspace = 0;
2463 break;
2464
Willy Tarreau2beef582012-12-20 17:22:52 +01002465 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002466 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002467 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002468 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002469 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002470 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002471 last_isspace = 0;
2472 break;
2473
William Lallemand1d705562012-03-12 12:46:41 +01002474 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002475 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2476 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002477 *tmplog = '\0';
2478 last_isspace = 0;
2479 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002480
William Lallemand1d705562012-03-12 12:46:41 +01002481 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002482 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2483 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002484 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2485 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 +01002486 last_isspace = 0;
2487 break;
2488
William Lallemand1d705562012-03-12 12:46:41 +01002489 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002490 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002491 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002492 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002493 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002494 last_isspace = 0;
2495 break;
2496
William Lallemand1d705562012-03-12 12:46:41 +01002497 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002498 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002499 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002500 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002501 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002502 last_isspace = 0;
2503 break;
2504
William Lallemand1d705562012-03-12 12:46:41 +01002505 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002506 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002507 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002508 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002509 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002510 last_isspace = 0;
2511 break;
2512
William Lallemand1d705562012-03-12 12:46:41 +01002513 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002514 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002515 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002516 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002517 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002518 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002519 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002520 last_isspace = 0;
2521 break;
2522
William Lallemand1d705562012-03-12 12:46:41 +01002523 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002524 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002525 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002526 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002527 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002528 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002529 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002530 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002531 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002532 last_isspace = 0;
2533 break;
2534
William Lallemand1d705562012-03-12 12:46:41 +01002535 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002536 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002537 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002538 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002539 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002540 last_isspace = 0;
2541 break;
2542
William Lallemand1d705562012-03-12 12:46:41 +01002543 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002544 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002545 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002546 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002547 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002548 last_isspace = 0;
2549 break;
2550
William Lallemand1d705562012-03-12 12:46:41 +01002551 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002552 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002553 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002554 if (tmp->options & LOG_OPT_QUOTE)
2555 LOGCHAR('"');
2556 LOGCHAR('{');
2557 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2558 if (hdr)
2559 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002560 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002561 ret = lf_encode_string(tmplog, dst + maxsize,
2562 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002563 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002564 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002565 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002566 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002567 }
2568 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002569 if (tmp->options & LOG_OPT_QUOTE)
2570 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002571 last_isspace = 0;
2572 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002573 break;
2574
William Lallemand1d705562012-03-12 12:46:41 +01002575 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002576 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002577 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002578 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2579 if (hdr > 0)
2580 LOGCHAR(' ');
2581 if (tmp->options & LOG_OPT_QUOTE)
2582 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002583 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002584 ret = lf_encode_string(tmplog, dst + maxsize,
2585 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002586 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002587 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002588 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002589 } else if (!(tmp->options & LOG_OPT_QUOTE))
2590 LOGCHAR('-');
2591 if (tmp->options & LOG_OPT_QUOTE)
2592 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002593 last_isspace = 0;
2594 }
2595 }
2596 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002597
William Lallemand1d705562012-03-12 12:46:41 +01002598
2599 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002600 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002601 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002602 if (tmp->options & LOG_OPT_QUOTE)
2603 LOGCHAR('"');
2604 LOGCHAR('{');
2605 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2606 if (hdr)
2607 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002608 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002609 ret = lf_encode_string(tmplog, dst + maxsize,
2610 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002611 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002612 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002613 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002614 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002615 }
2616 LOGCHAR('}');
2617 last_isspace = 0;
2618 if (tmp->options & LOG_OPT_QUOTE)
2619 LOGCHAR('"');
2620 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002621 break;
2622
William Lallemand1d705562012-03-12 12:46:41 +01002623 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002624 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002625 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002626 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2627 if (hdr > 0)
2628 LOGCHAR(' ');
2629 if (tmp->options & LOG_OPT_QUOTE)
2630 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002631 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002632 ret = lf_encode_string(tmplog, dst + maxsize,
2633 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002634 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002635 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002636 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002637 } else if (!(tmp->options & LOG_OPT_QUOTE))
2638 LOGCHAR('-');
2639 if (tmp->options & LOG_OPT_QUOTE)
2640 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002641 last_isspace = 0;
2642 }
2643 }
2644 break;
2645
William Lallemand1d705562012-03-12 12:46:41 +01002646 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002647 /* Request */
2648 if (tmp->options & LOG_OPT_QUOTE)
2649 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002650 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002651 ret = lf_encode_string(tmplog, dst + maxsize,
2652 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002653 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002654 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002655 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002656 if (tmp->options & LOG_OPT_QUOTE)
2657 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002658 last_isspace = 0;
2659 break;
William Lallemand5f232402012-04-05 18:02:55 +02002660
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002661 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002662 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002663
Willy Tarreaub7636d12015-06-17 19:58:02 +02002664 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002665 LOGCHAR('"');
2666
2667 end = uri + strlen(uri);
2668 // look for the first whitespace character
2669 while (uri < end && !HTTP_IS_SPHT(*uri))
2670 uri++;
2671
2672 // keep advancing past multiple spaces
2673 while (uri < end && HTTP_IS_SPHT(*uri)) {
2674 uri++; nspaces++;
2675 }
2676
2677 // look for first space or question mark after url
2678 spc = uri;
2679 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2680 spc++;
2681
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002682 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002683 chunk.area = "<BADREQ>";
2684 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002685 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002686 chunk.area = uri;
2687 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002688 }
2689
Dragan Dosen835b9212016-02-12 13:23:03 +01002690 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002691 if (ret == NULL || *ret != '\0')
2692 goto out;
2693
2694 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002695 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002696 LOGCHAR('"');
2697
2698 last_isspace = 0;
2699 break;
2700
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002701 case LOG_FMT_HTTP_QUERY: // %HQ
2702 if (tmp->options & LOG_OPT_QUOTE)
2703 LOGCHAR('"');
2704
Willy Tarreau57bc8912016-04-25 17:09:40 +02002705 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002706 chunk.area = "<BADREQ>";
2707 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002708 } else {
2709 uri = txn->uri;
2710 end = uri + strlen(uri);
2711 // look for the first question mark
2712 while (uri < end && *uri != '?')
2713 uri++;
2714
2715 qmark = uri;
2716 // look for first space or question mark after url
2717 while (uri < end && !HTTP_IS_SPHT(*uri))
2718 uri++;
2719
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002720 chunk.area = qmark;
2721 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002722 }
2723
Dragan Dosen835b9212016-02-12 13:23:03 +01002724 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002725 if (ret == NULL || *ret != '\0')
2726 goto out;
2727
2728 tmplog = ret;
2729 if (tmp->options & LOG_OPT_QUOTE)
2730 LOGCHAR('"');
2731
2732 last_isspace = 0;
2733 break;
2734
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002735 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002736 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002737
Willy Tarreaub7636d12015-06-17 19:58:02 +02002738 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002739 LOGCHAR('"');
2740
2741 end = uri + strlen(uri);
2742 // look for the first whitespace character
2743 while (uri < end && !HTTP_IS_SPHT(*uri))
2744 uri++;
2745
2746 // keep advancing past multiple spaces
2747 while (uri < end && HTTP_IS_SPHT(*uri)) {
2748 uri++; nspaces++;
2749 }
2750
2751 // look for first space after url
2752 spc = uri;
2753 while (spc < end && !HTTP_IS_SPHT(*spc))
2754 spc++;
2755
Willy Tarreau57bc8912016-04-25 17:09:40 +02002756 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002757 chunk.area = "<BADREQ>";
2758 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002759 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002760 chunk.area = uri;
2761 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002762 }
2763
Dragan Dosen835b9212016-02-12 13:23:03 +01002764 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002765 if (ret == NULL || *ret != '\0')
2766 goto out;
2767
2768 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002769 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002770 LOGCHAR('"');
2771
2772 last_isspace = 0;
2773 break;
2774
2775 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002776 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002777 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002778 LOGCHAR('"');
2779
2780 end = uri + strlen(uri);
2781 // look for the first whitespace character
2782 spc = uri;
2783 while (spc < end && !HTTP_IS_SPHT(*spc))
2784 spc++;
2785
2786 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002787 chunk.area = "<BADREQ>";
2788 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002789 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002790 chunk.area = uri;
2791 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002792 }
2793
Dragan Dosen835b9212016-02-12 13:23:03 +01002794 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002795 if (ret == NULL || *ret != '\0')
2796 goto out;
2797
2798 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002799 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002800 LOGCHAR('"');
2801
2802 last_isspace = 0;
2803 break;
2804
2805 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002806 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002807 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002808 LOGCHAR('"');
2809
2810 end = uri + strlen(uri);
2811 // look for the first whitespace character
2812 while (uri < end && !HTTP_IS_SPHT(*uri))
2813 uri++;
2814
2815 // keep advancing past multiple spaces
2816 while (uri < end && HTTP_IS_SPHT(*uri)) {
2817 uri++; nspaces++;
2818 }
2819
2820 // look for the next whitespace character
2821 while (uri < end && !HTTP_IS_SPHT(*uri))
2822 uri++;
2823
2824 // keep advancing past multiple spaces
2825 while (uri < end && HTTP_IS_SPHT(*uri))
2826 uri++;
2827
Willy Tarreau57bc8912016-04-25 17:09:40 +02002828 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002829 chunk.area = "<BADREQ>";
2830 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002831 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002832 chunk.area = "HTTP/0.9";
2833 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002834 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002835 chunk.area = uri;
2836 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002837 }
2838
Dragan Dosen835b9212016-02-12 13:23:03 +01002839 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002840 if (ret == NULL || *ret != '\0')
2841 goto out;
2842
2843 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002844 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002845 LOGCHAR('"');
2846
2847 last_isspace = 0;
2848 break;
2849
William Lallemand5f232402012-04-05 18:02:55 +02002850 case LOG_FMT_COUNTER: // %rt
2851 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002852 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002853 if (iret < 0 || iret > dst + maxsize - tmplog)
2854 goto out;
2855 last_isspace = 0;
2856 tmplog += iret;
2857 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002858 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002859 if (ret == NULL)
2860 goto out;
2861 tmplog = ret;
2862 last_isspace = 0;
2863 }
2864 break;
2865
Willy Tarreau7346acb2014-08-28 15:03:15 +02002866 case LOG_FMT_LOGCNT: // %lc
2867 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002868 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002869 if (iret < 0 || iret > dst + maxsize - tmplog)
2870 goto out;
2871 last_isspace = 0;
2872 tmplog += iret;
2873 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002874 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002875 if (ret == NULL)
2876 goto out;
2877 tmplog = ret;
2878 last_isspace = 0;
2879 }
2880 break;
2881
William Lallemand5f232402012-04-05 18:02:55 +02002882 case LOG_FMT_HOSTNAME: // %H
2883 src = hostname;
2884 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2885 if (ret == NULL)
2886 goto out;
2887 tmplog = ret;
2888 last_isspace = 0;
2889 break;
2890
2891 case LOG_FMT_PID: // %pid
2892 if (tmp->options & LOG_OPT_HEXA) {
2893 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2894 if (iret < 0 || iret > dst + maxsize - tmplog)
2895 goto out;
2896 last_isspace = 0;
2897 tmplog += iret;
2898 } else {
2899 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2900 if (ret == NULL)
2901 goto out;
2902 tmplog = ret;
2903 last_isspace = 0;
2904 }
2905 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002906
2907 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002908 ret = NULL;
Willy Tarreau02fdf4f2018-09-05 15:49:01 +02002909 src = s ? s->unique_id : NULL;
Thierry FOURNIER1be69102014-04-15 01:38:48 +02002910 ret = lf_text(tmplog, src, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002911 if (ret == NULL)
2912 goto out;
2913 tmplog = ret;
2914 last_isspace = 0;
2915 break;
2916
William Lallemandbddd4fd2012-02-27 11:23:10 +01002917 }
2918 }
2919
2920out:
William Lallemand1d705562012-03-12 12:46:41 +01002921 /* *tmplog is a unused character */
2922 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002923 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002924
Willy Tarreaubaaee002006-06-26 02:48:02 +02002925}
2926
William Lallemand1d705562012-03-12 12:46:41 +01002927/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002928 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002929 * Will not log if the frontend has no log defined.
2930 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002931void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002932{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002933 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002934 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002935 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01002936
2937 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02002938 err = (s->flags & SF_REDISP) ||
2939 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2940 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01002941 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02002942 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002943
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002944 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01002945 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002946
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002947 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01002948 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002949
Willy Tarreauabcd5142013-06-11 17:18:02 +02002950 if (s->logs.level) { /* loglevel was overridden */
2951 if (s->logs.level == -1) {
2952 s->logs.logwait = 0; /* logs disabled */
2953 return;
2954 }
2955 level = s->logs.level - 1;
2956 }
2957 else {
2958 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002959 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02002960 level = LOG_ERR;
2961 }
William Lallemand1d705562012-03-12 12:46:41 +01002962
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002963 /* if unique-id was not generated */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002964 if (!s->unique_id && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Willy Tarreaubafbe012017-11-24 17:34:44 +01002965 if ((s->unique_id = pool_alloc(pool_head_uniqueid)) != NULL)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002966 build_logline(s, s->unique_id, UNIQUEID_LEN, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002967 }
2968
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002969 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
2970 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
2971 &sess->fe->logformat_sd);
2972 }
2973
Dragan Dosen59cee972015-09-19 22:09:02 +02002974 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01002975 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002976 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02002977 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
2978 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01002979 s->logs.logwait = 0;
2980 }
2981}
William Lallemandbddd4fd2012-02-27 11:23:10 +01002982
Willy Tarreau53839352018-09-05 19:51:10 +02002983/*
2984 * send a minimalist log for the session. Will not log if the frontend has no
2985 * log defined. It is assumed that this is only used to report anomalies that
2986 * cannot lead to the creation of a regular stream. Because of this the log
2987 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
2988 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02002989 * function to report unimportant events. It is safe to call this function with
2990 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02002991 */
2992void sess_log(struct session *sess)
2993{
2994 int size, level;
2995 int sd_size = 0;
2996
Willy Tarreau9fa267d2018-10-05 10:22:27 +02002997 if (!sess)
2998 return;
2999
Willy Tarreau53839352018-09-05 19:51:10 +02003000 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3001 return;
3002
3003 level = LOG_INFO;
3004 if (sess->fe->options2 & PR_O2_LOGERRORS)
3005 level = LOG_ERR;
3006
3007 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3008 sd_size = sess_build_logline(sess, NULL,
3009 logline_rfc5424, global.max_syslog_len,
3010 &sess->fe->logformat_sd);
3011 }
3012
3013 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3014 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003015 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003016 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3017 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003018 }
3019}
3020
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003021void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3022{
3023 va_list argp;
3024 int data_len;
3025
3026 if (level < 0 || format == NULL || logline == NULL)
3027 return;
3028
3029 va_start(argp, format);
3030 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3031 if (data_len < 0 || data_len > global.max_syslog_len)
3032 data_len = global.max_syslog_len;
3033 va_end(argp);
3034
3035 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3036}
3037
Willy Tarreau869efd52019-11-15 15:16:57 +01003038/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3039static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003040{
Willy Tarreau869efd52019-11-15 15:16:57 +01003041 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3042 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003043
Willy Tarreau869efd52019-11-15 15:16:57 +01003044 if (!startup_logs)
3045 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3046
3047 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003048}
3049
3050/* register cli keywords */
3051static struct cli_kw_list cli_kws = {{ },{
3052 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003053 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003054 {{},}
3055}};
3056
Willy Tarreau0108d902018-11-25 19:14:37 +01003057INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3058
Willy Tarreau082b6282019-05-22 14:42:12 +02003059REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3060REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003061
Willy Tarreaubaaee002006-06-26 02:48:02 +02003062/*
3063 * Local variables:
3064 * c-indent-level: 8
3065 * c-basic-offset: 8
3066 * End:
3067 */