鍍金池/ 教程/ Java/ 日志輸出
定時(shí)任務(wù)
函數(shù)的參數(shù)
超時(shí)
一個(gè) openresty 內(nèi)存“泄漏”問(wèn)題
獲取 uri 參數(shù)
局部變量
sleep
灰度發(fā)布
TIME_WAIT
代碼覆蓋率
連接池
CentOS 平臺(tái)安裝
稀疏數(shù)組
如何只啟動(dòng)一個(gè) timer 工作?
變量的共享范圍
break,return 關(guān)鍵字
Nginx
SQL 注入
如何引用第三方 resty 庫(kù)
不同階段共享變量
獲取請(qǐng)求 body
動(dòng)態(tài)生成的 lua-resty-redis 模塊方法
動(dòng)態(tài)加載證書和 OCSP stapling
repeat 控制結(jié)構(gòu)
編碼為 array 還是 object
Nginx 靜態(tài)文件服務(wù)
執(zhí)行階段概念
Lua 函數(shù)
日期時(shí)間函數(shù)
健康監(jiān)測(cè)
與其他 location 配合
for 控制結(jié)構(gòu)
函數(shù)定義
HTTPS 時(shí)代
點(diǎn)號(hào)與冒號(hào)操作符的區(qū)別
String 庫(kù)
文件操作
OpenResty 最佳實(shí)踐
<code>ngx.shared.DICT</code> 非隊(duì)列性質(zhì)
使用動(dòng)態(tài) DNS 來(lái)完成 HTTP 請(qǐng)求
代碼規(guī)范
什么是 JIT?
Windows 平臺(tái)安裝
正確的記錄日志
LuaNginxModule
不用標(biāo)準(zhǔn)庫(kù)
C10K 編程
控制結(jié)構(gòu)
請(qǐng)求中斷后的處理
Lua 環(huán)境搭建
Test::Nginx 能指定現(xiàn)成的 nginx.conf,而不是自動(dòng)生成一個(gè)嗎
Lua 基礎(chǔ)數(shù)據(jù)類型
動(dòng)態(tài)限速
PostgresNginxModule
簡(jiǎn)單API Server框架
API 測(cè)試
location 匹配規(guī)則
虛變量
單元測(cè)試
防止 SQL 注入
select + set_keepalive 組合操作引起的數(shù)據(jù)讀寫錯(cuò)誤
阻塞操作
全動(dòng)態(tài)函數(shù)調(diào)用
Web 服務(wù)
典型應(yīng)用場(chǎng)景
Nginx 新手起步
TLS session resumption
輸出響應(yīng)體
調(diào)用代碼前先定義函數(shù)
module 是邪惡的
怎樣理解 cosocket
模塊
Socket 編程發(fā)展
如何對(duì) Nginx Lua module 添加新 api
如何在后臺(tái)開啟輕量級(jí)線程完成定時(shí)任務(wù)?
如何定位問(wèn)題
table 庫(kù)
json 解析的異常捕獲
如何安裝火焰圖生成工具
lua 中如何 continue
if 是邪惡的
為什么我們的域名不能被解析
抵制使用 module() 定義模塊
測(cè)試
body 在 location 中的傳遞
Lua 入門
子查詢
pipeline 壓縮請(qǐng)求數(shù)量
如何發(fā)起新 HTTP 請(qǐng)求
Lua 簡(jiǎn)介
緩存失效風(fēng)暴
Ubuntu 平臺(tái)安裝
日志輸出
緩存
Lua 面向?qū)ο缶幊?/span>
Nginx 陷阱和常見錯(cuò)誤
Redis 接口的二次封裝(發(fā)布訂閱)
日志
訪問(wèn)有授權(quán)驗(yàn)證的 Redis
正則表達(dá)式
lock
熱裝載代碼
調(diào)用 FFI 出現(xiàn) &quot;table overflow&quot;
數(shù)據(jù)合法性檢測(cè)
禁止某些終端訪問(wèn)
控制結(jié)構(gòu) if-else
調(diào)試
與 Docker 使用的網(wǎng)絡(luò)瓶頸
PostgresNginxModule 模塊的調(diào)用方式
用 do-end 整理你的代碼
FFI
什么時(shí)候使用
簡(jiǎn)介
環(huán)境搭建
Mac OS X 平臺(tái)安裝
火焰圖
負(fù)載均衡
while 型控制結(jié)構(gòu)
如何定位 openresty 崩潰 bug
使用 Nginx 內(nèi)置綁定變量
判斷數(shù)組大小
請(qǐng)求返回后繼續(xù)執(zhí)行
Redis 接口的二次封裝
KeepAlive
反向代理
協(xié)議無(wú)痛升級(jí)
數(shù)學(xué)庫(kù)
元表
Vanilla 介紹
HelloWorld
LuaCjsonLibrary
持續(xù)集成
代碼靜態(tài)分析
網(wǎng)上有大量對(duì) Lua 調(diào)優(yōu)的推薦,我們應(yīng)該如何看待?
script 壓縮復(fù)雜請(qǐng)求
非空判斷
性能測(cè)試
函數(shù)返回值
API 的設(shè)計(jì)
kong 介紹
表達(dá)式
不支持事務(wù)
LuaRestyDNSLibrary 簡(jiǎn)介

