my lua script
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("172.20.0.2", 6379)
if not ok then
ngx.log(ngx.CRIT, "Failed to connect to redis: ", err)
return
end
function save_bytes_sent()
local bytes_sent = ngx.var.bytes_sent
local res, err = red:set("bytes_sent_" .. ngx.var.uri, bytes_sent)
if not res then
ngx.log(ngx.CRIT, "Failed to save bytes_sent in redis: ", err)
return
end
local ok, err = red:close()
if not ok then
ngx.log(ngx.CRIT, "Failed to close the connection to redis: ", err)
return
end
ngx.log(ngx.CRIT, "Saved bytes_sent in redis successfully")
end
save_bytes_sent()
and my nginx.conf
location / {
access_by_lua_file /test.lua;
}
i use openresty docker image and all config is ok such as volumes, network and ...
I want to get the ngx.var.bytes_sent value from the response of each request and insert it in redis, but my problem is that in access_by_lua_file
, its value is zero, and if I use the log_by_lua_file
, I can get its value, but I cannot use Redis because there is no access to Redis in this phase.
What is the solution for this problem?
Since Rewrite/Access Phase precedes Content Phase, it is too early to use $bytes_sent
(ngx.var.bytes_sent
) in access_by_lua_*
directives (the value will be zero). See the figure below.
Log Phase (log_by_lua_*
) is the right place, but, as you mentioned, it is not possible to use the Redis client in this phase (Cosocket API is disabled in this context).
The common trick is to wrap your code in a callback and run it via zero-delay timer. See this section of the documentation: Cosockets Not Available Everywhere.
A rough example:
log_by_lua_block {
local redis = require "resty.redis"
local REDIS_HOST = "127.20.0.2"
local REDIS_PORT = 6379
local function get_redis_connection(host, port)
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect(host, port)
if not ok then
return nil, err
end
return red
end
local function save_bytes_sent(_, uri, bytes_sent)
local red, err = get_redis_connection(REDIS_HOST, REDIS_PORT)
if not red then
ngx.log(ngx.CRIT, "Failed to connect to redis: ", err)
return
end
local res, err = red:set("bytes_sent_" .. uri, bytes_sent)
if not res then
ngx.log(ngx.CRIT, "Failed to save bytes_sent in redis: ", err)
return
end
local ok, err = red:close()
if not ok then
ngx.log(ngx.CRIT, "Failed to close the connection to redis: ", err)
return
end
ngx.log(ngx.CRIT, "Saved bytes_sent in redis successfully")
end
ngx.timer.at(0, save_bytes_sent, ngx.var.uri, ngx.var.bytes_sent)
}