博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Nginx 日志分析
阅读量:6431 次
发布时间:2019-06-23

本文共 11923 字,大约阅读时间需要 39 分钟。

 

日志使用

  •   access_log的最小作用域是location, 关闭方式是:access_log off;

  •   error_log的最小作用域是http,关闭方式是:error_log /dev/null;

  •   示例:error_log  logs/errord.log debug;

源码分析

Nginx启动由main开始执行,在nginx.c的278行,调用ngx_log_init(ngx_prefix),如下:

log = ngx_log_init(ngx_prefix);

其中【ngx_log.c】ngx_log_init(ngx_prefix)代码如下【主要实现了创建日志文件/usr/local/logs/error.log】

ngx_log_t *ngx_log_init(u_char *prefix){    u_char  *p, *name;    size_t   nlen, plen;    ngx_log.file = &ngx_log_file;    ngx_log.log_level = NGX_LOG_NOTICE;    name = (u_char *) NGX_ERROR_LOG_PATH;    /*     * we use ngx_strlen() here since BCC warns about     * condition is always false and unreachable code     */    nlen = ngx_strlen(name);    if (nlen == 0) {        ngx_log_file.fd = ngx_stderr;        return &ngx_log;    }    p = NULL;#if (NGX_WIN32)    if (name[1] != ':') {#else    if (name[0] != '/') {#endif        if (prefix) {            plen = ngx_strlen(prefix);        } else {#ifdef NGX_PREFIX            prefix = (u_char *) NGX_PREFIX;            plen = ngx_strlen(prefix);#else            plen = 0;#endif        }        if (plen) {            name = malloc(plen + nlen + 2);            if (name == NULL) {                return NULL;            }            p = ngx_cpymem(name, prefix, plen);            if (!ngx_path_separator(*(p - 1))) {                *p++ = '/';            }            ngx_cpystrn(p, (u_char *) NGX_ERROR_LOG_PATH, nlen + 1);            p = name;        }    }    ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND,                                    NGX_FILE_CREATE_OR_OPEN,                                    NGX_FILE_DEFAULT_ACCESS);    if (ngx_log_file.fd == NGX_INVALID_FILE) {        ngx_log_stderr(ngx_errno,                       "[alert] could not open error log file: "                       ngx_open_file_n " \"%s\" failed", name);#if (NGX_WIN32)        ngx_event_log(ngx_errno,                       "could not open error log file: "                       ngx_open_file_n " \"%s\" failed", name);#endif        ngx_log_file.fd = ngx_stderr;    }    if (p) {        ngx_free(p);    }    return &ngx_log;}

在之后的解析配置文件nginx.conf的过程中

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_core_module_t  ngx_errlog_module_ctx = {    ngx_string("errlog"),    NULL,    NULL};ngx_module_t  ngx_errlog_module = {    NGX_MODULE_V1,    &ngx_errlog_module_ctx,                /* module context */    ngx_errlog_commands,                   /* module directives */    NGX_CORE_MODULE,                       /* module type */    NULL,                                  /* init master */    NULL,                                  /* init module */    NULL,                                  /* init process */    NULL,                                  /* init thread */    NULL,                                  /* exit thread */    NULL,                                  /* exit process */    NULL,                                  /* exit master */    NGX_MODULE_V1_PADDING};

其中ngx_error_log.c的代码如下【主要实现了按照配置文件的命令创建新的日志文件和设置日志输出的等级】

char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log){    ngx_uint_t   i, n, d, found;    ngx_str_t   *value;    value = cf->args->elts;        for (i = 2; i < cf->args->nelts; i++) {        found = 0;        for (n = 1; n <= NGX_LOG_DEBUG; n++) {            if (ngx_strcmp(value[i].data, err_levels[n].data) == 0) {                if (log->log_level != 0) {                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,                                       "duplicate log level \"%V\"",                                       &value[i]);                    return NGX_CONF_ERROR;                }                log->log_level = n;                found = 1;                break;            }        }          for (n = 0, d = NGX_LOG_DEBUG_FIRST; d <= NGX_LOG_DEBUG_LAST; d <<= 1) {            if (ngx_strcmp(value[i].data, debug_levels[n++]) == 0) {  //若已设置err_levels,则不允许设置debug level。  //即error_log  logs/error.log  DEBUG NGX_LOG_DEBUG;将报错。                if (log->log_level & ~NGX_LOG_DEBUG_ALL) {                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,                                       "invalid log level \"%V\"",                                       &value[i]);                    return NGX_CONF_ERROR;                }                log->log_level |= d;                found = 1;                break;            }        }        if (!found) {            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,                               "invalid log level \"%V\"", &value[i]);            return NGX_CONF_ERROR;        }    }    // 如果error_log  logs/error.log NGX_LOG_DEBUG;相当于设置了全部的debug level.    if (log->log_level == NGX_LOG_DEBUG) {        log->log_level = NGX_LOG_DEBUG_ALL;    }    return NGX_CONF_OK;}static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){    ngx_str_t  *value, name;    if (cf->cycle->new_log.file) {        return "is duplicate";    }    value = cf->args->elts;    if (ngx_strcmp(value[1].data, "stderr") == 0) {        ngx_str_null(&name);    } else {        name = value[1];    }    cf->cycle->new_log.file = ngx_conf_open_file(cf->cycle, &name);    if (cf->cycle->new_log.file == NULL) {        return NULL;    }    if (cf->args->nelts == 2) {        cf->cycle->new_log.log_level = NGX_LOG_ERR;        return NGX_CONF_OK;    }    cf->cycle->new_log.log_level = 0;    return ngx_log_set_levels(cf, &cf->cycle->new_log);}

若配置文件中没有配置使用error_log,则【ngx_cycle.c】如下代码,作用生成新的new_log。

(此处发现ngx_cycle_s中的new_log仅仅是为了记录新日志文件之用;另外为了记录日志初始化之前的日志,所以ngx_log_init中创建/usr/local/logs/error.log,若配置文件中重新配置,则以配置文件为准;若没有配置,则就以此文件记录日志

if (cycle->new_log.file == NULL) {        cycle->new_log.file = ngx_conf_open_file(cycle, &error_log);        if (cycle->new_log.file == NULL) {            goto failed;        }    }

最后,

cycle->log = &cycle->new_log;    pool->log = &cycle->new_log;

至此日志可正常使用。

 
日志使用
  •   access_log的最小作用域是location, 关闭方式是:access_log off;

  •   error_log的最小作用域是http,关闭方式是:error_log /dev/null;

  •   示例:error_log  logs/errord.log debug;

源码分析

Nginx启动由main开始执行,在nginx.c的278行,调用ngx_log_init(ngx_prefix),如下:

log = ngx_log_init(ngx_prefix);

其中【ngx_log.c】ngx_log_init(ngx_prefix)代码如下【主要实现了创建日志文件/usr/local/logs/error.log】

ngx_log_t *ngx_log_init(u_char *prefix){    u_char  *p, *name;    size_t   nlen, plen;    ngx_log.file = &ngx_log_file;    ngx_log.log_level = NGX_LOG_NOTICE;    name = (u_char *) NGX_ERROR_LOG_PATH;    /*     * we use ngx_strlen() here since BCC warns about     * condition is always false and unreachable code     */    nlen = ngx_strlen(name);    if (nlen == 0) {        ngx_log_file.fd = ngx_stderr;        return &ngx_log;    }    p = NULL;#if (NGX_WIN32)    if (name[1] != ':') {#else    if (name[0] != '/') {#endif        if (prefix) {            plen = ngx_strlen(prefix);        } else {#ifdef NGX_PREFIX            prefix = (u_char *) NGX_PREFIX;            plen = ngx_strlen(prefix);#else            plen = 0;#endif        }        if (plen) {            name = malloc(plen + nlen + 2);            if (name == NULL) {                return NULL;            }            p = ngx_cpymem(name, prefix, plen);            if (!ngx_path_separator(*(p - 1))) {                *p++ = '/';            }            ngx_cpystrn(p, (u_char *) NGX_ERROR_LOG_PATH, nlen + 1);            p = name;        }    }    ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND,                                    NGX_FILE_CREATE_OR_OPEN,                                    NGX_FILE_DEFAULT_ACCESS);    if (ngx_log_file.fd == NGX_INVALID_FILE) {        ngx_log_stderr(ngx_errno,                       "[alert] could not open error log file: "                       ngx_open_file_n " \"%s\" failed", name);#if (NGX_WIN32)        ngx_event_log(ngx_errno,                       "could not open error log file: "                       ngx_open_file_n " \"%s\" failed", name);#endif        ngx_log_file.fd = ngx_stderr;    }    if (p) {        ngx_free(p);    }    return &ngx_log;}

在之后的解析配置文件nginx.conf的过程中

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_core_module_t  ngx_errlog_module_ctx = {    ngx_string("errlog"),    NULL,    NULL};ngx_module_t  ngx_errlog_module = {    NGX_MODULE_V1,    &ngx_errlog_module_ctx,                /* module context */    ngx_errlog_commands,                   /* module directives */    NGX_CORE_MODULE,                       /* module type */    NULL,                                  /* init master */    NULL,                                  /* init module */    NULL,                                  /* init process */    NULL,                                  /* init thread */    NULL,                                  /* exit thread */    NULL,                                  /* exit process */    NULL,                                  /* exit master */    NGX_MODULE_V1_PADDING};

其中ngx_error_log.c的代码如下【主要实现了按照配置文件的命令创建新的日志文件和设置日志输出的等级】

char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log){    ngx_uint_t   i, n, d, found;    ngx_str_t   *value;    value = cf->args->elts;        for (i = 2; i < cf->args->nelts; i++) {        found = 0;        for (n = 1; n <= NGX_LOG_DEBUG; n++) {            if (ngx_strcmp(value[i].data, err_levels[n].data) == 0) {                if (log->log_level != 0) {                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,                                       "duplicate log level \"%V\"",                                       &value[i]);                    return NGX_CONF_ERROR;                }                log->log_level = n;                found = 1;                break;            }        }          for (n = 0, d = NGX_LOG_DEBUG_FIRST; d <= NGX_LOG_DEBUG_LAST; d <<= 1) {            if (ngx_strcmp(value[i].data, debug_levels[n++]) == 0) {  //若已设置err_levels,则不允许设置debug level。  //即error_log  logs/error.log  DEBUG NGX_LOG_DEBUG;将报错。                if (log->log_level & ~NGX_LOG_DEBUG_ALL) {                    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,                                       "invalid log level \"%V\"",                                       &value[i]);                    return NGX_CONF_ERROR;                }                log->log_level |= d;                found = 1;                break;            }        }        if (!found) {            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,                               "invalid log level \"%V\"", &value[i]);            return NGX_CONF_ERROR;        }    }    // 如果error_log  logs/error.log NGX_LOG_DEBUG;相当于设置了全部的debug level.    if (log->log_level == NGX_LOG_DEBUG) {        log->log_level = NGX_LOG_DEBUG_ALL;    }    return NGX_CONF_OK;}static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){    ngx_str_t  *value, name;    if (cf->cycle->new_log.file) {        return "is duplicate";    }    value = cf->args->elts;    if (ngx_strcmp(value[1].data, "stderr") == 0) {        ngx_str_null(&name);    } else {        name = value[1];    }    cf->cycle->new_log.file = ngx_conf_open_file(cf->cycle, &name);    if (cf->cycle->new_log.file == NULL) {        return NULL;    }    if (cf->args->nelts == 2) {        cf->cycle->new_log.log_level = NGX_LOG_ERR;        return NGX_CONF_OK;    }    cf->cycle->new_log.log_level = 0;    return ngx_log_set_levels(cf, &cf->cycle->new_log);}

若配置文件中没有配置使用error_log,则【ngx_cycle.c】如下代码,作用生成新的new_log。

(此处发现ngx_cycle_s中的new_log仅仅是为了记录新日志文件之用;另外为了记录日志初始化之前的日志,所以ngx_log_init中创建/usr/local/logs/error.log,若配置文件中重新配置,则以配置文件为准;若没有配置,则就以此文件记录日志

if (cycle->new_log.file == NULL) {        cycle->new_log.file = ngx_conf_open_file(cycle, &error_log);        if (cycle->new_log.file == NULL) {            goto failed;        }    }

最后,

cycle->log = &cycle->new_log;    pool->log = &cycle->new_log;

至此日志可正常使用。

 

 

转载地址:http://sltga.baihongyu.com/

你可能感兴趣的文章
J2me的异常处理和多线程
查看>>
选择、生成-EA与数据库的交互-by小雨
查看>>
客户网页WIZnet无线解决方案 之 太阳能逆变器
查看>>
CCRepeatForever和CCDelayTime
查看>>
android jni aotf 错误
查看>>
Azkaban的功能特点(二)
查看>>
[RxJS] Add debug method to Observable in TypeScript
查看>>
1、金融之关于BIAS
查看>>
[转]ASP.NET Core基本原理(11)-管理应用程序状态
查看>>
VS Code搭建.NetCore开发环境(一)
查看>>
01字典树贪心查询+建立+删除(个人模版)
查看>>
java-信息安全(十一)-非对称加密算法ECC以及ECDSA签名
查看>>
(转)Flex的编译过程--ActionScript字节码(ABC)
查看>>
Directory Listing Denied
查看>>
今天讲座的感悟--java
查看>>
o(1)复杂度之双边滤波算法的原理、流程、实现及效果。
查看>>
corner2
查看>>
我见过的几种类型的员工(转)
查看>>
web前端的十种jquery特效及源码下载
查看>>
poj 3414 Pots (bfs+线索)
查看>>