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.pswp.cn/news/390216.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/390216.shtml
英文地址,請注明出處:http://en.pswp.cn/news/390216.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

誰是贏家_贏家的真正作品是股東

誰是贏家As I wrote in the article “5 Skills to Look For When Hiring Remote Talent,” remote work is a fast emerging segment of the labor market. Today roughly eight million Americans work remotely full-time. And among the most commonly held jobs include m…

博客園代碼黑色主題高亮設置

參考鏈接&#xff1a; https://segmentfault.com/a/1190000013001367 先發鏈接&#xff0c;有空實踐后會整理。我的GitHub地址&#xff1a;https://github.com/heizemingjun我的博客園地址&#xff1a;http://www.cnblogs.com/chenmingjun我的螞蟻筆記博客地址&#xff1a;http…

Matplotlib課程–學習Python數據可視化

Learn the basics of Matplotlib in this crash course tutorial. Matplotlib is an amazing data visualization library for Python. You will also learn how to apply Matplotlib to real-world problems.在此速成班教程中學習Matplotlib的基礎知識。 Matplotlib是一個很棒…

Android 開發使用 Gradle 配置構建庫模塊的工作方式

Android 開發過程中&#xff0c;我們不可避免地需要引入其他人的工作成果。減少重復“造輪子”的時間&#xff0c;投入到更有意義的核心任務當中。Android 庫模塊在結構上與 Android 應用模塊相同。提供構建應用所需的一切內容&#xff0c;包括源代碼&#xff08;src&#xff0…

vue 組件庫發布_如何創建和發布Vue組件庫

vue 組件庫發布Component libraries are all the rage these days. They make it easy to maintain a consistent look and feel across an application. 如今&#xff0c;組件庫風行一時。 它們使在整個應用程序中保持一致的外觀和感覺變得容易。 Ive used a variety of diff…

angular

<input type"file" id"one-input" accept"image/*" file-model"images" οnchange"angular.element(this).scope().img_upload(this.files)"/>轉載于:https://www.cnblogs.com/loweringye/p/8441437.html

Java網絡編程 — Netty入門

認識Netty Netty簡介 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty is a NIO client server framework which enables quick and easy development o…

har文件分析http_如何使用HAR文件分析一段時間內的性能

har文件分析httpWhen I consider the performance of a website, several things come to mind. I think about looking at the requests of a page, understanding what resources are being loaded, and how long these resources take to be available to users.當我考慮網站…

第一階段:前端開發_Mysql——表與表之間的關系

2018-06-26 表與表之間的關系 一、一對多關系&#xff1a; 常見實例&#xff1a;分類和商品&#xff0c;部門和員工一對多建表原則&#xff1a;在從表&#xff08;多方&#xff09;創建一個字段&#xff0c;字段作為外鍵指向主表&#xff08;一方&#xff09;的一方      …

按鈕提交在url后添加字段_在輸入字段上定向單擊“清除”按鈕(X)

按鈕提交在url后添加字段jQuery makes it easy to get your project up and running. Though its fallen out of favor in recent years, its still worth learning the basics, especially if you want quick access to its powerful methods.jQuery使您可以輕松啟動和運行項目…

429. N 叉樹的層序遍歷

429. N 叉樹的層序遍歷 給定一個 N 叉樹&#xff0c;返回其節點值的層序遍歷。&#xff08;即從左到右&#xff0c;逐層遍歷&#xff09;。 樹的序列化輸入是用層序遍歷&#xff0c;每組子節點都由 null 值分隔&#xff08;參見示例&#xff09;。 - 示例 1&#xff1a;輸入…

javascript如何阻止事件冒泡和默認行為

阻止冒泡&#xff1a; 冒泡簡單的舉例來說&#xff0c;兒子知道了一個秘密消息&#xff0c;它告訴了爸爸&#xff0c;爸爸知道了又告訴了爺爺&#xff0c;一級級傳遞從而以引起事件的混亂&#xff0c;而阻止冒泡就是不讓兒子告訴爸爸&#xff0c;爸爸自然不會告訴爺爺。下面的d…

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&…

400. 第 N 位數字

400. 第 N 位數字 在無限的整數序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, …中找到第 n 位數字。 注意&#xff1a;n 是正數且在 32 位整數范圍內&#xff08;n < 231&#xff09;。 示例 1&#xff1a; 輸入&#xff1a;3 輸出&#xff1a;3 示例 2&#xff1a; 輸入&…

1.初識Linux

1.Linux 區分大小寫 2.shell命令行-bash 進入終端->[stulocalhost~]$ (其中,Stu為登錄用戶名&#xff0c;localhost為登錄主機名&#xff0c;’~’ 表示當前用戶正處在stu用戶的家目錄中, 普通用戶的提示符以$結尾&#xff0c;而根用戶以’#’結尾) 3.Linux中所謂的命令(…

這份NLP研究進展匯總請收好,GitHub連續3天最火的都是它

最近&#xff0c;有一份自然語言處理 (NLP) 進展合輯&#xff0c;一發布就受到了同性交友網站用戶的瘋狂標星&#xff0c;已經連續3天高居GitHub熱門榜首位。 合集里面包括&#xff0c;20多種NLP任務前赴后繼的研究成果&#xff0c;以及用到的數據集。 這是來自愛爾蘭的Sebasti…

基于模型的嵌入式開發流程_如何使用基于模型的測試來改善工作流程

基于模型的嵌入式開發流程Unit testing is not enough – so lets start using model-based testing to improve our workflows.單元測試還不夠–因此&#xff0c;讓我們開始使用基于模型的測試來改善我們的工作流程。 Software testing is an important phase in building a …

166. 分數到小數

166. 分數到小數 給定兩個整數&#xff0c;分別表示分數的分子 numerator 和分母 denominator&#xff0c;以 字符串形式返回小數 。 如果小數部分為循環小數&#xff0c;則將循環的部分括在括號內。 如果存在多個答案&#xff0c;只需返回 任意一個 。 對于所有給定的輸入…

最近用.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 /…