openresty 日志输出的处理

最近出了个故障,有个接口的请求居然出现了长达几十秒的处理时间,由于日志缺乏,网络故障也解除了,就没法再重现这个故障了。为了可以在下次出现问题的时候能追查到问题,所以需要添加一些追踪日志。
添加这些追踪日志,我希望能够达到如下几点:

1、只有请求超过一定时间才记录,不然请求太多,系统扛不住

2、添加的代码可以尽量的少

3、对接口的影响尽量小,比如不影响实际时延,甚至记录日志时出现了错误,也不影响系统正常运行

openresty这套工具,可以在nginx处理请求的每一个阶段介入,编写代码进行逻辑处理。其可介入的流程如下图:
图片描述

log Phase这个阶段,就是openresty能处理的最后阶段。到这个阶段的时候,实际上请求的响应已经发送给客户端了。所以使用 log_by_lua (知乎真特么蛋疼啊,左右下划线就自动斜体,还没提供转义功能)

log Phase这个阶段,就是openresty能处理的最后阶段。到这个阶段的时候,实际上请求的响应已经发送给客户端了。另外我也测试过了,即使在这个阶段发生了错误,如 io 错误,也不会影响接口的正常响应,所以使用 log_by_lua 很是符合需求。

好处不止如此, log_by_lua是一个请求的最后处理阶段,那么只要请求正常进行,比如会走到这一步,因此,在这一步,我们就知道了这个请求的耗时了。另外,则是我们的代码里有不少的 ngx.exit ,如果是在业务逻辑处理的时候就记录日志,那么每个出现 ngx.exit 的地方,都需要插入写日志到硬盘的操作,大大增加了代码量。

写日志到硬盘的这一步操作,可以在 log_by_lua 这个阶段来完成,剩下的另一个问题就是每一步记录的日志如何传递到 log_by_lua 这一阶段来了。

我处理的方式是使用ngx.ctx, 每一个请求,都会有自己独立的 ngx.ctx, 这个 ngx.ctx 会贯穿整个请求的始终,简单的log函数如下:

logger.lua
--------------------------
local _M = {}function _M.log(format, ...)if ngx.ctx.log_slot == nil thenngx.ctx.log_slot = {}endarg = {...}local logstr = ""if arg == nil thenlogstr = formatelselogstr = string.format(format, unpack(arg))endlogstr = logstr .. "\t" .. ngx.now()table.insert(ngx.ctx.log_slot, logstr)
endreturn _M

到了 log_by_lua 阶段要把追踪日志写入到硬盘里,处理代码如下:

log_slot.lua
---------------------
local request_time = ngx.var.request_time
if request_time < 1 thenreturn  --- 小于1秒的请求不记录
end
local slot = ngx.ctx.log_slot
if slot == nil or type(slot) ~= "table" thenreturn
end
local logs = table.concat(slot, "\n")
local f = assert(io.open("/logs/trace", "a"))
f:write(logs .. "\n")
f:close()

log_by_lua 可以用在 http 模块,也可以用在server模块,也能直接精确到location模块,即只到某个请求。所以你可以在nginx.conf 里的http里添加:

http{log_by_lua_file '/code/log_slot.lua';
} 

也可以在server的配置里添加:

server {log_by_lua_file '/code/log_slot.lua';
}

更能直接在某个接口里添加:

/v1/test {content_by_lua_file '/code/v1/test.lua';log_by_lua_file '/code/log_slot.lua';
}

http里添加,则对所有的server; server里添加,则只针对此server;location里添加,就只针对这个接口。

但是,比较坑爹的是,log_by_lua 不像 access log,可以多层级使用。log_by_lua 在某层使用了之后,上层的 log_by_lua 就对此一层无效了。比如 /v1/test 接口添加了 log_by_lua, 那么 http 或者 server 里添加的 log_by_lua 在接受/v1/test接口的请求时都不会被用到。

正是因为这个坑,浪费了我不少的时间来解决。我们的系统里,http 模块是配置了 log_by_lua 的,用来做接口监控,监控返回的错误码,处理的时延等。如果我在 /v1/test 里添加了只针对 /v1/test 的追踪日志,那么接口监控就无法正常运行了。

不过天无绝人之路,我想到了一个处理方法如下:

