Nginx模块开发-日志模型

来源:互联网 发布:wind数据库 免费版 编辑:程序博客网 时间:2024/06/06 00:33

1、日志级别

简介

Level

Description

Example

emerg

Emergencies - system is unusable

紧急 - 系统无法使用

Child cannot open lock file. Exiting

alert

Action must be taken immediately

必须立即采取措施

getpwuid: couldn't determine user name from uid

crit

Critical Conditions

致命情况

socket: Failed to get a socket, exiting child

error

Error conditions

错误情况

Premature end of script headers

warn

Warning conditions

警告情况

child process 1234 did not exit, sending another SIGHUP

notice

Normal but significant condition

一般重要情况

httpd: caught SIGBUS, attempting to dump core in ...

info

Informational

普通信息

Server seems busy, (you may need to increase StartServers, or Min/MaxSpareServers)...

debug

Debug-level messages

出错级别信息

Opening config file ...

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

备注:为了开发调试方便,日志被分成很多等级,Nginx的调试等级分成了两个维度,也可简称为errordebug维度,nginx支持的日志级别主要有emergalertcriterrorwarnnoticeinfodebugmain部分默认是error级别、HTTP部分默认是crit级别,server部分默认是crit级别。

1)第一个维度是0-8,对应nginx的配置如下所示:

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

 

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

2)第二个维度是0x10以上,我们可以自由扩展,这个维度是按照叠加效果计算的。

#define ngx_log_debug(level, log, args...)                                    \
    if ((log)->log_level & level)                                             \
        ngx_log_error_core(NGX_LOG_DEBUG, log, args)

2、数据结构

日志的源代码放在src/core/ngx_log.hngx_log.c中。

日志操作函数:

typedef u_char *(*ngx_log_handler_pt) (ngx_log_t *log, u_char *buf, size_t len);

struct ngx_log_s {

    ngx_uint_t           log_level;   //日志级别

    ngx_open_file_t      *file;        //对应的accesserror文件

    ngx_atomic_uint_t    connection;

    ngx_log_handler_pt   handler;

    void                *data;

    char                *action;

};

3、日志格式

access.log

访问日志格式(可自定义):

log_format  main  '$remote_addr $remote_user [$time_local] "$request" $http_host '

                  '$status $upstream_status $body_bytes_sent "$http_referer" '

                  '"$http_user_agent" $ssl_protocol $ssl_cipher $upstream_addr '

                  '$request_time $upstream_response_time';

有价值变量:

1$remote_addr:客户端IP地址,可以得到分省流量信息;

2$ssl_protocol 所用协议如TLSv1SSLv3

3$ssl_cipher:传输过程中的加密算法如RC4-SHAAES128-SHA

 

真实日志格式(1):

1.1.1.1 - [21/May/2012:09:00:01 +0800] "GET /tile/service/XX?hello=123 HTTP/1.1" hello.world.com$http_host

 200 200 3583 "https://hello.cj.com/standard/XXX?dddde=ddddd"$http_referer,来源地址) "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; 360SE)" TLSv1$ssl_protocol AES128-SHA$ssl_cipher 3.3.3.3:80$upstream_addr0.145 0.053

 

真实日志格式(2):

1.1.1.1 - [21/May/2012:09:00:01 +0800] "GET /index.htm HTTP/1.1" hello.world.com 302 302 37 "https://hello.cj.com/user/i

.htm?srcsdfsd=yysdfdsf" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" SSLv3$ssl_protocol RC4-SHA$ssl_cipher  3.3.3.3:80 $upstream_addr0.309 0.007

 

关闭访问日志:

access_log off;

error.log

错误日志格式(不能自定义):

error_log logs/error.log;

 

真实日志格式:

2012/05/21 09:00:09 [error] 9849#0: *354826826 upstream_ci:free the peer name:"3.3.3.3:80" fails:2 while connecting to upstre

am, client: 10.228.255.101, server: , request: "HEAD / HTTP/1.1", upstream: "http://3.3.3.3:80/", host: "hello.world.com"

 

关闭错误日志:

