ngx log 輸出函式解析

2021-06-21 23:44:29 字數 4177 閱讀 8517

對於乙個web伺服器程式來說,對字串處理的需求是必須的。由於web環境下的各種編碼,也導致了web伺服器程式字串處理的繁雜性。在nginx原始碼中,ngx_string.c 這個檔案就是來應對字串處理的一些原始碼,原始碼中經常的使用到了這裡中的函式,本文對ngx_string.c 進行一些簡單的分析,以方便閱讀其他原始碼。

我們來看它的基本資料結構:

typedef

struct ngx_str_t;

比較明顯的可以看出,ngx_str_t 只是將字串新增了乙個標誌長度的字段,並無其他特殊結構。

再來看它的功能函式的特點,和前面分析記憶體池(pool)中功能管理函式一樣許多函式直接以巨集定義的形式給出,如:

#define ngx_string(str)

初始化ngx_str_t,len中儲存str字串的出去結束符的長度,data中儲存str字串。

#define ngx_tolower(c) (u_char) ((c >= 'a' && c <= 'z') ? (c | 0x20) : c)

如果字元c是大寫字元就將其轉為小寫,直接用位操作進行。(為什麼 |0x20 就能實現?有興趣的把大寫字元用二進位制表示,而後試試就明白了)

#define ngx_strcmp(s1, s2) strcmp((const char *) s1, (const char *) s2)

比較,s1 和 s2 兩個字串,實質就是呼叫了strcmp。

#define ngx_memzero(buf, n) (void) memset(buf, 0, n)

初始化,buf為0。

等等,這樣的一些巨集定義函式,在這裡就不一一詳細說明了,都比較簡單容易看懂。

接下來就是一些nginx自己編寫的函式了,如:

void ngx_strlow(u_char *dst, u_char * src, size_t n)

}

將字串

src中前

n個字元全部變成小寫,放在

dst中,呼叫的

ngx_tolower

就是前面介紹了的巨集定義的函式,想想如果

dst=src

呢?把本身的字串中前

n個變成小寫。還有

ngx_cpystrn

、ngx_pstrdup

等函式,這部分函式**結構比較清晰易懂,不詳細一一說明了。

再來看,這樣的一組函式:

ngx_sprintf(u_char *buf, const char *fmt, …)

ngx_snprintf(u_char *buf, size_t max, const char *fmt, …)

ngx_slprintf(u_char *buf, u_char *last, const char *fmt, …)

ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)

從命名來看,就能略知一二,這些函式是對字串進行特定的標準格式的輸出到buf中。取ngx_sprintf(u_char *buf, const char *fmt, …)來瞧一瞧:

u_char * ngx_cdecl

ngx_sprintf(u_char *buf,

const

char * fmt, ...)

這是c語言標準的不定引數的寫法:

va_list args;

va_start(args, fmt);

p = ngx_vslprintf(buf, (void *) -1, fmt, args);

va_end(args);

可能有不是很了解這種寫法結構的,特別做下說明。va_start 是用來獲取不定引數,實際上就是獲取不定引數記憶體起始位址 放在va_list中,它的第乙個引數為 va_list 儲存位址,第二個引數為 最後乙個確定引數名,具體到ngx_sprintf 這個函式就是,兩個確定引數u_char *buf, const char *fmt

,所以最後乙個就是fmt。接下來將獲取的va_list 和一些引數傳給 ngx_vslprintf

。值得注意下的是 (void *) -1 這種寫法,指的是將整數-1 轉化為空指標位址,實際上就是 0xffffffff(對於32位機)這個 引數幹嘛什麼用呢?這個得看 ngx_vslprintf

。 ngx_vslprintf

的**就比較長了,但是功能很明確就是對於nginx自定義的資料結構進行標準格式化輸出,就像vprintf 一樣。而ngx_sprintf就相當於sprintf 命名應該也是這麼來的。原始碼中的這段注釋也是很明細的告訴我們這點:

/** supported formats:

* %[0][width][x][x]o off_t

* %[0][width]t time_t

* %[0][width][u][x|x]z ssize_t/size_t

* %[0][width][u][x|x]d int/u_int

* %[0][width][u][x|x]l long

* %[0][width|m][u][x|x]i ngx_int_t/ngx_uint_t

* %[0][width][u][x|x]d int32_t/uint32_t

* %[0][width][u][x|x]l int64_t/uint64_t

* %[0][width|m][u][x|x]a ngx_atomic_int_t/ngx_atomic_uint_t

* %[0][width][.width]f double, max valid number fits to %18.15f

* %p ngx_pid_t

* %m ngx_msec_t

* %r rlim_t

* %p void *

* %v ngx_str_t *

* %v ngx_variable_value_t *

* %s null-terminated string

* %*s length and string

* %z '\0'

* %n '\n'

* %c char

* %% %

** reserved:

* %t ptrdiff_t

* %s null-terminated wchar string

* %c wchar*/

那麼引數

0xffffffff

功能呢?來擷取部分

ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)

**來看,看到開頭的這句:

while (*fmt && buf < last)

。明白了吧

last

指的就是格式後輸出到

buf中的尾部界定指標,那麼如果

last= 0xffffffff

即代表了

buf < last

永遠成立,也就是說將

fmt

的所有內容格式化後輸出的

buf中去。看完這裡我們也可以知道

ngx_snprintf(u_char *buf, size_t max, const char *fmt, …)

,ngx_slprintf(u_char *buf, u_char *last, const char *fmt, …)

這兩個函式的功用了,乙個是給定

buf的最大值,乙個是給定

buf的界定。為了更為明晰的理解,

ngx_vslprintf

這個函式,我們給出解析

%v 也就是

nginx

中ngx_str_t *

這個結構體的標準格式化輸出過程,的**分析圖,如圖1

所示:圖1 解析 %v 示意圖

而在 case v 中我們可以看到,獲取不定引數中ngx_str_t 的指標,**為va_arg(args,ngx_str_t),然後確定進入buf的長度,拷貝ngx_str_t 中data的字串,最後完成%v的格式化,繼續下面的字元的分析。其他的格式化也是相似的過程,不過由於各個的特殊性而有所不同。

ngx_string.c中還包括了對uft8 編碼、urf的解析等操作,涉及到編碼的規則和一些相關標準,其實現的功能一般都能從其函式命名中得知,原始碼中遇到也能理解一二,本篇對於ngx_string.c簡單分析就到此結束。

nm 命令輸出項解析

0 linux下的nm命令詳解 nm命令的輸出包含三個部分 1 符號值。預設顯示十六進製制,也可以指定 2 符號型別。小寫表示是本地符號,大寫表示全域性符號 external 3 符號名稱。給個例子 00000000 b bss 00000000 d data 00000000 r rdata 00...

nginx日誌解析輸出elasticstack

需求 實時讀取nginx access日誌經過採集,快取,最終匯入到elasticsearch平台進行展示查詢。由於nginx日誌源主機與elasticsearch平台在不同的內網網段內,所以沒有採用通常直接的logstash讀取並解析然後直接輸出到elasticsearch。而是在日誌源執行log...

Top命令輸出資訊解析

在linux下top是乙個最基礎的命令,它可以將當前系統的執行狀況最直觀地告訴使用者。top命令的輸出的資訊很豐富,功能很強大,本篇我就詳細介紹一下它。第一行給出當前伺服器時間,啟動時間,當前登入使用者,以及系統負載情況。需要注意的是linux的系統負載是以1分鐘 3分鐘和15分鐘內的平均值來衡量的...