nginx内置日志切割实战

来源: DevOpSec公众号 作者: DevOpSec

背景

小明在维护nginx时通过自己写脚本切割日志,这里弊端有二:

一、日志可能丢失,在日志切割和新日志产生的一瞬间有日志的丢失。

二、维护成本高,由于业务量的增加nginx横向扩容了几台机器,小明很快就把nginx扩容上,但日志切割的定时任务忘记增加了。

在日常运维过程中我们希望日志自动的按天切割,而不是通过脚本加定时任务实现,增加了运维维护的复杂度,下面让我们看看怎么操作吧。

日志切割

我们知道nginx配置文件里是可以引用nginx的内置变量的,nginx的日志文件名是否可以把带有时间的变量拼接一起,随着时间的变化日志文件自动切割呢?

答案是可以的。下面看nginx内的的部分变量,我们通过time_iso8601变量分别实现http协议和tcp协议下nginx日志自动切割。

首先我们先看一下nginx内置常用变量,对我们定义打印日志内容有帮助。

1. nginx内置变量


变量名称变量描述
$time_iso8601本地ISO 8601时间
$arg_PARAMETER客户端GET请求中PARAMETER 字段的值
$args客户端请求中的参数
$binary_remote_addr远程地址的二进制表示
$body_bytes_sent已发送的消息体字节数
$content_lengthHTTP请求信息中content-length的字段
$content_type请求信息中content-type字段
$cookie_COOKIE客户端请求中COOKIE头域的值
$document_root针对当前请求的根路径设置值
$document_uri与$uri相同
$host请求信息中的host头域,如果请求中没有Host行,则等于设置的服务器名
$http_HEADERHTTP请求信息里的HEADER地段
$http_host与$host相同,但是如果请求信息中没有host行,则可能不同客户端cookie信息
$http_cookie客户端cookie信息
$http_referer客户端是从哪一个地址跳转过来的
$http_user_agent客户端代理信息,也就是你客户端浏览器
$http_via最后一个访问服务器的IP
$http_x_forwarded_forX-Forwarded-For 是一个扩展头, 用来表示HTTP 请求端真实IP
$is_args如果有args的值,则等于”?”,否则为空
$limit_rate对连接速率的限制
$nginx_version当前Nginx的版本
$pid当前Nginx服务器的进程的进程ID
$query_string与$args相同
$remote_addr客户端IP地址
$remote_port客户端的端口
$remote_user客户端的用户名,用于 auth basic module验证
$request客户端请求
$request_body客户端发送的报文体
$request_body_file发送后端服务器的本地临时缓存文件的名称
$request_filename当前请求的文件路径名,由root或alias指令与URI请求生成
$request_method请求后端数据的方法,例如”GET”,”POST”
$request_uri请求的URI,带参数,不包含主机名
$scheme所用的协议,如http或者HTTPS,比如rewrite^(.+)$$scheme://mysite.name$redirect
$sent_http_cache_control对应http请求头中的Cache-Control,需要打开chrome浏览器,右键检查,选中network,点中其中一个请求的资源
$sent_http_connection对应http请求中的Connection
$sent_http_content_type对应http请求中的Content-Type
$sent_last_modified对应请求中的Last-Modified
$server_addr服务端的地址
$server_name请求到达的服务器名
$server_port请求到达服务器端口号
$server_protocol请求协议的版本号,HTTP1.0/HTTP1.1
$uri请求的不带请求参数的URI,可能和最初的值有不同,比如经过重定向之类的
$request_timenginx接收到请求到发送给client端数据包耗时
$upstream_response_timenginx后端服务器的响应时间
$http_user_agent用户客户端UA标识

下面开始做nginx日志切割的配置了,对于nginxtcphttp协议都适用。

2. 全局通用配置,http或者stream模块里设置

首先通过nginx关键字map和内置变量time_iso8601拿到年月日,当然还可以按小时分钟甚至是按秒切割,按日志大小和需求情况来定

