0x01 前言

前几天我在配置ELK(安装配置Elastic Stack 5)的时候发现我的nginx日志并没有按照我设定的格式生成。

这并不是nginx的错,而是我没有仔细查看nginx的技术文档。我在这里做个记录。

0x02 错误

以下是我的日志格式:

    log_format main 			'$remote_addr - $remote_user [$time_local] "$request" $http_host ' 
					'$status $body_bytes_sent "$http_referer" '
					'"$http_user_agent" "$http_x_forwarded_for" '
					'$upstream_addr $upstream_status $upstream_cache_status "$upstream_http_content_type" $upstream_response_time > $request_time';

它生成的日志是这样的:

10.1.1.66 - - [22/Nov/2016:12:26:14 +0800] "GET /bundles/src/ui/public/styles/fonts/open_sans/open_sans_v13_latin_700italic.woff2 HTTP/1.1" kibana.t.com 304 0 "http://kibana.t.com/bundles/commons.style.css?v=14458" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36" "-" 127.0.0.1:5601 304 - "application/font-woff2" 0.004 > 0.004

然而我我实际收到的日志却是以下这样的:

113.87.241.226 - - [21/May/2016:02:44:16 +0600] "GET /s/oswald/v11/l1cOQ90roY9yC7voEhngDLO3LdcAZYWl9Si6vvxL-qU.woff HTTP/2.0" 200 16537 "https://terence.org.cn/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/601.5.17 (KHTML, like Gecko) Version/9.1 Safari/601.5.17"

上面这个日志的格式很明显和nginx默认的日志combined格式一致:

log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

那么问题来了,为什么我定义了日志的格式却没有生成正确的日志,而是nginx默认的格式?

0x03 解决

在翻查nginx log module的说明文档后我找到了答案:

Module ngx_http_log_module

原因很简单,我的配置文件仅配置了日志存放的路径,但却少了指定的日志格式。我一直使用类似以下的配置信息:

access_log              /var/log/nginx/access.log

在nginx log module的说明文档中有一句:

If the format is not specified then the predefined “combined” format is used.

如果未指定具体的格式,那么默认的combined将会被采用。那么问题来了,要怎样指定格式?

查看nginx log语法后发现:

Syntax:	log_format name string ...;
Default:	
log_format combined "...";
Context:	http

log_format后面紧跟着的就是格式名称,那么要将这个名词放到哪里才能生成正确的日志?

再次翻查语法后发现:

Syntax:	access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
Default:	
access_log logs/access.log combined;
Context:	http, server, location, if in location, limit_except

解决的办法很简单,需要在access_log path后面附上format,类似下面:

access_log              /var/log/nginx/access.log main;

最后的main就是我定义的日志格式名称。如果没有为access_log定义日志格式名称,那么会使用默认的combined格式。

0x04 结语

以前完全没有查看日志的习惯,日志也越来越大。要不是ELK这个非常棒的开源软件,我也没有发现我在nginx日志的配置上出现了错误。