在nginx中收集请求日志,异步归总到消息队列(nsq)
乐果 发表于 2018 年 07 月 24 日 标签:lua
最近公司的服务器经常因为磁盘被日志文件写爆,磁盘不可用后导致接口请求报错,为此经常要定期删除服务器日志以腾出磁盘空间。有没有更好的办法解决磁盘容量太小,日志保存不能太多、时间不能太长的麻烦呢?我试想过,将接口日志收收集后转储到公司内部服务器,做离线存储方案,这样有三个好处:
1、海量接口日志不用再占用线上服务器的有限磁盘空间,节省费用;
2、在负载均衡多节点的部署架构下,避免日志文件的分散导致的查阅不方便;
3、归总转储离线后,日志可以更长时间的存储,本地集中查阅高效,为进一步分析提供了可能性。 比如:收集日志后,可以统计每日访问的pu、pv,可以分析每个接口请求频次;但业务操作存在bug时,可以借助日志分析问题原因……
但如何转储呢?在网上查阅了一些资料,有人利用kafka消息队列+lua,集中存储nginx请求日志到kafka中。
最近刚好在研究nsq,借此做一个基于nsq+lua的nginx日志转储方案,如下!
一、资源下载:
依赖:
https://github.com/openresty/lua-cjson/archive/2.1.0.6.tar.gz
https://github.com/openresty/lua-resty-core/archive/v0.1.13.tar.gz
lua-nsq:
https://github.com/rainingmaster/lua-resty-nsq
注意将Makefile文件里修改lua相关参数 :
#LUA_INCLUDE_DIR ?= $(PREFIX)/include
#LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION)
LUA_INCLUDE_DIR ?= $(PREFIX)/include/luajit-2.0
LUA_LIB_DIR ?= $(PREFIX)/lib/lua/5.1
二、nginx站点server里配置如下:
body_filter_by_lua '
local resp_body = string.sub(ngx.arg[1], 1, 1000)
ngx.ctx.buffered = (ngx.ctx.buffered or"") .. resp_body
';
log_by_lua_file /data/service/tengine/conf/lua/log.lua;
三、log.lua脚步如下:
-- 引入lua所有api
local cjson = require "cjson"
-- 定义json便于日志数据整理收集
local log_json = {}
log_json["uri"]=ngx.var.uri
log_json["args"]=ngx.var.args
log_json["host"]=ngx.var.host
log_json["request_body"]=ngx.var.request_body
log_json["remote_addr"] = ngx.var.remote_addr
log_json["remote_user"] = ngx.var.remote_user
log_json["time_local"] = ngx.var.time_local
log_json["status"] = ngx.var.status
log_json["body_bytes_sent"] = ngx.var.body_bytes_sent
log_json["http_referer"] = ngx.var.http_referer
log_json["http_user_agent"] = ngx.var.http_user_agent
log_json["http_x_forwarded_for"] = ngx.var.http_x_forwarded_for
log_json["upstream_response_time"] = ngx.var.upstream_response_time
log_json["request_time"] = ngx.var.request_time
log_json["resq_body"] = ngx.ctx.buffered
-- 转换json为字符串
local message = cjson.encode(log_json);
local producer = require "resty.nsq.producer"
-- 字符串分隔方法
function string:split(sep)
local sep, fields = sep or ":", {}
local pattern = string.format("([^%s]+)", sep)
self:gsub(pattern, function (c) fields[#fields + 1] = c end)
return fields
end
local handler
handler = function(premature)
if premature then
return
end
local prod = producer:new()
local poolSlice = {"127.0.0.1:4150","127.0.0.1:4152"}
local connString = poolSlice[math.random(1,2)]
local connSlice = connString:split(":")
local ok, err = prod:connect(connSlice[1], connSlice[2])
if not ok then
ngx.say("failed to connect: ", err)
return
end
ok, err = prod:pub(topic, message)
if not ok then
ngx.say("failed to pub: ", err)
return
end
ok, err = prod:close()
if not ok then
ngx.say("failed to close: ", err)
return
end
end
local delay = 0
ok, err = ngx.timer.at(delay,handler)
if not ok then
ngx.log(ngx.ERR,"failed to create the timer:",err)
return
end
注意,要在nginx.conf的http配置里,指定lua扩展路径地址:
lua_package_path "/usr/local/lib/lua/5.1/?.lua;;";
乐果 发表于 2018 年 07 月 24 日 标签:lua