1. 程式人生 > 資料庫 >關於PostgreSQL錯誤日誌與慢查詢日誌收集

關於PostgreSQL錯誤日誌與慢查詢日誌收集

PostgreSQL錯誤日誌與慢查詢日誌對於線上系統分析、問題預警、問題排查起到非常重要的作用,在此不做贅述。

此文件記錄錯誤日誌與慢查詢日誌的收集、分析與儲存展示的方法。

一、總體思路

PostgreSQL日誌輸出可以配置多種多樣的格式,其中以csvlog格式輸出的日誌資訊最全面。但是CSV日誌只能以本地檔案的方式收集,不能直接寫入網路,實時上傳日誌伺服器。

日誌收集:

PostgreSQL伺服器分佈在不同的機器,我們使用rsyslog客戶端-伺服器的方式來收集日誌到日誌伺服器。具體方法:在PostgreSQL伺服器部署客戶端,在日誌伺服器部署伺服器,客戶端監控日誌檔案的變化,實時將新增日誌上傳到伺服器,伺服器根據不同客戶端上傳的日誌,分別記錄在不同的檔案中。

此方法的好處是在PostgreSQL伺服器本地可以儲存一份原始的完整的csv日誌,供全量資訊檢視與分析。

日誌分析:

使用Logstash進行日誌分析,Logstash是一個開源資料收集引擎,具有實時管道功能。Logstash可以動態地將來自不同檔案的資料統一起來,進行資料篩選清洗,並將資料標準化到你所選擇的目的地。

日誌儲存展示:

使用傳統的Elasticsearch進行資料儲存,Kibana進行資料展示。

二、rsyslog伺服器端配置

新增以下內容到rsyslog配置檔案/etc/rsyslog.conf,並重啟rsyslog服務。

$PreserveFQDN on   #用於正確的獲取主機名
$FileOwner root   #儲存的檔案屬主
$FileGroup root   #檔案屬主
$FileCreateMode 0644 #生成的檔案許可權
$DirCreateMode 0755 #生成的目錄許可權
$Umask 0022
$PrivDropToUser root  #可以刪除日誌的使用者
$PrivDropToGroup root  #可以刪除日誌的使用者組
module(load="imuxsock")
module(load="imklog")
module(load="imudp")
#input(type="imudp" port="514")
module(load="imtcp" MaxSessions="500")
input(type="imtcp" port="514")​
$template linefmt,"%msg:2:$%\n"  #接收日誌的格式(去掉開頭的空格)​
$template pgloglocation,"/data/pglogs/%hostname%/%$YEAR%-%$MONTH%-%$DAY%.csv"​
:rawmsg,contains,"pg_5432" ?pgloglocation;linefmt
##變數:%fromhost-ip%

三、rsyslog客戶端配置

新建配置檔案/etc/rsyslog.d/10-pg.conf,並重啟rsyslog服務。

cat /etc/rsyslog.d/10-pg.conf​
module(load="imuxsock")
module(load="imklog")
module(load="imfile")​
#module(load="imudp")
#input(type="imudp" port="514")​
module(load="imtcp" MaxSessions="500")
input(type="imtcp" port="514")​
ruleset(name="remote"){
    action(type="omfwd"
            target="x.x.x.x"  #日誌伺服器IP地址
            port="514"     #埠
            protocol="tcp"   #使用協議
            queue.type="linkedList" #使用非同步處理
            queue.spoolDirectory="/var/log/rsyslog" #佇列目錄
            queue.fileName="pglog"         #佇列名稱
            queue.maxDiskSpace="1g"         #佇列佔最大磁碟空間
            queue.saveOnShutdown="on"  #儲存記憶體資料如果rsyslog關閉
            action.resumeRetryCount="-1" #無限重試插入失敗
       )
    stop
}​
​
input(
 type="imfile"
 File="/pg/data/log/*.csv" #PG伺服器日誌路徑
 Facility="local1"
 Severity="info"
 Tag="pg_5432"       #定義日誌標籤,重要,服務端根據這個標籤可以識別日誌
 PersistStateInterval="1"  #回寫偏移量資料到檔案間隔時間(秒),根據實際情況而定 
 deleteStateOnFileDelete="on" 
 reopenOnTruncate="on"
 Ruleset="remote"      #rsyslog.conf中定義的rule名稱
)

