comparison src/core/ngx_syslog.c @ 5702:777202558122

Added syslog support for error_log and access_log directives.
author Vladimir Homutov <vl@nginx.com>
date Mon, 12 May 2014 16:34:15 +0400
parents
children aacd994167d3
comparison
equal deleted inserted replaced
5701:1209b8a7b077 5702:777202558122
1
2 /*
3 * Copyright (C) Nginx, Inc.
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10
11
12 #define NGX_SYSLOG_MAX_STR \
13 NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \
14 + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \
15 + 32 /* tag */ + 2 /* colon, space */
16
17
18 static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
19 static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer);
20 static void ngx_syslog_cleanup(void *data);
21
22
23 static char *facilities[] = {
24 "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp",
25 "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0",
26 "local1", "local2", "local3", "local4", "local5", "local6", "local7",
27 NULL
28 };
29
30 /* note 'error/warn' like in nginx.conf, not 'err/warning' */
31 static char *severities[] = {
32 "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL
33 };
34
35 static ngx_log_t ngx_syslog_dummy_log;
36 static ngx_event_t ngx_syslog_dummy_event;
37
38
39 char *
40 ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
41 {
42 peer->pool = cf->pool;
43 peer->facility = NGX_CONF_UNSET_UINT;
44 peer->severity = NGX_CONF_UNSET_UINT;
45
46 if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) {
47 return NGX_CONF_ERROR;
48 }
49
50 if (peer->server.sockaddr == NULL) {
51 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
52 "no syslog server specified");
53 return NGX_CONF_ERROR;
54 }
55
56 if (peer->facility == NGX_CONF_UNSET_UINT) {
57 peer->facility = 23; /* local7 */
58 }
59
60 if (peer->severity == NGX_CONF_UNSET_UINT) {
61 peer->severity = 6; /* info */
62 }
63
64 if (peer->tag.data == NULL) {
65 ngx_str_set(&peer->tag, "nginx");
66 }
67
68 peer->conn.fd = (ngx_socket_t) -1;
69
70 return NGX_CONF_OK;
71 }
72
73
74 static char *
75 ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
76 {
77 u_char *p, *comma, c;
78 size_t len;
79 ngx_str_t *value;
80 ngx_url_t u;
81 ngx_uint_t i;
82
83 value = cf->args->elts;
84
85 p = value[1].data + sizeof("syslog:") - 1;
86
87 for ( ;; ) {
88 comma = (u_char *) ngx_strchr(p, ',');
89
90 if (comma != NULL) {
91 len = comma - p;
92 *comma = '\0';
93
94 } else {
95 len = value[1].data + value[1].len - p;
96 }
97
98 if (ngx_strncmp(p, "server=", 7) == 0) {
99
100 if (peer->server.sockaddr != NULL) {
101 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
102 "duplicate syslog \"server\"");
103 return NGX_CONF_ERROR;
104 }
105
106 ngx_memzero(&u, sizeof(ngx_url_t));
107
108 u.url.data = p + 7;
109 u.url.len = len - 7;
110 u.default_port = 514;
111
112 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
113 if (u.err) {
114 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
115 "%s in syslog server \"%V\"",
116 u.err, &u.url);
117 }
118
119 return NGX_CONF_ERROR;
120 }
121
122 peer->server = u.addrs[0];
123
124 } else if (ngx_strncmp(p, "facility=", 9) == 0) {
125
126 if (peer->facility != NGX_CONF_UNSET_UINT) {
127 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
128 "duplicate syslog \"facility\"");
129 return NGX_CONF_ERROR;
130 }
131
132 for (i = 0; facilities[i] != NULL; i++) {
133
134 if (ngx_strcmp(p + 9, facilities[i]) == 0) {
135 peer->facility = i;
136 goto next;
137 }
138 }
139
140 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
141 "unknown syslog facility \"%s\"", p + 9);
142 return NGX_CONF_ERROR;
143
144 } else if (ngx_strncmp(p, "severity=", 9) == 0) {
145
146 if (peer->severity != NGX_CONF_UNSET_UINT) {
147 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
148 "duplicate syslog \"severity\"");
149 return NGX_CONF_ERROR;
150 }
151
152 for (i = 0; severities[i] != NULL; i++) {
153
154 if (ngx_strcmp(p + 9, severities[i]) == 0) {
155 peer->severity = i;
156 goto next;
157 }
158 }
159
160 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
161 "unknown syslog severity \"%s\"", p + 9);
162 return NGX_CONF_ERROR;
163
164 } else if (ngx_strncmp(p, "tag=", 4) == 0) {
165
166 if (peer->tag.data != NULL) {
167 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
168 "duplicate syslog \"tag\"");
169 return NGX_CONF_ERROR;
170 }
171
172 /*
173 * RFC 3164: the TAG is a string of ABNF alphanumeric characters
174 * that MUST NOT exceed 32 characters.
175 */
176 if (len - 4 > 32) {
177 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
178 "syslog tag length exceeds 32");
179 return NGX_CONF_ERROR;
180 }
181
182 for (i = 4; i < len; i++) {
183 c = ngx_tolower(p[i]);
184
185 if (c < '0' || (c > '9' && c < 'a') || c > 'z') {
186 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
187 "syslog \"tag\" only allows "
188 "alphanumeric characters");
189 return NGX_CONF_ERROR;
190 }
191 }
192
193 peer->tag.data = p + 4;
194 peer->tag.len = len - 4;
195
196 } else {
197 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
198 "unknown syslog parameter \"%s\"", p);
199 return NGX_CONF_ERROR;
200 }
201
202 next:
203
204 if (comma == NULL) {
205 break;
206 }
207
208 p = comma + 1;
209 }
210
211 return NGX_CONF_OK;
212 }
213
214
215 u_char *
216 ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf)
217 {
218 ngx_uint_t pri;
219
220 pri = peer->facility * 8 + peer->severity;
221
222 return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time,
223 &ngx_cycle->hostname, &peer->tag);
224 }
225
226
227 void
228 ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
229 size_t len)
230 {
231 u_char *p, msg[NGX_SYSLOG_MAX_STR];
232 ngx_uint_t head_len;
233 ngx_syslog_peer_t *peer;
234
235 peer = log->wdata;
236
237 if (peer->processing) {
238 return;
239 }
240
241 peer->processing = 1;
242 peer->severity = level - 1;
243
244 p = ngx_syslog_add_header(peer, msg);
245 head_len = p - msg;
246
247 len -= NGX_LINEFEED_SIZE;
248
249 if (len > NGX_SYSLOG_MAX_STR - head_len) {
250 len = NGX_SYSLOG_MAX_STR - head_len;
251 }
252
253 p = ngx_snprintf(p, len, "%s", buf);
254
255 (void) ngx_syslog_send(peer, msg, p - msg);
256
257 peer->processing = 0;
258 }
259
260
261 ssize_t
262 ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len)
263 {
264 if (peer->conn.fd == (ngx_socket_t) -1) {
265 if (ngx_syslog_init_peer(peer) != NGX_OK) {
266 return NGX_ERROR;
267 }
268 }
269
270 if (ngx_send) {
271 return ngx_send(&peer->conn, buf, len);
272
273 } else {
274 /* event module has not yet set ngx_io */
275 return ngx_os_io.send(&peer->conn, buf, len);
276 }
277 }
278
279
280 static ngx_int_t
281 ngx_syslog_init_peer(ngx_syslog_peer_t *peer)
282 {
283 ngx_socket_t fd;
284 ngx_pool_cleanup_t *cln;
285
286 peer->conn.read = &ngx_syslog_dummy_event;
287 peer->conn.write = &ngx_syslog_dummy_event;
288 peer->conn.log = &ngx_syslog_dummy_log;
289
290 ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log;
291
292 cln = ngx_pool_cleanup_add(peer->pool, 0);
293 if (cln == NULL) {
294 return NGX_ERROR;
295 }
296
297 cln->data = peer;
298 cln->handler = ngx_syslog_cleanup;
299
300 fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0);
301 if (fd == (ngx_socket_t) -1) {
302 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
303 ngx_socket_n " failed");
304 return NGX_ERROR;
305 }
306
307 if (ngx_nonblocking(fd) == -1) {
308 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
309 ngx_nonblocking_n " failed");
310 return NGX_ERROR;
311 }
312
313 if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) {
314 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
315 "connect() failed");
316 return NGX_ERROR;
317 }
318
319 peer->conn.fd = fd;
320 return NGX_OK;
321 }
322
323
324 static void
325 ngx_syslog_cleanup(void *data)
326 {
327 ngx_syslog_peer_t *peer = data;
328
329 if (peer->conn.fd != (ngx_socket_t) -1) {
330 (void) ngx_close_socket(peer->conn.fd);
331 }
332 }