天天看点

Nginx 日志配置、日志切割、日志切割脚本

文章目录

    • 前言
    • 一、access_log
      • 1、语法
      • 2、基本用法
      • 3、作用域
      • 4、log_format 自定义日志格式
    • 二、error_log
      • 1、语法
      • 2、基本用法
      • 3、作用域
      • 4、rewrite_log 指令
    • 三、Nginx变量
      • 1、简介
      • 2、自定义变量
        • (1)变量创建与赋值
        • (2)变量的可见性
        • (3)Perl的变量插值
        • (4)大括号插值
        • (5)变量创建,赋值及作用域问题
      • 3、内置预定义变量
        • (1)$uri vs $request_uri
        • (2) $arg_XXX
        • (3) $arg_XXX 不区分大小写
        • (4)对 uri 解码
    • 四、日志切割
      • 1、引言
      • 2、实现思路
      • 3、设计脚本
        • (1)脚本设计
        • (2)授权脚本
        • (3)定时任务
      • 4、crontab

前言

Nginx日志对于统计、系统服务排错很有用。Nginx日志主要分为两种:

access_log

:通过访问日志我们可以得到用户的IP地址、浏览器的信息,请求的处理时间等信息。

error_log

:错误日志记录了访问出错的信息,可以帮助我们定位错误的原因。

本文将详细描述一下如何配置Nginx日志。

一、access_log

访问日志主要记录客户端的请求。客户端向Nginx服务器发起的每一次请求都记录在这里。客户端IP,浏览器信息,referer,请求处理时间,请求URL等都可以在访问日志中得到。当然具体要记录哪些信息,你可以通过

log_format

指令定义。

1、语法

access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]]; 
# 设置访问日志

access_log off; 
# 关闭访问日志
           
  • path 指定日志的存放位置。
  • format 指定日志的格式。默认使用预定义的combined。
  • buffer 用来指定日志写入时的缓存大小。默认是64k。
  • gzip 日志写入前先进行压缩。压缩率可以指定,从1到9数值越大压缩比越高,同时压缩的速度也越慢。默认是1。
  • flush 设置缓存的有效时间。如果超过flush指定的时间,缓存中的内容将被清空。
  • if 条件判断。如果指定的条件计算为0或空字符串,那么该请求不会写入日志。
  • 另外,还有一个特殊的值off。如果指定了该值,当前作用域下的所有的请求日志都被关闭。

2、基本用法

该例子指定日志的写入路径为

/var/logs/nginx-access.log

,日志格式使用默认的

combined

access_log /var/logs/nginx-access.log buffer=32k gzip flush=1m
           

该例子指定日志的写入路径为/var/logs/nginx-access.log,日志格式使用默认的combined,指定日志的缓存大小为32k,日志写入前启用gzip进行压缩,压缩比使用默认值1,缓存数据有效时间为1分钟。

3、作用域

可以应用access_log指令的作用域分别有

http

server

location

以上是access_log指令的基本语法和参数的含义。下面我们看一几个例子加深一下理解。

4、log_format 自定义日志格式

Nginx预定义了名为

combined

日志格式,如果没有明确指定日志格式默认使用该格式:

access_log logs/access.log combined;
# “combined”日志格式:
log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';
           

如果不想使用Nginx预定义的格式,可以通过

log_format

指令来自定义。

语法

  • name 格式名称。在access_log指令中引用。
  • escape 设置变量中的字符编码方式是json还是default,默认是default。
  • string 要定义的日志格式内容。该参数可以有多个。参数中可以使用Nginx变量。

下面是log_format指令中常用的一些变量:

Nginx 日志配置、日志切割、日志切割脚本

二、error_log

错误日志在Nginx中是通过

error_log

指令实现的。该指令记录服务器和请求处理过程中的错误信息。

1、语法

配置错误日志文件的路径和日志级别。

error_log file [level];

默认:
error_log  logs/error.log  error;
           
  • 第一个参数指定日志的写入位置。
  • 第二个参数指定日志的级别。level可以是

    debug

    ,

    info

    ,

    notice

    ,

    warn

    ,

    error

    ,

    crit

    ,

    alert

    ,

    emerg

    中的任意值。可以看到其取值范围是按紧急程度从低到高排列的。只有日志的错误级别等于或高于level指定的值才会写入错误日志中。默认值是error。
  • 生产场景一般是

    warn

    |

    error

    |

    crit

    这三个级别之一

2、基本用法

例子中指定了错误日志的路径为:/var/logs/nginx/nginx-error.log,日志级别使用默认的error。

3、作用域

它可以配置在:

main

http

,

mail

,

stream