error_log /dev/null crit;

备注:不能使用error_log off,会创建一个名为off的日志文件。

4、操作函数

ngx_log_init (u_char *prefix)

函数功能:main函数初始化错误日志"./logs/error.log"

ngx_log_t *

ngx_log_init(u_char *prefix)

{

    ngx_log.file = &ngx_log_file;

    ngx_log.log_level = NGX_LOG_NOTICE;

 

    name = (u_char *) NGX_ERROR_LOG_PATH;    // "logs/error.log"

    nlen = ngx_strlen(name);

    。。。

    ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND,   

                                    NGX_FILE_CREATE_OR_OPEN,

                                    NGX_FILE_DEFAULT_ACCESS);  

//name ="./logs/error.log"

    return &ngx_log;

}

ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name)

函数功能:创建新的日志结构。

ngx_log_t *

ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name)

{

    ngx_log_t  *log;

 

    log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t));   //分配空间

    if (log == NULL) {

        return NULL;

    }

 

log->file = ngx_conf_open_file(cycle, name); 

//循环查找listcycle->open_files.part),如果文件已经打开,返回已有结构,否则分配空间,并放入cycle->open_files.part管理

    if (log->file == NULL) {

        return NULL;

    }

 

    return log;

}

ngx_log_set_levels (ngx_conf_t *cf, ngx_log_t *log)

函数功能:根据配置文件设定日志级别,error维度和debug维度。

char *

ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log)

{

    ngx_uint_t   i, n, d;

    ngx_str_t   *value;

 

    value = cf->args->elts; 

 

    //error_log logs/error.log info;

    for (i = 2; i < cf->args->nelts; i++) {  

 

        for (n = 1; n <= NGX_LOG_DEBUG; n++) {  

// NGX_LOG_DEBUGerror维度最低的级别

            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;

                continue;

            }

        }

             

           //error_log  logs/error.log debug_http

        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) {

                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;  //叠加级别

            }

        }

 

        if (log->log_level == 0) {

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                               "invalid log level \"%V\"", &value[i]);

            return NGX_CONF_ERROR;

        }

    }

 

    if (log->log_level == NGX_LOG_DEBUG) {

        log->log_level = NGX_LOG_DEBUG_ALL;

    }

 

    return NGX_CONF_OK;

}

ngx_log_error_core (ngx_uint_t level, ngx_log_t *log, ngx_err_t err, const char *fmt, ...)

Nginx模块开发(15)—日志模型 - cjhust - 我一直在努力 

函数功能:错误日志中最核心的函数,打印如下格式的错误日志(不能自定义),即时间+错误级别+nginx pid+错误详细信息。

2012/05/21 09:00:09 [error] 9849#0: *354826826 upstream_ci:free the peer name:"10.228.17.149:80" fails:2 while connecting to upstre

am, client: 10.228.255.101, server: , request: "HEAD / HTTP/1.1", upstream: "http://10.228.17.149:80/", host: "alipay.com"

 

void

ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,

    const char *fmt, va_list args)

 

#endif

{

#if (NGX_HAVE_VARIADIC_MACROS)

    va_list  args;

#endif

    u_char  *p, *last, *msg;

    u_char   errstr[NGX_MAX_ERROR_STR];

 

    if (log->file->fd == NGX_INVALID_FILE) {

        return;

    }

 

    last = errstr + NGX_MAX_ERROR_STR;

 

    ngx_memcpy(errstr, ngx_cached_err_log_time.data,

               ngx_cached_err_log_time.len);         //2012/05/21 09:00:09

 

    p = errstr + ngx_cached_err_log_time.len;

 

    p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);  //错误打印级别

 

    /* pid#tid */

    p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ",

                    ngx_log_pid, ngx_log_tid);       //nginxpid

 

    if (log->connection) {

        p = ngx_slprintf(p, last, "*%uA ", log->connection);

    }

 

    msg = p;

 

#if (NGX_HAVE_VARIADIC_MACROS)

 

    va_start(args, fmt);

    p = ngx_vslprintf(p, last, fmt, args);                //详细的错误信息

    va_end(args);

 