日志輸出

你如何測(cè)試和調(diào)試你的代碼呢?Lua 的兩個(gè)主力作者是這樣回復(fù)的:

Luiz Henrique de Figueiredo:我主要是一塊一塊的構(gòu)建,分塊測(cè)試。我很少使用調(diào)試器。即使用調(diào)試器,也只是調(diào)試 C 代碼。我從不用調(diào)試器調(diào)試 Lua 代碼。對(duì)于 Lua 來(lái)說(shuō),在適當(dāng)?shù)奈恢梅艓讞l打印語(yǔ)句通常就可以勝任了。

Roberto Ierusalimschy:我差不多也是這樣。當(dāng)我使用調(diào)試器時(shí),通常只是用來(lái)查找代碼在哪里崩潰了。對(duì)于 C 代碼,有個(gè)像 Valgrind 或者 Purify 這樣的工具是必要的。

摘自《編程之魂 -- 采訪 Lua 發(fā)明人的一篇文章》。

由此可見掌握日志輸出是多么重要,下至入門同學(xué),上至 Lua 作者,使用日志輸出來(lái)確定問(wèn)題,是很必要的基本手段。

標(biāo)準(zhǔn)日志輸出

OpenResty 的標(biāo)準(zhǔn)日志輸出原句為 ngx.log(log_level, ...) ,幾乎可以在任何 ngx_lua 階段進(jìn)行日志的輸出。

請(qǐng)看下面的示例:

#user  nobody;
worker_processes  1;

error_log  logs/error.log error;    # 日志級(jí)別
#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    server {
        listen    80;
        location / {
            content_by_lua_block {
                local num = 55
                local str = "string"
                local obj
                ngx.log(ngx.ERR, "num:", num)
                ngx.log(ngx.INFO, " string:", str)
                print([[i am print]])
                ngx.log(ngx.ERR, " object:", obj)
            }
        }
    }
}

訪問(wèn)網(wǎng)頁(yè),生成日志(logs/error.log 文件)結(jié)果如下:

2016/01/22 16:43:34 [error] 61610#0: *10 [lua] content_by_lua(nginx.conf:26):5:
 num:55, client: 127.0.0.1, server: , request: "GET /hello HTTP/1.1",
 host: "127.0.0.1"
2016/01/22 16:43:34 [error] 61610#0: *10 [lua] content_by_lua(nginx.conf:26):7:
 object:nil, client: 127.0.0.1, server: , request: "GET /hello HTTP/1.1",
 host: "127.0.0.1"

大家可以在單行日志中獲取很多有用的信息,例如:時(shí)間、日志級(jí)別、請(qǐng)求ID、錯(cuò)誤代碼位置、內(nèi)容、客戶端 IP 、請(qǐng)求參數(shù)等等,這些信息都是環(huán)境信息,可以用來(lái)輔助完成更多其他操作。當(dāng)然我們也可以根據(jù)自己需要定義日志格式,具體可以參考 nginx 的 log_format 章節(jié)。