,

server

,

location

作用域。

4、rewrite_log 指令

ngx_http_rewrite_module

模块提供的。用来记录重写日志的。对于调试重写规则建议开启,启用时将在

error log

中记录重写日志。

基本语法:

rewrite_log on | off;
默认值: 
rewrite_log off;
           

配置段 :

作用于

http

,

server

,

location

,

if

作用域。

三、Nginx变量

内置预定义变量即无需声明就可以使用的变量,通常包括一个http请求或响应中一部分内容的值,以下为一些常用的内置预定义变量

变量名 定义
$arg_PARAMETER GET请求中变量名PARAMETER参数的值。
$args 这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;这个变量只可以被修改
$binary_remote_addr 二进制码形式的客户端地址。
$body_bytes_sent 传送页面的字节数
$content_length 请求头中的Content-length字段。
$content_type 请求头中的Content-Type字段。
$cookie_COOKIE cookie COOKIE的值。
$document_root 当前请求在root指令中指定的值。
$document_uri 与$uri相同。
$host 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。
$hostname 机器名使用 gethostname系统调用的值
$http_HEADER HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值);
$sent_http_HEADER HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control, $sent_http_content_type…;
$is_args 如果$args设置,值为"?",否则为""。
$limit_rate 这个变量可以限制连接速率。
$nginx_version 当前运行的nginx版本号。
$query_string 与$args相同。
$remote_addr 客户端的IP地址。
$remote_port 客户端的端口。
$remote_user 已经经过Auth Basic Module验证的用户名。
$request_filename 当前连接请求的文件路径,由root或alias指令与URI请求生成。
$request_body 这个变量(0.7.58+)包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义。
$request_body_file 客户端请求主体信息的临时文件名。
$request_completion 如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空。
$request_method 这个变量是客户端请求的动作,通常为GET或POST。包括0.8.20及之前的版本中,这个变量总为main request中的动作,如果当前请求是一个子请求,并不使用这个当前请求的动作。
$request_uri 这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI。
$scheme 所用的协议,比如http或者是https,比如rewrite ^(.+)$ $scheme://example.com$1 redirect;
$server_addr 服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。
$server_name 服务器名称。
$server_port 请求到达服务器的端口号。
$server_protocol 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$uri 请求中的当前URI(不带请求参数,参数位于args,不同于浏览器传递的args),不同于浏览器传递的request_uri的值,它可以通过内部重定向,或者使用index指令进行修改。不包括协议和主机名,例如/foo/bar.html

1、简介

所有的 Nginx变量在 Nginx 配置文件中引用时都须带上 $ 前缀

在 Nginx 配置中,变量只能存放一种类型的值,有且也只存在一种类型,那就是字符串类型

nginx可以使用变量简化配置与提高配置的灵活性,所有的变量值都可以通过这种方式引用:

$变量名
           

nginx中的变量分为两种,自定义变量与内置预定义变量

2、自定义变量

(1)变量创建与赋值

可以在

sever

,

http

,

location

等标签中使用set命令(非唯一)声明变量,语法如下

set $变量名 变量值
           
  • nginx 中的变量必须都以$开头
  • nginx 的配置文件中所有使用的变量都必须是声明过的,否则 nginx 会无法启动并打印相关异常日志

(2)变量的可见性

在不同层级的标签中声明的变量性的可见性规则如下:

  • location标签中声明的变量中对这个location块可见
  • server标签中声明的变量对server块以及server块中的所有子块可见
  • http标签中声明的变量对http块以及http块中的所有子块可见

(3)Perl的变量插值

这里使用变量方法,直接写在双引号内,perl将检查引号内的每个字符,看看是否有特殊定义, 然后将它替换为其内容,这叫做变量插值

set $hello "hello world";
print "this is $hello.";
           
  • 写在单引号内会则是原文不会改变
  • 当然有些语法中不加算引号,直接写内容也是可以的

(4)大括号插值

在“变量插值”的上下文中,还有一种特殊情况,即当引用的变量名之后紧跟着变量名的构成字符时(比如后跟字母、数字以及下划线),我们就需要使用特别的记法来消除歧义。

set $hello "hello";
print "this is ${hello}World .";
           

(5)变量创建,赋值及作用域问题

变量的创建和赋值操作发生在全然不同的时间阶段。这意味着不创建而直接使用变量会导致启动失败,同时也意味着我们无法在请求处理时动态地创建新的 Nginx 变量。
  • Nginx 变量的创建只能发生在 Nginx 配置加载的时候,或者说 Nginx 启动的时候;
  • 赋值操作则只会发生在请求实际处理的时候。

