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

2023-11-03

前言

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、基本用法

access_log /var/logs/nginx-access.log combined;

该例子指定日志的写入路径为/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指令的作用域分别有httpserverlocation

以上是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指令来自定义。

语法

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

下面是log_format指令中常用的一些变量:
在这里插入图片描述

二、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、基本用法

error_log /var/logs/nginx/nginx-error.log error;

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

3、作用域

它可以配置在:mainhttp , 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]";
        }
}

输出

[root@192 conf.d]# curl 'http://localhost/foo'
foo = []
[root@192 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";
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-uri
uri = /test-uri
request_uri = /test-uri
 
[root@localhost 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";
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-arg
name: 
class:
 
[root@localhost html]# curl "localhost/test-arg?name=Tom&class=3"
name: Tom
class: 3
 
[root@localhost html]# curl "localhost/test-arg?name=hello%20world&class=9"
name: hello%20world
class: 9
(3) $arg_XXX 不区分大小写

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

[root@localhost html]# curl "localhost/test-arg?NAME=Marry"
name: Marry
class:
 
[root@localhost 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";
}

现在我们再看一下效果:

[root@localhost 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字段,表示每十分钟执行一次。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Nginx 日志配置、日志切割、日志切割脚本 的相关文章

随机推荐

  • Win10系统安装TensorRT

    一 Win10系统安装GPU版本CUDA Cudnn 二 Win10系统安装TensorRT 文章目录 环境搭建系列文章目录 TensorRT简介 一 版本对应关系 二 下载及安装 1 TensorRT 2 No module named
  • NodeJS + mysql 返回数据

    mysqlQuery js var mysql require mysql var connection mysql createConnection host localhost user root password port 3306
  • 【保姆级教程】手把手教你用github制作学术个人主页(学者必备)

    很多朋友到了本科生或者研究生或者博士生的高年级 有了制作个人主页的需求 今天这一期博客将以academicpages模板为例 手把手教你快速制作一个简洁能用的个人主页 1 首先你需要拥有一个github账号 2 然后我们来找模板 比如你可以
  • eclipse ide使用_开始使用Eclipse Che IDE在云端进行开发

    eclipse ide使用 在我职业生涯中经历的许多技术面试中 我注意到很少有人问到具有确定答案的问题 大多数情况下 我会被问到开放式问题 这些问题没有绝对正确的答案 但会评估我以前的经验以及我能很好地解释事情的能力 我多次被问到的一个有趣
  • kafka初探 版本0.10 java编程

    之前一直有项目用到 不过我并不负责这一块 所以了解不多 这次趁机会学习下 之前对kafka的了解其实仅限于知道它是一个分布式消息系统 这次详细了解了下 知道了一些关键概念 topic主题 broker服务 producers消息发布者 co
  • 类中数组成员变量怎么初始化,数组名与指针的区别

    使用STL标准模板库之后 编程时已经很少使用数组和指针 相反 多使用序列容器vector代替之 std vector
  • datetime.dt.day以及to_datetime函数讲解(Python时序量汇总)

    之前在别的博客记过pandas处理时间量的笔记 但是时间一长又忘了 所以决定另外写一篇记录下时序量的处理 1 关于pandas的to datetime函数的理解 参考 https blog csdn net qq 36523839 arti
  • MATLAB——数据及其运算

    MATLAB数值数据 数值数据类型的分类 1 整型 整型数据是不带小数的数 有带符号整数和无符号整数之分 表中列出了各种整型数据的取值范围和对应的转换函数 2 浮点型 浮点型数据有单精度 single 和双精度 double 之分 单精度型
  • 95-30-015-Channel-AbstractNioMessageChannel

    文章目录 1 概述 2 类图 2 1 继承关系 2 2 类图简介 3 内部类NioMessageUnsafe 3 1 read事件框架 1 概述 AbstractNioMessageChannel是底层数据为消息的NioChannel 在N
  • 动态规划入门之国王的金矿

    最近学习算法 对动态规划不太了解 使用的时候照搬转移方程式 知其然不知其所以然 今天看到一篇动态规划的教程 解释得非常通俗 原文在这里 动态规划入门教程 http blog csdn net woshioosm article detail
  • 并发编程--------JUC集合

    并发集合 一 ConcurrentHashMap 1 1 存储结构 ConcurrentHashMap是线程安全的HashMap ConcurrentHashMap在JDK1 8中是以CAS synchronized实现的线程安全 CAS
  • 不会“卷”,就会被淘汰?3招教你打破职场内卷焦虑

    内卷 这个词对大家来说都已经不新鲜了 时不时就会听到 人人皆在卷 万物皆可卷 从未出生那一刻的胎教到出生后的早教 从幼儿园开始的择校 一路 卷 到大学的名号 绩点 而职场内卷 是大家最熟悉的 战场 职场内卷是指在职场竞争中 为了争夺有限的资
  • 【目标检测】---- 正负样本匹配策略

    1 综述 无论是anchor box 还是anchor free 在训练计算类别 前背景损失时都需用到正负样本匹配 目前分为两大类 第一类 fixed label assignment 常用的主要有MaxIou ATSS focos 第二类
  • Docker loop volume VS direct LVM 选型和分析

    测试准备 测试目的 Docker在DeviceMapper这块支持两种存储模式 分别是docker默认的loop volume和Direct VLM 为了了解其中区别也是为了依据业务进行选型 所以选择了对二者进行性能测试 测试范围 性能指标
  • React 引入antd后启动项目时出现的警告信息

    Compiled with warnings Failed to parse source map webpack antd components config provider style index less URL is not su
  • windows不安装虚拟机如何使用Linux系统作为开发工具?

    哈喽 大家好 我是仲一 作为嵌入式开发程序员 常常需要在Linux环境下编译一些代码 安装虚拟机比较方便 但是 太占用内存了 性能不好的电脑开了一台虚拟机后 可能就干不了其他事情了 安装双系统也比较麻烦 常常需要重启电脑来完成系统的切换 今
  • RHCE第四次作业

    1 判新当前磁盘剩余空间是否有20G 如果小于20G 则将报警邮件发送给管理员 每天检查一次磁盘剩余空间 2 判web服务是否运行 1 查看进程的方式判断该程序是否运行 2 通过查看端口的方式判断该程序是否运行 如果没有运行 则启动该服务并
  • Leetcode刷题c++之575. 分糖果

    题目描述 定一个偶数长度的数组 其中不同的数字代表着不同种类的糖果 每一个数字代表一个糖果 你需要把这些糖果平均分给一个弟弟和一个妹妹 返回妹妹可以获得的最大糖果的种类数 示例 输入 candies 1 1 2 2 3 3 输出 3 解析
  • Python与Excel交互与处理

    一 Python与Excel交互的背景及意义 Excel是很多公司和个人在数据分析和处理中使用的工具 其可以通过公式和条件格式等功能 实现简单的数据分析和处理 但是对于复杂的数据分析和处理来说 Excel的局限性就很大 难以满足需求 而Py
  • Nginx 日志配置、日志切割、日志切割脚本

    文章目录 前言 一 access log 1 语法 2 基本用法 3 作用域 4 log format 自定义日志格式 二 error log 1 语法 2 基本用法 3 作用域 4 rewrite log 指令 三 Nginx变量 1 简