指令的语法很简单,下面我们翻译一下官方文档:
配置日志。在同一个level中,可以指定多个日志。
第一个参数定义了存储日志信息的文件。不同level的错误日志会操作指定level的日志文件。可以通过指定的配置:以‘syslog:’为前缀,使用syslog机制记录日志。
什么是syslog?
Unix/Linux系统中的大部分日志都是通过一种syslog的机制产生和维护的。Syslog是一种标准的协议,分为客户端与服务端,客户端是产生日志消息的一方,服务器端负责接收客户端发送来的日志消息,并做出保存到特定的日志文件或者其他方式的处理。
关于syslog,nginx官方文档说明中的Logging to Syslog部分有做详细的说明,语法如下:
继续翻译;如果想以内存缓冲的方式记录日志,可以通过指定的配置:以'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;
}