細(xì)心的讀者發(fā)現(xiàn)了,中間的兩行日志哪里去了?這里不賣關(guān)子,其實(shí)是日志輸出級(jí)別的原因。上面的例子,日志輸出級(jí)別使用的 error,只有等于或大于這個(gè)級(jí)別的日志才會(huì)輸出。這里還有一個(gè)知識(shí)點(diǎn)就是 OpenResty 里面的 print 語(yǔ)句是 INFO 級(jí)別。

有關(guān) Nginx 的日志級(jí)別,請(qǐng)看下表:

ngx.STDERR     -- 標(biāo)準(zhǔn)輸出
ngx.EMERG      -- 緊急報(bào)錯(cuò)
ngx.ALERT      -- 報(bào)警
ngx.CRIT       -- 嚴(yán)重,系統(tǒng)故障,觸發(fā)運(yùn)維告警系統(tǒng)
ngx.ERR        -- 錯(cuò)誤,業(yè)務(wù)不可恢復(fù)性錯(cuò)誤
ngx.WARN       -- 告警,業(yè)務(wù)中可忽略錯(cuò)誤
ngx.NOTICE     -- 提醒,業(yè)務(wù)比較重要信息
ngx.INFO       -- 信息,業(yè)務(wù)瑣碎日志信息,包含不同情況判斷等
ngx.DEBUG      -- 調(diào)試

他們是一些常量,越往上等級(jí)越高。讀者朋友可以嘗試把 error log 日志級(jí)別修改為 info,然后重新執(zhí)行一下測(cè)試用例,就可以看到全部日志輸出結(jié)果了。

對(duì)于應(yīng)用開發(fā),一般使用 ngx.INFO 到 ngx.CRIT 就夠了。生產(chǎn)中錯(cuò)誤日志開啟到 error 級(jí)別就夠了。如何正確使用這些級(jí)別呢?可能不同的人、不同的公司可能有不同見解。

網(wǎng)絡(luò)日志輸出

如果你的日志需要?dú)w集,并且對(duì)時(shí)效性要求比較高那么這里要推薦的庫(kù)可能就讓你很喜歡了。 lua-resty-logger-socket ,可以說(shuō)很好的解決了上面提及的幾個(gè)特性。

lua-resty-logger-socket 的目標(biāo)是替代 Nginx 標(biāo)準(zhǔn)的 ngx_http_log_module 以非阻塞 IO 方式推送 access log 到遠(yuǎn)程服務(wù)器上。對(duì)遠(yuǎn)程服務(wù)器的要求是支持 syslog-ng 的日志服務(wù)。

引用官方示例:

lua_package_path "/path/to/lua-resty-logger-socket/lib/?.lua;;";

    server {
        location / {
            log_by_lua_block {
                local logger = require "resty.logger.socket"
                if not logger.initted() then
                    local ok, err = logger.init{
                        host = 'xxx',
                        port = 1234,
                        flush_limit = 1234,
                        drop_limit = 5678,
                    }
                    if not ok then
                        ngx.log(ngx.ERR, "failed to initialize the logger: ",
                                err)
                        return
                    end
                end

                -- construct the custom access log message in
                -- the Lua variable "msg"

                local bytes, err = logger.log(msg)
                if err then
                    ngx.log(ngx.ERR, "failed to log message: ", err)
                    return
                end
            }
        }
    }

例舉幾個(gè)好處:

  • 基于 cosocket 非阻塞 IO 實(shí)現(xiàn)
  • 日志累計(jì)到一定量,集體提交,增加網(wǎng)絡(luò)傳輸利用率
  • 短時(shí)間的網(wǎng)絡(luò)抖動(dòng),自動(dòng)容錯(cuò)
  • 日志累計(jì)到一定量,如果沒(méi)有傳輸完畢,直接丟棄
  • 日志傳輸過(guò)程完全不落地,沒(méi)有任何磁盤 IO 消耗