天天看點

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字段,表示每十分鐘執行一次。

繼續閱讀