设为首页 收藏本站
查看: 925|回复: 0

[经验分享] Nginx源代码分析

[复制链接]

尚未签到

发表于 2016-12-26 09:20:46 | 显示全部楼层 |阅读模式
我看Nginx源代码的时候,感觉整个系统都在传递log指针。log在nginx里是比较关键的。日志和内存分配是最基础的两个起点代码,最好是在自己写的程序框架中早点完善并实现。以免未来要用大量的精力调整。

1. 日志的源代码位置

日志的源代码在src/code/ngx_log.c及ngx_log.h里。

2. 日志的初始化

在main()函数一开始,对一些基础数据进行初始化,其中之一就是日志,源代码如下:

log = ngx_log_init();
if (log == NULL) {
return 1;
}

3. 传递日志指针

在创建任何结构或执行任何函数,无论那种结构体都至少会包含一个向下传递的日志指针,例如以下代码:

init_cycle.log = log;
ngx_cycle = &init_cycle;

init_cycle.pool = ngx_create_pool(1024, log);
if (init_cycle.pool == NULL) {
return 1;
}

说明cycle结构体内含有日志指针、在创建内存池的时候最后一个参数也是日志指针。

我们在列举一些结构,例如:

struct ngx_connection_s {
void *data;
ngx_event_t *read;
ngx_event_t *write;

ngx_socket_t fd;

ngx_recv_pt recv;
ngx_send_pt send;
ngx_recv_chain_pt recv_chain;
ngx_send_chain_pt send_chain;

ngx_listening_t *listening;

off_t sent;

ngx_log_t *log;

在connection结构里也传递了log指针。

4. 日志的分级

为了开发调试方便,日志被分成很多等级,我们可以只写入我们关心等级的日志,Nginx的调试等级分成了两个维度,如下:

#define NGX_LOG_STDERR 0
#define NGX_LOG_EMERG 1
#define NGX_LOG_ALERT 2
#define NGX_LOG_CRIT 3
#define NGX_LOG_ERR 4
#define NGX_LOG_WARN 5
#define NGX_LOG_NOTICE 6
#define NGX_LOG_INFO 7
#define NGX_LOG_DEBUG 8

#define NGX_LOG_DEBUG_CORE 0x010
#define NGX_LOG_DEBUG_ALLOC 0x020
#define NGX_LOG_DEBUG_MUTEX 0x040
#define NGX_LOG_DEBUG_EVENT 0x080
#define NGX_LOG_DEBUG_HTTP 0x100
#define NGX_LOG_DEBUG_MAIL 0x200
#define NGX_LOG_DEBUG_MYSQL 0x400

#define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG_CORE
#define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_MYSQL
#define NGX_LOG_DEBUG_CONNECTION 0x80000000
#define NGX_LOG_DEBUG_ALL 0x7ffffff0


第一个维度是0-8,当我们在配置文件中如下设置:

#error_log logs/debug.log debug;
#error_log logs/error.log notice;
#error_log logs/error.log info;

常量如何与字符串对应起来的可以看,log.c文件中的一段定义:

static const char *err_levels[] = {
"stderr", "emerg", "alert", "crit", "error",
"warn", "notice", "info", "debug"
};

在nginx的判断中只要是debug就一定会输出小于8的所有信息,源代码如下:

#define ngx_log_error(level, log, args...) \
if ((log)->log_level >= level) ngx_log_error_core(level, log, args)

或者我们管这种维度叫做 error 维度。

另外一个维度是0x10以上,我们可以自由扩展,这个维度是按照叠加效果计算的,源代码如下:
#define ngx_log_debug(level, log, args...) \
if ((log)->log_level & level) \
ngx_log_error_core(NGX_LOG_DEBUG, log, args)

ngx_set_error_log_levels() {

...

for (n = 1; n <= NGX_LOG_DEBUG; n++) {
if (ngx_strcmp(value.data, err_levels[n]) == 0) {

if (log->log_level != 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"duplicate log level \"%s\"",
value.data);
return NGX_CONF_ERROR;
}

log->log_level = n;
continue;
}
}

...

}

按照这个逻辑,nginx只认第一有效设置,不能使用这样的配置

error_log logs/debug.log debug | info;

错误是 [emerg] 3596#0: duplicate log level "info" in /data/services/nginx/conf/nginx.conf:6

但可以写

error_log logs/debug.log debug | langwan;

写错了没事 :)


或者我们管这个维度叫做 debug 维度,相关源代码如下:

#define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG_CORE
#define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_MYSQL

ngx_set_error_log_levels() {

...

for (n = 0, d = NGX_LOG_DEBUG_FIRST; d <= NGX_LOG_DEBUG_LAST; d <<= 1) {
if (ngx_strcmp(value.data, debug_levels[n++]) == 0) {
if (log->log_level & ~NGX_LOG_DEBUG_ALL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid log level \"%s\"",
value.data);
return NGX_CONF_ERROR;
}

log->log_level |= d;
}
}

...

}

由于NGX_LOG_DEBUG_ALL的限制,限制了0-8这9个等级,不能出现在相同的配置里,例如下面的设置是错误的:

error_log logs/debug.log debug | debug_alloc;

错误是 [emerg] 3579#0: invalid log level "debug_alloc" in /data/services/nginx/conf/nginx.conf:6

只能写成

error_log logs/debug.log debug_http | debug_alloc;

5. debug与debug_http之间的关系

实际上开启了debug等级会输出所有debug_开头的调试信息,如果我们想过滤一下信息,只能详细去按照 debug_http|debug_alloc 这样去设置,否则光设置debug就全出来了,具体表示关系的代码如下:

if (log->log_level == 0) {
log->log_level = NGX_LOG_ERR;

} else if (log->log_level == NGX_LOG_DEBUG) {
log->log_level = NGX_LOG_DEBUG_ALL;
}

当错误等级包含NGX_LOG_DEBUG设置所有的调试等级给log_level。

6. 默认的错误等级

上面的代码实际上也已经说明了,默认的错误等级是NGX_LOG_ERR

7. 错误日志有关的四个函数之间的调度关系

ngx_log_error() 按照优先级的大小判定是否输出错误信息,例如:

error_log logs/debug.log error;

不会输出 NGX_LOG_WARN、NGX_LOG_NOTICE、NGX_LOG_INFO、NGX_LOG_DEBUG 信息。

ngx_log_debug() 系列函数一共有10个,这里的0-8表示参数个数,不代表错误等级,用于输出DEBUG_HTTP等调试信息。这9个函数均是ngx_log_debug()的一种宏定义,例如:

#define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3) \
if ((log)->log_level & level) \
ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3)

剩下还有ngx_log_debug_core()、与ngx_log_error_core()两个函数

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-319460-1-1.html 上篇帖子: nginx多进程模型之热代码平滑升级 下篇帖子: 在Nginx中记录自定义Header
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表