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