四、logstash配置

在日誌伺服器上編輯好配置檔案後,啟動logstash即可。配置檔案如下:

input {
 file {
  path => ["/data/pglogs/*/*.csv"]
  start_position => "end"
  codec => multiline {
   pattern => "^20[0-9]{2}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}"
   negate => true
   what => "previous"
  }
 }
}
​
filter {
 csv {
  separator => ","
  columns => ["log_time","user_name","database_name","process_id","connection_from","session_id","session_line_num","command_tag","session_start_time","virtual_transaction_id","transaction_id","error_severity","sql_state_code","message","detail","hint","internal_query","internal_query_pos","context","query","query_pos","location","application_name"]
  convert => {
   "process_id" => "integer"
   "session_line_num" => "integer"
   "transaction_id" => "integer"
   "internal_query_pos" => "integer"
   "query_pos" => "integer"
  }
  skip_empty_columns => true
 }
​
 mutate{
   split => { "log_time" => " CST" }
   add_field => { "log_time_tmp" => "%{[log_time][0]}" }
   remove_field => ["log_time"]
 }
​
 date {
   match => ["log_time_tmp","yyyy-MM-dd HH:mm:ss.SSS"]
   target => "@timestamp"
   locale => "cn"
   remove_field => ["log_time_tmp"]
 }
​
 if "duration:" in [message] and "ms" in [message] and "statement:" in [message] {
  grok{
   match => { "message" => "duration: %{NUMBER:duration} ms" }
  }
  mutate{
   split => { "message" => "statement: " }
   add_field => { "statement" => "%{[message][1]}" }
   remove_field => ["message"]
  }
 }
 mutate{
  split => { "path" => "/" }
  add_field => { "db_host" => "%{[path][3]}" }
  remove_field => ["path","host"]
  convert => { "duration" => "float" }
 }
}​
​
output {
 if [error_severity] == "ERROR" or [error_severity] == "FATAL" or [error_severity] == "PANIC" {
  elasticsearch {
   hosts => ["x.x.x.x:x","x.x.x.x:x"]
   index => "pg_error"
   id => "elasticsearch_pg_error"
  }
 }else if [duration] and [statement] {
  elasticsearch {
   hosts => ["x.x.x.x:x","x.x.x.x:x"]
   index => "pg_slow"
   id => "elasticsearch_pg_slow"
  }
 }
}

五、此處省略了Elasticsearch儲存與Kibana展示,這裡不多介紹

補充:PostgreSQL開發者模式錯誤反饋與日誌設定

####when何時記錄

#client_min_messages = notice
log_min_messages = debug5 #debug級別是提供給開發人員使用的,這個可以看到程式呼叫的資訊以及SQL轉化為資料結構的資訊,每分鐘的級別

####where記錄到哪裡

#log_destination = 'stderr'
logging_collector = on  #開啟日誌收集
log_directory = 'pg_log' #日誌目錄
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'  

####what寫什麼日誌

debug_print_parse = on #解析樹
debug_print_rewritten = on #查詢重寫後的SQL
debug_print_plan = on  #執行計劃詳細
debug_pretty_print = on #對debug_print_parse,debug_print_rewritten,debug_print_plan可讀性格式化
#log_checkpoints = off #如果是研究pg的磁碟IO,這個需要設定為on
log_connections = on #連線日誌
log_disconnection = on #斷開連線日誌
#log_duration=on #語句執行時間,對於分析

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援我們。如有錯誤或未考慮完全的地方,望不吝賜教。