PostgreSQL错误日志与慢查询日志对于线上系统分析、问题预警、问题排查起到非常重要的作用,在此不做赘述。
此文档记录错误日志与慢查询日志的收集、分析与存储展示的方法。
一、总体思路
PostgreSQL日志输出可以配置多种多样的格式,其中以csvlog格式输出的日志信息最全面。但是CSV日志只能以本地文件的方式收集,不能直接写入网络,实时上传日志服务器。
日志收集:
PostgreSQL服务器分布在不同的机器,我们使用rsyslog客户端-服务器的方式来收集日志到日志服务器。具体方法:在PostgreSQL服务器部署客户端,在日志服务器部署服务器,客户端监控日志文件的变化,实时将新增日志上传到服务器,服务器根据不同客户端上传的日志,分别记录在不同的文件中。
此方法的好处是在PostgreSQL服务器本地可以保存一份原始的完整的csv日志,供全量信息查看与分析。
日志分析:
使用Logstash进行日志分析,Logstash是一个开源数据收集引擎,具有实时管道功能。Logstash可以动态地将来自不同文件的数据统一起来,进行数据筛选清洗,并将数据标准化到你所选择的目的地。
日志存储展示:
使用传统的Elasticsearch进行数据存储,Kibana进行数据展示。
二、rsyslog服务器端配置
新增以下内容到rsyslog配置文件/etc/rsyslog.conf,并重启rsyslog服务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
$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服务。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
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即可。配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
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何时记录
1
2
|
#client_min_messages = notice
log_min_messages = debug5 #debug级别是提供给开发人员使用的,这个可以看到程序调用的信息以及SQL转化为数据结构的信息,每分钟的级别
|
####where记录到哪里
1
2
3
4
|
#log_destination = 'stderr'
logging_collector = on #打开日志收集
log_directory = 'pg_log' #日志目录
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
|
####what写什么日志
1
2
3
4
5
6
7
8
|
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 #语句执行时间,对于分析
|
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。如有错误或未考虑完全的地方,望不吝赐教。
原文链接:https://my.oschina.net/207miner/blog/3021932