openresty开发系列36--openresty执行流程之6日志模块处理阶段
一)header_filter_by_lua
语法:header_filter_by_lua <lua-script-str>
语境:http,server,location,location if
阶段:output-header-filter
通常用来设置cookie和headers,在该阶段不能使用以下几个API:
一、output API(ngx.say和ngx.send_headers)
二、control API(ngx.exit和ngx.exec)
三、subrequest API(ngx.location.capture和ngx.location.capture_multi)
四、cosocket API(ngx.socket.tcp和ngx.req.socket)
案例一:
location / {
header_filter_by_lua 'ngx.header.Foo = "blah"';
echo "Hello World!";
}
案例二:
http {
log_format main '$msec $status $request $request_time '
'$http_referer $remote_addr [ $time_local ] '
'$upstream_response_time $host $bytes_sent '
'$request_length $upstream_addr';
access_log logs/access.log main buffer=32k flush=1s;
upstream remote_world {
server 127.0.0.1:8080;
}
server {
listen 80;
location /exec {
content_by_lua '
local cjson = require "cjson"
local headers = {
["Etag"] = "662222165e216225df78fbbd47c9333",
["Last-Modified"] = "Sat, 24 July 2019 16:58:22 GMT",
}
ngx.var.my_headers = cjson.encode(headers)
ngx.var.my_upstream = "remote_world"
ngx.var.my_uri = "/world"
ngx.exec("/upstream")
';
}
location /upstream {
internal;
set $my_headers $my_headers;
set $my_upstream $my_upstream;
set $my_uri $my_uri;
proxy_pass http://$my_upstream$my_uri;
header_filter_by_lua '
local cjson = require "cjson"
headers = cjson.decode(ngx.var.my_headers)
for k, v in pairs(headers) do
ngx.header[k] = v
end
';
}
}
server {
listen 8080;
location /world {
echo "hello world";
}
}
}
二)body_filter_by_lua
语法:body_filter_by_lua <lua-script-str>
语境:http,server,location,location if
阶段:output-body-filter
输入的数据时经过ngx.arg[1](做为lua的string值),经过ngx.arg[2]这个bool类型表示响应数据流的结尾。
这个指令能够用来篡改http的响应正文的;会调用几回
在该阶段不能利用以下几个API:
一、output API(ngx.say和ngx.send_headers)
二、control API(ngx.exit和ngx.exec)
三、subrequest API(ngx.location.capture和ngx.location.capture_multi)
四、cosocket API(ngx.socket.tcp和ngx.req.socket)
输入的数据时经过ngx.arg[1],经过ngx.arg[2]这个bool范例暗示响应数据流的末了。
基于这个缘由,’eof’只是nginx的连接缓冲区的last_buf(对主requests)或last_in_chain(对subrequests)的标志。
运行如下呼吁能够立即终止运行接下来的lua代码:
return ngx.ERROR
这会将响应体截断致使无效的响应。lua代码能够经过修改ngx.arg[1]的内容将数据传输到下游的
nginx output body filter阶段的其它模块中去。譬喻,将response body中的小写字母举办反转,咱们能够这么写:
案例一
location /t {
echo hello world12;
echo hi yile;
body_filter_by_lua '
ngx.log(ngx.ERR,"ngx.arg[1]=",ngx.arg[1]," arg[2]=",ngx.arg[2])
ngx.arg[1] = string.upper(ngx.arg[1])
';
}
尽管只有两个 echo,可是 body_filter_by_lua* 会被调用三次!
第三次调用的时候,ngx.arg[1] 为空字符串,而 ngx.arg[2] 为 true。
这是由于,Nginx 的 upstream 相关模块,以及 OpenResty 的 content_by_lua,
会单独发送一个设置了 last_buf 的空 buffer,来表示流的结束。这算是一个约定俗成的惯例,因此有必要在运行相关逻辑以前,
检查 ngx.arg[1] 是否为空。固然反过来不必定成立,ngx.arg[2] == true 并不表明 ngx.arg[1] 必定为空。
案例二
location /t {
echo hello world;
echo hiya globe;
body_filter_by_lua '
ngx.log(ngx.ERR,"ngx.arg[1]=",ngx.arg[1]," arg[2]=",ngx.arg[2])
local chunk = ngx.arg[1]
if string.match(chunk, "hello") then
ngx.arg[2] = true -- new eof
return
end
ngx.arg[1] = nil
';
}
这是由于,当body filter看到了一块包括”hello“的字符块后立即将”eof“标志配置为了true,
从而致使响应被截断了但仍然是有效的回覆。
三)log_by_lua,log_by_lua_file
在log阶段指定的lua日志,并不会替换access log,而是在那以后调用。
在该阶段不能利用以下几个API:
一、output API(ngx.say和ngx.send_headers)
二、control API(ngx.exit和ngx.exec)
三、subrequest API(ngx.location.capture和ngx.location.capture_multi)
四、cosocket API(ngx.socket.tcp和ngx.req.socket)
能够利用此阶段,把日志统一收集到日志服务器中
location / {
echo "Hello World!";
log_by_lua_block {
ngx.log(ngx.ERR,msg)
}
}
elk日志收集分析
nginx