ChianXu 发表于 2011-12-22 08:54

nginx中日志分析

<DIV>我看Nginx源代码的时候,感觉整个系统都在传递log指针。log在nginx里是比较关键的。日志和内存分配是最基础的两个起点代码,最好是在自己写的程序框架中早点完善并实现。以免未来要用大量的精力调整。<BR><BR><FONT size=3><STRONG>1. 日志的源代码位置</STRONG></FONT><BR><BR>日志的源代码在src/code/ngx_log.c及ngx_log.h里。<BR><BR><FONT size=3><STRONG>2. 日志的初始化</STRONG></FONT><BR><BR>在main()函数一开始,对一些基础数据进行初始化,其中之一就是日志,源代码如下:<BR><BR>&nbsp;&nbsp;&nbsp; log = ngx_log_init();<BR>&nbsp;&nbsp;&nbsp; if (log == NULL) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<BR>&nbsp;&nbsp;&nbsp; }<BR><BR><FONT size=3><STRONG>3. 传递日志指针</STRONG></FONT><BR><BR>在创建任何结构或执行任何函数,无论那种结构体都至少会包含一个向下传递的日志指针,例如以下代码:<BR><BR>&nbsp;&nbsp;&nbsp; init_cycle.log = log;<BR>&nbsp;&nbsp;&nbsp; ngx_cycle = &amp;init_cycle;<BR><BR>&nbsp;&nbsp;&nbsp; init_cycle.pool = ngx_create_pool(1024, log);<BR>&nbsp;&nbsp;&nbsp; if (init_cycle.pool == NULL) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<BR>&nbsp;&nbsp;&nbsp; }<BR><BR>说明cycle结构体内含有日志指针、在创建内存池的时候最后一个参数也是日志指针。<BR><BR>我们在列举一些结构,例如:<BR><BR>struct ngx_connection_s {<BR>&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *data;<BR>&nbsp;&nbsp;&nbsp; ngx_event_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *read;<BR>&nbsp;&nbsp;&nbsp; ngx_event_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *write;<BR><BR>&nbsp;&nbsp;&nbsp; ngx_socket_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fd;<BR><BR>&nbsp;&nbsp;&nbsp; ngx_recv_pt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recv;<BR>&nbsp;&nbsp;&nbsp; ngx_send_pt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; send;<BR>&nbsp;&nbsp;&nbsp; ngx_recv_chain_pt&nbsp;&nbsp; recv_chain;<BR>&nbsp;&nbsp;&nbsp; ngx_send_chain_pt&nbsp;&nbsp; send_chain;<BR><BR>&nbsp;&nbsp;&nbsp; ngx_listening_t&nbsp;&nbsp;&nbsp; *listening;<BR><BR>&nbsp;&nbsp;&nbsp; off_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sent;<BR><BR>&nbsp;&nbsp;&nbsp; ngx_log_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *log;<BR><BR>在connection结构里也传递了log指针。<BR><BR><FONT size=3><STRONG>4. 日志的分级</STRONG></FONT><BR><BR>为了开发调试方便,日志被分成很多等级,我们可以只写入我们关心等级的日志,Nginx的调试等级分成了两个维度,如下:<BR><BR>#define NGX_LOG_STDERR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<BR>#define NGX_LOG_EMERG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<BR>#define NGX_LOG_ALERT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2<BR>#define NGX_LOG_CRIT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3<BR>#define NGX_LOG_ERR&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4<BR>#define NGX_LOG_WARN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5<BR>#define NGX_LOG_NOTICE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6<BR>#define NGX_LOG_INFO&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7<BR>#define NGX_LOG_DEBUG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8<BR><BR>#define NGX_LOG_DEBUG_CORE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x010<BR>#define NGX_LOG_DEBUG_ALLOC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x020<BR>#define NGX_LOG_DEBUG_MUTEX&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x040<BR>#define NGX_LOG_DEBUG_EVENT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x080<BR>#define NGX_LOG_DEBUG_HTTP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x100<BR>#define NGX_LOG_DEBUG_MAIL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x200<BR>#define NGX_LOG_DEBUG_MYSQL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x400<BR><BR>#define NGX_LOG_DEBUG_FIRST&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NGX_LOG_DEBUG_CORE<BR>#define NGX_LOG_DEBUG_LAST&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NGX_LOG_DEBUG_MYSQL<BR>#define NGX_LOG_DEBUG_CONNECTION 0x80000000<BR>#define NGX_LOG_DEBUG_ALL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0x7ffffff0<BR><BR><BR>第一个维度是0-8,当我们在配置文件中如下设置:<BR><BR>#error_log logs/debug.log debug;<BR>#error_log logs/error.log notice;<BR>#error_log logs/error.log info;<BR><BR>常量如何与字符串对应起来的可以看,log.c文件中的一段定义:<BR><BR>static const char *err_levels[] = {<BR>&nbsp;&nbsp;&nbsp; "stderr", "emerg", "alert", "crit", "error",<BR>&nbsp;&nbsp;&nbsp; "warn", "notice", "info", "debug"<BR>};<BR><BR>在nginx的判断中只要是debug就一定会输出小于8的所有信息,源代码如下:<BR><BR>#define ngx_log_error(level, log, args...)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<BR>&nbsp;&nbsp;&nbsp; if ((log)-&gt;<FONT color=#ff0000>log_level &gt;= level</FONT>) ngx_log_error_core(level, log, args)<BR><BR>或者我们管这种维度叫做 error 维度。<BR><BR>另外一个维度是0x10以上,我们可以自由扩展,这个维度是按照叠加效果计算的,源代码如下:<BR>#define ngx_log_debug(level, log, args...)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<BR>&nbsp;&nbsp;&nbsp; if ((log)-&gt;<FONT color=#ff0000>log_level &amp; level</FONT>)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ngx_log_error_core(NGX_LOG_DEBUG, log, args)<BR><BR>ngx_set_error_log_levels() {<BR><BR>...<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (n = 1; n &lt;= NGX_LOG_DEBUG; n++) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ngx_strcmp(value.data, err_levels) == 0) {<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (log-&gt;log_level != 0) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "duplicate log level \"%s\"",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value.data);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NGX_CONF_ERROR;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log-&gt;log_level = n;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>...<BR><BR>}<BR><BR>按照这个逻辑,nginx只认第一有效设置,不能使用这样的配置<BR><BR>error_log logs/debug.log debug | info;<BR><BR>错误是 3596#0: duplicate log level "info" in /data/services/nginx/conf/nginx.conf:6<BR><BR>但可以写<BR><BR>error_log logs/debug.log debug | langwan;<BR><BR>写错了没事 :)<BR><BR><BR>或者我们管这个维度叫做 debug 维度,相关源代码如下:<BR><BR>#define NGX_LOG_DEBUG_FIRST&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NGX_LOG_DEBUG_CORE<BR>#define NGX_LOG_DEBUG_LAST&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NGX_LOG_DEBUG_MYSQL<BR><BR>ngx_set_error_log_levels() {<BR><BR>...<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (n = 0, d = NGX_LOG_DEBUG_FIRST; d &lt;= NGX_LOG_DEBUG_LAST; d &lt;&lt;= 1) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ngx_strcmp(value.data, debug_levels) == 0) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (log-&gt;log_level &amp; ~NGX_LOG_DEBUG_ALL) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "invalid log level \"%s\"",<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value.data);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return NGX_CONF_ERROR;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log-&gt;log_level |= d;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<BR><BR>...<BR><BR>}<BR><BR>由于NGX_LOG_DEBUG_ALL的限制,限制了0-8这9个等级,不能出现在相同的配置里,例如下面的设置是错误的:<BR><BR>error_log logs/debug.log debug | debug_alloc;<BR><BR>错误是 3579#0: invalid log level "debug_alloc" in /data/services/nginx/conf/nginx.conf:6<BR><BR>只能写成<BR><BR>error_log logs/debug.log debug_http | debug_alloc;<BR><BR><FONT size=3><STRONG>5. debug与debug_http之间的关系</STRONG></FONT><BR><BR>实际上开启了debug等级会输出所有debug_开头的调试信息,如果我们想过滤一下信息,只能详细去按照 debug_http|debug_alloc 这样去设置,否则光设置debug就全出来了,具体表示关系的代码如下:<BR><BR>&nbsp;&nbsp;&nbsp; if (log-&gt;log_level == 0) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log-&gt;log_level = NGX_LOG_ERR;<BR><BR>&nbsp;&nbsp;&nbsp; } else if (log-&gt;log_level == NGX_LOG_DEBUG) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log-&gt;log_level = NGX_LOG_DEBUG_ALL;<BR>&nbsp;&nbsp;&nbsp; }<BR><BR>&nbsp;&nbsp; 当错误等级包含NGX_LOG_DEBUG设置所有的调试等级给log_level。<BR><BR><STRONG><FONT size=3>6. 默认的错误等级</FONT></STRONG><BR><BR>上面的代码实际上也已经说明了,默认的错误等级是NGX_LOG_ERR<BR><BR><FONT size=3><STRONG>7. 错误日志有关的四个函数之间的调度关系</STRONG></FONT><BR><BR>ngx_log_error() 按照优先级的大小判定是否输出错误信息,例如:<BR><BR>error_log logs/debug.log error;<BR><BR>不会输出 NGX_LOG_WARN、NGX_LOG_NOTICE、NGX_LOG_INFO、NGX_LOG_DEBUG 信息。<BR><BR>ngx_log_debug() 系列函数一共有10个,这里的0-8表示参数个数,不代表错误等级,用于输出DEBUG_HTTP等调试信息。这9个函数均是ngx_log_debug()的一种宏定义,例如:<BR><BR>#define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<BR>&nbsp;&nbsp;&nbsp; if ((log)-&gt;log_level &amp; level)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3)<BR><BR>剩下还有ngx_log_debug_core()、与ngx_log_error_core()两个函数,四个函数的基本关系如下图所示:<BR><BR></DIV>
<DIV forimg="1"><IMG class=blogimg src="http://hiphotos.baidu.com/langwan/pic/item/a02f33fa363ed8ac9f514625.jpg" border=0 small="0"></DIV>
<DIV><FONT size=3><STRONG>8. 魔术配置</STRONG></FONT><BR><BR>通过对源代码的阅读感觉下面这种配置会有一点小问题,配置如下:<BR><BR>error_log logs/debug.log debug;<BR>error_log logs/info.log debug_event;<BR>error_log logs/langwan.log;<BR><BR>日志会记录到langwan.log中并且是按照 debug|debug_event|error 三个级别的叠加进行输出的,而实际上按照逻辑分析就是debug,而不是标准的error。因为在Nginx的全局只有一份定义,那就是定义在ngx_log.c当中的:<BR><BR>static ngx_log_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ngx_log;<BR><BR>所以不是按照逻辑上的想象,不同的日志会记录不同种类的信息。而是被覆盖掉了。</DIV>
<DIV><BR>本文摘自:</DIV>
<DIV><a href="http://hi.baidu.com/langwan/blog/category/%D4%B4%C2%EB%B7%D6%CE%F6" target="_blank">http://hi.baidu.com/langwan/blog/category/%D4%B4%C2%EB%B7%D6%CE%F6</A><BR></DIV>
页: [1]
查看完整版本: nginx中日志分析