天天看點

Nginx日志加工分析

資料加工服務簡介

資料加工服務是阿裡雲SLS推出的面向日志ETL處理的服務,主要解決資料加工過程中轉換、過濾、分發、富化等場景。

Nginx日志加工分析

接下來,我們以nginx日志解析為例, 幫助大家快速入門阿裡雲日志服務的資料加工。

用于實驗的Nginx日志

假設我們通過極簡模式采集了Nginx預設日志。預設的nginx 日志format如下

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';           

通過使用極簡模式采集Nginx日志,樣例如下:

Nginx日志加工分析

資料加工互動界面

點選 準備資料加工的Logstore,在查詢欄的上方,有一個“資料加工”的開關,打開

Nginx日志加工分析

資料加工的代碼編輯、預覽、釋出相關界面如下圖:

Nginx日志加工分析

一般情況下,我們都可以使用快速預覽模式,如果我們的資料加工涉及到使用mysql、oss等維表,可以使用進階預覽做實際預覽測試。

對Nginx日志進行資料加工 (Step by Step)

Step1. 使用正則抽取基礎字段

對于極簡模式采集的日志,内容都在一個字段叫content的字段裡,不利于我們做分析。可以通過資料加工正則函數,抽取nginx日志裡的字段,使用到的加工函數如下:

# 用于将源字段裡的内容,通過正則捕獲組抽取出對應的字段
e_regex("源字段", "正則或有命名捕獲正則", "目标字段名或數組(可選)")           

針對Nginx日志,使用以下語句進行正則抽取

# 通用字段抽取
e_regex("content",'(?<remote_addr>[0-9:\.]*) - (?<remote_user>[a-zA-Z0-9\-_]*) \[(?<local_time>[a-zA-Z0-9\/ :\-\+]*)\] "(?<request>[^"]*)" (?<status>[0-9]*) (?<body_bytes_sent>[0-9\-]*) "(?<refer>[^"]*)" "(?<http_user_agent>[^"]*)"')           

通過正則抽取以後,可以看到日志的字段增加了refer、remote_addr、remote_user、request等字段。

Nginx日志加工分析

Step2. 處理時間字段

目前提取到的localtime不易讀,我們把它解析成易讀的格式,會用到的以下資料加工函數:

# 用于設定字段值
e_set("字段名", "固定值或表達式函數")

# 将時間字元串解析為日期時間對象
dt_strptime('值如v("字段名")', "格式化字元串")

# 将日期時間對象按照指定格式轉換為字元串
dt_strftime(日期時間表達式, "格式化字元串")           

實作思路,先通過 dt_strptime 将local_time的時間轉化為日期時間對象,然後再通過dt_strftime将日期時間對象轉化為标準的日期時間字元串。 針對Nginx local_time的轉化,使用如下資料加工語句:

e_set("local_time", dt_strftime(dt_strptime(v("local_time"),"%d/%b/%Y:%H:%M:%S %z"),"%Y-%m-%d %H:%M:%S"))           

實作效果如下:

Nginx日志加工分析

Step3. 解析request uri

可以看到request字段由 METHOD URI VERSION組成,我們希望對 requst字段進行抽取,擷取到請求的METHOD、URI以及VERSION,并且将請求URI中的請求的參數變成字段,友善後續進行查詢。可以用以下函數來做實作

# 使用正則将request uri抽取
e_regex("源字段名", "正則或有命名捕獲正則", "目标字段名或數組(可選)", mode="fill-auto")

