发布时间:2020-07-07 16:46:09来源:阅读:
之前的一篇文章openresty(nginx lua)统计域名状态码、平均响应时间和流量实现了对域名状态码,平均响应时间和流量的统计。但之前的统计方法没有实现当某一域名404或500等状态码超过一定数量后发送具体的url来快速定位位置。这个功能我们其实是通过统计网站日志来实现了。为了摆脱对网站日志的依赖以及提高统计性能,我们尝试把此功能也用nginx lua来实现。具体的使用方法与之前的文章一样,这里只是更新了两个lua脚本。
1、获取域名www.centos.bz 404状态码数量
curl -s "localhost/domain_status?count=status&host=www.centos.bz&status=404"
输出:
10 688
第一列为状态码数量,第二列为域名请求总数
2、获取当域名www.centos.bz 404状态码超过50个时,输出前10个url
curl -s "localhost/domain_status?count=statusUrl&host=www.centos.bz&status=404&exceed=50&output=10"
输出:
/hello-world 90
/centos 10
第一列为url,第二列为url请求次数。
3、获取域名www.centos.bz upstream一分钟内平均耗时
curl -s "localhost/domain_status?count=upT&host=www.centos.bz"
输出:
0.02 452
第一列为upstream平均耗时,第二列为域名总请求次数。
4、获取当域名www.centos.bz upstream平均耗时超过0.5秒时,输出其url
curl -s "localhost/domain_status?count=upTUrl&host=www.centos.bz&exceed=0.5"
输出:
/hello.php 0.82 52
第一列为url,第二列为此url平均耗时,第三列为此url请求次数。监控此接口数据可以快速定位出具体哪些url慢了。
5、获取域名www.centos.bz request time平均耗时
curl -s "localhost/domain_status?count=reqT&host=www.centos.bz"
输出:
1.82 52
第一列为平均耗时,第二列为域名请求数。request time是指完成整个请求所需要的时间(包括把数据传输到用户浏览器的时间)。对于php请求,upstream time指的是nginx把php请求传给fastcgi到完成数据接收所需时间。所以request time永远大于upstream time。
6、获取域名www.centos.bz占用的带宽(单位:字节/秒)
curl -s "localhost/domain_status?count=flow&host=www.centos.bz"
输出:
1024 52
第一列为此域名一分钟内平均传输速率,单位为字节/秒,第二列为域名请求总数。
local access = ngx.shared.access
local host = ngx.var.host or "unknow"
local status = ngx.var.status
local body_bytes_sent = ngx.var.body_bytes_sent
local request_time = ngx.var.request_time
local upstream_response_time = ngx.var.upstream_response_time or 0
local request_uri = ngx.var.request_uri or "/unknow"
local timestamp = ngx.time()
local expire_time = 70
local status_key = table.concat({host,"-",status,"-",timestamp})
local flow_key = table.concat({host,"-flow-",timestamp})
local req_time_key = table.concat({host,"-reqt-",timestamp})
local up_time_key = table.concat({host,"-upt-",timestamp})
local total_key = table.concat({host,"-total-",timestamp})
-- 域名总请求数
local n,e = access:incr(total_key,1)
if not n then
access:set(total_key, 1, expire_time)
end
-- 域名状态码请求数
local n,e = access:incr(status_key,1)
if not n then
access:set(status_key, 1, expire_time)
end
-- 域名流量
local n,e = access:incr(flow_key,body_bytes_sent)
if not n then
access:set(flow_key, body_bytes_sent, expire_time)
end
-- 域名请求耗时
local n,e = access:incr(req_time_key,request_time)
if not n then
access:set(req_time_key, request_time, expire_time)
end
-- 域名upstream耗时
local n,e = access:incr(up_time_key,upstream_response_time)
if not n then
access:set(up_time_key, upstream_response_time, expire_time)
end
-- 获取不带参数的uri
local m, err = ngx.re.match(request_uri, "(.*?)?")
local request_without_args = m and m[1] or request_uri
-- 存储状态码大于400的url
if tonumber(status) >= 400 then
-- 拼接url,状态码,字节数等字段
local request_log_t = {}
table.insert(request_log_t,host)
table.insert(request_log_t,request_without_args)
table.insert(request_log_t,status)
local request_log = table.concat(request_log_t," ")
-- 把拼接的字段储存在字典中
local log_key = table.concat({"status-",timestamp})
local request_log_dict = access:get(log_key) or ""
if request_log_dict == "" then
request_log_dict = request_log
else
request_log_dict = table.concat({request_log_dict,"
",request_log})
end
access:set(log_key, request_log_dict, expire_time)
end
-- 存储upstream time大于0.5的url
if tonumber(upstream_response_time) > 0.5 then
-- 拼接url,状态码,字节数等字段
local request_log_t = {}
table.insert(request_log_t,host)
table.insert(request_log_t,request_without_args)
table.insert(request_log_t,upstream_response_time)
local request_log = table.concat(request_log_t," ")
-- 把拼接的字段储存在字典中
local log_key = table.concat({"upt-",timestamp})
local request_log_dict = access:get(log_key) or ""
if request_log_dict == "" then
request_log_dict = request_log
else
request_log_dict = table.concat({request_log_dict,"
",request_log})
end
access:set(log_key, request_log_dict, expire_time)
end
-- 各参数用法:
-- count=status,host=xxx.com,status=404 统计xxx.com域名一分钟内404状态码个数.
-- count=statusUrl,host=xxx.com,status=404,exceed=50,output=30 当xxx.com域名404状态码一分钟内超过50个时,输出前30个url,否则返回空.
-- count=upT,host=xxx.com 统计xxx.com域名一分钟内平均upsteam耗时
-- count=upTUrl,host=xxx.com,exceed=0.5 输出upstreamTime超过0.5秒的url,没有就返回空
-- count=reqT,host=xxx.com 统计xxx.com域名一分钟内平均请求耗时
-- count=flow,host=xxx.com 统计xxx.com域名一分钟内流量(单位字节/秒)
-- 函数: 获取迭代器值
local get_field = function(iterator)
local m,err = iterator
if err then
ngx.log(ngx.ERR, "get_field iterator error: ", err)
ngx.exit(ngx.HTTP_OK)
end
return m[0]
end
-- 函数: 按值排序table
local getKeysSortedByValue = function (tbl, sortFunction)
local keys = {}
for key in pairs(tbl) do
table.insert(keys, key)
end
table.sort(keys, function(a, b)
return sortFunction(tbl[a], tbl[b])
end)
return keys
end
-- 函数: 判断table是否存在某元素
local tbl_contain = function(table,element)
for k in pairs(table) do
if k == element then
return true
end
end
return false
end
local access = ngx.shared.access
local now = ngx.time()
local one_minute_ago = now - 60
-- 获取参数
local args = ngx.req.get_uri_args()
local count_arg = args["count"]
local host_arg = args["host"]
local status_arg = args["status"]
local exceed_arg = args["exceed"]
local output_arg = args["output"]
local count_t = {["status"]=0,["statusUrl"]=0,["upT"]=0,["upTUrl"]=0,["reqT"]=0,["flow"]=0}
-- 检查参数是否满足
if not tbl_contain(count_t,count_arg) then
ngx.print("count arg invalid.")
ngx.exit(ngx.HTTP_OK)
end
if not host_arg then
ngx.print("host arg not found.")
ngx.exit(ngx.HTTP_OK)
end
if count_arg == "status" and not status_arg then
ngx.print("status arg not found.")
ngx.exit(ngx.HTTP_OK)
end
if count_arg == "statusUrl" and not (status_arg and exceed_arg and output_arg) then
ngx.print("status or exceed or output arg not found.")
ngx.exit(ngx.HTTP_OK)
end
if count_arg == "upTUrl" and not exceed_arg then
ngx.print("exceed arg not found.")
ngx.exit(ngx.HTTP_OK)
end
-- 检查参数是否合法
if status_arg and ngx.re.find(status_arg, "^[0-9]{3}$") == nil then
ngx.print("status arg must be a valid httpd code.")
ngx.exit(ngx.HTTP_OK)
end
if exceed_arg and ngx.re.find(exceed_arg, "^[0-9.]+$") == nil then
ngx.print("exceed arg must be a number.")
ngx.exit(ngx.HTTP_OK)
end
if output_arg and ngx.re.find(output_arg, "^[0-9]+$") == nil then
ngx.print("output arg must be a number.")
ngx.exit(ngx.HTTP_OK)
end
-- 开始统计
local url
local status_code
local upstream_time
local status_total = 0
local host
local req_total = 0
local flow_total = 0
local reqtime_total = 0
local upstream_total = 0
local status_url_t = {}
local upstream_url_t = {}
local upstream_url_count_t = {}
local status_log
local upt_log
for second_num=one_minute_ago,now do
local flow_key = table.concat({host_arg,"-flow-",second_num})
local req_time_key = table.concat({host_arg,"-reqt-",second_num})
local up_time_key = table.concat({host_arg,"-upt-",second_num})
local total_req_key = table.concat({host_arg,"-total-",second_num})
local log_key
local log_line
-- 合并状态码大于等于400的请求日志到变量status_log
log_key = table.concat({"status-",second_num})
log_line = access:get(log_key) or ""
if not (log_line == "") then
status_log = table.concat({log_line,"
",status_log})
end
-- 合并upstream time大于0.5秒的请求日志到变量upt_log
log_key = table.concat({"upt-",second_num})
log_line = access:get(log_key) or ""
if not (log_line == "") then
upt_log = table.concat({log_line,"
",upt_log})
end
-- 域名总请求数
local req_sum = access:get(total_req_key) or 0
req_total = req_total + req_sum
if count_arg == "status" or count_arg == "statusUrl" then
local status_key = table.concat({host_arg,"-",status_arg,"-",second_num})
local status_sum = access:get(status_key) or 0
status_total = status_total + status_sum
end
if count_arg == "flow" then
local flow_sum = access:get(flow_key) or 0
flow_total = flow_total + flow_sum
end
if count_arg == "reqT" then
local req_time_sum = access:get(req_time_key) or 0
reqtime_total = reqtime_total + req_time_sum
end
if count_arg == "upT" then
local up_time_sum = access:get(up_time_key) or 0
upstream_total = upstream_total + up_time_sum
end
end
-- 统计状态码url
if count_arg == "statusUrl" and status_log and not (status_log == "") then
local iterator, err = ngx.re.gmatch(status_log,".+
")
if not iterator then
ngx.log(ngx.ERR, "status_log iterator error: ", err)
return
end
for line in iterator do
if not line[0] then
ngx.log(ngx.ERR, "line[0] is nil")
return
end
local iterator, err = ngx.re.gmatch(line[0],"[^
]+")
if not iterator then
ngx.log(ngx.ERR, "line[0] iterator error: ", err)
return
end
host = get_field(iterator())
url = get_field(iterator())
status_code = get_field(iterator())
if status_code == status_arg then
if status_url_t[url] then
status_url_t[url] = status_url_t[url] + 1
else
status_url_t[url] = 1
end
end
end
end
-- 统计upstream time大于0.5秒url
if count_arg == "upTUrl" and upt_log and not (upt_log == "") then
local iterator, err = ngx.re.gmatch(upt_log,".+
")
if not iterator then
ngx.log(ngx.ERR, "upt_log iterator error: ", err)
return
end
for line in iterator do
if not line[0] then
ngx.log(ngx.ERR, "line[0] is nil")
return
end
local iterator, err = ngx.re.gmatch(line[0],"[^
]+")
if not iterator then
ngx.log(ngx.ERR, "line[0] iterator error: ", err)
return
end
host = get_field(iterator())
url = get_field(iterator())
upstream_time = get_field(iterator())
upstream_time = tonumber(upstream_time) or 0
-- 统计各url upstream平均耗时
if host == host_arg then
if upstream_url_t[url] then
upstream_url_t[url] = upstream_url_t[url] + upstream_time
else
upstream_url_t[url] = upstream_time
end
if upstream_url_count_t[url] then
upstream_url_count_t[url] = upstream_url_count_t[url] + 1
else
upstream_url_count_t[url] = 1
end
end
end
end
-- 输出结果
if count_arg == "status" then
ngx.print(status_total," ",req_total)
elseif count_arg == "flow" then
ngx.print(flow_total," ",req_total)
elseif count_arg == "reqT" then
local reqt_avg = 0
if req_total == 0 then
reqt_avg = 0
else
reqt_avg = reqtime_total/req_total
end
ngx.print(reqt_avg," ",req_total)
elseif count_arg == "upT" then
local upt_avg = 0
if req_total == 0 then
upt_avg = 0
else
upt_avg = upstream_total/req_total
end
ngx.print(upt_avg," ",req_total)
elseif count_arg == "statusUrl" then
if status_total > tonumber(exceed_arg) then
-- 排序table
status_url_t_key = getKeysSortedByValue(status_url_t, function(a, b) return a > b end)
local output_body = ""
for i, uri in ipairs(status_url_t_key) do
if output_body == "" then
output_body = table.concat({uri," ",status_url_t[uri]})
else
output_body = table.concat({output_body,"
",uri," ",status_url_t[uri]})
end
if i >= tonumber(output_arg) then
ngx.print(output_body)
ngx.exit(ngx.HTTP_OK)
end
end
ngx.print(output_body)
ngx.exit(ngx.HTTP_OK)
end
elseif count_arg == "upTUrl" then
local max_output = 30
local total_time = 0
local total_count = 0
local output_body = ""
local i = 0
for url in pairs(upstream_url_t) do
i = i + 1
total_time = upstream_url_t[url]
total_count = upstream_url_count_t[url]
avg_time = upstream_url_t[url] / upstream_url_count_t[url]
if avg_time > tonumber(exceed_arg) then
output_body = table.concat({url," ",avg_time," ",total_count,"
",output_body})
end
if i >= max_output then
ngx.print(output_body)
ngx.exit(ngx.HTTP_OK)
end
end
ngx.print(output_body)
ngx.exit(ngx.HTTP_OK)
end 上一篇:杀毒软件的工作原理
网站多客宝下载 v1.6.2.1官方版
27.0M
网站安全狗下载
32.75M
CrystalDiskInfo(硬盘信息检测工具)萌化版 v8.2.0绿色中文版下载
209.77MB
Desktop Info(桌面系统信息)下载 v2.0.1绿色版
345KB
Develve(数据统计分析软件) v4.5.0.0 绿色版
4.4MB
Kainet LogViewPro(网站日志分析软件) v3.19.4 免费版
5.9M
PageAdmin自助建站系统(网站管理系统) v4.0.10 官方版
17.2M
Responsive Site Designer(网站设计软件) v4.0.3290 免费版
200.2MB
WYSIWYG Web Builder(网站制作建设软件)15.4 破解版
29.8M
everest ultimate edition(测试软硬件系统信息的工具)v5.51 免费版
6.7M
webzip(网站下载工具)V7.0 官方版
1.5M
亿图信息图软件 V8.7 官方版
243MB
公租房管理软件(公租房信息管理工具) 11.0.0.0 免费版
29.36MB
啄木鸟下载器(网站图片下载软件) v2020 破解版
5.75MB
宏达青少年信息管理系统 v4.3.13.9487
8.16 MB
谷歌访问助手(浏览器扩展插件) 2021 破解版
107.23MB
金花站长工具(网站优化工具)v8.8.19 绿色版
11.6M
Extreme Picture Finder下载
4.88 MB
PhotoLightning下载
7.85M
Rank Tracker下载
308.1M
2020-05-29
Nginx ngx_http_limit_conn ngx_http_limit_conn模块(请求限制和连接数限制)使用指南
为什么MP3读卡器无法与PC相连并下载MP3歌曲?
指纹识别功能不能识别指纹信息,即不识别指纹扫描
CODEBLOCKS 17.12汉化方法,CODEBLOCKS怎么汉化
Windows系统盘(C盘)容量释放的操作指导
Adaptec 2410SA RAID卡用户手册
Tomcat manager无法访问
Y50-70笔记本Windows 8升Windows 10,电池只能充电55-60%情况
Windows 8如何注册账号以及无账号登录