1http | stream { 2 #..... 3 #设置变量 year month day hour minutes seconds 4 map $time_iso8601 $year { 5 default '0000'; 6 "~^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})" $1; 7 } 8 map $time_iso8601 $month { 9 default '00'; 10 "~^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})" $2; 11 } 12 map $time_iso8601 $day { 13 default '00'; 14 "~^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})" $3; 15 } 16 map $time_iso8601 $hour { 17 default '00'; 18 "~^^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})" $4; 19 } 20 map $time_iso8601 $minutes { 21 default '00'; 22 "~^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})" $5; 23 } 24 map $time_iso8601 $seconds { 25 default '00'; 26 "~^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})" $6; 27 } 28}

定义日志格式,nginx日志json化,日志格式化后续方便处理,比如入kafkastorm等流式处理

1http | stream { 2# 日志格式 3log_format logjsonv1 escape=json '{' 4 '"version": "logjsonv1", ' 5 '"hostname": "${hostname}", ' 6 '"remote_addr": "${remote_addr}", ' 7 '"remote_port": "${remote_port}", ' 8 '"proxy_protocol_addr": "${proxy_protocol_addr}", ' 9 '"http_x_forwarded_for": "${http_x_forwarded_for}", ' 10 '"upstream_addr": "${upstream_addr}", ' 11 '"time_iso8601": "${time_iso8601}", ' 12 '"request_method": "${request_method}", ' 13 '"scheme": "${scheme}", ' 14 '"server_name": "${host}", ' 15 '"server_port": "${server_port}", ' 16 '"uri": "${uri}", ' 17 '"args": "${args}", ' 18 '"status": "$status", ' 19 '"http_referer": "${http_referer}", ' 20 '"body_bytes_sent": "${body_bytes_sent}", ' 21 '"request_time": "${request_time}", ' 22 '"http_cookie": "${http_cookie}", ' 23 '"upstream_response_time": "${upstream_response_time}", ' 24 '"http_user_agent": "${http_user_agent}", ' 25 '"sent_http_location": "${sent_http_location}", ' 26 '"sent_http_content_type": "${sent_http_content_type}" ' 27'}'; 28 29 #记录日志,按天切割,也可以根据需要按小时切割 30 access_log logs/access_$year$month$day.log logjsonv1; 31 32 #..... 33}

我们还可以简单的map以下比如:

1 map $time_iso8601 $formatted_date { 2 default 'date-not-found'; 3 '~^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})' $year-$month-$day; 4 } 5access_log logs/access_$formatted_date.log logjsonv1;

注意:可能还有人说还可以用if啊,如下:

1 if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") { 2 set $year $1; 3 set $month $2; 4 set $day $3; 5 set $hour $4; 6 }

ifhttp模块里是没有问题的,但在stream模块里不支持if语句,此方法就没有map方式通用。

以上就是本文重点tcphttp协议下怎样用nginx内置变量和命令做日志的自动切换,下面是map的简单介绍和三方工具logrotate实现的日志切割,感兴趣可以学习一下。

map介绍和三方工具logrotate实现日志切割

1. map用法

map 指令是由 ngx_http_map_modulengx_stream_map_module模块提供的,默认情况下安装 nginx 都会安装该模块。

map 的主要作用是创建自定义变量,通过使用 nginx 的内置变量,去匹配某些特定规则,如果匹配成功则设置某个值给自定义变量。 而这个自定义变量便可作于它用,比如日志切割。

map语法

1http下: 2Syntax: map string $variable { ... } 3Default:4Context: http 5 6 7stream下: 8Syntax: map string $variable { ... } 9Default:10Context: stream 11

例子: 默认mobile 变量默认值是0,当http_user_agent匹配上Opera Mini后其值被赋值为1

1map $http_user_agent $mobile { 2 default 0; 3 "~Opera Mini" 1; 4}

2. logrotate 切割nginx日志

安装logrotate

yum install logrotate

安装完成后,自动在/etc/cron.daily/下生成个logrotate脚本文件。

1 2cd /etc/logrotate.d/ 3 4vim nginx 内容如下: 5 6/path/nginx/logs/*log { 7 su root www 8 create 600 www www 9 daily 10 dateext 11 rotate 10 12 missingok 13 notifempty 14 compress 15 sharedscripts 16 olddir /path/nginx/logs/oldlogs # 这个目录要事先创建好,并给相关权限 17 postrotate 18 kill -USR1 `cat /path/nginx/logs/nginx.pid` 19 endscript 20} 21

#设置定时任务

1crontab -e 2 30 0 * * * /usr/sbin/logrotate -f /etc/logrotate.d/nginx 4

除了三方工具我们还可以写脚本实现日志切割,脚本方式大家可以尝试一下。

nginx内置工具实现有一个弊端没有压缩和日志保留时长的处理,这个大家也可以思考一下怎么处理,大家可以在评论区留言讨论。

点赞
收藏

评论区

加载中...

相关推荐

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

UIWebView长按保存图片和识别图片二维码的实现方案(使用缓存)

0x00需求:长按识别UIWebView中的二维码,如下图长按识别二维码0x01方案1:给UIWebView增加一个长按手势,激活长按手势时获取当前UIWebView的截图,分析是否包含二维码。核心代码:略优点:流程简单,可以快速实现。不足:无法实现保存UIWebView中图片,如果当前We

nginx配置系列-日志切割

nginx配置系列日志切割背景nginx日志中我们希望日志能够每天或者每小时自动切割,nginx本身没有提供自动切割的机制,但是我们可以通过脚本或者稍加改造让其具备这种能力。下面让我们看看怎么操作吧。日志切割常见做法有四种,在我们做之前我们来学习一下nginx日志中常用的内置变量字段都是什么意思nginx内置变量

FLV文件格式

1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.