最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Nginx 日志模塊源碼與開發(fā)實(shí)戰(zhàn)指南

 更新時(shí)間:2026年07月15日 09:40:44   作者:chexus  
本文將結(jié)合 src/core/ngx_log.h、src/core/ngx_log.c 以及 src/http/modules/ngx_http_log_module.c,從零開始剖析日志相關(guān)的數(shù)據(jù)結(jié)構(gòu)、輸出流程,并結(jié)合示例代碼演示如何在模塊中輸出日志,最后歸納常用的日志格式變量,感興趣的朋友一起看看吧

1. 引言

Nginx 的日志系統(tǒng)是觀察服務(wù)狀態(tài)、排查問題的核心工具。它分為錯(cuò)誤日志(Error Log)和訪問日志(Access Log)兩套機(jī)制:錯(cuò)誤日志記錄啟動、運(yùn)行、異常等信息,訪問日志則記錄每個(gè) HTTP 請求的詳情。整個(gè)日志體系建立在幾組精心設(shè)計(jì)的 C 結(jié)構(gòu)體之上,理解這些結(jié)構(gòu)體是讀懂 Nginx 源碼、開發(fā)自定義模塊的前提。本文將結(jié)合 src/core/ngx_log.h、src/core/ngx_log.c 以及 src/http/modules/ngx_http_log_module.c,從零開始剖析日志相關(guān)的數(shù)據(jù)結(jié)構(gòu)、輸出流程,并結(jié)合示例代碼演示如何在模塊中輸出日志,最后歸納常用的日志格式變量。

2. 錯(cuò)誤日志核心結(jié)構(gòu)體

Nginx 錯(cuò)誤日志以 ngx_log_t 為核心,所有模塊通過統(tǒng)一的宏和函數(shù)輸出日志。

2.1 ngx_log_t — 日志對象

typedef struct ngx_log_s   ngx_log_t;
struct ngx_log_s {
    ngx_uint_t           log_level;        // 當(dāng)前日志級別
    ngx_open_file_t     *file;             // 日志文件描述符信息
    ngx_atomic_uint_t    connection;       // 連接數(shù),用于限制日志輸出頻率
    time_t               disk_full_time;   // 磁盤寫滿時(shí)間戳
    ngx_log_handler_pt   handler;          // 自定義日志處理函數(shù)
    void                *data;             // handler 的上下文
    ngx_log_writer_pt    writer;           // 寫入函數(shù)指針(默認(rèn) ngx_log_write)
    void                *wdata;            // writer 的上下文
    char                *action;           // 當(dāng)前動作描述,如 "request line"
    ngx_log_t           *next;             // 下一個(gè)日志對象(鏈表)
};
  • log_level:由指令 error_log 設(shè)置,可取 NGX_LOG_STDERRNGX_LOG_EMERG、NGX_LOG_ALERTNGX_LOG_CRIT、NGX_LOG_ERR、NGX_LOG_WARNNGX_LOG_NOTICE、NGX_LOG_INFO、NGX_LOG_DEBUG,定義在 ngx_log.h 中。
  • file:指向 ngx_open_file_t,包含文件描述符、文件名、緩沖區(qū)等。
  • handlerwriter:支持自定義日志處理,默認(rèn) writerngx_log_write,負(fù)責(zé)將格式化后的字符串寫入文件。
  • next:Nginx 支持同時(shí)記錄多個(gè)錯(cuò)誤日志,通過鏈表串聯(lián)。

2.2 ngx_open_file_t — 文件描述信息

typedef struct {
    ngx_fd_t              fd;
    ngx_str_t             name;
    u_char               *buffer;         // 日志寫入緩沖區(qū)
    u_char               *pos;
    u_char               *last;
    // … 其他 flags 等
} ngx_open_file_t;

每個(gè) ngx_log_t 最終通過 ngx_open_file_t 中的 fdbuffer 完成 I/O。

2.3 錯(cuò)誤日志輸出 API 與示例

