Line data Source code
1 :
2 : /*
3 : * Copyright (C) Xiaozhe Wang (chaoslawful)
4 : * Copyright (C) Yichun Zhang (agentzh)
5 : */
6 :
7 :
8 : #ifndef DDEBUG
9 : #define DDEBUG 0
10 : #endif
11 : #include "ddebug.h"
12 :
13 :
14 : #include "ngx_http_lua_log.h"
15 : #include "ngx_http_lua_util.h"
16 : #include "ngx_http_lua_log_ringbuf.h"
17 :
18 :
19 : static int ngx_http_lua_print(lua_State *L);
20 : static int ngx_http_lua_ngx_log(lua_State *L);
21 : static int log_wrapper(ngx_log_t *log, const char *ident,
22 : ngx_uint_t level, lua_State *L);
23 : static void ngx_http_lua_inject_log_consts(lua_State *L);
24 :
25 :
26 : /**
27 : * Wrapper of nginx log functionality. Take a log level param and varargs of
28 : * log message params.
29 : *
30 : * @param L Lua state pointer
31 : * @retval always 0 (don't return values to Lua)
32 : * */
33 : int
34 0 : ngx_http_lua_ngx_log(lua_State *L)
35 : {
36 : ngx_log_t *log;
37 : ngx_http_request_t *r;
38 : const char *msg;
39 : int level;
40 :
41 0 : r = ngx_http_lua_get_req(L);
42 :
43 0 : if (r && r->connection && r->connection->log) {
44 0 : log = r->connection->log;
45 :
46 : } else {
47 0 : log = ngx_cycle->log;
48 : }
49 :
50 0 : level = luaL_checkint(L, 1);
51 0 : if (level < NGX_LOG_STDERR || level > NGX_LOG_DEBUG) {
52 0 : msg = lua_pushfstring(L, "bad log level: %d", level);
53 0 : return luaL_argerror(L, 1, msg);
54 : }
55 :
56 : /* remove log-level param from stack */
57 0 : lua_remove(L, 1);
58 :
59 0 : return log_wrapper(log, "[lua] ", (ngx_uint_t) level, L);
60 : }
61 :
62 :
63 : /**
64 : * Override Lua print function, output message to nginx error logs. Equal to
65 : * ngx.log(ngx.NOTICE, ...).
66 : *
67 : * @param L Lua state pointer
68 : * @retval always 0 (don't return values to Lua)
69 : * */
70 : int
71 0 : ngx_http_lua_print(lua_State *L)
72 : {
73 : ngx_log_t *log;
74 : ngx_http_request_t *r;
75 :
76 0 : r = ngx_http_lua_get_req(L);
77 :
78 0 : if (r && r->connection && r->connection->log) {
79 0 : log = r->connection->log;
80 :
81 : } else {
82 0 : log = ngx_cycle->log;
83 : }
84 :
85 0 : return log_wrapper(log, "[lua] ", NGX_LOG_NOTICE, L);
86 : }
87 :
88 :
89 : static int
90 0 : log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level,
91 : lua_State *L)
92 : {
93 : u_char *buf;
94 : u_char *p, *q;
95 : ngx_str_t name;
96 : int nargs, i;
97 : size_t size, len;
98 0 : size_t src_len = 0;
99 : int type;
100 : const char *msg;
101 : lua_Debug ar;
102 :
103 0 : if (level > log->log_level) {
104 0 : return 0;
105 : }
106 :
107 : #if 1
108 : /* add debug info */
109 :
110 0 : lua_getstack(L, 1, &ar);
111 0 : lua_getinfo(L, "Snl", &ar);
112 :
113 : /* get the basename of the Lua source file path, stored in q */
114 0 : name.data = (u_char *) ar.short_src;
115 0 : if (name.data == NULL) {
116 0 : name.len = 0;
117 :
118 : } else {
119 0 : p = name.data;
120 0 : while (*p != '\0') {
121 0 : if (*p == '/' || *p == '\\') {
122 0 : name.data = p + 1;
123 : }
124 0 : p++;
125 : }
126 :
127 0 : name.len = p - name.data;
128 : }
129 :
130 : #endif
131 :
132 0 : nargs = lua_gettop(L);
133 :
134 0 : size = name.len + NGX_INT_T_LEN + sizeof(":: ") - 1;
135 :
136 0 : if (*ar.namewhat != '\0' && *ar.what == 'L') {
137 0 : src_len = ngx_strlen(ar.name);
138 0 : size += src_len + sizeof("(): ") - 1;
139 : }
140 :
141 0 : for (i = 1; i <= nargs; i++) {
142 0 : type = lua_type(L, i);
143 0 : switch (type) {
144 0 : case LUA_TNUMBER:
145 : case LUA_TSTRING:
146 0 : lua_tolstring(L, i, &len);
147 0 : size += len;
148 0 : break;
149 :
150 0 : case LUA_TNIL:
151 0 : size += sizeof("nil") - 1;
152 0 : break;
153 :
154 0 : case LUA_TBOOLEAN:
155 0 : if (lua_toboolean(L, i)) {
156 0 : size += sizeof("true") - 1;
157 :
158 : } else {
159 0 : size += sizeof("false") - 1;
160 : }
161 :
162 0 : break;
163 :
164 0 : case LUA_TTABLE:
165 0 : if (!luaL_callmeta(L, i, "__tostring")) {
166 0 : return luaL_argerror(L, i, "expected table to have "
167 : "__tostring metamethod");
168 : }
169 :
170 0 : lua_tolstring(L, -1, &len);
171 0 : size += len;
172 0 : break;
173 :
174 0 : case LUA_TLIGHTUSERDATA:
175 0 : if (lua_touserdata(L, i) == NULL) {
176 0 : size += sizeof("null") - 1;
177 0 : break;
178 : }
179 :
180 0 : continue;
181 :
182 0 : default:
183 0 : msg = lua_pushfstring(L, "string, number, boolean, or nil "
184 : "expected, got %s",
185 : lua_typename(L, type));
186 0 : return luaL_argerror(L, i, msg);
187 : }
188 : }
189 :
190 0 : buf = lua_newuserdata(L, size);
191 :
192 0 : p = ngx_copy(buf, name.data, name.len);
193 :
194 0 : *p++ = ':';
195 :
196 0 : p = ngx_snprintf(p, NGX_INT_T_LEN, "%d",
197 0 : ar.currentline ? ar.currentline : ar.linedefined);
198 :
199 0 : *p++ = ':'; *p++ = ' ';
200 :
201 0 : if (*ar.namewhat != '\0' && *ar.what == 'L') {
202 0 : p = ngx_copy(p, ar.name, src_len);
203 0 : *p++ = '(';
204 0 : *p++ = ')';
205 0 : *p++ = ':';
206 0 : *p++ = ' ';
207 : }
208 :
209 0 : for (i = 1; i <= nargs; i++) {
210 0 : type = lua_type(L, i);
211 0 : switch (type) {
212 0 : case LUA_TNUMBER:
213 : case LUA_TSTRING:
214 0 : q = (u_char *) lua_tolstring(L, i, &len);
215 0 : p = ngx_copy(p, q, len);
216 0 : break;
217 :
218 0 : case LUA_TNIL:
219 0 : *p++ = 'n';
220 0 : *p++ = 'i';
221 0 : *p++ = 'l';
222 0 : break;
223 :
224 0 : case LUA_TBOOLEAN:
225 0 : if (lua_toboolean(L, i)) {
226 0 : *p++ = 't';
227 0 : *p++ = 'r';
228 0 : *p++ = 'u';
229 0 : *p++ = 'e';
230 :
231 : } else {
232 0 : *p++ = 'f';
233 0 : *p++ = 'a';
234 0 : *p++ = 'l';
235 0 : *p++ = 's';
236 0 : *p++ = 'e';
237 : }
238 :
239 0 : break;
240 :
241 0 : case LUA_TTABLE:
242 0 : luaL_callmeta(L, i, "__tostring");
243 0 : q = (u_char *) lua_tolstring(L, -1, &len);
244 0 : p = ngx_copy(p, q, len);
245 0 : break;
246 :
247 0 : case LUA_TLIGHTUSERDATA:
248 0 : *p++ = 'n';
249 0 : *p++ = 'u';
250 0 : *p++ = 'l';
251 0 : *p++ = 'l';
252 :
253 0 : break;
254 :
255 0 : default:
256 0 : return luaL_error(L, "impossible to reach here");
257 : }
258 : }
259 :
260 0 : if (p - buf > (off_t) size) {
261 0 : return luaL_error(L, "buffer error: %d > %d", (int) (p - buf),
262 : (int) size);
263 : }
264 :
265 0 : ngx_log_error(level, log, 0, "%s%*s", ident, (size_t) (p - buf), buf);
266 :
267 0 : return 0;
268 : }
269 :
270 :
271 : void
272 18 : ngx_http_lua_inject_log_api(lua_State *L)
273 : {
274 18 : ngx_http_lua_inject_log_consts(L);
275 :
276 18 : lua_pushcfunction(L, ngx_http_lua_ngx_log);
277 18 : lua_setfield(L, -2, "log");
278 :
279 18 : lua_pushcfunction(L, ngx_http_lua_print);
280 18 : lua_setglobal(L, "print");
281 18 : }
282 :
283 :
284 : static void
285 18 : ngx_http_lua_inject_log_consts(lua_State *L)
286 : {
287 : /* {{{ nginx log level constants */
288 18 : lua_pushinteger(L, NGX_LOG_STDERR);
289 18 : lua_setfield(L, -2, "STDERR");
290 :
291 18 : lua_pushinteger(L, NGX_LOG_EMERG);
292 18 : lua_setfield(L, -2, "EMERG");
293 :
294 18 : lua_pushinteger(L, NGX_LOG_ALERT);
295 18 : lua_setfield(L, -2, "ALERT");
296 :
297 18 : lua_pushinteger(L, NGX_LOG_CRIT);
298 18 : lua_setfield(L, -2, "CRIT");
299 :
300 18 : lua_pushinteger(L, NGX_LOG_ERR);
301 18 : lua_setfield(L, -2, "ERR");
302 :
303 18 : lua_pushinteger(L, NGX_LOG_WARN);
304 18 : lua_setfield(L, -2, "WARN");
305 :
306 18 : lua_pushinteger(L, NGX_LOG_NOTICE);
307 18 : lua_setfield(L, -2, "NOTICE");
308 :
309 18 : lua_pushinteger(L, NGX_LOG_INFO);
310 18 : lua_setfield(L, -2, "INFO");
311 :
312 18 : lua_pushinteger(L, NGX_LOG_DEBUG);
313 18 : lua_setfield(L, -2, "DEBUG");
314 : /* }}} */
315 18 : }
316 :
317 :
318 : #ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH
319 : ngx_int_t
320 0 : ngx_http_lua_capture_log_handler(ngx_log_t *log,
321 : ngx_uint_t level, u_char *buf, size_t n)
322 : {
323 : ngx_http_lua_log_ringbuf_t *ringbuf;
324 :
325 : dd("enter");
326 :
327 0 : ringbuf = (ngx_http_lua_log_ringbuf_t *)
328 0 : ngx_cycle->intercept_error_log_data;
329 :
330 0 : if (level > ringbuf->filter_level) {
331 0 : return NGX_OK;
332 : }
333 :
334 0 : ngx_http_lua_log_ringbuf_write(ringbuf, level, buf, n);
335 :
336 : dd("capture log: %s\n", buf);
337 :
338 0 : return NGX_OK;
339 : }
340 : #endif
341 :
342 :
343 : #ifndef NGX_LUA_NO_FFI_API
344 : int
345 0 : ngx_http_lua_ffi_errlog_set_filter_level(int level, u_char *err, size_t *errlen)
346 : {
347 : #ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH
348 : ngx_http_lua_log_ringbuf_t *ringbuf;
349 :
350 0 : ringbuf = ngx_cycle->intercept_error_log_data;
351 :
352 0 : if (ringbuf == NULL) {
353 0 : *errlen = ngx_snprintf(err, *errlen,
354 : "directive \"lua_capture_error_log\" is not set")
355 0 : - err;
356 0 : return NGX_ERROR;
357 : }
358 :
359 0 : if (level > NGX_LOG_DEBUG || level < NGX_LOG_STDERR) {
360 0 : *errlen = ngx_snprintf(err, *errlen, "bad log level: %d", level)
361 0 : - err;
362 0 : return NGX_ERROR;
363 : }
364 :
365 0 : ringbuf->filter_level = level;
366 0 : return NGX_OK;
367 : #else
368 : *errlen = ngx_snprintf(err, *errlen,
369 : "missing the capture error log patch for nginx")
370 : - err;
371 : return NGX_ERROR;
372 : #endif
373 : }
374 :
375 :
376 : int
377 0 : ngx_http_lua_ffi_errlog_get_msg(char **log, int *loglevel, u_char *err,
378 : size_t *errlen, double *log_time)
379 : {
380 : #ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH
381 : ngx_uint_t loglen;
382 :
383 : ngx_http_lua_log_ringbuf_t *ringbuf;
384 :
385 0 : ringbuf = ngx_cycle->intercept_error_log_data;
386 :
387 0 : if (ringbuf == NULL) {
388 0 : *errlen = ngx_snprintf(err, *errlen,
389 : "directive \"lua_capture_error_log\" is not set")
390 0 : - err;
391 0 : return NGX_ERROR;
392 : }
393 :
394 0 : if (ringbuf->count == 0) {
395 0 : return NGX_DONE;
396 : }
397 :
398 0 : ngx_http_lua_log_ringbuf_read(ringbuf, loglevel, (void **) log, &loglen,
399 : log_time);
400 0 : return loglen;
401 : #else
402 : *errlen = ngx_snprintf(err, *errlen,
403 : "missing the capture error log patch for nginx")
404 : - err;
405 : return NGX_ERROR;
406 : #endif
407 : }
408 :
409 :
410 : int
411 0 : ngx_http_lua_ffi_errlog_get_sys_filter_level(ngx_http_request_t *r)
412 : {
413 : ngx_log_t *log;
414 : int log_level;
415 :
416 0 : if (r && r->connection && r->connection->log) {
417 0 : log = r->connection->log;
418 :
419 : } else {
420 0 : log = ngx_cycle->log;
421 : }
422 :
423 0 : log_level = log->log_level;
424 0 : if (log_level == NGX_LOG_DEBUG_ALL) {
425 0 : log_level = NGX_LOG_DEBUG;
426 : }
427 :
428 0 : return log_level;
429 : }
430 :
431 : #endif
432 :
433 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|