Postgresql 将rsyslog中的传入文本时间戳转换为PostSQL的时间戳
我有来自各种linux服务器的日志,这些日志由rsyslog提供给PostgreSQL数据库。传入的时间戳是rsyslog的RFC3339格式的时间,如下所示:Postgresql 将rsyslog中的传入文本时间戳转换为PostSQL的时间戳,postgresql,rsyslog,timestamp-with-timezone,Postgresql,Rsyslog,Timestamp With Timezone,我有来自各种linux服务器的日志,这些日志由rsyslog提供给PostgreSQL数据库。传入的时间戳是rsyslog的RFC3339格式的时间,如下所示:2020-10-12T12:01:18.162329+02:00 在数据库日志表的原始测试设置中,我将时间戳字段创建为“text”。我需要解析的大部分内容都正常工作,所以我希望将时间戳表列从文本转换为时间戳数据类型(如果可能的话,保留亚秒和时区) 最终结果应该是一个时间戳数据类型,这样我就可以使用PostgreSQL数据函数进行日期范围查
2020-10-12T12:01:18.162329+02:00
在数据库日志表的原始测试设置中,我将时间戳字段创建为“text”。我需要解析的大部分内容都正常工作,所以我希望将时间戳表列从文本转换为时间戳数据类型(如果可能的话,保留亚秒和时区)
最终结果应该是一个时间戳数据类型,这样我就可以使用PostgreSQL数据函数进行日期范围查询
这在PostgreSQL 11中可行吗?还是最好首先使用正确的时间戳列数据类型重新创建表
提前感谢您提供的任何指针、建议、查找位置或代码片段
相关rsyslog配置:
$template CustomFormat,"%timegenerated:::date-rfc3339% %syslogseverity-text:::uppercase% %hostname% %syslogtag% %msg%\n"
$ActionFileDefaultTemplate CustomFormat
...
template(name="rsyslog" type="list" option.sql="on") {
constant(value="INSERT INTO log (timestamp, severity, hostname, syslogtag, message)
values ('")
property(name="timegenerated" dateFormat="rfc3339") constant(value="','")
property(name="syslogseverity-text" caseConversion="upper") constant(value="','")
property(name="hostname") constant(value="','")
property(name="syslogtag") constant(value="','")
property(name="msg") constant(value="')")
}
以及日志表结构:
CREATE TABLE public.log
(
id integer NOT NULL DEFAULT nextval('log_id_seq'::regclass),
"timestamp" text COLLATE pg_catalog."default" DEFAULT timezone('UTC'::text, CURRENT_TIMESTAMP),
severity character varying(10) COLLATE pg_catalog."default",
hostname character varying(20) COLLATE pg_catalog."default",
syslogtag character varying(24) COLLATE pg_catalog."default",
program character varying(24) COLLATE pg_catalog."default",
process text COLLATE pg_catalog."default",
message text COLLATE pg_catalog."default",
CONSTRAINT log_pkey PRIMARY KEY (id)
)
一些示例数据已经输入到表中(忽略消息中的时间戳,它们是由我的前任使用独立的手工记录系统完成的):
理论上,您可以将
文本
列转换为带时区的时间戳
和更改表。。更改列。。。设置数据类型。。。使用
,例如:
postgres=# CREATE TABLE tstest (tsval TEXT NOT NULL);
CREATE TABLE
postgres=# INSERT INTO tstest values('2020-10-12T12:01:18.162329+02:00');
INSERT 0 1
postgres=# ALTER TABLE tstest
ALTER COLUMN tsval SET DATA TYPE TIMESTAMP WITH TIME ZONE
USING tsval::TIMESTAMPTZ;
ALTER TABLE
postgres=# \d tstest
Table "public.tstest"
Column | Type | Collation | Nullable | Default
--------+--------------------------+-----------+----------+---------
tsval | timestamp with time zone | | not null |
postgres=# SELECT * FROM tstest ;
tsval
-------------------------------
2020-10-12 12:01:18.162329+02
(1 row)
PostgreSQL可以解析RFC3339
格式,因此后续插入应该可以正常工作:
postgres=# INSERT INTO tstest values('2020-10-12T12:01:18.162329+02:00');
INSERT 0 1
postgres=# SELECT * FROM tstest ;
tsval
-------------------------------
2020-10-12 12:01:18.162329+02
2020-10-12 12:01:18.162329+02
(2 rows)
但是注意表中的任何坏数据(即不能被解析为时间戳的值)将导致<代码> ALTER表< /代码>操作失败,因此您应该考虑在转换数据之前验证值。类似于
选择“timestamp”::TIMESTAMPTZ FROM public.log
将失败,并出现类似于带有时区的timestamp类型的无效输入语法:“somebadvalue”
还要记住,这种ALTER TABLE
需要重写表,这可能需要一些时间才能完成(取决于表的大小),并且需要ACCESS EXCLUSIVE
锁,使得表在操作期间无法访问
如果要避免长时间运行的ACCESS EXCLUSIVE
锁,您可能可以执行以下操作(未经测试):
- 添加一个新的
列(添加列不会重写表,而且如果不使用易失性默认值,成本相当低廉)timestamtz
- 创建触发器以复制插入原始列中的任何值
- 复制现有值(使用一组批处理的更新,如
updatepublic.foo SET newlog=log::TIMESTAMPTZ
- (在单个事务中)删除触发器和现有列,并将新列重命名为旧列