monitor_log.lua
---------------------
local _M = {}function _M.monitor_log()local f = _M.api_monitor_log_funcif f == nil thenf, err = loadfile("/code/monitor.lua")if f == nil thenngx.log(ngx.ERR, "/code/monitor.lua, ", err)--- 如果不存在接口监控,直接给一个空函数f = function() endend_M.api_monitor_log_func = fendlocal status, err = pcall(f)if not status thenngx.log(ngx.ERR, "run api monitor /code/monitor.lua failed", err)end
endreturn _M

修改log_slot.lua代码如下:

local logger = require "code.monitor"
local request_time = ngx.var.request_time
logger.monitor_log()
if request_time < 1 thenreturn  --- 小于1秒的请求不记录
end
local slot = ngx.ctx.log_slot
if slot == nil or type(slot) ~= "table" thenreturn
end
local logs = table.concat(slot, "\n")
local f = assert(io.open("/logs/trace", "a"))
f:write(logs .. "\n")
f:close()

如上,就可以进行其他层级的 log_by_lua 代码运行了,皆大欢喜,问题解决了。
当系统并发请求较低的时候,worker够用,则使用 log_by_lua 可以说是毫无坏处。当然,一旦 log_by_lua 出现了故障,如死循环,则会长时间占用worker,造成整个系统崩溃掉。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/390216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一阶段:前端开发_Mysql——表与表之间的关系

2018-06-26 表与表之间的关系 一、一对多关系&#xff1a; 常见实例&#xff1a;分类和商品&#xff0c;部门和员工一对多建表原则&#xff1a;在从表&#xff08;多方&#xff09;创建一个字段&#xff0c;字段作为外键指向主表&#xff08;一方&#xff09;的一方      …

89. Gray Code - LeetCode

为什么80%的码农都做不了架构师&#xff1f;>>> Question 89. Gray Code Solution 思路&#xff1a; n 0 0 n 1 0 1 n 2 00 01 10 11 n 3 000 001 010 011 100 101 110 111 Java实现&#xff1a; public List<Integer> grayCode(int n) {List&…

这份NLP研究进展汇总请收好,GitHub连续3天最火的都是它

最近&#xff0c;有一份自然语言处理 (NLP) 进展合辑&#xff0c;一发布就受到了同性交友网站用户的疯狂标星&#xff0c;已经连续3天高居GitHub热门榜首位。 合集里面包括&#xff0c;20多种NLP任务前赴后继的研究成果&#xff0c;以及用到的数据集。 这是来自爱尔兰的Sebasti…

最近用.NET实现DHT爬虫,全.NET实现

最近用.NET实现DHT爬虫&#xff0c;全.NET实现&#xff0c;大家可以加我QQ交流下 309159808 转载于:https://www.cnblogs.com/oshoh/p/9236186.html

C++贪吃蛇

动画链接 GitHub链接&#xff1a;https://github.com/yanpeng1314/Snake 1 #include "Snake.h"2 3 int iScore 0;4 int iGrade 1;5 6 //蛇头蛇尾初始位置7 int x_head 1, y_head 3;8 int x_tail 1, y_tail 1;9 10 //地图坐标11 int i_Map 1, j_Map 1;12 13 /…

10分钟腾讯云配置免费https

腾讯云免费证书申请地址&#xff1a; https://console.cloud.tencent... 填写相关信息 域名身份验证 文件验证 将fileauth.text 创建在网站访问根目录的 .well-known/pki-validation/目录使得 www.**.com/.well-known/pki-validation/fileauth.text 能够访问详情 等待5分钟左右…

web前端【第十一篇】jQuery属性相关操作

知识点总结 1、属性 属性&#xff08;如果你的选择器选出了多个对象&#xff0c;那么默认只会返回出第一个属性&#xff09;、 attr(属性名|属性值) - 一个参数是获取属性的值&#xff0c;两个参数是设置属性值 - 点击加载图片示例 re…

85. 最大矩形

85. 最大矩形 给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵&#xff0c;找出只包含 1 的最大矩形&#xff0c;并返回其面积。 示例 1&#xff1a; 输入&#xff1a;matrix [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”…

html单行元素居中显示,多行元素居左显示

有很多的业务需要元素或者文字如果单行&#xff0c;居中显示&#xff0c;如果数据增多&#xff0c;居中显示代码&#xff08;直接复制到编辑器可用&#xff09;&#xff1a;<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8&q…

