微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将传入的文本时间戳从rsyslog转换为postrgesql的时间戳

如何解决将传入的文本时间戳从rsyslog转换为postrgesql的时间戳

我有来自各种Linux服务器的日志,这些日志由rsyslog馈送到Postgresql数据库。传入的时间戳是rsyslog的RFC3339格式的时间,例如:2020-10-12T12:01:18.162329+02:00

数据库日志记录表的原始测试设置中,我将该时间戳记字段创建为“文本”。我需要解析的大多数东西都能正常工作,因此我希望将时间戳表列从文本转换为时间戳数据类型(并尽可能保留亚秒和时区)。

最终结果应该是时间戳记数据类型,以便我可以使用Postgresql数据函数进行日期范围查询

这在Postgresql 11中可行吗?还是重新开始使用正确的timestamp列数据类型重新创建表?

提前感谢任何指针,建议,查找位置或代码段。

相关的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)
)

一些已经送入表中的示例数据(忽略消息中的时间戳,它们由我的前任使用独立的手工记录系统完成):

enter image description here

解决方法

理论上,您可以使用SELECT wf.name "wherefrom",wt.name "whereto" FROM Flights f JOIN Cities wf ON f.wherefrom_id = wf.id JOIN Cities wt ON f.whereto_id = wt.id order by f.id TEXT列转换为TIMESTAMP WITH TIME ZONE,例如:

ALTER TABLE .. ALTER COLUMN ... SET DATA TYPE ... USING

PostgreSQL可以解析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) 格式,因此后续插入应该可以工作:

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 TABLE之类的错误将因诸如SELECT "timestamp"::TIMESTAMPTZ FROM public.log之类的错误而失败。

还请记住,这种invalid input syntax for type timestamp with time zone: "somebadvalue"需要对表进行重写,这可能需要一些时间才能完成(取决于表的大小),并且需要ALTER TABLE锁来呈现表在操作期间无法访问。

如果您想避免长时间运行的ACCESS EXCLUSIVE锁,则可以执行以下操作(未经测试):

  • 添加新的ACCESS EXCLUSIVE列(添加列不会重写表,并且如果您不使用易失的默认值,则费用相当便宜)
  • 创建触发器以复制插入到原始列中的所有值
  • 复制现有值(使用诸如TIMESTAMPTZ之类的一批批量更新
  • (在单个事务中)删除触发器和现有列,然后将新列重命名为旧列

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。