開發(fā) Nginx 模塊時(shí),使用一組宏即可輸出錯(cuò)誤日志:

#define ngx_log_error(level, log, ...)    \
    if ((log)->log_level >= level)        \
        ngx_log_error_core(level, log, __VA_ARGS__)
void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ...);

示例:在 HTTP 模塊中輸出錯(cuò)誤日志

static ngx_int_t
ngx_http_example_handler(ngx_http_request_t *r)
{
    ngx_log_t  *log;
    log = r->connection->log;
    ngx_log_error(NGX_LOG_INFO, log, 0,
                  "example module: request to \"%V\" started", &r->uri);
    // 業(yè)務(wù)邏輯 …
    ngx_log_error(NGX_LOG_ERR, log, 0,
                  "example module: something went wrong, status=%d",
                  r->headers_out.status);
    return NGX_OK;
}

ngx_log_error_core 內(nèi)部會格式化時(shí)間戳、拼接級別、進(jìn)程 ID、action 等內(nèi)容,最終調(diào)用 log->writer(log, ...) 寫入文件。錯(cuò)誤日志格式大致為:

2024/08/20 09:52:03 [error] 2345#0: *1024 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.1, server: localhost, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "localhost"

3. 訪問日志模塊源碼結(jié)構(gòu)

訪問日志由 ngx_http_log_module 實(shí)現(xiàn),除了依賴上述基礎(chǔ)錯(cuò)誤日志結(jié)構(gòu)外,還定義了一組專用結(jié)構(gòu)體。

3.1 配置結(jié)構(gòu)體:ngx_http_log_loc_conf_t

typedef struct {
    ngx_array_t           *logs;           // ngx_http_log_t 數(shù)組(支持多個(gè)日志文件)
    ngx_open_file_cache_t *open_file_cache;
    ngx_uint_t             off;            // 是否關(guān)閉 access_log
} ngx_http_log_loc_conf_t;

每條 access_log 指令對應(yīng)一個(gè) ngx_http_log_t。

3.2 單條日志描述:ngx_http_log_t

typedef struct {
    ngx_open_file_t       *file;           // 打開的日志文件
    ngx_http_log_script_t *script;         // 日志格式編譯后的腳本
    time_t                 disk_full_time;
    time_t                 error_log_time;
    ngx_http_log_fmt_t    *format;         // 日志格式定義(if= 條件等)
    ngx_log_t             *log;            // 指向 error log(用于日志輸出錯(cuò)誤)
    unsigned               error:1;
    unsigned               filter:1;       // 是否啟用過濾
} ngx_http_log_t;

3.3 日志格式定義:ngx_http_log_fmt_t

typedef struct {
    ngx_chain_t          *op;              // 編譯后的操作鏈
    ngx_array_t           ops;             // 原始操作數(shù)組
    ngx_array_t           args;            // 參數(shù)(變量名等)
    // ...
} ngx_http_log_fmt_t;

Nginx 將 log_format 定義的組合字符串(如 $remote_addr - $request)編譯成一系列操作,運(yùn)行時(shí)遍歷操作鏈生成日志行。

3.4 操作與腳本結(jié)構(gòu)

typedef struct {
    ngx_http_log_op_t          *op;        // 當(dāng)前操作
    ngx_str_t                  *name;      // 變量名稱
    ngx_http_variable_value_t  *value;     // 運(yùn)行時(shí)變量值
    uintptr_t                   text;      // 常量字符串指針
    size_t                      len;
} ngx_http_log_script_t;
typedef enum {
    ngx_http_log_op_text = 0,      // 固定文本
    ngx_http_log_op_var,           // 變量
    ngx_http_log_op_filter         // 過濾條件
} ngx_http_log_op_t;

例如 log_format main '$remote_addr - $request $status'; 會被編譯為:

  1. TEXT: " - " → 常量
  2. VAR: $remote_addr
  3. TEXT: " "
  4. VAR: $request
  5. TEXT: " "
  6. VAR: $status

