如何处理 NLog 的所有事件属性布局渲染器产生的空值?
How to handle empty values produced by NLog's all-event-properties layout renderer?
我正在为 PostgreSQL 配置 NLog 的数据库目标,我想为此使用 hstore
column to store all event properties. I'm using all-event-properties
layout renderer。
这是我当前的目标配置:
<target name="database"
xsi:type="Database"
dbProvider="Npgsql.NpgsqlConnection, Npgsql"
connectionString="Server=localhost;Port=5432;Database=db;User Id=postgres">
<install-command>
<text>
CREATE EXTENSION IF NOT EXISTS hstore WITH SCHEMA public;
CREATE TABLE IF NOT EXISTS logs (
id bigserial PRIMARY KEY,
moment timestamp NOT NULL,
level text NOT NULL,
message text NOT NULL,
args hstore NOT NULL
);
</text>
</install-command>
<commandText>
INSERT INTO logs (moment, level, message, args)
VALUES (@moment::timestamp, @level, @message, @args::hstore);
</commandText>
<parameter name="@moment" layout="${longdate:universalTime=true}" />
<parameter name="@level" layout="${level}" />
<parameter name="@message" layout="${message}" />
<!-- (!) Here's where the format of event properties adopted for hstore syntax (!)-->
<parameter name="@args" layout="${all-event-properties:format=[key]=>[value]" />
</target>
它适用于不带参数的日志,但带参数时会生成以下 SQL:
INSERT INTO logs (moment, level, message, args) VALUES (
'2019-05-24 18:44:49.7494'::timestamp,
'Info',
'Message text here',
'a=>1, b=>2, c=>3, EventId_Id=>555, EventId_Name=>, EventId=>555'::hstore);
-- no value here--------^
这是无效语法,因为 PostgreSQL 语法需要 NULL
关键字作为值或根本不包含键:
这是错误:
ERROR: Syntax error near 'E' at position 51
当我手动执行此操作时它完全重现并在我删除 EventId_Name=>,
键时消失。所以,我很确定我需要以某种方式 skip/handle 那些空钥匙才能快乐。
我也同意 SQL 中的任何解决方案,但找不到一种简单而可靠的方法来处理这些值。
我不完全理解这种情况下的语法应该是什么,但无论如何您都可以使用自定义布局渲染器来解决这个问题
创建:
// register ${all-properties-postgresql}
LayoutRenderer.Register("all-properties-postgresql",
(logEvent) => SerializeProps(logEvent.Properties));
您需要编写 SerializeProps
来序列化 LogEventInfo.Properties
- 请参阅 API docs
为了回答这个问题,我阅读了 hstore format documentation:
Double-quote keys and values that include whitespace, commas, =s or >s. To include a double quote or a backslash in a key or value, escape it with a backslash.
不确定 =s
和 >s
是什么,我决定 double-quote 转义双引号和反斜杠的所有内容。这是我的解决方案:
LayoutRenderer.Register("all-event-properties-hstore", e =>
{
var sb = new StringBuilder();
var first = true;
var fp = e.FormatProvider ?? CultureInfo.InvariantCulture;
string GetString(object o) =>
Convert.ToString(o, fp).Replace("\", "\\").Replace("\"", "\\"");
foreach (var (key, value) in e.Properties)
{
if (first)
first = false;
else
sb.Append(",");
sb.Append("\"");
sb.Append(GetString(key));
sb.Append("\"=>\"");
sb.Append(GetString(value));
sb.Append("\"");
}
return sb.ToString();
});
我正在为 PostgreSQL 配置 NLog 的数据库目标,我想为此使用 hstore
column to store all event properties. I'm using all-event-properties
layout renderer。
这是我当前的目标配置:
<target name="database"
xsi:type="Database"
dbProvider="Npgsql.NpgsqlConnection, Npgsql"
connectionString="Server=localhost;Port=5432;Database=db;User Id=postgres">
<install-command>
<text>
CREATE EXTENSION IF NOT EXISTS hstore WITH SCHEMA public;
CREATE TABLE IF NOT EXISTS logs (
id bigserial PRIMARY KEY,
moment timestamp NOT NULL,
level text NOT NULL,
message text NOT NULL,
args hstore NOT NULL
);
</text>
</install-command>
<commandText>
INSERT INTO logs (moment, level, message, args)
VALUES (@moment::timestamp, @level, @message, @args::hstore);
</commandText>
<parameter name="@moment" layout="${longdate:universalTime=true}" />
<parameter name="@level" layout="${level}" />
<parameter name="@message" layout="${message}" />
<!-- (!) Here's where the format of event properties adopted for hstore syntax (!)-->
<parameter name="@args" layout="${all-event-properties:format=[key]=>[value]" />
</target>
它适用于不带参数的日志,但带参数时会生成以下 SQL:
INSERT INTO logs (moment, level, message, args) VALUES (
'2019-05-24 18:44:49.7494'::timestamp,
'Info',
'Message text here',
'a=>1, b=>2, c=>3, EventId_Id=>555, EventId_Name=>, EventId=>555'::hstore);
-- no value here--------^
这是无效语法,因为 PostgreSQL 语法需要 NULL
关键字作为值或根本不包含键:
这是错误:
ERROR: Syntax error near 'E' at position 51
当我手动执行此操作时它完全重现并在我删除 EventId_Name=>,
键时消失。所以,我很确定我需要以某种方式 skip/handle 那些空钥匙才能快乐。
我也同意 SQL 中的任何解决方案,但找不到一种简单而可靠的方法来处理这些值。
我不完全理解这种情况下的语法应该是什么,但无论如何您都可以使用自定义布局渲染器来解决这个问题
创建:
// register ${all-properties-postgresql}
LayoutRenderer.Register("all-properties-postgresql",
(logEvent) => SerializeProps(logEvent.Properties));
您需要编写 SerializeProps
来序列化 LogEventInfo.Properties
- 请参阅 API docs
为了回答这个问题,我阅读了 hstore format documentation:
Double-quote keys and values that include whitespace, commas, =s or >s. To include a double quote or a backslash in a key or value, escape it with a backslash.
不确定 =s
和 >s
是什么,我决定 double-quote 转义双引号和反斜杠的所有内容。这是我的解决方案:
LayoutRenderer.Register("all-event-properties-hstore", e =>
{
var sb = new StringBuilder();
var first = true;
var fp = e.FormatProvider ?? CultureInfo.InvariantCulture;
string GetString(object o) =>
Convert.ToString(o, fp).Replace("\", "\\").Replace("\"", "\\"");
foreach (var (key, value) in e.Properties)
{
if (first)
first = false;
else
sb.Append(",");
sb.Append("\"");
sb.Append(GetString(key));
sb.Append("\"=>\"");
sb.Append(GetString(value));
sb.Append("\"");
}
return sb.ToString();
});