两大特性:

  • Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块
  • Nginx变量名的可见范围虽然是整个配置,但每个请求都有所有变量的独立副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰。

例子:

server {
        listen 80;
        server_name     localhost;
        location /foo {
                echo "foo = [$foo]";
        }
        location /bar {
                set $foo 32;
                echo "foo = [$foo]";
        }
}
           

输出

[[email protected] conf.d]# curl 'http://localhost/foo'
foo = []
[[email protected] conf.d]# curl 'http://localhost/bar'
foo = [32]
           

从这个例子中,前面我们请求了

/bar

接口后,

foo

变量被赋予了值 32,但它丝毫不会影响后续对

/foo

接口的请求所对应的

foo

值(它仍然是空的!),因为各个请求都有自己独立的

$foo

变量的副本。

3、内置预定义变量

(1)$uri vs $request_uri

ngx_http_core

模块提供的内建变量

$uri

,可以用来获取当前请求的 URI(经过解码,并且不含请求参数),而

$request_uri

则用来获取请求最原始的

URI

(未经解码,并且包含请求参数)。

$sent_trailer_NAME

$sent_trailer_name可以用来获取任意http响应字段;变量名中的后半部分NAME可以替换成任意响应字段

location /test-uri {
    echo "uri = $uri";
    echo "request_uri = $request_uri";
}
           

输出

[[email protected] html]# nginx -s reload
[[email protected] html]# curl localhost/test-uri
uri = /test-uri
request_uri = /test-uri
 
[[email protected] html]# curl "localhost/test-uri?a=3&b=4"
uri = /test-uri
request_uri = /test-uri?a=3&b=4
           

(2) $arg_XXX

另一个特别常用的内建变量其实并不是单独一个变量,而是有无限多变种的一群变量,即名字以 arg_ 开头的所有变量,我们估且称之为 $arg_XXX 变量群。

一个例子是 $arg_name,这个变量的值是当前请求中名为 name 的参数的值,而且还是未解码的原始形式的值。

location /test-arg {
    echo "name: $arg_name";
    echo "class: $arg_class";
}
           

输出

[[email protected] html]# nginx -s reload
[[email protected] html]# curl localhost/test-arg
name: 
class:
 
[[email protected] html]# curl "localhost/test-arg?name=Tom&class=3"
name: Tom
class: 3
 
[[email protected] html]# curl "localhost/test-arg?name=hello%20world&class=9"
name: hello%20world
class: 9
           

(3) $arg_XXX 不区分大小写

其实

$arg_name

不仅可以匹配

name

参数,也可以匹配 NAME 参数,抑或是 Name,Nginx 会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写的形式。

[[email protected] html]# curl "localhost/test-arg?NAME=Marry"
name: Marry
class:
 
[[email protected] html]# curl "localhost/test-arg?Name=Jimmy"
name: Jimmy
class:
           

(4)对 uri 解码

如果你想对 URI 参数值中的 %XX 这样的编码序列进行解码,可以使用第三方

ngx_set_misce

模块提供的

location /test-unescape-uri {
    set_unescape_uri $name $arg_name;
    set_unescape_uri $class $arg_class;
    echo "name: $name";
    echo "class: $class";
}
           

现在我们再看一下效果:

[[email protected] html]# curl "localhost/test-arg?name=hello%20world&class=9"
name: hello world
class: 9
           

从这个例子我们同时可以看到,这个

set_unescape_uri

指令也像 set 指令那样,拥有自动创建 Nginx 变量的功能。

$arg_XXX

这种类型的变量拥有无穷无尽种可能的名字,所以它们并不对应任何存放值的容器。

类 似

$arg_XXX

的内建变量还有不少,比如

  • $arg_XXX

    :可以用来获取GET请求中NAME参数的值
  • $cookie_XXX

    :可以匹配任意cookie中的变量
  • $http_XXX

    :可以用来获取任意请求头字段
  • $sent_http_XXX

    :可以用来获取任意http响应头字段

四、日志切割

1、引言

在生产环境中每一天的日志文件都是要打包备份的,如果每天都手动的去截取日志,重命名这样就很不方便,所以我们编写一个脚本并建立一个定时任务来进行这些工作。

nginx日志切割的2种情况

  • rpm安装:日志切割自动配置完成。
  • 源码包安装:手动的通过脚本计划任务的方式实现日志切割。

2、实现思路

shell脚本+定时任务+nginx信号控制,完成日志定时切割

3、设计脚本

第一步、重命名日志文件,不用担心重命名后nginx找不到日志文件而丢失日志。在你未重新打开原名字的日志文件前,nginx还是会向你重命名的文件写日志,Linux是靠文件描述符而不是文件名定位文件。