4. 日志輸出流程與格式

4.1 Error Log 輸出流程

  1. 模塊調(diào)用宏 ngx_log_error(level, log, fmt, …)
  2. 宏檢查 log->log_level,確定是否輸出。
  3. 調(diào)用 ngx_log_error_core(),其中:
    • 使用 ngx_cached_err_log_time 格式化時(shí)間戳;
    • 拼接 [level]、pid#tid、action 以及用戶自定義消息;
    • 調(diào)用 log->writer(log, ...)(默認(rèn) ngx_log_write)寫入;
    • 若寫失敗則記錄 disk_full_time 防止反復(fù)寫盤。
  4. 最終通過 write() 系統(tǒng)調(diào)用輸出。

4.2 Access Log 輸出流程

  1. 請求結(jié)束時(shí)調(diào)用 ngx_http_log_handler()(注冊在 NGX_HTTP_LOG_PHASE 階段)。
  2. 遍歷 ngx_http_log_loc_conf_t 中的 logs 數(shù)組,對每個(gè) ngx_http_log_t
    • 檢查 filter 條件,不滿足則跳過;
    • 遍歷 script 數(shù)組,依次執(zhí)行每個(gè) ngx_http_log_script_t
      • 若為 TEXT,直接拷貝固定字符串;
      • 若為 VAR,調(diào)用 ngx_http_get_indexed_variable(r, index) 獲取變量值并追加;
    • 將收集到的整行數(shù)據(jù)寫入文件緩沖區(qū);
    • 調(diào)用 ngx_write_fd() 真正輸出。
  3. 最終日志行完全是編譯后操作鏈的一次動態(tài)執(zhí)行結(jié)果。

經(jīng)典 combined 格式示例:

log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

運(yùn)行時(shí)生成類似:

127.0.0.1 - frank [20/Aug/2024:09:52:03 +0800] "GET /api HTTP/1.1" 200 2326 "https://example.com" "Mozilla/5.0 ..."

5. 常用日志格式變量一覽

Nginx 日志格式中可以使用大量內(nèi)置變量(也可理解為“格式轉(zhuǎn)義字符”),下面是開發(fā)與配置中最常用的一部分:

