blob: 214b272ef430b4c7ea895a2321c5b2a950d5cba5 [file] [log] [blame]
Willy Tarreau67b5a162019-08-11 16:38:56 +02001/*
2 * Event sink management
3 *
4 * Copyright (C) 2000-2019 Willy Tarreau - w@1wt.eu
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation, version 2.1
9 * exclusively.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <sys/uio.h>
Willy Tarreau799e9ed2019-08-27 10:34:32 +020022#include <fcntl.h>
23#include <unistd.h>
Willy Tarreau67b5a162019-08-11 16:38:56 +020024#include <common/compat.h>
25#include <common/config.h>
26#include <common/ist.h>
27#include <common/mini-clist.h>
28#include <proto/log.h>
29#include <proto/sink.h>
30
31struct list sink_list = LIST_HEAD_INIT(sink_list);
32
33struct sink *sink_find(const char *name)
34{
35 struct sink *sink;
36
37 list_for_each_entry(sink, &sink_list, sink_list)
38 if (strcmp(sink->name, name) == 0)
39 return sink;
40 return NULL;
41}
42
43/* creates a new sink and adds it to the list, it's still generic and not fully
44 * initialized. Returns NULL on allocation failure. If another one already
45 * exists with the same name, it will be returned. The caller can detect it as
46 * a newly created one has type SINK_TYPE_NEW.
47 */
Willy Tarreau973e6622019-08-20 11:57:52 +020048static struct sink *__sink_new(const char *name, const char *desc, enum sink_fmt fmt)
Willy Tarreau67b5a162019-08-11 16:38:56 +020049{
50 struct sink *sink;
51
52 sink = sink_find(name);
53 if (sink)
54 goto end;
55
56 sink = malloc(sizeof(*sink));
57 if (!sink)
58 goto end;
59
60 sink->name = name;
61 sink->desc = desc;
62 sink->fmt = fmt;
63 sink->type = SINK_TYPE_NEW;
64 /* set defaults for syslog ones */
65 sink->syslog_facility = 0;
66 sink->syslog_minlvl = 0;
67 sink->maxlen = MAX_SYSLOG_LEN;
68 /* address will be filled by the caller if needed */
Willy Tarreau973e6622019-08-20 11:57:52 +020069 sink->ctx.fd = -1;
Willy Tarreau67b5a162019-08-11 16:38:56 +020070 sink->ctx.dropped = 0;
71 HA_RWLOCK_INIT(&sink->ctx.lock);
72 LIST_ADDQ(&sink_list, &sink->sink_list);
73 end:
74 return sink;
75}
76
Willy Tarreau973e6622019-08-20 11:57:52 +020077/* creates a sink called <name> of type FD associated to fd <fd>, format <fmt>,
78 * and description <desc>. Returns NULL on allocation failure or conflict.
79 * Perfect duplicates are merged (same type, fd, and name).
80 */
81struct sink *sink_new_fd(const char *name, const char *desc, enum sink_fmt fmt, int fd)
82{
83 struct sink *sink;
84
85 sink = __sink_new(name, desc, fmt);
86 if (!sink || (sink->type == SINK_TYPE_FD && sink->ctx.fd == fd))
87 goto end;
88
89 if (sink->type != SINK_TYPE_NEW) {
90 sink = NULL;
91 goto end;
92 }
93
Willy Tarreau799e9ed2019-08-27 10:34:32 +020094 /* FD not yet initialized to non-blocking mode.
95 * DON'T DO IT ON A TERMINAL!
96 */
97 if (!isatty(fd))
98 fcntl(fd, F_SETFL, O_NONBLOCK);
Willy Tarreau973e6622019-08-20 11:57:52 +020099 sink->type = SINK_TYPE_FD;
100 sink->ctx.fd = fd;
101 end:
102 return sink;
103}
104
Willy Tarreau67b5a162019-08-11 16:38:56 +0200105/* tries to send <nmsg> message parts (up to 8, ignored above) from message
106 * array <msg> to sink <sink>. Formating according to the sink's preference is
107 * done here. Lost messages are accounted for in the sink's counter.
108 */
109void sink_write(struct sink *sink, const struct ist msg[], size_t nmsg)
110{
111 struct iovec iovec[10];
112 char short_hdr[4];
113 size_t maxlen = sink->maxlen ? sink->maxlen : ~0;
114 size_t sent = 0;
115 int vec = 0;
116
117 /* keep one char for a possible trailing '\n' in any case */
118 maxlen--;
119
120 if (sink->fmt == SINK_FMT_SHORT) {
121 short_hdr[0] = '<';
122 short_hdr[1] = '0' + sink->syslog_minlvl;
123 short_hdr[2] = '>';
124
125 iovec[vec].iov_base = short_hdr;
126 iovec[vec].iov_len = MIN(maxlen, 3);
127 maxlen -= iovec[vec].iov_len;
128 vec++;
129 }
130
131 /* copy the remaining entries from the original message. Skip empty fields and
132 * truncate the whole message to maxlen.
133 */
134 while (nmsg && vec < (sizeof(iovec) / sizeof(iovec[0]) - 1)) {
135 iovec[vec].iov_base = msg->ptr;
136 iovec[vec].iov_len = MIN(maxlen, msg->len);
137 maxlen -= iovec[vec].iov_len;
138 if (iovec[vec].iov_len)
139 vec++;
140 msg++; nmsg--;
141 }
142
Willy Tarreau973e6622019-08-20 11:57:52 +0200143 if (sink->type == SINK_TYPE_FD) {
144 /* For the FD we always emit the trailing \n. It was already provisioned above. */
145 iovec[vec].iov_base = "\n";
146 iovec[vec].iov_len = 1;
147 vec++;
148
149 HA_RWLOCK_WRLOCK(LOGSRV_LOCK, &sink->ctx.lock);
150 sent = writev(sink->ctx.fd, iovec, vec);
151 HA_RWLOCK_WRUNLOCK(LOGSRV_LOCK, &sink->ctx.lock);
152 /* sent > 0 if the message was delivered */
153 }
Willy Tarreau67b5a162019-08-11 16:38:56 +0200154
155 /* account for errors now */
156 if (sent <= 0)
157 HA_ATOMIC_ADD(&sink->ctx.dropped, 1);
158}
159
Willy Tarreau973e6622019-08-20 11:57:52 +0200160static void sink_init()
161{
162 sink_new_fd("stdout", "standard output (fd#1)", SINK_FMT_RAW, 1);
163 sink_new_fd("stderr", "standard output (fd#2)", SINK_FMT_RAW, 2);
164}
165
166INITCALL0(STG_REGISTER, sink_init);
167
Willy Tarreau67b5a162019-08-11 16:38:56 +0200168/*
169 * Local variables:
170 * c-indent-level: 8
171 * c-basic-offset: 8
172 * End:
173 */