萬盛學電腦網

 萬盛學電腦網 >> 服務器教程 >> Nginx的error

Nginx的error

   nginx配置中有關日志的配置主要是圍繞著下面兩個指令:

  1、error_log

  2、access_log:記錄訪問日志

  首先要強調的一點是,如果access日志和error日志都是常量文件名(因為access支持變量文件名,後續會講到),那麼nginx進程會緩存文件描述符直到進程結束。

  什麼時候日志的fd會改變呢?

  1)進程重啟

  2)收到了NGX_REOPEN_SIGNAL信號,會產生新的日志文件

  其他情況下,日志的fd不變,所以當進程運行中,刪除了日志文件的話,並不會生成新的日志文件,且日志都會丟失

  下面詳細講一下這兩個指令的來龍去脈

  一:先說error_log:

  nginx有兩個模塊支持error_log指令:

  一個是 ngx_errlog_module ,這個模塊只有一個指令,就是error_log ,配置類型為:NGX_MAIN_CONF,回調函數為:ngx_error_log;

  另一個是 ngx_http_core_module,這個模塊中也有指令:error_log ,配置類型為:NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF,回調函數為:ngx_http_core_error_log。

  static ngx_command_t ngx_errlog_commands[] = {

  {ngx_string("error_log"),

  NGX_MAIN_CONF|NGX_CONF_1MORE,

  ngx_error_log,

  0,

  0,

  NULL},

  ngx_null_command

  };

  static ngx_command_t ngx_http_core_commands[] = {

  { ngx_string("error_log"),

  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,

  ngx_http_core_error_log,

  NGX_HTTP_LOC_CONF_OFFSET,

  0,

  NULL },

  }

  這樣會產生幾個疑問:

  1:為什麼需要兩個相同的指令實現相同的功能。

  2:兩個指令的類型均支持NGX_HTTP_MAIN_CONF ,那麼在main中配置的error_log到底使用的是哪一個

  3:兩者的作用關系。

  下面來解釋一下:

  nginx在進行模塊注冊時,會發現 ngx_errlog_module 模塊是先於 ngx_http_core_module 模塊注冊的 。

  在nginx在解析配置文件的時候 ,見到 error_log,會按照注冊模塊的順序查找指令,這樣,會先找到ngx_errlog_module模塊,如果此時,error_log是在main配置的,那麼和ngx_errlog_module模塊error_log的NGX_HTTP_MAIN_CONF match,執行ngx_error_log。

  如果error_log是在http{}配置的,也會按照注冊模塊的順序查找指令,找到ngx_errlog_module模塊的error_log,發現type是NGX_HTTP_MAIN_CONF,不match,繼續往下找,找到ngx_http_core_module的error_log,type是NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF ,match後執行ngx_http_core_error_log。

  上面提到了ngx_error_log 和 ngx_http_core_error_log兩個函數,這兩個函數的功能基本一致,但是因為兩個配置作用域不同,所以配置存儲位置不同:ngx_errlog_module存儲在cycle->new_log,ngx_http_core_module存儲在http core模塊數據結構ngx_http_core_loc_conf_s的error_log(在此簡寫成:clcf->error_log)。

  clcf->error_log是http模塊中的,其主要記錄和http請求相關的日志。

  cycle->new_log主要記錄如進程啟動,event等。

  但是主進程啟動的時候,此時還沒有讀取配置文件,即沒有指定日志打印在哪裡。nginx這時候雖然可以將一些出錯內容或者結果輸到標准輸出,但是如果要記錄一些系統初始化情況,socket監聽狀況,還是需要寫到日志文件中去的。在nginx的main函數中,首先會調用ngx_log_init 函數,默認日志文件為:安裝路徑/logs/error.log,如果這個文件沒有權限訪問的話,會直接報錯退出。在mian函數結尾處,在ngx_master_process_cycle函數調用之前,會close掉這個日志文件。

  如果只在main配置了error_log,http{}中沒有設置,那麼clcf->error_log賦值為clcf->error_log,如下:

  static char *

  ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)

  {

  ngx_http_core_loc_conf_t *prev = parent;

  ngx_http_core_loc_conf_t *conf = child;

  。。。。。。

  if (conf->error_log == NULL) {

  if (prev->error_log) {

  conf->error_log = prev->error_log;

  } else {

  conf->error_log = &cf->cycle->new_log;

  }

  }

  。。。。。。

  }

  那為什麼不把兩個指令合並到一起呢。

  首先看一下模塊注冊順序:

  ngx_module_t *ngx_modules[] = {

  &ngx_core_module,

  &ngx_errlog_module,

  &ngx_conf_module,

  &ngx_events_module,

  &ngx_event_core_module,

  &ngx_rtsig_module,

  &ngx_epoll_module,

  &ngx_regex_module,

  &ngx_http_module,

  &ngx_http_core_module,

  &ngx_http_log_module,

  ......

  }

  可見ngx_errlog_module 和 ngx_http_core_module中間有n多模塊。這些模塊是獨立於http的,而且需要日志的打印,這些日志肯定是需要記錄的。

  則此模塊不可省,那麼考慮把ngx_http_core_module的error_log合並過來呢,想想也不行,為什麼呢?

  想想ngx_errlog_module將error_log信息存在哪裡,想想ngx_http_core_module的error_log信息存在哪裡。

  在調用ngx_error_log時候,把針對不同server或者location的error_log信息存儲在哪裡。(模塊之間不能深度耦合)

  為了兩個模塊互不影響,這是個好辦法呀!

  二:access_log

  接下來看一下access_log,access_log指令是屬於ngx_http_log_module模塊。

  ngx_http_log_module有三個指令:

  static ngx_command_t ngx_http_log_commands[] = {

  { ngx_string("log_format"),

  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,

  ngx_http_log_set_format,

  NGX_HTTP_MAIN_CONF_OFFSET,

  0,

  NULL },

  { ngx_string("access_log"),

  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF

  |NGX_HTTP_LMT_CONF|NGX_CONF_TAKE123,

  ngx_http_log_set_log,

  NGX_HTTP_LOC_CONF_OFFSET,

  0,

  NULL },

  { ngx_string("open_log_file_cache"),

  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,

  ngx_http_log_open_file_cache,

  NGX_HTTP_LOC_CONF_OFFSET,

  0,

  NULL },

  ngx_null_command

  };

  每個block都可以配置上面的指令 ,這些指令對應著各個block配置中的loc[ngx_http_log_module.index](要理解這個,需要知道配置文件的整個解析過程和block對應關系),即下面這個數據結構:

  typedef struct {

  ngx_array_t *logs; /* array of ngx_http_log_t */

  ngx_open_file_cache_t *open_file_cache;

  time_t open_file_cache_valid;

  ngx_uint_t open_file_cache_min_uses;

  ngx_uint_t off; /* unsigned off:1 */

  } ngx_http_log_loc_conf_t;

  關於access_log主要有以下幾個點:

  1、ngx_http_log_module是屬於nginx狀態機最後一個階段NGX_HTTP_LOG_PHASE的處理模塊,即一個http請求結束時執行的,它的任務就是打印這次request的訪問情況。

  2、access_log支持根據變量指令路徑,如:

  access_log logs/'$remote_addr'access.log main;

  3、不管是變量路徑還是常量路徑,都將信息放入了 ngx_http_log_loc_conf_t的logs這個數組裡進行管理,logs數組的元素是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;

  } ngx_http_log_t;

  當是常量的時候使用file記錄,這個文件記錄會放入到cycle->open_files

  struct ngx_open_file_s {

  ngx_fd_t fd;

  ngx_str_t name;

  u_char *buffer;

  u_char *pos;

  u_char *last;

  };

  當是變量的時候使用script記錄

  typedef struct {

  ngx_array_t *lengths;

  ngx_array_t *values;

  } ngx_http_log_script_t;

  4、不管是error_log還是access_log,nginx都是通過保存文件句柄來進行快速寫日志文件的。但是因為access_log支持根據變量指令路徑,如果按照request或者ip來分隔不同的access日志,那麼可想而至,若還按照保存文件句柄的方式來

copyright © 萬盛學電腦網 all rights reserved