使用 Loki 收集 nginx 日志
之前日志服務(wù)用的較多的一般是ELK,EFK,graylog等,但這些日志由java編寫,運(yùn)行需要jdk,而且配置上面,還是有點(diǎn)復(fù)雜,比如需要對(duì)日志需要寫grok將復(fù)雜的日志進(jìn)行匹配,好在后面出了可以根據(jù)分隔符的方式進(jìn)行日志的提取,也就是dissect插件,可以根據(jù)分隔符進(jìn)行分割。
ELK在日志方面給我的感覺是大而全,查詢匹配是杠杠的,Kibana圖表非常豐富。但如果面對(duì)大量的數(shù)據(jù),需要查詢,在不堆機(jī)器的情況下,還是會(huì)比較疲軟,查詢比較慢,之前公司每當(dāng)突發(fā)流量的時(shí)候,由于日志寫入比較大,隊(duì)列都在kafka,es消費(fèi)慢,導(dǎo)致無法實(shí)時(shí)出數(shù)據(jù)。
Loki 受到了 prometheus啟 發(fā),對(duì)日志進(jìn)行打標(biāo)簽的方式而非全文索引的方,而且也可以跟kubernetes集成。
Like Prometheus, but for logs!
1安裝Loki(使用Local方式)
安裝和運(yùn)行
https://github.com/grafana/loki/releases/
找到要安裝的版本,我采用的是v2.1.0
下載Loki和Promtail, (Loki為日志的引擎,通過Promtail來發(fā)送日志到Loki)
在本機(jī)找一個(gè)目錄存放這兩個(gè)2進(jìn)制文件
下載兩者的配置文件
wget https://raw.githubusercontent.com/grafana/loki/master/cmd/loki/loki-local-config.yaml
wget https://raw.githubusercontent.com/grafana/loki/master/cmd/promtail/promtail-local-config.yaml使用如下命令啟動(dòng)Loki
./loki-linux-amd64 -config.file=loki-local-config.yamlroot@test:~$cd /usr/local/loki/
root@test:/usr/local/loki$ls
loki-linux-amd64 loki-local-config.yaml promtail-linux-amd64 promtail-local-config.yaml
root@test:/usr/local/loki$./loki-linux-amd64 -config.file=loki-local-config.yaml
2嘗試搜集nginx日志
所以首先對(duì)nginx默認(rèn)的日志進(jìn)行改造,讓他以json的方式進(jìn)行輸出到目錄,然后用Promtail對(duì)其進(jìn)行讀取。 讀取使用LogQL的json方式去讀取,這個(gè)LogQL內(nèi)容填寫在grafana中。
nginx的部分配置改造
虛擬server配置
server {
server_name loki.test.com; # 域名設(shè)置
listen 8888;
access_log /var/log/nginx/loki_access.log promtail_json;
location / {
return 200 "It's ok!";
}
}
promtail_json日志格式配置
log_format promtail_json '{"@timestamp":"$time_iso8601",'
'"@version":"Promtail json",'
'"server_addr":"$server_addr",'
'"remote_addr":"$remote_addr",'
'"host":"$host",'
'"uri":"$uri",'
'"body_bytes_sent":$body_bytes_sent,'
'"bytes_sent":$body_bytes_sent,'
'"request":"$request",'
'"request_length":$request_length,'
'"request_time":$request_time,'
'"status":"$status",'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent"'
'}';
訪問127.0.0.1:8888,觀察日志已經(jīng)正常輸出為json格式,請(qǐng)保證該json格式正確。
root@test:/etc/nginx/conf.d$tail -f /var/log/nginx/loki_access.log
{"@timestamp":"2021-03-06T01:54:42-05:00","@version":"Promtail json","server_addr":"127.0.0.1","remote_addr":"192.168.65.130","host":"127.0.0.1","uri":"/","body_bytes_sent":8,"bytes_sent":8,"request":"GET / HTTP/1.1","request_length":78,"request_time":0.000,"status":"200","http_referer":"-","http_user_agent":"curl/7.29.0"}
nginx日志改造完畢
Promtail配置文件修改
因?yàn)樗鸭罩臼荘romtail處理,所以自然而然是需要根據(jù)自己需求來配置Promtail的配置文件。
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/loki-positions.yaml # 記錄pos點(diǎn)
sync_period: 5s # 5s一次將當(dāng)前讀取到的pos點(diǎn)同步至filename配置的文件內(nèi)
clients:
- url: http://localhost:3100/loki/api/v1/push
scrape_configs:
- job_name: Loki
static_configs:
- labels: # 設(shè)定的部分標(biāo)簽
job: Loki-nginx
host: localhost
app: nginx
__path__: /var/log/nginx/loki_access.log # 待讀取的nginx日志
LogQL json部分文檔理解
json的提取分為兩種方式,帶參數(shù)和不帶參數(shù)
不帶參數(shù)的方式
使用 |json來提取日志的json內(nèi)容,前提是json內(nèi)容為有效json格式。嵌套的字段會(huì)用”_”將內(nèi)外層的key進(jìn)行拼接。 忽略數(shù)組。
看一下官網(wǎng)中不帶參數(shù)方式的樣例
{
"protocol": "HTTP/2.0",
"servers": ["129.0.1.1","10.2.1.3"],
"request": {
"time": "6.032",
"method": "GET",
"host": "foo.grafana.net",
"size": "55",
"headers": {
"Accept": "*/*",
"User-Agent": "curl/7.68.0"
}
},
"response": {
"status": 401,
"size": "228",
"latency_seconds": "6.031"
}
}
被json解后,得到如下:
"protocol" => "HTTP/2.0"
"request_time" => "6.032"
"request_method" => "GET"
"request_host" => "foo.grafana.net"
"request_size" => "55"
"response_status" => "401"
"response_size" => "228"
"response_size" => "228"
從輸出能看到,原本request字段內(nèi)容為嵌套,所以request里面的內(nèi)容的key驗(yàn)證了如上第二點(diǎn),使用”_”進(jìn)行了拼接。同時(shí)servers由于是個(gè)數(shù)組,所以在解析后直接丟棄了servers這個(gè)key,驗(yàn)證了第三點(diǎn)。
帶參數(shù)的方式
帶參數(shù)的方式,json只會(huì)根據(jù)參數(shù)來解開需要的部分(當(dāng)單條json數(shù)據(jù)比較大的時(shí)候應(yīng)該能省很多資源)。 使用| json label=”expression”, another=”expression”的方式來編寫該方法。可以存在多個(gè)參數(shù)
看一下官網(wǎng)中帶參數(shù)方式的樣例
使用| json first_server=”servers[0]”, ua=”request.headers["User-Agent"]進(jìn)行提取
{
"protocol": "HTTP/2.0",
"servers": ["129.0.1.1","10.2.1.3"],
"request": {
"time": "6.032",
"method": "GET",
"host": "foo.grafana.net",
"size": "55",
"headers": {
"Accept": "*/*",
"User-Agent": "curl/7.68.0"
}
},
"response": {
"status": 401,
"size": "228",
"latency_seconds": "6.031"
}
}
輸出結(jié)果為:
"first_server" => "129.0.1.1"
"ua" => "curl/7.68.0"
first_server和ua都為原先參數(shù)中指定的key
如果要提取整個(gè)對(duì)象,可以使用| json server_list=”servers”, headers=”request.headers 這樣就能得到如下輸出:
"server_list" => `["129.0.1.1","10.2.1.3"]`
"headers" => `{"Accept": "*/*", "User-Agent": "curl/7.68.0"}`
嘗試寫一條LogQL表達(dá)式
一條完整的LogQL表達(dá)式由兩部分構(gòu)成:
a log stream selector,可以理解為,通過設(shè)定的label去匹配要抓取哪些日志。 a log pipeline,可以理解為表達(dá)式。比如json的提取。
比如如下表達(dá)式
{container="query-frontend",namespace="tempo-dev"} |= "metrics.go" | logfmt | duration > 10s and throughput_mb < 500
`{container=”query-frontend”,namespace=”tempo-dev”}`` 部分為log stream selector,后面部分為log pipeline。
編寫一個(gè)簡(jiǎn)單的nginx日志需求
Loki-nginx日志中狀態(tài)碼為200的條數(shù)。 根據(jù)當(dāng)前選定時(shí)間范圍,自動(dòng)調(diào)整。
思考:
如何指定Loki-nginx,可以使用log stream selector的表達(dá)式來選定。 nginx日志已經(jīng)轉(zhuǎn)變?yōu)榱薺son,所以可以用 |json來提取。如何獲取status字段的信息? |json后面直接跟隨|status即可,即 |json|status。如何根據(jù)當(dāng)前選定的時(shí)間范圍?使用內(nèi)置變量 [$\_\_interval]。條數(shù)該得用什么方法獲得?LogQL有內(nèi)置函數(shù) count_over_time配合sum,這邊需要注意的是count_over_time是根據(jù)指定時(shí)間范圍返回日志條目的具體內(nèi)容,所以還需要配合sum獲得時(shí)間段內(nèi)的總數(shù)。
編寫:
首先選定Loki-nginx的日志, {job="Loki-nginx"}。使用count_over_time函數(shù)配合 [$\_\_interval]來獲取總共的條數(shù)。count_over_time({job="Loki-nginx"}[$\_\_interval])過濾status字段,讓其等于200,表達(dá)式 count_over_time({job="Loki-nginx"} | json | status = 200 [$\_\_interval]),此時(shí)會(huì)報(bào)錯(cuò),因?yàn)閟tatus為字符串,可以添加__error__=””讓其忽略轉(zhuǎn)換出現(xiàn)的異常。得到count_over_time({job="Loki-nginx"} | json | status = 200 \_\_error\_\_="" [$\_\_interval])此時(shí)在grafana上顯示為多條數(shù)據(jù),配合sum得到單獨(dú)一個(gè)數(shù)值。 最終的表達(dá)式為: sum(count_over_time({job="Loki-nginx"} | json | status = 200 __error__="" [$__interval]))

原文鏈接:https://kirakirazone.com/2021/03/06/Loki%E6%97%A5%E5%BF%97%E6%9C%8D%E5%8A%A101/