怎样在减少数据中心成本的同时不牺牲性能?

2019独角兽企业重金招聘Python工程师标准>>> 导读虽然组织对数据中心提出了更高的要求&#xff0c;但IT管理人员确实有办法在严格的预算内展开工作。如今&#xff0c;组织认为即使性能预期不断提高&#xff0c;其数据中心预算也在缩减。尽管2018年IT支出总体预计增长…

赛普拉斯 12864_如何使用赛普拉斯自动化辅助功能测试

赛普拉斯 12864In my previous post, I covered how to add screenshot testing in Cypress to ensure components dont unintentionally change over time. 在上一篇文章中 &#xff0c;我介绍了如何在赛普拉斯中添加屏幕截图测试&#xff0c;以确保组件不会随时间变化。 Now…

Android App 的主角:Activity

Android App 程序主要由4种类型组成&#xff1a; 1.Activity&#xff08;活动&#xff09;&#xff1a;主要负责屏幕显示画面&#xff0c;并处理与用户的互动。每个Android App至少都会有一个Activity&#xff0c;在程序一启动时显示主画面供用户操作。 2.Service&#xff08;后…

通过构建Paint App学习React Hooks

According to people in the know, React Hooks are hot, hot, hot. In this article, we follow Christian Jensens 14-part tutorial to find out about the basics of this new feature of React. Follow along to find out more! 据知情人士称&#xff0c;React Hooks很热&…

Npoi导出excel整理(附源码)

前些日子做了一个简单的winform程序&#xff0c;需要导出的功能&#xff0c;刚开始省事直接使用微软的组件&#xff0c;但是导出之后发现效率极其低下&#xff0c;绝对像web那样使用npoi组件&#xff0c;因此简单的进行了整理&#xff0c;包括直接根据DataTable导出excel及Data…

入库成本与目标成本对比报表中我学到的东西

1、SQL方面&#xff1a; &#xff08;1&#xff09;、用DECODE函数解决除数为零的情况 具体语法&#xff1a; DECODE&#xff08;参数&#xff0c;0&#xff0c;1&#xff0c;参数&#xff09; ->DECODE(TAB1.A8&#xff0c;0&#xff0c;1&#xff0c;TAB1.A8) &#xff08…

【小摘抄】关于C++11下 string各类用法(持续更新)

http://blog.csdn.net/autocyz/article/details/42391155 提供了最简单的详解 下列对本人近期开发中的一些心得体会进行摘抄 1.string按照字符进行截取 示例代码&#xff1a; string teststring "#12313#kajlkfdsa";//通讯消息示例&#xff0c;结合string的内置函数…

【VMware vSAN 6.6】5.5.Update Manager:vSAN硬件服务器解决方案

目录 1. 简介 1.1.适用于HCI的企业级存储2. 体系结构 2.1.带有本地存储的服务器2.2.存储控制器虚拟系统套装的缺点2.3.vSAN在vSphere Hypervisor中自带2.4.集群类型2.5.硬件部署选项3. 启用vSAN 3.1.启用vSAN3.2.轻松安装3.3.主动测试4. 可用性 4.1.对象和组件安置4.2.重新构建…

32位JDK和64位JDK

32位和64位系统在计算机领域中常常提及&#xff0c;但是仍然很多人不知道32位和64位的区别&#xff0c;所以本人在网上整理了一些资料&#xff0c;并希望可以与大家一起分享。对于32位和64位之分&#xff0c;本文将分别从处理器&#xff0c;操作系统&#xff0c;JVM进行讲解。 …

中小企业如何选择OA协同办公产品?最全的对比都在这里了

对于中小企业来说&#xff0c;传统的OA 产品&#xff0c;如泛微、蓝凌、致远、华天动力等存在价格高、使用成本高、二次开发难等特点&#xff0c;并不适合企业的协同管理。 国内OA市场也出现了一批轻便、低价的OA产品&#xff0c;本文针对以下几款适合中小企业的OA产品在功能、…

Elasticsearch学习(2)—— 常见术语

为什么80%的码农都做不了架构师&#xff1f;>>> cluster (集群)&#xff1a;一个或多个拥有同一个集群名称的节点组成了一个集群。每个集群都会自动选出一个主节点&#xff0c;如果该主节点故障&#xff0c;则集群会自动选出新的主节点来替换故障节点。 node (节点…