第二步、向nginx主进程发送USR1信号。nginx主进程接到信号后会从配置文件中读取日志文件名称,重新打开日志文件(以配置文件中的日志名称命名),并以工作进程的用户作为日志文件的所有者。重新打开日志文件后,nginx主进程会关闭重名的日志文件并通知工作进程使用新打开的日志文件。工作进程立刻打开新的日志文件并关闭重名名的日志文件。然后你就可以处理旧的日志文件了。[或者重启nginx服务]。

(1)脚本设计

  • 按天
#!/bin/bash

# 指定日志和切割后日志备份的目录
YEAR=$(date +%Y)
MONTH=$(date +%m)
DAY=$(date +%d)
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
LOGS_PATH=/data/docker/saber/logs    #安装目录下日志文件
LOGS_BAK_PATH=/data/docker/saber/logs-bak  #需要保存的目录位置

# 得到1级目录名
if [[ $(($DAY)) -eq 1 ]]
  then
    if [[ $(($MONTH)) -eq 1 ]]
      then
        LOGS_BAK_PATH=$LOGS_BAK_PATH/$((${YEAR}-1))-12
    else
      if [[ $(($MONTH)) -gt 10 ]]
        then
          LOGS_BAK_PATH=$LOGS_BAK_PATH/${YEAR}-$((${MONTH}-1))
      else
          LOGS_BAK_PATH=$LOGS_BAK_PATH/${YEAR}-0$((${MONTH}-1))
      fi
    fi
else
    LOGS_BAK_PATH=$LOGS_BAK_PATH/${YEAR}-${MONTH}
fi

# 创建目录
mkdir -p $LOGS_BAK_PATH/${YESTERDAY}

# 复制当前的日志文件到备份的目录
mv ${LOGS_PATH}/access.log ${LOGS_BAK_PATH}/${YESTERDAY}/access_${YESTERDAY}.log
#cp ${LOGS_PATH}/admin_access.log ${LOGS_BAK_PATH}/${YESTERDAY}/admin_access_${YESTERDAY}.log
mv ${LOGS_PATH}/error.log ${LOGS_BAK_PATH}/${YESTERDAY}/error_${YESTERDAY}.log

kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
           

注:

USR1

亦通常被用来告知应用程序重载配置文件,

kill -USR1 pid

等同于重启这个服务,所以也可以用

systemctl reload nginx

代替。

  • 按小时
#!/bin/bash
# Every hour running time.
# by bobliu.
 
# The Nginx logs path
log_year=$(date +"%Y")
log_month=$(date +"%m")
log_day=$(date +"%d")
log_hour=$(date +"%H")
log_min=$(date +"%M")
logs_path="/usr/local/nginx/logs/"
save_path="/usr/local/nginx/logs/log"
 
if [ ! -d "$save_path" ]; then
mkdir -p "$save_path"
fi
 
mv ${logs_path}access.log ${save_path}access_${log_year}${log_month}${log_day}_${log_hour}_${log_min}.log
 
if [ $log_hour = 00 ]; then
mv ${logs_path}error.log ${save_path}error_$log_year$log_month$log_day.log
fi
 
kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
           

(2)授权脚本

脚本放好后,接下来就可以创建一个计划任务来执行这个脚本,首先给这个脚本授予可执行权限:

chmod +x  nginx_logs.sh
           

(3)定时任务

crontab -e

创建任务,添加一行任务

0 0 * * *  sh  /var/log/nginx/nginx_logs.sh
           

注:表示每天的0点0分把nginx日志重命名为日期格式,并重新生成今天的新日志文件。

4、crontab

用法

$ crontab -e 创建任务
$ crontab -l 查看任务
$ crontab -r 删除任务
           

格式

*     *     *    *      *       command
 
minute hour  day  month  week     command
分     时    天    月     星期     命令
           
  • minute: 表示分钟,可以是从0到59之间的任何整数。
  • hour:表示小时,可以是从0到23之间的任何整数。
  • day:表示日期,可以是从1到31之间的任何整数。
  • month:表示月份,可以是从1到12之间的任何整数。
  • week:表示星期几,可以是从0到7之间的任何整数,这里的0或7代表星期日。
  • command:要执行的命令,可以是系统命令,也可以是自己编写的脚本文件。

特殊字符:

  • 星号(*):代表所有可能的值,例如month字段如果是星号,则表示在满足其它字段的制约条件后每月都执行该命令操作。
  • 逗号(,):可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”。
  • 中杠(-):可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”。
  • 正斜线(/):可以用正斜线指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次。

继续阅读