# 進行urldecode
url_decoding('值如v("字段名")’)

# 設定字段值
e_set("字段名", "固定值或表達式函數", ..., mode="overwrite")

# 将request_uri中的key=value的組合抽取成字段 值的模式
e_kv("源字段正則或清單", sep="=", prefix="")           

實作語句

e_regex("request", "(?<request_method>[^\s]*) (?<request_uri>[^\s]*) (?<http_version>[^\s]*)")
e_set("request_uri", url_decoding(v("request_uri")))
e_kv("request_uri", prefix="uri_")           

實作效果

Nginx日志加工分析

Step4. http code狀态碼映射

每一個http狀态碼都代表了不同的含義,下面是一份http狀态碼的映射表, 我們可以通過e_table_map 函數來将狀态碼的資訊擴充到我們的日志字段中,友善後續做統計分析。

Nginx日志加工分析

涉及到的資料加工函數如下:

# 用來做字段富化,類似sql裡join的功能
e_table_map("表格如通過tab_parse_csv(...)解析得到的",
            "源字段清單或映射清單如[('f1', 'f1_new'), ('f2', 'f2_new')]", 
            "目标字段清單")

# 用來把csv檔案解析成table對象
tab_parse_csv(CSV文本資料, sep=',', quote='"')

# code的映射關系次元表是一個csv檔案,存在oss上,使用res_oss_file
res_oss_file(endpoint="OSS的endpoint", ak_id="OSS的AK_ID", 
             ak_key="OSS的AK_KEY", bucket="OSS的bucket", file="在OSS中存的檔案位址", 
             change_detect_interval="定時更新時間,預設為0")           

實際使用到的DSL語句如下

# http狀态碼映射
e_table_map(
      tab_parse_csv(
           res_oss_file(endpoint="oss-cn-shanghai.aliyuncs.com",
              ak_id='',ak_key='',
              bucket="etl-test", 
              file="http_code.csv", format='text')),
              [("status","code")],
              [("alias","http_code_alias"),
               ("description","http_code_desc"),
               ("category","http_code_category")])           

看一下映射後的效果

Nginx日志加工分析

Step5. 通過UserAgent判斷用戶端作業系統

我們想了解客戶用的是什麼os版本,可以通過user agent裡的字段用正則比對來判斷,用到dsl語句

# 取某個字段的值
v("字段名")

# 擷取ua相關資訊
ua_parse_all("帶useragent資訊的内容")

# 展開json字段, 因為ua_parse_all得到的是一個json對象,為了展開到一級字段使用e_json做展開
# 模式有 simple、full、parent、root 參考https://help.aliyun.com/document_detail/125488.html#section-o7x-7rl-2qh
e_json("源字段名", fmt="模式", sep="字段分隔符")

# 丢棄臨時産生的字段
e_drop_fields("字段1", "字段2")           

用到的dsl語句

# 通過User Agent解析獲得用戶端資訊
e_set("ua",ua_parse_all(v("http_user_agent")))
e_json("ua", fmt='full',sep='_')
e_drop_fields("ua",regex=False)           

加工效果

Nginx日志加工分析

Step6. 非200的日志投遞到指定logstore

可以使用e_output函數來做日志投遞,用regex_match做字段比對

# 條件判斷if
e_if("條件1如e_match(...)", "操作1如e_regex(...)", "條件2", "操作2", ....)

# 判斷是否相等
op_ne(v("字段名1"), v("字段名2"))

# output發送到目标名稱,目标名稱在資料加工儲存任務的時候配置對應的logstore資訊
e_output(name="指定的目标名稱")           

實際的dsl語句

# 分發非200的日志
e_if(op_ne(v("http_code_alias"),"2xx"), e_output(name="nginx-log-bad"))           

在預覽裡看到這個效果。(儲存加工的時候,需要設定好對應project、logstore的ak資訊)

Nginx日志加工分析

完整的DSL代碼以及上線流程

好了,通過一步一步的開發調試,現得到完整的DSL代碼如下

# 通用字段抽取
e_regex("content",'(?<remote_addr>[0-9:\.]*) - (?<remote_user>[a-zA-Z0-9\-_]*) \[(?<local_time>[a-zA-Z0-9\/ :\-]*)\] "(?<request>[^"]*)" (?<status>[0-9]*) (?<body_bytes_sent>[0-9\-]*) "(?<refer>[^"]*)" "(?<http_user_agent>[^"]*)"')

# 設定localttime
e_set("local_time", dt_strftime(dt_strptime(v("local_time"),"%d/%b/%Y:%H:%M:%S"),"%Y-%m-%d %H:%M:%S"))

# uri字段抽取
e_regex("request", "(?<request_method>[^\s]*) (?<request_uri>[^\s]*) (?<http_version>[^\s]*)")
e_set("request_uri", url_decoding(v("request_uri")))
e_kv("request_uri", prefix="uri_")

# http狀态碼映射
e_table_map(
      tab_parse_csv(
           res_oss_file(endpoint="oss-cn-shanghai.aliyuncs.com",
              ak_id='',ak_key='',
              bucket="etl-test", 
              file="http_code.csv", format='text')),
              [("status","code")],
              [("alias","http_code_alias"),
               ("description","http_code_desc"),
               ("category","http_code_category")])

# 通過User Agent解析獲得用戶端資訊
e_set("ua",ua_parse_all(v("http_user_agent")))
e_json("ua", fmt='full',sep='_')
e_drop_fields("ua",regex=False)

# 分發非200的日志
e_if(op_ne(v("http_code_alias"),"2xx"), e_coutput(name="nginx-log-bad"))           

在頁面送出代碼以後,儲存資料加工

配置目标logstore資訊,預設走完加工邏輯的日志都會發送到第一個目标logstore,我們在代碼裡指定了e_output到指定logstore,是以還需要第二個目标,并且目标的名字和e_output裡指定的目标名稱一緻。

Nginx日志加工分析

儲存完即完成上線,可以在資料處理-加工下看到該任務,點選進去可以看到加工延遲等資訊。

Nginx日志加工分析

Nginx日志查詢、可視化、報警

查詢

假設,我們想對nginx異常的日志進行查詢,以便做問題定位。我們可以針對需要查詢的字段開啟索引

Nginx日志加工分析

開啟索引可以使用“自動生成索引”來自動幫助生成字段索引清單(否則需要手工填寫字段)

Nginx日志加工分析

點選确定後,即完成索引配置。比如我們要查詢 uri_item_name參數值為“測試商品_89”的錯誤情況,可以使用這樣的query

* and uri_item_name : 測試商品_89           
Nginx日志加工分析

可視化

我們關心每個請求的http請求是否成功,對于異常狀态碼,想做相應的統計,以友善我們做問題發現。 可以使用如下query統計 nginx-log-bad(非2xx類請求的logstore)狀态碼分布

* | select http_code_alias,count(*) as c 
         from log where http_code_alias is not null 
             group by http_code_alias order by c           

使用餅圖做可視化

Nginx日志加工分析

點選,“添加到儀表盤”,即可完成儀表盤的建立

Nginx日志加工分析

添加完成後,在左側儀表盤就

Nginx日志加工分析

報警

針對非2xx的狀态碼,我們不僅要做可視化,還需要對它進行報警。 可以在剛才建立的儀表盤裡,點選“告警->建立”,根據提示建立相應的告警規則。

Nginx日志加工分析
Nginx日志加工分析
Nginx日志加工分析

總結

本次訓練營,以最常見的Nginx日志作為例,介紹資料加工在日志的轉化、處理、富化、轉發等場景下相關的算子使用,幫助大家入門SLS的資料加工。除了文中提到的算子,資料加工還有200+的算子以支援更多的日志處理的場景,相關内容可以參考如下:

a) SLS資料加工整體簡介:

https://help.aliyun.com/document_detail/125384.html

b) SLS資料加工函數總覽:

https://help.aliyun.com/document_detail/159702.html

在資料加工之後,針對相關字段建立索引,可以友善地對日志内容進行各種場景的分析,并且針對有需要的場景設定對應的報警,提升系統的穩定性。

繼續閱讀