?本文討論使用日志作為數(shù)據(jù)源生成 Prometheus 指標(biāo)。如果現(xiàn)有 exporters 提供的指標(biāo)無法滿足需求,或者 exporter 因授權(quán)原因無法對外公開,則可以參考本文提供的方式。
寫本文的原因是,我們的一位客戶希望能夠及時獲取有關(guān)從應(yīng)用程序到 PostgreSQL v14 數(shù)據(jù)庫的失敗查詢的信息。同時,我們必須在不對應(yīng)用程序代碼進(jìn)行任何更改的情況下實(shí)現(xiàn)此監(jiān)控。在查看現(xiàn)有的 PostgreSQL exporter后,我們未能找到任何能夠發(fā)送錯誤報告的合適指標(biāo),因此我們決定自己新建一個。
1.準(zhǔn)備日志以供進(jìn)一步使用
從技術(shù)角度來看,步驟大致為:解析日志文件、從數(shù)據(jù)中提取指標(biāo)、將其輸出到 Prometheus 以及設(shè)置告警。早期的 PostgreSQL 版本(15 版本之前)不支持 JSON 結(jié)構(gòu)化日志格式。在生產(chǎn)環(huán)境中安裝第三方模塊并不推薦,我們也與推薦以 CSV 格式存儲日志數(shù)據(jù)。但是,我們能夠根據(jù)需要使用配置文件來格式化輸出。我們的客戶使用了以下日志格式:
postgresql.conf log_line_prefix = '%m %p %u@%d from %h [vxid:%v txid:%x] [%i] '`描述如下:
- %m是一個時間戳,包括毫秒;
- %p– 進(jìn)程號;
- %u- 用戶名;
- %d- 數(shù)據(jù)庫名稱。
有關(guān)其他變量的用途以及可以寫入日志的其他信息的更多信息,請參閱 PostgreSQL 文檔
(https://www.postgresql.org/docs/14/runtime-config-logging.html)。
結(jié)果如下:
2022-05-12 07:33:54.285 UTC 2672031 @ from [vxid: txid:0] [] LOG: checkpoint complete: wrote 64 buffers (0.0%); 0 WAL file(s) added, 0 removed, 10 recycled; write=6.266
s, sync=0.004 s, total=6.285 s; sync files=10, lnotallow=0.003 s, average=0.001 s; distance=163840 kB, estimate=163844 kB
2.尋找最佳解決方案
我們嘗試了 fluentd (https://docs.fluentd.org/?) 、 Promtail (https://grafana.com/docs/loki/latest/clients/promtail/?) 和 exporter (https://vector.dev/docs/) 從日志中檢索指標(biāo)并將它們發(fā)送到 Prometheus。
Fluentd 有一個廣泛的插件系統(tǒng)來適應(yīng)所有用例。例如, fluent-plugin-prometheus (https://github.com/fluent/fluent-plugin-prometheus) 將數(shù)據(jù)轉(zhuǎn)換為指標(biāo)格式并將其交付給 Prometheus。然而,自從發(fā)布 v2.0.0 以來,該項(xiàng)目發(fā)展緩慢。出于這個原因,我們這次決定換一種方式——盡管我們真的很喜歡 fluentd 并且經(jīng)常使用它。
我們嘗試的第一個工具是 Promtail。它具有解析文本日志(包括多行日志)、基于任務(wù)處理它們(包括提取指標(biāo))以及基于指定參數(shù)過濾內(nèi)容的能力。
為了進(jìn)行測試,我們創(chuàng)建了一個配置文件來計算日志行數(shù)。
這是日志處理階段的示例:
pipeline_stages:
- multiline:
firstline: '^\[\d{4}-\d{2}-\d{2} \d{1,2}:\d{2}:\d{2}\]'
- regex:
expression: '^(?P\[\d{4}-\d{2}-\d{2} \d{1,2}:\d{2}:\d{2}\]) (?P(?s:.*))$'
- metrics:
log_lines_total:
type: Counter
description: "total number of log lines"
prefix: pg_custom_
max_idle_duration: 24h
config:
match_all: true
action: inc
log_bytes_total:
type: Counter
description: "total bytes of log lines"
prefix: pg_custom_
max_idle_duration: 24h
config:
match_all: true
count_entry_bytes: true
action: add
配置工作正常;然而,我們錯過了一個關(guān)鍵點(diǎn)。Promtail需要Loki(Grafana開發(fā)的日志聚合工具)的地址作為強(qiáng)制配置參數(shù)。沒有這個參數(shù)集,它根本不會啟動。我們認(rèn)為同時安裝 Loki 是不切實(shí)際的。
注意。如果您仍然想使用 Promtail,您可以將 Loki 地址替換為任何能夠?yàn)槿魏握埱筇峁?200 響應(yīng)代碼的 Web 服務(wù)器(例如,nginx)的地址。但是,我們不建議在生產(chǎn)環(huán)境中使用此解決方法。
終于輪到 Vector 了。這對我們來說效果很不錯。
3.Vector:解析日志并輸出到 Prometheus
Vector 必須安裝在要解析的日志文件所在的主機(jī)上,以便將日志輸出到 Prometheus。安裝完成后,進(jìn)行相應(yīng)的配置。你可以使用,例如,Ansible 來做到這一點(diǎn):
# playbook-vector.yaml
---
- name: Setup vector
hosts:
- pg
become: yes
vars:
arch: amd64
version: 0.18.1
vector_template: files/40-vector.toml
vector_config_file: /etc/vector/vector.toml
tasks:
- name: Setup install vector
become: yes
apt:
deb: "https://packages.timber.io/vector/` version `/vector-` version `-` arch `.deb"
install_recommends: yes
notify:
- restart vector
- name: Copy config
copy:
src: "` vector_template `"
dest: "` vector_config_file `"
mode: 0644
owner: vector
group: vector
notify: restart vector
- name: Start Vector
service:
state: started
enabled: yes
name: vector
handlers:
- name: restart vector
service:
state: restarted
daemon_reload: yes
name: vector
Vector 配置存儲在 TOML 文件中。在此文件中指定日志文件的位置及其類型:
# vector.toml
[sources.postgres_logs.multiline]
start_pattern = '^\d{4}-[0-1]\d-[0-3]\d \d+:\d+:\d+\.\d+ [A-Z]{3}'
mode = "halt_before"
condition_pattern = '^\d{4}-[0-1]\d-[0-3]\d \d+:\d+:\d+\.\d+ [A-Z]{3}'
timeout_ms = 1000
請注意,halt_before?mode 意味著 Vector 會將跟在condition_pattern(并且不以后者開頭)之后的所有行視為單個消息。
您也可以使用其他multiline.mode?值。例如,該half_with?模式包括所有連續(xù)的行,直到并包括與condition_pattern消息中匹配的第一行。
然后使用VRL (https://vector.dev/docs/reference/vrl) 解析消息:
# vector.toml
[transforms.postgres_remap]
type = "remap"
inputs = [ "postgres_logs" ]
source = """. |= parse_regex!(.message, r'^(?P\\d{4}-[0-1]\\d-[0-3]\\d \\d+:\\d+:\\d+\\.\\d+ [A-Z]{3}) (?P\\d+) (?P(\\[\\w+\\]@\\w+|@|\\w+@\\w+)) from (?P(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\[\\w+\\]|\\s*)) (?P\\[\\w+:.+:\\d+\\]) (?P(\\[\\]|\\[\\w.+\\])) (?P.*[A-Z]): (?P.*)$')del(.timestamp)message_parts, err = split(.message, ", ", limit: 2)structured = parse_key_value(message_parts[1], key_value_delimiter: ":", field_delimiter: ",") ?? {}message = message_parts[0]. = merge(., structured)del(."please try the setup again")del(.message)"""
在這里,我們:
- 指定日志源;
- 設(shè)置一個正則表達(dá)式來解析日志消息;
- 刪除了不必要的字段;
- 使用“,”分隔符拆分消息;
- 將結(jié)果保存到map數(shù)組中,對其進(jìn)行處理,并獲得 JSON 輸出,以便我們可以繼續(xù)操作其字段。
現(xiàn)在讓我們過濾掉錯誤消息:
# vector.toml
[transforms.postgres_filter]
type = "filter"
inputs = [ "postgres_remap" ]
condition = '.level == "ERROR" || .level == "FATAL"'
此配置將在指標(biāo)中包含ERROR和FATAL消息。
接下來,根據(jù)過濾的日志消息創(chuàng)建一個指標(biāo)。設(shè)置要使用的指標(biāo)類型和字段,適當(dāng)?shù)孛?,并附加額外的標(biāo)簽。
# vector.toml
[transforms.postgres_metric]
type = "log_to_metric"
inputs = [ "postgres_filter" ]
[[transforms.postgres_metric.metrics]]
type = "counter"
field = "level"
name = "error_total"
namespace = "pg_log"
[transforms.postgres_metric.metrics.tags]
level = "`level`"
host = "`host`"
最后一步是發(fā)布 exporter。Prometheus 將使用它來抓取指標(biāo)。
[sinks.postgres_export_metric]
type = "prometheus_exporter"
inputs = [ "postgres_metric" ]
address = "0.0.0.0:9598"
default_namespace = "pg_log"
4.根據(jù)檢索到的指標(biāo)設(shè)置警報
為了讓 Prometheus 能夠從新 exporter 器中抓取指標(biāo),我們現(xiàn)在必須設(shè)置常規(guī)目標(biāo):
scrape_configs:
- job_name: custom-pg-log-exporter
static_configs:
- targets: ['10.10.10.2:9598', '10.10.10.3:9598', '10.10.10.4:9598']
下一步是創(chuàng)建基于指標(biāo)的規(guī)則,Alertmanager 將根據(jù)其路由設(shè)置處理該規(guī)則:
- alert: PgErrorCountChangeWarning
expr: | increase(pg_log_error_total{level="ERROR"}[30m]) > 0
for: 10m
labels:
severity: warning
annotations:
summary: The amount of errors in pg host {{$labels.host}} log has changed to {{$value}}
description: | There are errors in the PostgreSQL logs on the {{$labels.host}} server.
- alert: PgErrorCountChangeCritical
expr: | increase(pg_log_error_total{level="FATAL"}[30m]) > 0
for: 10m
labels:
severity: critical
annotations:
summary: The amount of fatal errors in pg host {{$labels.host}} log has changed to {{$value}}
description: |
There are fatal errors in the PostgreSQL logs on the {{$labels.host}} server.
pg_log_error_total這里計算向量時間序列30分鐘的增量。其值大于零意味著計數(shù)器已更改,從而導(dǎo)致向用戶發(fā)送警報。然后用戶可以檢查 PostgreSQL 日志以找出問題的原因。
5.結(jié)論
因此,我們使用了一個簡單的錯誤計數(shù)器來說明如何根據(jù)日志文件設(shè)置指標(biāo)收集。如果現(xiàn)有的 exporter 沒有提供我們想要的指標(biāo),并且沒有辦法更改應(yīng)用程序代碼,這可以作為一個相對簡單的解決方案。
我們的選擇受到 Vector 的簡單配置和廣泛功能的影響,使其成為各種任務(wù)的理想選擇。此外,其高性能 (https://medium.com/ibm-cloud/log-collectors-performance-benchmarking-8c5218a08fea) 意味著可用資源得到有效利用。vector top Cli工具有助于調(diào)試日志管道和查看 Vector 的指標(biāo)。它在漂亮的 TUI 界面中顯示信息。
Vector 不僅限于基本的計數(shù)器功能——它還可以解析日志以查找緩慢的數(shù)據(jù)庫查詢。然后,您可以使用 VRL 處理結(jié)果,聚合 (https://vector.dev/docs/reference/configuration/transforms/aggregate/) 它們,將它們轉(zhuǎn)換為指標(biāo),然后顯示 Grafana 中排名前 10 位的查詢。它還可以通過處理連接日志和根據(jù)獲得的數(shù)據(jù)創(chuàng)建指標(biāo)來證明對安全審計很有用。換句話說,Vector 有很多的應(yīng)用場景——這完全取決于用戶的需求。
原文:https://blog.palark.com/vector-to-export-pgsql-logs-into-prometheus/?