You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

360 lines
13 KiB

  1. From dc2695cc531bd7fc98f09df5f6e1e57290ab1a14 Mon Sep 17 00:00:00 2001
  2. From: Willy Tarreau <w@1wt.eu>
  3. Date: Fri, 27 Jun 2014 18:10:07 +0200
  4. Subject: [PATCH 9/9] MEDIUM: log: support a user-configurable max log line
  5. length
  6. With all the goodies supported by logformat, people find that the limit
  7. of 1024 chars for log lines is too short. Some servers do not support
  8. larger lines and can simply drop them, so changing the default value is
  9. not always the best choice.
  10. This patch takes a different approach. Log line length is specified per
  11. log server on the "log" line, with a value between 80 and 65535. That
  12. way it's possibly to satisfy all needs, even with some fat local servers
  13. and small remote ones.
  14. (cherry picked from commit 18324f574f349d510622ff45635de899437a3a11)
  15. ---
  16. doc/configuration.txt | 28 ++++++++++++++++--
  17. include/proto/log.h | 1 +
  18. include/types/global.h | 1 +
  19. include/types/log.h | 1 +
  20. src/cfgparse.c | 80 ++++++++++++++++++++++++++++++++++++++++----------
  21. src/log.c | 36 ++++++++++++++++-------
  22. 6 files changed, 118 insertions(+), 29 deletions(-)
  23. diff --git a/doc/configuration.txt b/doc/configuration.txt
  24. index 080d8fc..e53bb21 100644
  25. --- a/doc/configuration.txt
  26. +++ b/doc/configuration.txt
  27. @@ -559,7 +559,7 @@ group <group name>
  28. Similar to "gid" but uses the GID of group name <group name> from /etc/group.
  29. See also "gid" and "user".
  30. -log <address> <facility> [max level [min level]]
  31. +log <address> [len <length>] <facility> [max level [min level]]
  32. Adds a global syslog server. Up to two global servers can be defined. They
  33. will receive logs for startups and exits, as well as all logs from proxies
  34. configured with "log global".
  35. @@ -584,6 +584,18 @@ log <address> <facility> [max level [min level]]
  36. optionally enclosing them with braces ('{}'), similarly to what is done
  37. in Bourne shell.
  38. + <length> is an optional maximum line length. Log lines larger than this value
  39. + will be truncated before being sent. The reason is that syslog
  40. + servers act differently on log line length. All servers support the
  41. + default value of 1024, but some servers simply drop larger lines
  42. + while others do log them. If a server supports long lines, it may
  43. + make sense to set this value here in order to avoid truncating long
  44. + lines. Similarly, if a server drops long lines, it is preferable to
  45. + truncate them before sending them. Accepted values are 80 to 65535
  46. + inclusive. The default value of 1024 is generally fine for all
  47. + standard usages. Some specific cases of long captures or
  48. + JSON-formated logs may require larger values.
  49. +
  50. <facility> must be one of the 24 standard syslog facilities :
  51. kern user mail daemon auth syslog lpr news
  52. @@ -3349,7 +3361,7 @@ ignore-persist { if | unless } <condition>
  53. log global
  54. -log <address> <facility> [<level> [<minlevel>]]
  55. +log <address> [len <length>] <facility> [<level> [<minlevel>]]
  56. no log
  57. Enable per-instance logging of events and traffic.
  58. May be used in sections : defaults | frontend | listen | backend
  59. @@ -3389,6 +3401,18 @@ no log
  60. sign ('$') and optionally enclosing them with braces ('{}'),
  61. similarly to what is done in Bourne shell.
  62. + <length> is an optional maximum line length. Log lines larger than this
  63. + value will be truncated before being sent. The reason is that
  64. + syslog servers act differently on log line length. All servers
  65. + support the default value of 1024, but some servers simply drop
  66. + larger lines while others do log them. If a server supports long
  67. + lines, it may make sense to set this value here in order to avoid
  68. + truncating long lines. Similarly, if a server drops long lines,
  69. + it is preferable to truncate them before sending them. Accepted
  70. + values are 80 to 65535 inclusive. The default value of 1024 is
  71. + generally fine for all standard usages. Some specific cases of
  72. + long captures or JSON-formated logs may require larger values.
  73. +
  74. <facility> must be one of the 24 standard syslog facilities :
  75. kern user mail daemon auth syslog lpr news
  76. diff --git a/include/proto/log.h b/include/proto/log.h
  77. index e3c1a75..54c51d1 100644
  78. --- a/include/proto/log.h
  79. +++ b/include/proto/log.h
  80. @@ -39,6 +39,7 @@ extern char *log_format;
  81. extern char default_tcp_log_format[];
  82. extern char default_http_log_format[];
  83. extern char clf_http_log_format[];
  84. +extern char *logline;
  85. int build_logline(struct session *s, char *dst, size_t maxsize, struct list *list_format);
  86. diff --git a/include/types/global.h b/include/types/global.h
  87. index 23e3f3d..77df1dd 100644
  88. --- a/include/types/global.h
  89. +++ b/include/types/global.h
  90. @@ -110,6 +110,7 @@ struct global {
  91. int last_checks;
  92. int spread_checks;
  93. int max_spread_checks;
  94. + int max_syslog_len;
  95. char *chroot;
  96. char *pidfile;
  97. char *node, *desc; /* node name & description */
  98. diff --git a/include/types/log.h b/include/types/log.h
  99. index b3288bd..c7e47ea 100644
  100. --- a/include/types/log.h
  101. +++ b/include/types/log.h
  102. @@ -152,6 +152,7 @@ struct logsrv {
  103. int facility;
  104. int level;
  105. int minlvl;
  106. + int maxlen;
  107. };
  108. #endif /* _TYPES_LOG_H */
  109. diff --git a/src/cfgparse.c b/src/cfgparse.c
  110. index 762978a..e6e65b4 100644
  111. --- a/src/cfgparse.c
  112. +++ b/src/cfgparse.c
  113. @@ -1254,6 +1254,8 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
  114. struct sockaddr_storage *sk;
  115. int port1, port2;
  116. struct logsrv *logsrv;
  117. + int arg = 0;
  118. + int len = 0;
  119. if (*(args[1]) == 0 || *(args[2]) == 0) {
  120. Alert("parsing [%s:%d] : '%s' expects <address> and <facility> as arguments.\n", file, linenum, args[0]);
  121. @@ -1263,28 +1265,50 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
  122. logsrv = calloc(1, sizeof(struct logsrv));
  123. - logsrv->facility = get_log_facility(args[2]);
  124. + /* just after the address, a length may be specified */
  125. + if (strcmp(args[arg+2], "len") == 0) {
  126. + len = atoi(args[arg+3]);
  127. + if (len < 80 || len > 65535) {
  128. + Alert("parsing [%s:%d] : invalid log length '%s', must be between 80 and 65535.\n",
  129. + file, linenum, args[arg+3]);
  130. + err_code |= ERR_ALERT | ERR_FATAL;
  131. + goto out;
  132. + }
  133. + logsrv->maxlen = len;
  134. +
  135. + /* skip these two args */
  136. + arg += 2;
  137. + }
  138. + else
  139. + logsrv->maxlen = MAX_SYSLOG_LEN;
  140. +
  141. + if (logsrv->maxlen > global.max_syslog_len) {
  142. + global.max_syslog_len = logsrv->maxlen;
  143. + logline = realloc(logline, global.max_syslog_len + 1);
  144. + }
  145. +
  146. + logsrv->facility = get_log_facility(args[arg+2]);
  147. if (logsrv->facility < 0) {
  148. - Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
  149. + Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[arg+2]);
  150. err_code |= ERR_ALERT | ERR_FATAL;
  151. logsrv->facility = 0;
  152. }
  153. logsrv->level = 7; /* max syslog level = debug */
  154. - if (*(args[3])) {
  155. - logsrv->level = get_log_level(args[3]);
  156. + if (*(args[arg+3])) {
  157. + logsrv->level = get_log_level(args[arg+3]);
  158. if (logsrv->level < 0) {
  159. - Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
  160. + Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[arg+3]);
  161. err_code |= ERR_ALERT | ERR_FATAL;
  162. logsrv->level = 0;
  163. }
  164. }
  165. logsrv->minlvl = 0; /* limit syslog level to this level (emerg) */
  166. - if (*(args[4])) {
  167. - logsrv->minlvl = get_log_level(args[4]);
  168. + if (*(args[arg+4])) {
  169. + logsrv->minlvl = get_log_level(args[arg+4]);
  170. if (logsrv->minlvl < 0) {
  171. - Alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[4]);
  172. + Alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[arg+4]);
  173. err_code |= ERR_ALERT | ERR_FATAL;
  174. logsrv->minlvl = 0;
  175. }
  176. @@ -4791,22 +4815,46 @@ stats_error_parsing:
  177. else if (*(args[1]) && *(args[2])) {
  178. struct sockaddr_storage *sk;
  179. int port1, port2;
  180. + int arg = 0;
  181. + int len = 0;
  182. logsrv = calloc(1, sizeof(struct logsrv));
  183. - logsrv->facility = get_log_facility(args[2]);
  184. + /* just after the address, a length may be specified */
  185. + if (strcmp(args[arg+2], "len") == 0) {
  186. + len = atoi(args[arg+3]);
  187. + if (len < 80 || len > 65535) {
  188. + Alert("parsing [%s:%d] : invalid log length '%s', must be between 80 and 65535.\n",
  189. + file, linenum, args[arg+3]);
  190. + err_code |= ERR_ALERT | ERR_FATAL;
  191. + goto out;
  192. + }
  193. + logsrv->maxlen = len;
  194. +
  195. + /* skip these two args */
  196. + arg += 2;
  197. + }
  198. + else
  199. + logsrv->maxlen = MAX_SYSLOG_LEN;
  200. +
  201. + if (logsrv->maxlen > global.max_syslog_len) {
  202. + global.max_syslog_len = logsrv->maxlen;
  203. + logline = realloc(logline, global.max_syslog_len + 1);
  204. + }
  205. +
  206. + logsrv->facility = get_log_facility(args[arg+2]);
  207. if (logsrv->facility < 0) {
  208. - Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[2]);
  209. + Alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[arg+2]);
  210. err_code |= ERR_ALERT | ERR_FATAL;
  211. goto out;
  212. }
  213. logsrv->level = 7; /* max syslog level = debug */
  214. - if (*(args[3])) {
  215. - logsrv->level = get_log_level(args[3]);
  216. + if (*(args[arg+3])) {
  217. + logsrv->level = get_log_level(args[arg+3]);
  218. if (logsrv->level < 0) {
  219. - Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[3]);
  220. + Alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[arg+3]);
  221. err_code |= ERR_ALERT | ERR_FATAL;
  222. goto out;
  223. @@ -4814,10 +4862,10 @@ stats_error_parsing:
  224. }
  225. logsrv->minlvl = 0; /* limit syslog level to this level (emerg) */
  226. - if (*(args[4])) {
  227. - logsrv->minlvl = get_log_level(args[4]);
  228. + if (*(args[arg+4])) {
  229. + logsrv->minlvl = get_log_level(args[arg+4]);
  230. if (logsrv->minlvl < 0) {
  231. - Alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[4]);
  232. + Alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[arg+4]);
  233. err_code |= ERR_ALERT | ERR_FATAL;
  234. goto out;
  235. diff --git a/src/log.c b/src/log.c
  236. index 114ab7b..3e3acb4 100644
  237. --- a/src/log.c
  238. +++ b/src/log.c
  239. @@ -146,7 +146,7 @@ char *log_format = NULL;
  240. /* This is a global syslog line, common to all outgoing messages. It begins
  241. * with the syslog tag and the date that are updated by update_log_hdr().
  242. */
  243. -static char logline[MAX_SYSLOG_LEN];
  244. +char *logline = NULL;
  245. struct logformat_var_args {
  246. char *name;
  247. @@ -736,7 +736,7 @@ static char *update_log_hdr()
  248. tvsec = date.tv_sec;
  249. get_localtime(tvsec, &tm);
  250. - hdr_len = snprintf(logline, MAX_SYSLOG_LEN,
  251. + hdr_len = snprintf(logline, global.max_syslog_len,
  252. "<<<<>%s %2d %02d:%02d:%02d %s%s[%d]: ",
  253. monthname[tm.tm_mon],
  254. tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
  255. @@ -746,8 +746,8 @@ static char *update_log_hdr()
  256. * either -1 or the number of bytes that would be needed to store
  257. * the total message. In both cases, we must adjust it.
  258. */
  259. - if (hdr_len < 0 || hdr_len > MAX_SYSLOG_LEN)
  260. - hdr_len = MAX_SYSLOG_LEN;
  261. + if (hdr_len < 0 || hdr_len > global.max_syslog_len)
  262. + hdr_len = global.max_syslog_len;
  263. dataptr = logline + hdr_len;
  264. }
  265. @@ -772,9 +772,9 @@ void send_log(struct proxy *p, int level, const char *format, ...)
  266. data_len = dataptr - logline;
  267. va_start(argp, format);
  268. - data_len += vsnprintf(dataptr, logline + sizeof(logline) - dataptr, format, argp);
  269. - if (data_len < 0 || data_len > MAX_SYSLOG_LEN)
  270. - data_len = MAX_SYSLOG_LEN;
  271. + data_len += vsnprintf(dataptr, logline + global.max_syslog_len - dataptr, format, argp);
  272. + if (data_len < 0 || data_len > global.max_syslog_len)
  273. + data_len = global.max_syslog_len;
  274. va_end(argp);
  275. __send_log(p, level, logline, data_len);
  276. @@ -811,8 +811,6 @@ void __send_log(struct proxy *p, int level, char *message, size_t size)
  277. if (!logsrvs)
  278. return;
  279. - message[size - 1] = '\n';
  280. -
  281. /* Send log messages to syslog server. */
  282. nblogger = 0;
  283. list_for_each_entry(tmp, logsrvs, list) {
  284. @@ -820,6 +818,8 @@ void __send_log(struct proxy *p, int level, char *message, size_t size)
  285. int *plogfd = logsrv->addr.ss_family == AF_UNIX ?
  286. &logfdunix : &logfdinet;
  287. int sent;
  288. + int max;
  289. + char backup;
  290. nblogger++;
  291. @@ -858,9 +858,23 @@ void __send_log(struct proxy *p, int level, char *message, size_t size)
  292. } while (fac_level && log_ptr > dataptr);
  293. *log_ptr = '<';
  294. - sent = sendto(*plogfd, log_ptr, size - (log_ptr - dataptr),
  295. + max = size - (log_ptr - dataptr);
  296. + if (max > logsrv->maxlen)
  297. + max = logsrv->maxlen;
  298. +
  299. + /* insert a \n at the end of the message, but save what was
  300. + * there first because we could have different max lengths
  301. + * for different log targets.
  302. + */
  303. + backup = log_ptr[max - 1];
  304. + log_ptr[max - 1] = '\n';
  305. +
  306. + sent = sendto(*plogfd, log_ptr, max,
  307. MSG_DONTWAIT | MSG_NOSIGNAL,
  308. (struct sockaddr *)&logsrv->addr, get_addr_len(&logsrv->addr));
  309. +
  310. + log_ptr[max - 1] = backup;
  311. +
  312. if (sent < 0) {
  313. Alert("sendto logger #%d failed: %s (errno=%d)\n",
  314. nblogger, strerror(errno), errno);
  315. @@ -1604,7 +1618,7 @@ void sess_log(struct session *s)
  316. tmplog = update_log_hdr();
  317. size = tmplog - logline;
  318. - size += build_logline(s, tmplog, sizeof(logline) - size, &s->fe->logformat);
  319. + size += build_logline(s, tmplog, global.max_syslog_len - size, &s->fe->logformat);
  320. if (size > 0) {
  321. __send_log(s->fe, level, logline, size + 1);
  322. s->logs.logwait = 0;
  323. --
  324. 1.8.5.5