Nginx map 實(shí)現(xiàn)時(shí)間格式轉(zhuǎn)換
哈嘍大家好,我是咸魚
最近我們需要把 Nginx 的日志接入到自研的日志采集平臺(tái)上,但是這個(gè)平臺(tái)只支持 JSON 格式,所以需要把 Nginx 日志格式改成 JSON 格式
例如下面這樣的效果
剛開始在主配置文件 nginx.conf 中定義了一個(gè)名叫 json 的日志格式字段
驗(yàn)證的時(shí)候其他內(nèi)容沒啥問題,但是時(shí)間是2023-09-12T13:54:22+08:00 這樣子的,不太符合預(yù)期
咸魚想著把 $time_iso8601 變量中的年月日時(shí)分秒分別提取出來然后用變量去接受它,如下所示:
我自定義了一個(gè)時(shí)間格式 $year-$month-$day $hour:$minutes:$seconds:000,然后接著用了一個(gè) if 語句用于檢查請(qǐng)求的時(shí)間是否匹配 ISO8601 時(shí)間格式(例如:2023-09-12T13:54:22+08:00)
如果匹配,它將執(zhí)行其中的代碼塊。在代碼塊中,使用正則表達(dá)式提取時(shí)間的年、月、日、小時(shí)、分鐘和秒,并將它們賦值給變量 $year、$month、$day、$hour、$minutes 和 $seconds
但是 nginx -t 檢測(cè)的時(shí)候我發(fā)現(xiàn) if 語句不能夠放在 http 塊內(nèi),否則會(huì)報(bào)錯(cuò)
在 Nginx 中,if 語句主要用于在 server 或 location 塊內(nèi)設(shè)置條件,以便根據(jù)請(qǐng)求的屬性來執(zhí)行不同的配置。if 語句通常應(yīng)該包含在 server 或 location 塊內(nèi),而不是直接放在 http 塊中
如果將 if 語句放在一個(gè)一個(gè) server 塊中,這不得累死我(有很多個(gè) server 塊),而且后期維護(hù)也不方便
所以如何將自定義變量在全局配置中生效則成為了一個(gè)問題
map
map 指令是由 ngx_http_map_module 模塊提供的,是 Nginx 配置文件中的一種用于創(chuàng)建變量映射的指令
模塊鏈接:https://nginx.org/en/docs/http/ngx_http_map_module.html
它允許我們將一個(gè)或多個(gè)輸入值映射到一個(gè)輸出值,類似于字典或哈希表的概念。map 指令通常用于根據(jù)特定條件為請(qǐng)求設(shè)置自定義變量,或者執(zhí)行基于請(qǐng)求屬性的條件控制
比較常見的 map 用法是通過 map 來實(shí)現(xiàn)允許多個(gè)域名跨域訪問的問題
語法如下:
其中:
- $variable 輸入變量,通常是 nginx 的內(nèi)置變量。
- $new_variable 輸出變量,它將根據(jù)輸入值的映射設(shè)置為特定的結(jié)果。
- value1, value2, ... 輸入值,可以列出多個(gè)值。
- result1, result2, ... 與相應(yīng)輸入值相關(guān)聯(lián)的輸出結(jié)果。
- default 一個(gè)可選項(xiàng),表示如果沒有匹配的輸入值,將使用默認(rèn)結(jié)果
需要注意的是,map 只能放在 http 塊中
有了 map,我們就可以輕易的把 $time_iso8601 變量中的 ISO 8601 格式的時(shí)間戳轉(zhuǎn)換為指定的時(shí)間格式,然后存儲(chǔ)到自定義變量 $log_time 中
我們可以看到:
- 輸入變量為 $time_iso8601,輸出變量為 $log_time;
- default "":如果沒有匹配任何條件,將使用空字符串作為 $log_time 的值
- "~^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})T(?<hour>\d{2}):(?<minutes>\d{2}):(?<seconds>\d{2})":這是一個(gè)正則表達(dá)式條件,它用于匹配 ISO 8601 格式的時(shí)間戳。該正則表達(dá)式包含了多個(gè)捕獲組(使用 ?<name> 語法),用于從時(shí)間戳中提取年、月、日、小時(shí)、分鐘和秒的值
- "${year}-${month}-${day} ${hour}:${minutes}:${seconds}":這是與正則表達(dá)式條件匹配時(shí)設(shè)置的輸出值。當(dāng)正則表達(dá)式條件匹配時(shí),它會(huì)將捕獲組中提取的年、月、日、小時(shí)、分鐘和秒的值組合成一個(gè)自定義的時(shí)間格式,然后將該值設(shè)置為 $log_time 變量的值
例如,如果 $time_iso8601 的值是 "2023-09-09T14:30:00",則 $log_time 將被設(shè)置為 "2023-09-09 14:30:00"
然后我們?cè)侔?$log_time 放進(jìn)我們自定義的日志格式里面,完整配置如下
最后我們驗(yàn)證一下