nginx转发日志提示302_nginx

指令的语法很简单,下面我们翻译一下官方文档:

nginx转发日志提示302_nginx转发日志提示302_02

配置日志。在同一个level中,可以指定多个日志。

第一个参数定义了存储日志信息的文件。不同level的错误日志会操作指定level的日志文件。可以通过指定的配置:以‘syslog:’为前缀,使用syslog机制记录日志。

什么是syslog?

Unix/Linux系统中的大部分日志都是通过一种syslog的机制产生和维护的。Syslog是一种标准的协议,分为客户端与服务端,客户端是产生日志消息的一方,服务器端负责接收客户端发送来的日志消息,并做出保存到特定的日志文件或者其他方式的处理。

关于syslog,nginx官方文档说明中的Logging to Syslog部分有做详细的说明,语法如下:

nginx转发日志提示302_nginx_03

继续翻译;如果想以内存缓冲的方式记录日志,可以通过指定的配置:以'memory:'为前缀,并定义buffer大小,这通常在调试日志中会使用。第二个参数用来定义记录日志的等级,以严重程度升序的排列顺序为:debug,info,notice,warn,error,crit,alert,emerg。指定level后,只会记录同等级或更高等级的日志信息。如:默认的error等级,只能记录error,crit,alert,emerg等级的日志信息。(此处需注意,在Logging to syslog说明中指出error_log指令中的level值通常是无效的,nginx会自动的选择一种error_log的level)。

nginx的初始化是在/src/core/nginx.c文件中的main()函数(main(int argc, char  *const  *argv){...})中完成的,并做了如下的初始化工作:

main(int  argc,  char  *const  *argv)
{
...
ngx_debug_init();
ngx_strerror_init();
ngx_get_options(argc,  argv);
ngx_time_init();
log = ngx_log_init(ngx_prefix);//日志初始化
}

首先构造函数ngx_log_s()定义在/src/core/ngx_log.h中:

struct ngx_log_s {
    ngx_uint_t           log_level;
    ngx_open_file_t     *file;

    ngx_atomic_uint_t    connection;

    ngx_log_handler_pt   handler;
    void                *data;

    /*
     * we declare "action" as "char *" because the actions are usually
     * the static strings and in the "u_char *" case we have to override
     * their types all the time
     */

    char                *action;

    ngx_log_t           *next;
};



函数ngx_log_init()定义在/src/core/ngx_log.c中,其实现为:

ngx_log_t *
ngx_log_init(u_char *prefix)
{
    u_char  *p, *name;
    size_t   nlen, plen;

	//static ngx_log_t        ngx_log;
	//static ngx_open_file_t  ngx_log_file;
    ngx_log.file = &ngx_log_file;
    ngx_log.log_level = NGX_LOG_NOTICE;

    name = (u_char *) NGX_ERROR_LOG_PATH;//NGX_ERROR_LOG_PATH 这个应该就是nginx.conf配置文件中error_log指令中的第一个参数:file参数

    /*
     * we use ngx_strlen() here since BCC warns about
     * condition is always false and unreachable code
     */

    nlen = ngx_strlen(name);
	
	/*
	 * 在nginx自定义的数据结构中,通过长度来表示字符串长度,减少计算字符串长度的次数
	 * nginx可以重复引用一段字符串内存,data可以指向任意内存,长度表示结束,而不用去copy一份自己的字符串
	 */
	 
	 //如果长度为0,则错误信息赋值给 已打开文件的文件描述符(file descriptor),并返回
    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;
}