Mercurial > hg > nginx
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 } |