變量含義示例值
$remote_addr客戶端 IP 地址192.168.1.1
$remote_userHTTP 基礎(chǔ)認(rèn)證用戶名(若有)frank
$time_local本地時(shí)間(格式 [日/月/年:時(shí):分:秒 時(shí)區(qū)][20/Aug/2024:09:52:03 +0800]
$request完整的請求行GET /api HTTP/1.1
$status響應(yīng)狀態(tài)碼200
$body_bytes_sent發(fā)送給客戶端的字節(jié)數(shù)(不含響應(yīng)頭)2326
$http_refererReferer 頭https://example.com
$http_user_agentUser-Agent 頭Mozilla/5.0 ...
$request_time處理請求的總時(shí)間(秒)0.052
$upstream_addr上游服務(wù)器地址192.168.2.1:80
$upstream_response_time上游服務(wù)器響應(yīng)時(shí)間(秒)0.051
$uri當(dāng)前請求的 URI(不含參數(shù))/index.html
$args請求參數(shù)id=1&lang=zh
$host請求的主機(jī)名(Host 頭)www.example.com
$server_name虛擬主機(jī)的 server_nameexample.com
$connection連接序列號1024
$pipe若請求為管道(pipeline)則為 pp 或空

通過在 log_format 中組合這些變量,可以定制出滿足業(yè)務(wù)需求的日志格式。如需自定義變量,可在模塊中調(diào)用 ngx_http_add_variable() 注冊,并在編譯日志格式時(shí)自動參與操作鏈生成。

6. 實(shí)戰(zhàn)配置示例

下面給出兩個(gè)完整的 nginx.conf 片段,展示如何結(jié)合上述知識在實(shí)際環(huán)境中配置日志。

6.1 多級別錯(cuò)誤日志與自定義 Access Log

worker_processes  1;
error_log  logs/error.log  warn;   # 全局僅輸出警告及以上
events {
    worker_connections  1024;
}
http {
    log_format timing '$remote_addr - $remote_user [$time_local] '
                      '"$request" $status $body_bytes_sent '
                      '"$http_referer" "$http_user_agent" '
                      'rt=$request_time uct="$upstream_addr"';
    access_log  logs/access.log  timing;
    server {
        listen       80;
        server_name  example.com;
        # 為當(dāng)前虛擬主機(jī)打開 info 級別錯(cuò)誤日志
        error_log  logs/example_error.log  info;
        location / {
            root   html;
            index  index.html;
        }
        location /api {
            proxy_pass  http://backend;
            # 僅記錄狀態(tài)碼 >= 400 的請求到獨(dú)立文件
            access_log  logs/api_error.log  timing  if=$status >= 400;
        }
    }
}

6.2 按域名分離日志

http {
    log_format vhost '$host $remote_addr - $remote_user [$time_local] '
                     '"$request" $status $body_bytes_sent';
    server {
        listen       80;
        server_name  example.com www.example.com;
        # 利用 $host 變量自動分離日志文件
        access_log  logs/access_$host.log  vhost;
        error_log   logs/error_$host.log   warn;
    }
    server {
        listen       80;
        server_name  api.example.com;
        access_log  logs/access_api.log  vhost;
        error_log   logs/error_api.log   info;
    }
}

這些配置直接反映了底層 ngx_log_tngx_http_log_t 以及操作鏈的工作方式:error_log 指令創(chuàng)建 ngx_log_t 并設(shè)置級別,access_log 指令創(chuàng)建 ngx_http_log_t,格式字符串被編譯為腳本鏈,條件過濾則通過腳本中的 ngx_http_log_op_filter 實(shí)現(xiàn)。

7. 開發(fā)者實(shí)踐建議

  • 添加自定義變量:通過 ngx_http_add_variable() 注冊新變量,并在 log_format 中使用,無需改動日志核心代碼。
  • 自定義日志過濾:利用 ngx_http_log_t.filter 選項(xiàng),配合 if= 參數(shù)控制日志生成條件,例如只記錄慢請求或錯(cuò)誤請求。
  • 錯(cuò)誤日志擴(kuò)展:如有特殊需求(如發(fā)送到 syslog),可設(shè)置 log->handlerlog->writer 接管日志輸出。
  • 調(diào)試時(shí)靈活使用 ngx_log_debug 宏:在編譯 Nginx 時(shí)開啟 --with-debug,可以在模塊中使用 ngx_log_debug() 系列宏輸出詳細(xì)的調(diào)試信息。

8. 總結(jié)

Nginx 的日志系統(tǒng)通過清晰的模塊化設(shè)計(jì)和編譯期優(yōu)化,將繁瑣的格式化工作轉(zhuǎn)化為高效的操作鏈遍歷。錯(cuò)誤日志以 ngx_log_t 為核心,訪問日志則圍繞 ngx_http_log_t、ngx_http_log_fmt_t 以及操作腳本展開。掌握這些結(jié)構(gòu)體以及它們?nèi)绾伪恢噶铗?qū)動,不僅能深入理解 Nginx 的行為,更是定制化模塊開發(fā)的必備基礎(chǔ)。

