Permalink
Browse files

optimize: now we register the "ndk" and "ngx" lua tables for log_by_l…

…ua* at config time rather than request time. this gives significant performance boost. also improved error handling in log_by_lua*.
  • Loading branch information...
agentzh committed Jun 11, 2012
1 parent f3a3757 commit 8481276e1aee6d1f7f14adb93c6bfb53f5c90ddc
Showing with 142 additions and 40 deletions.
  1. +59 −37 src/ngx_http_lua_logby.c
  2. +6 −1 src/ngx_http_lua_logby.h
  3. +5 −0 src/ngx_http_lua_util.c
  4. +19 −1 t/018-ndk.t
  5. +1 −1 t/062-count.t
  6. +52 −0 t/075-logby.t
View
@@ -26,13 +26,13 @@
static ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r);
+/* light user data key for the "ngx" table in the Lua VM regsitry */
+static char ngx_http_lua_logby_ngx_key;
+
+
static void
ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r)
{
- ngx_http_lua_main_conf_t *lmcf;
-
- lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
-
/* set nginx request pointer to current lua thread's globals table */
lua_pushlightuserdata(L, &ngx_http_lua_request_key);
lua_pushlightuserdata(L, r);
@@ -49,16 +49,36 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r)
* all variables created in the script-env will be thrown away at the end
* of the script run.
* */
- lua_newtable(L); /* new empty environment aka {} */
-#if defined(NDK) && NDK
- ngx_http_lua_inject_ndk_api(L);
-#endif /* defined(NDK) && NDK */
+ lua_createtable(L, 0 /* narr */, 1 /* nrec */); /* new empty environment */
/* {{{ initialize ngx.* namespace */
- lua_createtable(L, 0 /* narr */, 72 /* nrec */); /* ngx.* */
+ lua_pushlightuserdata(L, &ngx_http_lua_logby_ngx_key);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ lua_setfield(L, -2, "ngx");
+ /* }}} */
+
+ /* {{{ make new env inheriting main thread's globals table */
+ lua_newtable(L); /* the metatable for the new env */
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+ lua_setfield(L, -2, "__index");
+ lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */
+ /* }}} */
+
+ lua_setfenv(L, -2); /* set new running env for the code closure */
+}
- ngx_http_lua_inject_internal_utils(r->connection->log, L);
+
+void
+ngx_http_lua_inject_logby_ngx_api(ngx_conf_t *cf, lua_State *L)
+{
+ ngx_http_lua_main_conf_t *lmcf;
+
+ lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module);
+
+ lua_pushlightuserdata(L, &ngx_http_lua_logby_ngx_key);
+
+ lua_createtable(L, 0 /* narr */, 69 /* nrec */); /* ngx.* */
ngx_http_lua_inject_http_consts(L);
ngx_http_lua_inject_core_consts(L);
@@ -69,23 +89,13 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r)
#if (NGX_PCRE)
ngx_http_lua_inject_regex_api(L);
#endif
- ngx_http_lua_inject_req_api_no_io(r->connection->log, L);
+ ngx_http_lua_inject_req_api_no_io(cf->log, L);
ngx_http_lua_inject_resp_header_api(L);
ngx_http_lua_inject_variable_api(L);
ngx_http_lua_inject_shdict_api(lmcf, L);
ngx_http_lua_inject_misc_api(L);
- lua_setfield(L, -2, "ngx");
- /* }}} */
-
- /* {{{ make new env inheriting main thread's globals table */
- lua_newtable(L); /* the metatable for the new env */
- lua_pushvalue(L, LUA_GLOBALSINDEX);
- lua_setfield(L, -2, "__index");
- lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */
- /* }}} */
-
- lua_setfenv(L, -2); /* set new running env for the code closure */
+ lua_rawset(L, LUA_REGISTRYINDEX);
}
@@ -134,7 +144,7 @@ ngx_http_lua_log_handler(ngx_http_request_t *r)
if (ctx->ctx_ref != LUA_NOREF) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "lua release ngx.ctx");
+ "lua release ngx.ctx");
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
@@ -239,40 +249,52 @@ ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r)
{
ngx_int_t rc;
u_char *err_msg;
+ size_t len;
#if (NGX_PCRE)
ngx_pool_t *old_pool;
#endif
/* set Lua VM panic handler */
lua_atpanic(L, ngx_http_lua_atpanic);
- /* initialize nginx context in Lua VM, code chunk at stack top sp = 1 */
- ngx_http_lua_log_by_lua_env(L, r);
+ NGX_LUA_EXCEPTION_TRY {
+
+ /* initialize nginx context in Lua VM, code chunk at stack top sp = 1 */
+ ngx_http_lua_log_by_lua_env(L, r);
#if (NGX_PCRE)
- /* XXX: work-around to nginx regex subsystem */
- old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
+ /* XXX: work-around to nginx regex subsystem */
+ old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
#endif
- /* protected call user code */
- rc = lua_pcall(L, 0, 1, 0);
+ /* protected call user code */
+ rc = lua_pcall(L, 0, 1, 0);
#if (NGX_PCRE)
- /* XXX: work-around to nginx regex subsystem */
- ngx_http_lua_pcre_malloc_done(old_pool);
+ /* XXX: work-around to nginx regex subsystem */
+ ngx_http_lua_pcre_malloc_done(old_pool);
#endif
- if (rc != 0) {
- /* error occured when running loaded code */
- err_msg = (u_char *) lua_tostring(L, -1);
+ if (rc != 0) {
+ /* error occured when running loaded code */
+ err_msg = (u_char *) lua_tolstring(L, -1, &len);
+
+ if (err_msg == NULL) {
+ err_msg = (u_char *) "unknown reason";
+ len = sizeof("unknown reason") - 1;
+ }
- if (err_msg != NULL) {
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "(lua-error) %s",
- err_msg);
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "failed to run log_by_lua*: %*s", len, err_msg);
lua_settop(L, 0); /* clear remaining elems on stack */
+
+ return NGX_ERROR;
}
+ } NGX_LUA_EXCEPTION_CATCH {
+
+ dd("nginx execution restored");
return NGX_ERROR;
}
View
@@ -6,8 +6,13 @@
ngx_int_t ngx_http_lua_log_handler(ngx_http_request_t *r);
+
ngx_int_t ngx_http_lua_log_handler_inline(ngx_http_request_t *r);
+
ngx_int_t ngx_http_lua_log_handler_file(ngx_http_request_t *r);
+void ngx_http_lua_inject_logby_ngx_api(ngx_conf_t *cf, lua_State *L);
+
+
+#endif /* NGX_HTTP_LUA_LOGBY_H */
-#endif /* NGX_HTTP_LUA_REWRITEBY_H */
View
@@ -31,6 +31,7 @@
#include "ngx_http_lua_sleep.h"
#include "ngx_http_lua_setby.h"
#include "ngx_http_lua_headerfilterby.h"
+#include "ngx_http_lua_logby.h"
char ngx_http_lua_code_cache_key;
@@ -535,6 +536,10 @@ ngx_http_lua_init_globals(ngx_conf_t *cf, lua_State *L)
ngx_http_lua_inject_headerfilterby_ngx_api(cf, L);
}
+ if (lmcf->requires_log) {
+ ngx_http_lua_inject_logby_ngx_api(cf, L);
+ }
+
#if defined(NDK) && NDK
ngx_http_lua_inject_setby_ngx_api(cf, L);
View
@@ -5,7 +5,7 @@ use Test::Nginx::Socket;
repeat_each(2);
-plan tests => repeat_each() * (blocks() * 2 + 1);
+plan tests => repeat_each() * (blocks() * 2 + 2);
#no_diff();
#no_long_string();
@@ -131,3 +131,21 @@ GET /read
--- response_body
a b
+
+
+=== TEST 8: log_by_lua
+--- config
+ location /read {
+ echo ok;
+ log_by_lua '
+ local foo = ndk.set_var.set_unescape_uri("a%20b")
+ ngx.log(ngx.WARN, "foo = ", foo)
+ ';
+ }
+--- request
+GET /read
+--- response_body
+ok
+--- error_log
+foo = a b
+
View
@@ -301,5 +301,5 @@ GET /t
--- response_body_like: 404 Not Found
--- error_code: 404
--- error_log
-ngx. entry count: 72
+ngx. entry count: 69
View
@@ -189,3 +189,55 @@ GET /t2
--- error_log
lua release ngx.ctx
+
+
+=== TEST 9: lua error (string)
+--- config
+ location /lua {
+ log_by_lua 'error("Bad")';
+ echo ok;
+ }
+--- request
+GET /lua
+--- response_body
+ok
+--- error_log
+failed to run log_by_lua*: [string "log_by_lua"]:1: Bad
+
+
+
+=== TEST 10: lua error (nil)
+--- config
+ location /lua {
+ log_by_lua 'error(nil)';
+ echo ok;
+ }
+--- request
+GET /lua
+--- response_body
+ok
+--- error_log
+failed to run log_by_lua*: unknown reason
+
+
+
+=== TEST 11: globals get cleared for every single request
+--- config
+ location /lua {
+ echo ok;
+ log_by_lua '
+ if not foo then
+ foo = 1
+ else
+ foo = foo + 1
+ end
+ ngx.log(ngx.WARN, "foo = ", foo)
+ ';
+ }
+--- request
+GET /lua
+--- response_body
+ok
+--- error_log
+foo = 1
+

0 comments on commit 8481276

Please sign in to comment.