blob: fdb3b8c456d87f608ac47dce29b0f61c41d15487 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * General logging functions.
3 *
4 * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
5 *
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 Tarreauc8f24f82007-11-30 18:38:35 +010013#include <fcntl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020014#include <stdarg.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <syslog.h>
19#include <time.h>
20#include <unistd.h>
Robert Tsai81ae1952007-12-05 10:47:29 +010021#include <errno.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020022
23#include <sys/time.h>
24
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020025#include <common/config.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020026#include <common/standard.h>
Willy Tarreaufb278672006-10-15 15:38:50 +020027#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020028
29#include <types/backend.h>
30#include <types/global.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020031#include <types/log.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020032#include <types/session.h>
33
Robert Tsai81ae1952007-12-05 10:47:29 +010034#ifndef MSG_NOSIGNAL
35#define MSG_NOSIGNAL (0)
36#endif /* !MSG_NOSIGNAL */
Willy Tarreaubaaee002006-06-26 02:48:02 +020037
38const char *log_facilities[NB_LOG_FACILITIES] = {
39 "kern", "user", "mail", "daemon",
40 "auth", "syslog", "lpr", "news",
41 "uucp", "cron", "auth2", "ftp",
42 "ntp", "audit", "alert", "cron2",
43 "local0", "local1", "local2", "local3",
44 "local4", "local5", "local6", "local7"
45};
46
47
48const char *log_levels[NB_LOG_LEVELS] = {
49 "emerg", "alert", "crit", "err",
50 "warning", "notice", "info", "debug"
51};
52
53const char *monthname[12] = {
54 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
55 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
56};
57
58const char sess_term_cond[8] = "-cCsSPRI"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal */
Willy Tarreaub8750a82006-09-03 09:56:00 +020059const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +020060
61/*
62 * Displays the message on stderr with the date and pid. Overrides the quiet
63 * mode during startup.
64 */
Willy Tarreaub17916e2006-10-15 15:17:57 +020065void Alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +020066{
67 va_list argp;
Willy Tarreaufe944602007-10-25 10:34:16 +020068 struct tm tm;
Willy Tarreaubaaee002006-06-26 02:48:02 +020069
70 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
71 va_start(argp, fmt);
72
Willy Tarreaufe944602007-10-25 10:34:16 +020073 get_localtime(now.tv_sec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +020074 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
Willy Tarreaufe944602007-10-25 10:34:16 +020075 tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
Willy Tarreaubaaee002006-06-26 02:48:02 +020076 vfprintf(stderr, fmt, argp);
77 fflush(stderr);
78 va_end(argp);
79 }
80}
81
82
83/*
84 * Displays the message on stderr with the date and pid.
85 */
Willy Tarreaub17916e2006-10-15 15:17:57 +020086void Warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +020087{
88 va_list argp;
Willy Tarreaufe944602007-10-25 10:34:16 +020089 struct tm tm;
Willy Tarreaubaaee002006-06-26 02:48:02 +020090
91 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
92 va_start(argp, fmt);
93
Willy Tarreaufe944602007-10-25 10:34:16 +020094 get_localtime(now.tv_sec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +020095 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
Willy Tarreaufe944602007-10-25 10:34:16 +020096 tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
Willy Tarreaubaaee002006-06-26 02:48:02 +020097 vfprintf(stderr, fmt, argp);
98 fflush(stderr);
99 va_end(argp);
100 }
101}
102
103/*
104 * Displays the message on <out> only if quiet mode is not set.
105 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200106void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200107{
108 va_list argp;
109
110 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
111 va_start(argp, fmt);
112 vfprintf(out, fmt, argp);
113 fflush(out);
114 va_end(argp);
115 }
116}
117
118/*
119 * returns log level for <lev> or -1 if not found.
120 */
121int get_log_level(const char *lev)
122{
123 int level;
124
125 level = NB_LOG_LEVELS - 1;
126 while (level >= 0 && strcmp(log_levels[level], lev))
127 level--;
128
129 return level;
130}
131
132
133/*
134 * returns log facility for <fac> or -1 if not found.
135 */
136int get_log_facility(const char *fac)
137{
138 int facility;
139
140 facility = NB_LOG_FACILITIES - 1;
141 while (facility >= 0 && strcmp(log_facilities[facility], fac))
142 facility--;
143
144 return facility;
145}
146
Robert Tsai81ae1952007-12-05 10:47:29 +0100147/*
148 * Return the length of the address endpoint, suitable for use with sendto().
149 */
Willy Tarreau019767b2007-12-05 11:11:55 +0100150static inline int logsrv_addrlen(const struct logsrv *logsrv)
Robert Tsai81ae1952007-12-05 10:47:29 +0100151{
152#ifdef __SOCKADDR_COMMON
153 switch (logsrv->u.addr.sa_family) {
154 case AF_UNIX:
155 return sizeof(logsrv->u.un);
156 case AF_INET:
157 return sizeof(logsrv->u.in);
158 default:
159 break;
160 }
161#else /* !__SOCKADDR_COMMON */
162 switch (logsrv->u.addr.sa_family) {
163 case AF_UNIX:
164 return logsrv->u.un.sun_len;
165 case AF_INET:
166 return logsrv->u.in.sin_len;
167 default:
168 break;
169 }
170#endif /* !__SOCKADDR_COMMON */
171 return -1;
172}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200173
Willy Tarreaubaaee002006-06-26 02:48:02 +0200174/*
175 * This function sends a syslog message to both log servers of a proxy,
176 * or to global log servers if the proxy is NULL.
177 * It also tries not to waste too much time computing the message header.
178 * It doesn't care about errors nor does it report them.
179 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200180void send_log(struct proxy *p, int level, const char *message, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200181{
Robert Tsai81ae1952007-12-05 10:47:29 +0100182 static int logfdunix = -1; /* syslog to AF_UNIX socket */
183 static int logfdinet = -1; /* syslog to AF_INET socket */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200184 static long tvsec = -1; /* to force the string to be initialized */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200185 va_list argp;
186 static char logmsg[MAX_SYSLOG_LEN];
187 static char *dataptr = NULL;
188 int fac_level;
189 int hdr_len, data_len;
Robert Tsai81ae1952007-12-05 10:47:29 +0100190 struct logsrv *logsrvs[2];
Willy Tarreaubaaee002006-06-26 02:48:02 +0200191 int facilities[2], loglevel[2];
Robert Tsai81ae1952007-12-05 10:47:29 +0100192 int nblogger;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200193 int nbloggers = 0;
194 char *log_ptr;
195
Willy Tarreaubaaee002006-06-26 02:48:02 +0200196 if (level < 0 || progname == NULL || message == NULL)
197 return;
198
Willy Tarreau2b35c952006-10-15 15:25:48 +0200199 if (now.tv_sec != tvsec || dataptr == NULL) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200200 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +0200201 struct tm tm;
202
Willy Tarreau2b35c952006-10-15 15:25:48 +0200203 tvsec = now.tv_sec;
Willy Tarreaufe944602007-10-25 10:34:16 +0200204 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200205
206 hdr_len = snprintf(logmsg, sizeof(logmsg),
207 "<<<<>%s %2d %02d:%02d:%02d %s[%d]: ",
Willy Tarreaufe944602007-10-25 10:34:16 +0200208 monthname[tm.tm_mon],
209 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreaubaaee002006-06-26 02:48:02 +0200210 progname, pid);
211 /* WARNING: depending upon implementations, snprintf may return
212 * either -1 or the number of bytes that would be needed to store
213 * the total message. In both cases, we must adjust it.
214 */
215 if (hdr_len < 0 || hdr_len > sizeof(logmsg))
216 hdr_len = sizeof(logmsg);
217
218 dataptr = logmsg + hdr_len;
219 }
220
221 va_start(argp, message);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100222 /*
223 * FIXME: we take a huge performance hit here. We might have to replace
224 * vsnprintf() for a hard-coded log writer.
225 */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200226 data_len = vsnprintf(dataptr, logmsg + sizeof(logmsg) - dataptr, message, argp);
227 if (data_len < 0 || data_len > (logmsg + sizeof(logmsg) - dataptr))
228 data_len = logmsg + sizeof(logmsg) - dataptr;
229 va_end(argp);
230 dataptr[data_len - 1] = '\n'; /* force a break on ultra-long lines */
231
232 if (p == NULL) {
233 if (global.logfac1 >= 0) {
Robert Tsai81ae1952007-12-05 10:47:29 +0100234 logsrvs[nbloggers] = &global.logsrv1;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200235 facilities[nbloggers] = global.logfac1;
236 loglevel[nbloggers] = global.loglev1;
237 nbloggers++;
238 }
239 if (global.logfac2 >= 0) {
Robert Tsai81ae1952007-12-05 10:47:29 +0100240 logsrvs[nbloggers] = &global.logsrv2;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200241 facilities[nbloggers] = global.logfac2;
242 loglevel[nbloggers] = global.loglev2;
243 nbloggers++;
244 }
245 } else {
246 if (p->logfac1 >= 0) {
Robert Tsai81ae1952007-12-05 10:47:29 +0100247 logsrvs[nbloggers] = &p->logsrv1;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200248 facilities[nbloggers] = p->logfac1;
249 loglevel[nbloggers] = p->loglev1;
250 nbloggers++;
251 }
252 if (p->logfac2 >= 0) {
Robert Tsai81ae1952007-12-05 10:47:29 +0100253 logsrvs[nbloggers] = &p->logsrv2;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200254 facilities[nbloggers] = p->logfac2;
255 loglevel[nbloggers] = p->loglev2;
256 nbloggers++;
257 }
Robert Tsai81ae1952007-12-05 10:47:29 +0100258 }
259
260 /* Lazily set up syslog sockets for protocol families of configured
261 * syslog servers. */
262 for (nblogger = 0; nblogger < nbloggers; nblogger++) {
263 const struct logsrv *logsrv = logsrvs[nblogger];
264 int proto, *plogfd;
265 if (logsrv->u.addr.sa_family == AF_UNIX) {
266 proto = 0;
267 plogfd = &logfdunix;
268 } else {
269 /* sa_family == AF_INET */
270 proto = IPPROTO_UDP;
271 plogfd = &logfdinet;
272 }
273 if (*plogfd >= 0) {
274 /* socket already created. */
275 continue;
276 }
277 if ((*plogfd = socket(logsrv->u.addr.sa_family, SOCK_DGRAM,
278 proto)) < 0) {
279 Alert("socket for logger #%d failed: %s (errno=%d)\n",
280 nblogger + 1, strerror(errno), errno);
281 return;
282 }
283 /* we don't want to receive anything on this socket */
284 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
285 /* does nothing under Linux, maybe needed for others */
286 shutdown(*plogfd, SHUT_RD);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200287 }
288
Robert Tsai81ae1952007-12-05 10:47:29 +0100289 /* Send log messages to syslog server. */
290 for (nblogger = 0; nblogger < nbloggers; nblogger++) {
291 const struct logsrv *logsrv = logsrvs[nblogger];
292 int *plogfd = logsrv->u.addr.sa_family == AF_UNIX ?
293 &logfdunix : &logfdinet;
294 int sent;
295
Willy Tarreaubaaee002006-06-26 02:48:02 +0200296 /* we can filter the level of the messages that are sent to each logger */
Robert Tsai81ae1952007-12-05 10:47:29 +0100297 if (level > loglevel[nblogger])
Willy Tarreaubaaee002006-06-26 02:48:02 +0200298 continue;
299
300 /* For each target, we may have a different facility.
301 * We can also have a different log level for each message.
302 * This induces variations in the message header length.
303 * Since we don't want to recompute it each time, nor copy it every
304 * time, we only change the facility in the pre-computed header,
305 * and we change the pointer to the header accordingly.
306 */
Robert Tsai81ae1952007-12-05 10:47:29 +0100307 fac_level = (facilities[nblogger] << 3) + level;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200308 log_ptr = logmsg + 3; /* last digit of the log level */
309 do {
310 *log_ptr = '0' + fac_level % 10;
311 fac_level /= 10;
312 log_ptr--;
313 } while (fac_level && log_ptr > logmsg);
314 *log_ptr = '<';
315
316 /* the total syslog message now starts at logptr, for dataptr+data_len-logptr */
Robert Tsai81ae1952007-12-05 10:47:29 +0100317 sent = sendto(*plogfd, log_ptr, dataptr + data_len - log_ptr,
318 MSG_DONTWAIT | MSG_NOSIGNAL, &logsrv->u.addr, logsrv_addrlen(logsrv));
319 if (sent < 0) {
320 Alert("sendto logger #%d failed: %s (errno=%d)\n",
321 nblogger, strerror(errno), errno);
322 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200323 }
324}
325
326
327/*
328 * send a log for the session when we have enough info about it
329 */
Willy Tarreau42250582007-04-01 01:30:43 +0200330void tcp_sess_log(struct session *s)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200331{
332 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
Willy Tarreau73de9892006-11-30 11:40:23 +0100333 struct proxy *fe = s->fe;
Willy Tarreauddb358d2006-12-17 22:55:52 +0100334 struct proxy *be = s->be;
335 struct proxy *prx_log;
Willy Tarreau42250582007-04-01 01:30:43 +0200336 int tolog;
337 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200338 struct tm tm;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200339
Willy Tarreaubaaee002006-06-26 02:48:02 +0200340 if (s->cli_addr.ss_family == AF_INET)
341 inet_ntop(AF_INET,
342 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
343 pn, sizeof(pn));
344 else
345 inet_ntop(AF_INET6,
346 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
347 pn, sizeof(pn));
348
Willy Tarreaufe944602007-10-25 10:34:16 +0200349 get_localtime(s->logs.tv_accept.tv_sec, &tm);
Willy Tarreauddb358d2006-12-17 22:55:52 +0100350
351 if (fe->logfac1 >= 0)
352 prx_log = fe;
Willy Tarreau97de6242006-12-27 17:18:38 +0100353 /*
354 * FIXME: should we fall back to the backend if the frontend did not
355 * define any log ? It seems like we should not permit such complex
356 * setups because they would induce a debugging nightmare for the
357 * admin.
358 */
359 // else if (be->logfac1 >= 0)
360 // prx_log = be;
Willy Tarreauddb358d2006-12-17 22:55:52 +0100361 else
362 prx_log = NULL; /* global */
363
Willy Tarreau42250582007-04-01 01:30:43 +0200364 /* FIXME: let's limit ourselves to frontend logging for now. */
365 tolog = fe->to_log;
366 svid = (tolog & LW_SVID) ? (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "-";
Willy Tarreaubaaee002006-06-26 02:48:02 +0200367
Willy Tarreau42250582007-04-01 01:30:43 +0200368 send_log(prx_log, LOG_INFO, "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
369 " %s %s/%s %d/%d/%s%d %s%lld"
370 " %c%c %d/%d/%d/%d %d/%d\n",
371 pn,
372 (s->cli_addr.ss_family == AF_INET) ?
373 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
374 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +0200375 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
376 tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.tv_accept.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +0200377 fe->id, be->id, svid,
378 (s->logs.t_queue >= 0) ? s->logs.t_queue : -1,
379 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
380 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
381 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_in,
382 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
383 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
384 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
385 s->logs.srv_queue_size, s->logs.prx_queue_size);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200386
387 s->logs.logwait = 0;
388}
389
Willy Tarreaubaaee002006-06-26 02:48:02 +0200390
391/*
392 * Local variables:
393 * c-indent-level: 8
394 * c-basic-offset: 8
395 * End:
396 */