到此這篇關(guān)于Nginx 日志模塊源碼與開發(fā)實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)nginx 日志系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Nginx處理請求時(shí)的匹配規(guī)則詳析

    Nginx處理請求時(shí)的匹配規(guī)則詳析

    這篇文章主要給大家介紹了關(guān)于Nginx處理請求時(shí)的匹配規(guī)則的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Nginx具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Nginx部署https網(wǎng)站并配置地址重寫的步驟詳解

    Nginx部署https網(wǎng)站并配置地址重寫的步驟詳解

    今天小編就為大家分享一篇關(guān)于Nginx部署https網(wǎng)站并配置地址重寫的步驟詳解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • 開發(fā)環(huán)境服務(wù)器vs生產(chǎn)環(huán)境服務(wù)器:開發(fā)與生產(chǎn)須分明詳解

    開發(fā)環(huán)境服務(wù)器vs生產(chǎn)環(huán)境服務(wù)器:開發(fā)與生產(chǎn)須分明詳解

    開發(fā)環(huán)境服務(wù)器(如Vite)和生產(chǎn)環(huán)境服務(wù)器(如Nginx和Node.js)在職責(zé)和工作方式上存在顯著差異,開發(fā)環(huán)境服務(wù)器專注于快速開發(fā)和調(diào)試,而生產(chǎn)環(huán)境服務(wù)器則強(qiáng)調(diào)穩(wěn)定性和高并發(fā)處理,Vite適合開發(fā)環(huán)境,而Nginx和Node.js更適合生產(chǎn)環(huán)境
    2025-01-01
  • 在Nginx中阻止來自特定的IP地址訪問的操作指南

    在Nginx中阻止來自特定的IP地址訪問的操作指南

    在網(wǎng)絡(luò)安全方面,有時(shí)你可能需要限制特定國家或地區(qū)的訪問權(quán)限,本文將介紹如何使用?Nginx?配置文件來阻止來自特定國家或地區(qū)的?IP?地址訪問你的網(wǎng)站,需要的朋友可以參考下
    2024-07-07
  • 教你如何解決Nginx禁止ip加端口訪問的問題

    教你如何解決Nginx禁止ip加端口訪問的問題

    這篇文章主要介紹了Nginx禁止ip加端口訪問的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • Nginx部署React項(xiàng)目時(shí)重定向循環(huán)問題的解決方案

    Nginx部署React項(xiàng)目時(shí)重定向循環(huán)問題的解決方案

    Nginx在處理React項(xiàng)目請求時(shí)出現(xiàn)重定向循環(huán),通常是由于`try_files`配置錯(cuò)誤或`root`路徑配置不當(dāng)導(dǎo)致的,本文給大家詳細(xì)介紹了相關(guān)的解決方法,需要的朋友可以參考下
    2025-05-05
  • Nginx中return和rewrite的寫法及區(qū)別淺析

    Nginx中return和rewrite的寫法及區(qū)別淺析

    在Nginx中,return和rewrite都用于重定向,但有所區(qū)別,return立即終止請求并返回指定HTTP狀態(tài)碼,不額外請求,rewrite則重寫URI并引發(fā)新請求,需要的朋友可以參考下
    2024-09-09
  • angular6+springboot實(shí)現(xiàn)前后分離nginx配置

    angular6+springboot實(shí)現(xiàn)前后分離nginx配置

    這篇文章主要介紹了angular6+springboot實(shí)現(xiàn)前后分離nginx配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Nginx 502 Bad Gateway錯(cuò)誤原因及解決方案

    Nginx 502 Bad Gateway錯(cuò)誤原因及解決方案

    這篇文章主要介紹了Nginx 502 Bad Gateway錯(cuò)誤原因及解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 在Nginx上配置多個(gè)站點(diǎn)的方法

    在Nginx上配置多個(gè)站點(diǎn)的方法

    這篇文章主要介紹了在Nginx上配置多個(gè)站點(diǎn)的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-07-07

最新評論

聂拉木县| 剑川县| 泽州县| 卢氏县| 安阳县| 永宁县| 嘉黎县| 迁西县| 阿合奇县| 义乌市| 濉溪县| 巫溪县| 炎陵县| 金塔县| 绍兴市| 深水埗区| 长兴县| 山东| 夹江县| 新沂市| 清河县| 越西县| 胶州市| 乐平市| 庆安县| 乡城县| 营口市| 琼海市| 夏津县| 丹阳市| 宁南县| 镶黄旗| 沂源县| 白水县| 忻州市| 濮阳县| 古田县| 珠海市| 康乐县| 恭城| 罗定市|