本篇內(nèi)容主要講解“nginx日志模塊的源碼分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“nginx日志模塊的源碼分析”吧!
從事成都服務(wù)器托管,服務(wù)器租用,云主機(jī),網(wǎng)絡(luò)空間,主機(jī)域名,CDN,網(wǎng)絡(luò)代維等服務(wù)。
ngx_http_log_module模塊按指定的格式寫訪問日志。
請(qǐng)求在處理結(jié)束時(shí),會(huì)按請(qǐng)求路徑的配置上下文記訪問日志。 如果在請(qǐng)求處理期間產(chǎn)生了內(nèi)部跳轉(zhuǎn)(參考另一篇nginx跳轉(zhuǎn)講述), 請(qǐng)求結(jié)束時(shí)的路徑可能不同于原始的請(qǐng)求路徑。
官方模塊使用說明http://nginx.org/en/docs/http/ngx_http_log_module.html
在nginx.conf中相關(guān)的配置指令為:
log_format proxyformat "$time_iso8601 $remote_addr:$remote_port $server_addr:$server_port $upstream_addr $request_time $upstream_response_time $status $upstream_status $request_leng
th $body_bytes_sent \"$request_method $scheme://$http_host$request_uri $server_protocol\" \"$http_referer\" \"$http_user_agent\"";
access_log syslog:facility=local3,severity=info,server=127.0.0.1:514,tag=tengine proxyformat;
log_format gzip '$remote_addr - $remote_user [$time_local] ' '"$request" $status $bytes_sent ' '"$http_referer" "$http_user_agent" "$gzip_ratio"'; access_log /spool/logs/nginx-access.log gzip buffer=32k;
語法格式: | access_logpath [format [buffer=size]]; access_logoff; |
默認(rèn): | access_log logs/access.log combined; |
配置生效空間上下文: | http , server , location , if in location , limit_except |
為訪問日志設(shè)置路徑,格式和緩沖區(qū)大?。╪ginx訪問日志支持緩存)。
在同一個(gè)配置層級(jí)里可以指定多個(gè)日志。
特定值off
會(huì)取消當(dāng)前配置層級(jí)里的所有access_log指令。
如果沒有指定日志格式則會(huì)使用預(yù)定義的combined格式。
緩沖區(qū)的大小不能超過磁盤文件原子性寫入的大小。
對(duì)于FreeBSD來說緩沖區(qū)大小是無限制的。
日志文件的路徑可以包含變量(0.7.6+), 但此類日志存在一些限制:
應(yīng)該擁有在目錄里創(chuàng)建文件的權(quán)限。
寫緩沖無效。
每條日志寫入都會(huì)打開和關(guān)閉文件。頻繁使用的文件描述符可以存儲(chǔ)在緩存中, 在open_log_file_cache指令的valid參數(shù)指定的時(shí)間里,寫操作能持續(xù)寫到舊文件。
每次日志寫入的操作都會(huì)檢查請(qǐng)求的根目錄是否存在(即ngx root配置), 如果不存在則日志不會(huì)被創(chuàng)建。 在一個(gè)層級(jí)里同時(shí)指定root和access_log是個(gè)不錯(cuò)的辦法:
server { root /spool/vhost/data/$host; access_log /spool/vhost/logs/$host; ... }
語法: | log_formatname string ...; |
默認(rèn): | log_format combined "..."; |
配置生效空間上下文: | http |
指定日志的格式。
日志格式允許包含普通變量和只在日志寫入時(shí)存在的變量:
$body_bytes_sent
發(fā)送給客戶端的字節(jié)數(shù),不包括響應(yīng)頭的大??; 該變量與Apache模塊mod_log_config
里的“%B
”參數(shù)兼容。
$bytes_sent
發(fā)送給客戶端的總字節(jié)數(shù)。
$connection
連接的序列號(hào)。
$connection_requests
當(dāng)前通過一個(gè)連接獲得的請(qǐng)求數(shù)量。
$msec
日志寫入時(shí)間。單位為秒,精度是毫秒。
$pipe
如果請(qǐng)求是通過HTTP流水線(pipelined)發(fā)送,pipe值為“p
”,否則為“.
”。
$request_length
請(qǐng)求的長(zhǎng)度(包括請(qǐng)求行,請(qǐng)求頭和請(qǐng)求正文)。
$request_time
請(qǐng)求處理時(shí)間,單位為秒,精度毫秒; 從讀入客戶端的第一個(gè)字節(jié)開始,直到把最后一個(gè)字符發(fā)送給 客戶端后進(jìn)行日志寫入為止。
$status
響應(yīng)狀態(tài)。
$time_iso8601
ISO8601標(biāo)準(zhǔn)格式下的本地時(shí)間。
$time_local
通用日志格式下的本地時(shí)間。
發(fā)送給客戶端的響應(yīng)頭擁有"sent_http_"前綴,比如$sent_http_content_range。
配置始終包含預(yù)先定義的"combined"日志格式:
log_format combined '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';
語法: | open_log_file_cachemax=N [inactive=time] [min_uses=N] [valid=time]; open_log_file_cacheoff; |
默認(rèn): | open_log_file_cache off; |
配置生效空間上下文: | http , server , location |
定義一個(gè)緩存,用來存儲(chǔ)頻繁使用的文件名中包含變量的日志文件描述符。 該指令包含以下參數(shù):
max
設(shè)置緩存中描述符的最大數(shù)量;如果緩存被占滿,最近最少使用(LRU)的描述符將被關(guān)閉。
inactive
設(shè)置緩存文件描述符在多長(zhǎng)時(shí)間內(nèi)沒有被訪問就關(guān)閉; 默認(rèn)為10秒。
min_uses
設(shè)置在inactive參數(shù)指定的時(shí)間里, 最少訪問多少次才能使文件描述符保留在緩存中;默認(rèn)為1。
valid
設(shè)置一段用于檢查超時(shí)后文件是否仍以同樣名字存在的時(shí)間; 默認(rèn)為60秒。
off
禁用緩存。
使用實(shí)例:
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
先關(guān)注log模塊的初始化
static ngx_http_module_t ngx_http_log_module_ctx = {
NULL, /* preconfiguration */
ngx_http_log_init, /* postconfiguration */
ngx_http_log_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_log_create_loc_conf, /* create location configuration */
ngx_http_log_merge_loc_conf /* merge location configuration */
};
static void *
ngx_http_log_create_main_conf(ngx_conf_t *cf)
{
ngx_http_log_main_conf_t *conf;
ngx_http_log_fmt_t *fmt;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
if (conf == NULL) {
return NULL;
}
// 初始化format
if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t)) != NGX_OK)
{
return NULL;
}
return conf;
}
static ngx_int_t ngx_http_log_init(ngx_conf_t *cf)
{
// 這塊有判斷是否使用默認(rèn)的combine的邏輯,在tengine中,自定義了一波,所以不care
// 將handler加入log階段
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_log_handler;
return NGX_OK;
}
而在log_format指令的處理函數(shù)中,將這個(gè)fmt給保存下來
static char * ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
// 獲取loc_main_conf
ngx_http_log_main_conf_t *lmcf = conf;
// 初始化fmt
fmt = lmcf->formats.elts;
fmt = ngx_array_push(&lmcf->formats);
if (fmt == NULL) {
return NGX_CONF_ERROR;
}
// 賦值name
fmt->name = value[1];
// 初始化flushes和ops
fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
if (fmt->flushes == NULL) {
return NGX_CONF_ERROR;
}
fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
if (fmt->ops == NULL) {
return NGX_CONF_ERROR;
}
// 最后把整個(gè)日志格式編譯
return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
}
static char * ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
{
// 遍歷所有的args
for ( /* void */ ; s < args->nelts; s++) {
// 在已有的ngx_http_log_vars中看有沒有指定的日志格式
for (v = ngx_http_log_vars; v->name.len; v++) {
if (v->name.len == var.len && ngx_strncmp(v->name.data, var.data, var.len) == 0)
{
// 將對(duì)應(yīng)的方法,長(zhǎng)度賦值給對(duì)應(yīng)op,等待寫入
op->len = v->len;
op->getlen = NULL;
op->run = v->run;
op->data = 0;
goto found;
}
}
// 沒有的話則調(diào)用該函數(shù)
if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (len) {
op->len = len;
op->getlen = NULL;
// 如果長(zhǎng)度小的話,就直接用data來記錄
if (len <= sizeof(uintptr_t)) {
op->run = ngx_http_log_copy_short;
op->data = 0;
// 記錄data
while (len--) {
op->data <<= 8;
op->data |= data[len];
}
// 比較長(zhǎng)的話,記錄成指針來指向,函數(shù)也是獲取指針來進(jìn)行獲取值
} else {
op->run = ngx_http_log_copy_long;
p = ngx_pnalloc(cf->pool, len);
if (p == NULL) {
return NGX_CONF_ERROR;
}
ngx_memcpy(p, data, len);
op->data = (uintptr_t) p;
}
}
}
static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, ngx_str_t *value)
{
ngx_int_t index;
index = ngx_http_get_variable_index(cf, value);
op->len = 0;
op->getlen = ngx_http_log_variable_getlen;
op->run = ngx_http_log_variable;
op->data = index;
}
// 而這些可以進(jìn)入日志中的參數(shù),則是在core_preconfiguration函數(shù)中的ngx_http_variables_add_core_vars函數(shù)
ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf)
{
cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
sizeof(ngx_hash_keys_arrays_t));
for (cv = ngx_http_core_variables; cv->name.len; cv++) {
v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
if (v == NULL) {
return NGX_ERROR;
}
*v = *cv;
rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, NGX_HASH_READONLY_KEY);
if (rc == NGX_OK) {
continue;
}
if (rc == NGX_BUSY) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "conflicting variable name \"%V\"", &v->name);
}
return NGX_ERROR;
}
接下來可以看下整個(gè)的ngx_http_core_variables
static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("http_host"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.host), 0, 0 },
{ ngx_string("http_user_agent"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.user_agent), 0, 0 },
{ ngx_string("http_referer"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.referer), 0, 0 },
#if (NGX_HTTP_GZIP)
{ ngx_string("http_via"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.via), 0, 0 },
#endif
#if (NGX_HTTP_X_FORWARDED_FOR)
{ ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_headers,
offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
#endif
{ ngx_string("http_cookie"), NULL, ngx_http_variable_cookies,
offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 },
{ ngx_string("content_length"), NULL, ngx_http_variable_content_length,
0, 0, 0 },
{ ngx_string("content_type"), NULL, ngx_http_variable_header,
offsetof(ngx_http_request_t, headers_in.content_type), 0, 0 },
{ ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 },
{ ngx_string("binary_remote_addr"), NULL,
ngx_http_variable_binary_remote_addr, 0, 0, 0 },
{ ngx_string("remote_addr"), NULL, ngx_http_variable_remote_addr, 0, 0, 0 },
{ ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
{ ngx_string("proxy_protocol_addr"), NULL,
ngx_http_variable_proxy_protocol_addr, 0, 0, 0 },
{ ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
{ ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 },
{ ngx_string("server_protocol"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, http_protocol), 0, 0 },
{ ngx_string("scheme"), NULL, ngx_http_variable_scheme, 0, 0, 0 },
{ ngx_string("https"), NULL, ngx_http_variable_https, 0, 0, 0 },
{ ngx_string("full_request"), NULL, ngx_http_variable_full_request,
0, 0, 0 },
{ ngx_string("normalized_request"), NULL, ngx_http_variable_normalized_request,
0, 0, 0 },
{ ngx_string("request_uri"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, unparsed_uri), 0, 0 },
{ ngx_string("raw_uri"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, raw_uri), 0, 0 },
{ ngx_string("uri"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, uri),
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("document_uri"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, uri),
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("request"), NULL, ngx_http_variable_request_line, 0, 0, 0 },
{ ngx_string("document_root"), NULL,
ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("realpath_root"), NULL,
ngx_http_variable_realpath_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("query_string"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, args),
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("args"),
ngx_http_variable_set_args,
ngx_http_variable_request,
offsetof(ngx_http_request_t, args),
NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("is_args"), NULL, ngx_http_variable_is_args,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("request_filename"), NULL,
ngx_http_variable_request_filename, 0,
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("server_name"), NULL, ngx_http_variable_server_name, 0, 0, 0 },
{ ngx_string("request_method"), NULL,
ngx_http_variable_request_method, 0,
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 },
{ ngx_string("bytes_sent"), NULL, ngx_http_variable_bytes_sent,
0, 0, 0 },
{ ngx_string("body_bytes_sent"), NULL, ngx_http_variable_body_bytes_sent,
0, 0, 0 },
{ ngx_string("pipe"), NULL, ngx_http_variable_pipe,
0, 0, 0 },
{ ngx_string("request_completion"), NULL,
ngx_http_variable_request_completion,
0, 0, 0 },
{ ngx_string("request_body"), NULL,
ngx_http_variable_request_body,
0, 0, 0 },
{ ngx_string("request_body_file"), NULL,
ngx_http_variable_request_body_file,
0, 0, 0 },
{ ngx_string("request_length"), NULL, ngx_http_variable_request_length,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("request_time"), NULL, ngx_http_variable_request_time,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("status"), NULL,
ngx_http_variable_status, 0,
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("sent_http_content_type"), NULL,
ngx_http_variable_sent_content_type, 0, 0, 0 },
{ ngx_string("sent_http_content_length"), NULL,
ngx_http_variable_sent_content_length, 0, 0, 0 },
{ ngx_string("sent_http_location"), NULL,
ngx_http_variable_sent_location, 0, 0, 0 },
{ ngx_string("sent_http_last_modified"), NULL,
ngx_http_variable_sent_last_modified, 0, 0, 0 },
{ ngx_string("sent_http_connection"), NULL,
ngx_http_variable_sent_connection, 0, 0, 0 },
{ ngx_string("sent_http_keep_alive"), NULL,
ngx_http_variable_sent_keep_alive, 0, 0, 0 },
{ ngx_string("sent_http_transfer_encoding"), NULL,
ngx_http_variable_sent_transfer_encoding, 0, 0, 0 },
{ ngx_string("sent_http_cache_control"), NULL, ngx_http_variable_headers,
offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 },
{ ngx_string("limit_rate"), ngx_http_variable_request_set_size,
ngx_http_variable_request_get_size,
offsetof(ngx_http_request_t, limit_rate),
NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("connection"), NULL,
ngx_http_variable_connection, 0, 0, 0 },
{ ngx_string("connection_requests"), NULL,
ngx_http_variable_connection_requests, 0, 0, 0 },
{ ngx_string("nginx_version"), NULL, ngx_http_variable_nginx_version,
0, 0, 0 },
{ ngx_string("hostname"), NULL, ngx_http_variable_hostname,
0, 0, 0 },
{ ngx_string("pid"), NULL, ngx_http_variable_pid,
0, 0, 0 },
{ ngx_string("msec"), NULL, ngx_http_variable_msec,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("dollar"), NULL, ngx_http_variable_dollar,
0, 0, 0 },
{ ngx_string("host_comment"), NULL, ngx_http_variable_host_comment,
0, 0, 0 },
{ ngx_string("unix_time"), NULL, ngx_http_variable_unix_time,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("year"), NULL, ngx_http_variable_year,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("year2"), NULL, ngx_http_variable_year2,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("month"), NULL, ngx_http_variable_month,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("day"), NULL, ngx_http_variable_day,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("hour"), NULL, ngx_http_variable_hour,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("hour12"), NULL, ngx_http_variable_hour12,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("minute"), NULL, ngx_http_variable_minute,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("second"), NULL, ngx_http_variable_second,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("time_iso8601"), NULL, ngx_http_variable_time_iso8601,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("time_local"), NULL, ngx_http_variable_time_local,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("time_http"), NULL, ngx_http_variable_time_http,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
#if (NGX_HAVE_TCP_INFO)
{ ngx_string("tcpinfo_rtt"), NULL, ngx_http_variable_tcpinfo,
0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("tcpinfo_rttvar"), NULL, ngx_http_variable_tcpinfo,
1, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("tcpinfo_snd_cwnd"), NULL, ngx_http_variable_tcpinfo,
2, NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("tcpinfo_rcv_space"), NULL, ngx_http_variable_tcpinfo,
3, NGX_HTTP_VAR_NOCACHEABLE, 0 },
#endif
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
這塊是在ngx_http_variables_init_vars中初始化
ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf)
{
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
v = cmcf->variables.elts;
key = cmcf->variables_keys->keys.elts;
for (i = 0; i < cmcf->variables.nelts; i++) {
for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
av = key[n].value;
if (v[i].name.len == key[n].key.len && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len) == 0)
{
// 將get_handler和data賦值過來
v[i].get_handler = av->get_handler;
v[i].data = av->data;
}
到此,相信大家對(duì)“nginx日志模塊的源碼分析”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
網(wǎng)站欄目:nginx日志模塊的源碼分析
URL網(wǎng)址:http://muchs.cn/article2/jiococ.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、全網(wǎng)營銷推廣、定制網(wǎng)站、網(wǎng)站策劃、網(wǎng)站制作、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)