#else

 

    p = ngx_vslprintf(p, last, fmt, args);

 

#endif

 

    if (err) {

        p = ngx_log_errno(p, last, err);

    }

 

    if (level != NGX_LOG_DEBUG && log->handler) {

        p = log->handler(log, p, last - p);

    }

 

    if (p > last - NGX_LINEFEED_SIZE) {

        p = last - NGX_LINEFEED_SIZE;

    }

 

    ngx_linefeed(p);

 

    (void) ngx_write_fd(log->file->fd, errstr, p - errstr);     //写入文件

    ngx_http_tracker_add_error_count();

 

    if (!ngx_use_stderr

        || level > NGX_LOG_WARN

        || log->file->fd == ngx_stderr)

    {

        return;

    }

 

    msg -= (7 + err_levels[level].len + 3);

 

    (void) ngx_sprintf(msg, "nginx: [%V] ", &err_levels[level]);

 

    (void) ngx_write_console(ngx_stderr, msg, p - msg);    //写到终端

}

ngx_log_debug_core (ngx_log_t *log, ngx_err_t err, const char *fmt, ...)

函数功能:将日志级别设置为NGX_LOG_DEBUG,调用ngx_log_error_core打印错误日志。

void ngx_cdecl

ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, const char *fmt, ...)

{

    va_list  args;

 

    va_start(args, fmt);

    ngx_log_error_core(NGX_LOG_DEBUG, log, err, fmt, args);

    va_end(args);

}

 

ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err

函数功能:配置错误的入口,一般levelEMEG

ngx_log_error(level, cf->log, 0, "%*s in %s:%ui",

                  p - errstr, errstr,

                  cf->conf_file->file.name.data, cf->conf_file->line);

ngx_log_error (level, log, ...) 

函数功能:比较日志错误级别,调用ngx_log_error_core打印错误日志。

#define ngx_log_error(level, log, ...)                                        \

    if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)

ngx_log_abort (ngx_err_t err, const char *fmt, ...)

ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,

                  "%*s", p - errstr, errstr);

ngx_log_stderr

函数功能:将错误信息,直接打印到终端。

ngx_http_log_handler(ngx_http_request_t *r)

函数功能:ngx_http_log_init(ngx_conf_t *cf)ngx_http_log_handler放入NGX_HTTP_LOG_PHASE中,在请求过来的时候写access_log

h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);

if (h == NULL) {

  return NGX_ERROR;

}

*h = ngx_http_log_handler;

5、切割日志

nginxweb服务器,如果没有处理好日志,日志文件可能会很恐怖~10G20G。解决方法:

1access_log /dev/null,将日志丢到系统的黑洞,延长硬盘的寿命。

2)用定时任务来切割日志,kill –USR1来发送命令;

#crontab –l

00 * * * * /home/admin/spanner/sbin/log_rotate.sh

 

Filename: /home/admin/spanner/sbin/log_rotate.sh

#!/bin/bash

 

log_dir="/home/admin/spanner/logs"

backup_dir="/home/admin/spanner_logs"

date_dir=`date +%Y/%m/%d/%H`

 

/bin/mkdir -p ${backup_dir}/${date_dir} > /dev/null 2>&1

/bin/mv ${log_dir}/access.log ${backup_dir}/${date_dir}/access.log

/bin/mv ${log_dir}/error.log ${backup_dir}/${date_dir}/error.log

kill -USR1 `cat ${log_dir}/nginx.pid`

/bin/gzip ${backup_dir}/${date_dir}/access.log &

/bin/gzip ${backup_dir}/${date_dir}/error.log &

6、使用实例

ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]);

函数功能:向终端打印错误信息;

 

ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]);

函数功能:在启动过程中,配置错误打印接口;

 

ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "[white list]: access allowed by rule");

函数功能:运行过程中,向错误日志文件写入信息,级别是DEBUG

 

ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "[black list]: access forbidden by rule");

函数功能:运行过程中,向错误日志文件写入信息,级别是ERROR

0 0
原创粉丝点击