程序员技术交流、面试、职场、生活、游戏,综合讨论QQ群:387017550,群内经常发红包,欢迎加入
Nginx里,日志配置是在 http 里,默认配置如下:
# log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
# access_log logs/access.log main;
说明:
- $log_format 表示日志格式,main 表示该格式名;
- $access_log 表示日志存放位置,main 表示采用格式名为 mian 的日志格式;
- $remote_addr:远程客户端用户的 IP;
- $remote_user:远程客户端用户名称;
- $time_local:时间和时区;
- $resuest:请求方式(比如GET)、请求URL(比如/)、HTTP协议(比如HTTP/1.1);
- $status:HTTP状态码,例如成功是200,未找到是404;
- $body_bytes_send:发送给客户端的主体文件内容大小,不包括响应头的大小; 该变量与Apache模块mod_log_config里的“%B”参数兼容;
- $http_referer:从哪个链接访问过来的(但非重定向可能为空);
- $http_x_forwarded_for:重定向之前,用户真实的 IP 地址;
log_format 属性:
只能放在 http 属性内(即和 server 平级的位置);
默认的格式名为 combined
access_log 属性:
可以放在多个位置,包括:
- http
- server
- location
- if in location
- limit_except
log_format常用的变量参数
以下是我从其他地方拷贝过来的(出处较多,故不附链接),仅供参考;
参数 说明 示例
$remote_addr 客户端地址 211.28.65.253
$remote_user 客户端用户名称 --
$time_local 访问时间和时区 18/Jul/2012:17:00:01 +0800
$request 请求的URI和HTTP协议 "GET /article-10000.html HTTP/1.1"
$http_host 请求地址,即浏览器中你输入的地址(IP或域名) www.wang.com 192.168.100.100
$status HTTP请求状态 200
$upstream_status upstream状态 200
$body_bytes_sent 发送给客户端文件内容大小,不包括响应头的大小 1547
$http_referer url跳转来源 https://www.baidu.com/
$http_user_agent 用户终端浏览器等信息 "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; SV1; GTB7.0; .NET4.0C;
$ssl_protocol SSL协议版本 TLSv1
$ssl_cipher 交换数据中的算法 RC4-SHA
$upstream_addr 后台upstream的地址,即真正提供服务的主机地址 10.10.10.100:80
$request_time 整个请求的总时间 0.205
$upstream_response_time 请求过程中,upstream响应时间 0.002
补充内容:
$bytes_sent 发送给客户端的总字节数。
$connection 连接的序列号。
$connection_requests 当前通过一个连接获得的请求数量。
$msec 日志写入时间。单位为秒,精度是毫秒。
$pipe 如果请求是通过HTTP流水线(pipelined)发送,pipe值为“p”,否则为“.”。
$request_length 请求的长度(包括请求行,请求头和请求正文)。
$time_iso8601 ISO8601标准格式下的本地时间。
我们可以根据自己实际需要改为:
log_format mylogformat '$remote_addr | $http_x_forwarded_for | "$http_referer" | '
'$remote_user | $time_local | $http_host | "$request" | '
'$status | $body_bytes_sent | "$http_user_agent"';
access_log logs/access2.log mylogformat;
以上配置表示:
- 日志存储到 logs/access2.log
- 日志格式名是 mylogformat
- 该格式是(注意,实际上不换行):
[重定向之前的用户 IP] | [原始用户访问 IP] | [用户访问的URL] |
[用户名] | [访问时间和时区] | [请求的域名的host部分] | [请求方式、地址、HTTP协议版本] |
[HTTP状态码] | [返回报文大小] | [用户浏览器信息]
;
示例数据:
- | "-" | - | 24/Jan/2019:19:55:40 +0800 | a.test.com | "GET /index.html HTTP/1.1" | 200 | 396 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
$remote_addr 和 $http_x_forwarded_for 的区别:
- $remote_addr 是用户 IP;
- 但若如果被负载均衡设备、或者 Nginx 反向代理后,$remote_addr 则是反向代理设备的 IP;
- 此时真实 IP 可能被添加到 HTTP 头信息中,属性名是
X-Forwarded-For
,$http_x_forwarded_for 可以获取到这个值;
非常简单
access_log off;
Nginx 0.7.4 后,日志文件路径可以包含变量。
具体来说,可以包含server名,以及年月日时分秒等变量时间。
具体不多讲,参考以下代码和效果说明即可知道。
年月日时分秒:
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})")
{
set $year $1;
set $month $2;
set $day $3;
set $hour $4;
set $minutes $5;
set $seconds $6;
}
- 放在 server 范围内方可使用;
- $time_iso8601 格式如下:2019-01-25T00:12:02+08:00
- 因此 $year 为 2019,其他依次类推,很好理解;
$server_name :
之所以说 $server_name ,是因为我们通常日志是跟 $server_name 关联的。
配置方法:
server {
listen 80;
server_name a.test.com;
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})")
{
set $year $1;
set $month $2;
set $day $3;
set $hour $4;
set $minutes $5;
set $seconds $6;
}
# 核心在这里
access_log logs/[$year-$month-$day]$server_name.log mylogformat;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
日志文件名:
写文章这天是2019-01-25
[2019-01-25]a.test.com.log
假如我在 http 有一次 access_log 配置,再在 server 有一次 access_log 配置。
那么优先匹配 server 的 access_log 的配置,取不到再取 http 的配置;
默认情况下:
- 运行 Nginx 的用户需要有读写权限,否则无法创建和读写;
- 无缓冲,即每产生一条日志,会先打开日志,写入,再关闭(IO较多);
由于IO较多,因此需要配置 open_log_file_cache
属性来避免 IO 带来的性能损失。
具体来说:
- 首先不能批量写入,原因在于,server可能有多个,而日志(access_log)的配置,是可以配置到 server 级的;
- 这会导致可能出现,两个 server 原本应该交叉写入的日志,实际却先写了第一个 server 的全部日志,再写了第二个 server 的全部日志;
- 但多次 IO 还是有一定性能损失;
于是分析linux对文件系统的管理,引一段别人写的博客:
文件指针(fp)和文件描述符(fd)有什么关系呢?
文件指针是指向一个FILE的结构体,这个结构体里包括一个文件描述符(在Windows下也被称为文件句柄)和一个I/O缓冲区。
文件描述符用于C标准的IO库调用中,用于标识文件。
FILE中包含文件描述符元素,可以用fopen()直接获取指针fp,然后使用fp获得fp中所包含文件描述符fd的信息。
文件描述符应该是唯一的,而文件指针却不是唯一的,但指向的对象是唯一的。
文件指针比fd更适合跨平台。
文件描述符就是open文件时产生的一个很小的正整数,,是一个索引值。
文件描述符:在linux系统中打开文件就会获得文件描述符,它是个很小的正整数。
每个进程在PCB(Process Control Block)中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针。
简单归纳:文件描述符(fd)只是一个整数,在open时产生,起到一个索引的作用,进程通过PCB中的文件描述符表找到该fd所指向的文件指针file。
我总结一下,简单来说,文件指针(fp) = 文件描述符(fd) + 其他的;
而 文件描述符(fd) 指向文件;
因此缓存 文件描述符(fd),可以加快 查找/打开 日志文件的速度;
在日志文件比较多的时候,缓存 文件描述符(fd) 可以提高性能。
因此有了 open_log_file_cache 配置属性。
open_log_file_cache 说明:
- 默认值为 off(关闭);
- 语法:
open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
属性说明:
- max:(必填)设置缓存中最多容纳的文件描述符数量,如果被占满,采用LRU算法将描述符关闭。
- inactive:(选填)设置缓存存活时间,默认是10s。
- min_uses:(选填)在inactive时间段内,日志文件最少使用几次,该日志文件描述符记入缓存,默认是1次。
- valid:(选填)设置多久对日志文件名进行检查,看是否发生变化,默认是60s。
- off:不使用缓存,默认值为off。
基本用法:
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
它可以配置在http、server、location作用域中。
例子中,设置缓存最多缓存1000个日志文件描述符,20s内如果缓存中的日志文件描述符至少被被访问2次,才不会被缓存关闭。每隔1分钟检查缓存中的文件描述符的文件名是否还存在。
主要应用于多个日志(使用了日志变量)时的场景。
- http://www.ttlsa.com/linux/the-nginx-log-configuration/
- https://juejin.im/post/59f94f626fb9a045023af34c
- http://blog.51cto.com/longlei/2132170 (推荐这个,讲的比较细致,例如如何按日自动切割日志)
- https://yq.aliyun.com/ziliao/29200 (有讲如何以JSON格式存储日志,但他的方案有一个缺点是,需要注意在每一个数据后加逗号。以及采集使用数据时,需要在文件头尾加中括号以让其是一个真正的JSON数组);
- http://www.ttlsa.com/nginx/nginx-configure-file-log-rotation/ (nginx 直接在配置文章中设置日志分割,不用挂定时任务去做了)