Merge pull request #7683 from EMQ-YangM/rule-engine-doc

feat(rule-engine): add i18n support
This commit is contained in:
Yang Miao 2022-04-20 15:39:49 +08:00 committed by GitHub
commit 1dc9ddeac7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1177 additions and 198 deletions

View File

@ -72,9 +72,9 @@ A host entry has the following form: `Host[:Port]`.<br/>
The MongoDB default port 27017 is used if `[:Port]` is not specified.
"""
zh: """
集群要连接的节点列表。 节点之间用逗号分隔,如:`Node[,Node].<br/>`
对于每个节点,应为:将要连接的 IPv4 或 IPv6 地址或主机名。<br/>
主机条目具有以下形式:`Host[:Port]`。<br/>
集群要连接的节点列表。 节点之间用逗号分隔,如:`Node[,Node].<br/>`
每个节点的配置为:将要连接的 IPv4 或 IPv6 地址或主机名。<br/>
主机具有以下形式:`Host[:Port]`。<br/>
如果未指定 `[:Port]`,则使用 MongoDB 默认端口 27017。
"""
}

View File

@ -72,9 +72,10 @@ A host entry has the following form: `Host[:Port]`.<br/>
The MongoDB default port 27017 is used if `[:Port]` is not specified.
"""
zh: """
集群要连接的节点列表。 节点之间用逗号分隔,如:`Node[,Node].<br/>`
对于每个节点,应为:将要连接的 IPv4 或 IPv6 地址或主机名。<br/>
主机条目具有以下形式:`Host[:Port]`。<br/>
集群将要连接的节点列表。 节点之间用逗号分隔,如:`Node[,Node].<br/>`
每个节点的配置为:将要连接的 IPv4 或 IPv6 地址或主机名。<br/>
主机名具有以下形式:`Host[:Port]`。<br/>
如果未指定 `[:Port]`,则使用 Redis 默认端口 6379。
"""
}

View File

@ -0,0 +1,685 @@
emqx_rule_api_schema {
event_event_type {
desc {
en: "Event Type"
zh: "事件类型"
}
label: {
en: "Event Type"
zh: "事件类型"
}
}
event_id {
desc {
en: "Message ID"
zh: "消息 ID"
}
label: {
en: "Message ID"
zh: "消息 ID"
}
}
event_clientid {
desc {
en: "The Client ID"
zh: "客户端 ID"
}
label: {
en: "Client ID"
zh: "客户端 ID"
}
}
event_username {
desc {
en: "The User Name"
zh: ""
}
label: {
en: "Username"
zh: "用户名"
}
}
event_payload {
desc {
en: "The Message Payload"
zh: "消息负载"
}
label: {
en: "Message Payload"
zh: "消息负载"
}
}
event_peerhost {
desc {
en: "The IP Address of the Peer Client"
zh: "对等客户端的 IP 地址"
}
label: {
en: "Peer IP Address"
zh: "对等客户端的 IP"
}
}
event_topic {
desc {
en: "Message Topic"
zh: "消息主题"
}
label: {
en: "Message Topic"
zh: "消息主题"
}
}
event_publish_received_at {
desc {
en: "The Time that this Message is Received"
zh: "消息被接受的时间"
}
label: {
en: "Message Received Time"
zh: "消息被接受的时间"
}
}
event_qos {
desc {
en: "The Message QoS"
zh: "消息的 QoS"
}
label: {
en: "Message QoS"
zh: "消息 QoS"
}
}
event_from_clientid {
desc {
en: "The Client ID"
zh: "事件来源客户端的 ID"
}
label: {
en: "Client ID"
zh: "客户端 ID"
}
}
event_from_username {
desc {
en: "The User Name"
zh: "事件来源客户端的用户名"
}
label: {
en: "Username"
zh: "用户名"
}
}
event_mountpoint {
desc {
en: "The Mountpoint"
zh: "挂载点"
}
label: {
en: "Mountpoint"
zh: "挂载点"
}
}
event_peername {
desc {
en: "The IP Address and Port of the Peer Client"
zh: "对等客户端的 IP 地址和端口"
}
label: {
en: "IP Address And Port"
zh: "IP 地址和端口"
}
}
event_sockname {
desc {
en: "The IP Address and Port of the Local Listener"
zh: "本地监听的 IP 地址和端口"
}
label: {
en: "IP Address And Port"
zh: "IP 地址和端口"
}
}
event_proto_name {
desc {
en: "Protocol Name"
zh: "协议名称"
}
label: {
en: "Protocol Name"
zh: "协议名称"
}
}
event_proto_ver {
desc {
en: "Protocol Version"
zh: "协议版本"
}
label: {
en: "Protocol Version"
zh: "协议版本"
}
}
event_keepalive {
desc {
en: "KeepAlive"
zh: "保持连接"
}
label: {
en: "KeepAlive"
zh: "保持连接"
}
}
event_clean_start {
desc {
en: "Clean Start"
zh: "清除会话"
}
label: {
en: "Clean Start"
zh: "清除会话"
}
}
event_expiry_interval {
desc {
en: "Expiry Interval"
zh: "到期间隔"
}
label: {
en: "Expiry Interval"
zh: "到期间隔"
}
}
event_is_bridge {
desc {
en: "Is Bridge"
zh: "是否桥接"
}
label: {
en: "Is Bridge"
zh: "是否桥接"
}
}
event_connected_at {
desc {
en: "The Time that this Client is Connected"
zh: "客户端连接完成时的时刻"
}
label: {
en: "Connected Time"
zh: "连接完成时的时刻"
}
}
event_action {
desc {
en: "Publish or Subscribe"
zh: "订阅或发布"
}
label: {
en: "Publish or Subscribe"
zh: "订阅或发布"
}
}
event_authz_source {
desc {
en: "Cache, Plugs or Default"
zh: "缓存,插件或者默认值"
}
label: {
en: "Auth Source"
zh: "认证源"
}
}
event_result {
desc {
en: "Allow or Deny"
zh: "允许或禁止"
}
label: {
en: "Auth Result"
zh: "认证结果"
}
}
event_server {
desc {
en: "The IP address (or hostname) and port of the MQTT broker, in IP:Port format"
zh: "MQTT broker的 IP 地址(或主机名)和端口,采用 IP:Port 格式"
}
label: {
en: "Server IP And Port"
zh: "服务器 IP 地址和端口"
}
}
event_dup {
desc {
en: "The DUP flag of the MQTT message"
zh: "MQTT 消息的 DUP 标志"
}
label: {
en: "DUP Flag"
zh: "DUP 标志"
}
}
event_retain {
desc {
en: "If is a retain message"
zh: "是否是保留消息"
}
label: {
en: "Retain Message"
zh: "保留消息"
}
}
event_ctx_dropped {
desc {
en: "The Reason for Dropping"
zh: "消息被丢弃的原因"
}
label: {
en: "Dropped Reason"
zh: "丢弃原因"
}
}
event_ctx_disconnected_reason {
desc {
en: "The Reason for Disconnect"
zh: "断开连接的原因"
}
label: {
en: "Disconnect Reason"
zh: "断开连接原因"
}
}
event_ctx_disconnected_da {
desc {
en: "The Time that this Client is Disconnected"
zh: "客户端断开连接的时刻"
}
label: {
en: "Disconnected Time"
zh: "客户端断开连接时刻"
}
}
event_ctx_connack_reason_code {
desc {
en: "The reason code"
zh: "错误码"
}
label: {
en: "Reason Code"
zh: "错误码"
}
}
rule_id {
desc {
en: "The ID of the rule"
zh: "规则的 ID "
}
label: {
en: "Rule ID"
zh: "规则 ID "
}
}
node_node {
desc {
en: "The node name"
zh: "节点名字"
}
label: {
en: "Node Name"
zh: "节点名字"
}
}
metrics_sql_matched {
desc {
en: "How much times the FROM clause of the SQL is matched."
zh: "SQL 的 FROM 子句匹配的次数。"
}
label: {
en: "Matched"
zh: "命中数"
}
}
metrics_sql_matched_rate {
desc {
en: "The rate of matched, times/second"
zh: "命中速率,次/秒"
}
label: {
en: "命中速率"
zh: "Matched Rate"
}
}
metrics_sql_matched_rate_max {
desc {
en: "The max rate of matched, times/second"
zh: "最大命中速率,次/秒"
}
label: {
en: "Max Matched Rate"
zh: "最大命中速率"
}
}
metrics_sql_matched_rate_last5m {
desc {
en: "The average rate of matched in last 5 minutes, times/second"
zh: "5分钟平均命中速率次/秒"
}
label: {
en: "Average Matched Rate"
zh: "平均命中速率"
}
}
metrics_sql_passed {
desc {
en: "How much times the SQL is passed"
zh: "SQL 通过的次数"
}
label: {
en: "SQL Passed"
zh: "SQL 通过"
}
}
metrics_sql_failed {
desc {
en: "How much times the SQL is failed"
zh: "SQL 失败的次数"
}
label: {
en: "SQL Failed"
zh: "SQL 失败"
}
}
metrics_sql_failed_exception {
desc {
en: "How much times the SQL is failed due to exceptions. This may because of a crash when calling a SQL function, or trying to do arithmetic operation on undefined variables"
zh: "SQL 由于执行异常而失败的次数。 这可能是因为调用 SQL 函数时崩溃,或者试图对未定义的变量进行算术运算"
}
label: {
en: "SQL Exception"
zh: "SQL 执行异常"
}
}
metrics_sql_failed_unknown {
desc {
en: "How much times the SQL is failed due to an unknown error."
zh: "由于未知错误导致 SQL 失败的次数。"
}
label: {
en: "SQL Unknown Error"
zh: "SQL 未知错误"
}
}
metrics_outputs_total {
desc {
en: "How much times the outputs are called by the rule. This value may several times of 'sql.matched', depending on the number of the outputs of the rule."
zh: "规则调用输出的次数。 该值可能是“sql.matched”的几倍具体取决于规则输出的数量。"
}
label: {
en: "Output Total"
zh: "调用输出次数"
}
}
metrics_outputs_success {
desc {
en: "How much times the rule success to call the outputs."
zh: "规则成功调用输出的次数。"
}
label: {
en: "Success Output"
zh: "成功调用输出次数"
}
}
metrics_outputs_failed {
desc {
en: "How much times the rule failed to call the outputs."
zh: "规则调用输出失败的次数。"
}
label: {
en: "Failed Output"
zh: "调用输出失败次数"
}
}
metrics_outputs_failed_out_of_service {
desc {
en: "How much times the rule failed to call outputs due to the output is out of service. For example, a bridge is disabled or stopped."
zh: "由于输出停止服务而导致规则调用输出失败的次数。 例如,桥接被禁用或停止。"
}
label: {
en: "Fail Output"
zh: "调用输出失败次数"
}
}
metrics_outputs_failed_unknown {
desc {
en: "How much times the rule failed to call outputs due to to an unknown error."
zh: "由于未知错误,规则调用输出失败的次数。"
}
label: {
en: "Fail Output"
zh: "调用输出失败次数"
}
}
test_context {
desc {
en: "The context of the event for testing"
zh: "测试事件的上下文"
}
label: {
en: "Event Conetxt"
zh: "事件上下文"
}
}
test_sql {
desc {
en: "The SQL of the rule for testing"
zh: "测试的 SQL"
}
label: {
en: "Test SQL"
zh: "测试 SQL"
}
}
rs_event {
desc {
en: "The event topics"
zh: "事件主题"
}
label: {
en: "Event Topics"
zh: "事件主题"
}
}
rs_title {
desc {
en: "The title"
zh: "标题"
}
label: {
en: "Title"
zh: "标题"
}
}
rs_description {
desc {
en: "The description"
zh: "描述"
}
label: {
en: "Description"
zh: "描述"
}
}
rs_columns {
desc {
en: "The columns"
zh: "列"
}
label: {
en: "Column"
zh: "列"
}
}
rs_test_columns {
desc {
en: "The test columns"
zh: "测试列"
}
label: {
en: "Test Columns"
zh: "测试列"
}
}
rs_sql_example {
desc {
en: "The sql_example"
zh: "SQL 例子"
}
label: {
en: "SQL Example"
zh: "SQL 例子"
}
}
ri_metrics {
desc {
en: "The metrics of the rule"
zh: "规则的计数器"
}
label: {
en: "Rule Metrics"
zh: "规则计数器"
}
}
ri_node_metrics {
desc {
en: "The metrics of the rule for each node"
zh: "每个节点的规则计数器"
}
label: {
en: "Each Node Rule Metrics"
zh: "每个节点规则计数器"
}
}
ri_from {
desc {
en: "The topics of the rule"
zh: "规则指定的主题"
}
label: {
en: "Topics of Rule"
zh: "规则指定的主题"
}
}
ri_created_at {
desc {
en: "The created time of the rule"
zh: "规则创建时间"
}
label: {
en: "Rule Create Time"
zh: "规则创建时间"
}
}
root_rule_creation {
desc {
en: "Schema for creating rules"
zh: "用于创建规则的 Schema"
}
label: {
en: "Create Schema"
zh: "用于创建规则的 Schema"
}
}
root_rule_info {
desc {
en: "Schema for rule info"
zh: "用于规则信息的 Schema"
}
label: {
en: "Info Schema"
zh: "用于规则信息的 Schema"
}
}
root_rule_events {
desc {
en: "Schema for rule events"
zh: "用于事件的 Schema"
}
label: {
en: "Rule Events Schema"
zh: "用于规则事件的 Schema"
}
}
root_rule_test {
desc {
en: "Schema for testing rules"
zh: "用于规则测试的 Schema"
}
label: {
en: "Rule Test Schema"
zh: "用于规则测试的 Schema"
}
}
}

View File

@ -0,0 +1,100 @@
emqx_rule_engine_api {
api1 {
desc {
en: "List all rules"
zh: "列出所有规则"
}
label: {
en: "List All Rules"
zh: "列出所有规则"
}
}
api2 {
desc {
en: "Create a new rule using given Id"
zh: "通过指定 ID 创建规则"
}
label: {
en: "Create Rule By ID"
zh: "通过指定 ID 创建规则"
}
}
api3 {
desc {
en: "List all events can be used in rules"
zh: "列出所有能被规则使用的事件"
}
label: {
en: "List All Events Can Be Used In Rule"
zh: "列出所有能被规则使用的事件"
}
}
api4 {
desc {
en: "Get a rule by given Id"
zh: "通过 ID 查询规则"
}
label: {
en: "Get Rule"
zh: "查询规则"
}
}
api5 {
desc {
en: "Update a rule by given Id to all nodes in the cluster"
zh: "通过 ID 更新集群里所有节点上的规则"
}
label: {
en: "Update Cluster Rule"
zh: "更新集群规则"
}
}
api6 {
desc {
en: "Delete a rule by given Id from all nodes in the cluster"
zh: "通过 ID 删除集群里所有节点上的规则"
}
label: {
en: "Delete Cluster Rule"
zh: "删除集群规则"
}
}
api7 {
desc {
en: "Reset a rule metrics"
zh: "重置规则计数"
}
label: {
en: "Reset Rule Metrics"
zh: "重置规则计数"
}
}
api8 {
desc {
en: "Test a rule"
zh: "测试一个规则"
}
label: {
en: "Test Rule"
zh: "测试规则"
}
}
desc9 {
desc {
en: "List of rules"
zh: "列出所有规则"
}
label: {
en: "List Rules"
zh: "列出所有规则"
}
}
}

View File

@ -0,0 +1,242 @@
emqx_rule_engine_schema {
rules_name {
desc {
en: "The name of the rule"
zh: "规则名字"
}
label: {
en: "Rule Name"
zh: "规则名字"
}
}
rules_sql {
desc {
en: """
SQL query to transform the messages.<br>
Example: <code>SELECT * FROM "test/topic" WHERE payload.x = 1</code><br>
"""
zh: """
用于处理消息的 SQL 。<br>
示例:<code>SELECT * FROM "test/topic" WHERE payload.x = 1</code><br>
"""
}
label: {
en: "Rule SQL"
zh: "规则 SQL"
}
}
rules_outputs {
desc {
en: """
A list of outputs of the rule.<br>
An output can be a string that refers to the channel ID of an EMQX bridge, or an object
that refers to a function.<br>
There a some built-in functions like "republish" and "console", and we also support user
provided functions in the format: "{module}:{function}".<br>
The outputs in the list are executed sequentially.
This means that if one of the output is executing slowly, all the following outputs will not
be executed until it returns.<br>
If one of the output crashed, all other outputs come after it will still be executed, in the
original order.<br>
If there's any error when running an output, there will be an error message, and the 'failure'
counter of the function output or the bridge channel will increase.
"""
zh: """
规则的动作列表。<br>
动作可以是指向 EMQX bridge 的引用,也可以是一个指向函数的对象。<br>
我们支持一些内置函数如“republish”和“console”我们还支持用户提供的函数它的格式为“{module}:{function}”。<br>
列表中的动作按顺序执行。这意味着如果其中一个动作执行缓慢,则以下所有动作都不会被执行直到它返回。<br>
如果其中一个动作崩溃,在它之后的所有动作仍然会被按照原始顺序执行。<br>
如果运行动作时出现任何错误,则会出现错误消息,并且相应的计数器会增加。
"""
}
label: {
en: "Rule Action List"
zh: "动作列表"
}
}
rules_enable {
desc {
en: "Enable or disable the rule"
zh: "启用或禁用规则引擎"
}
label: {
en: "Enable Or Disable Rule"
zh: "启用或禁用规则引擎"
}
}
rules_description {
desc {
en: "The description of the rule"
zh: "规则的描述"
}
label: {
en: "Rule Description"
zh: "规则描述"
}
}
republish_function {
desc {
en: """Republish the message as a new MQTT message"""
zh: """将消息重新发布为新的 MQTT 消息"""
}
label: {
en: "Republish Function"
zh: "重新发布函数"
}
}
console_function {
desc {
en: """Print the outputs to the console"""
zh: "将输出打印到控制台"
}
label: {
en: "Console Function"
zh: "控制台函数"
}
}
user_provided_function_function {
desc {
en: """
The user provided function. Should be in the format: '{module}:{function}'.<br>
Where {module} is the Erlang callback module and {function} is the Erlang function.
<br>
To write your own function, checkout the function <code>console</code> and
<code>republish</code> in the source file:
<code>apps/emqx_rule_engine/src/emqx_rule_outputs.erl</code> as an example.
"""
zh: """
用户提供的函数。 格式应为:'{module}:{function}'。<br>
其中 {module} 是 Erlang 回调模块, {function} 是 Erlang 函数。<br>
要编写自己的函数,请检查源文件:<code>apps/emqx_rule_engine/src/emqx_rule_outputs.erl</code> 中的示例函数 <code>console</code> 和<code>republish</code> 。
"""
}
label: {
en: "User Provided Function"
zh: "用户提供的函数"
}
}
user_provided_function_args {
desc {
en: """
The args will be passed as the 3rd argument to module:function/3,
checkout the function <code>console</code> and <code>republish</code> in the source file:
<code>apps/emqx_rule_engine/src/emqx_rule_outputs.erl</code> as an example.
"""
zh: """
用户提供的参数将作为函数 module:function/3 的第三个参数,
请检查源文件:<code>apps/emqx_rule_engine/src/emqx_rule_outputs.erl</code> 中的示例函数 <code>console</code> 和<code>republish</code> 。
"""
}
label: {
en: "User Provided Function Args"
zh: "用户提供函数的参数"
}
}
republish_args_topic {
desc {
en: """
The target topic of message to be re-published.<br>
Template with variables is allowed, see description of the 'republish_args'.
"""
zh: """
重新发布消息的目标主题。<br>
允许使用带有变量的模板请参阅“republish_args”的描述。
"""
}
label: {
en: "Target Topic"
zh: "目标主题"
}
}
republish_args_qos {
desc {
en: """
The qos of the message to be re-published.
Template with variables is allowed, see description of the 'republish_args'.<br>
Defaults to ${qos}. If variable ${qos} is not found from the selected result of the rule,
0 is used.
"""
zh: """
要重新发布的消息的 qos。允许使用带有变量的模板请参阅“republish_args”的描述。<br>
默认为 ${qos}。 如果从规则的选择结果中没有找到变量 ${qos},则使用 0。
"""
}
label: {
en: "Message QoS"
zh: "消息 QoS 等级"
}
}
republish_args_retain {
desc {
en: """
The 'retain' flag of the message to be re-published.
Template with variables is allowed, see description of the 'republish_args'.<br>
Defaults to ${retain}. If variable ${retain} is not found from the selected result
of the rule, false is used.
"""
zh: """
要重新发布的消息的“保留”标志。允许使用带有变量的模板请参阅“republish_args”的描述。<br>
默认为 ${retain}。 如果从所选结果中未找到变量 ${retain},则使用 false。
"""
}
label: {
en: "Retain Flag"
zh: "保留消息标志"
}
}
republish_args_payload {
desc {
en: """
The payload of the message to be re-published.
Template with variables is allowed, see description of the 'republish_args'.<br>.
Defaults to ${payload}. If variable ${payload} is not found from the selected result
of the rule, then the string "undefined" is used.
"""
zh: """
要重新发布的消息的有效负载。允许使用带有变量的模板请参阅“republish_args”的描述。<br>。
默认为 ${payload}。 如果从所选结果中未找到变量 ${payload},则使用字符串 "undefined"。
"""
}
label: {
en: "Message Payload"
zh: "消息负载"
}
}
rule_engine_ignore_sys_message {
desc {
en: "When set to 'true' (default), rule-engine will ignore messages published to $SYS topics."
zh: "当设置为“true”默认规则引擎将忽略发布到 $SYS 主题的消息。"
}
label: {
en: "Ignore Sys Message"
zh: "忽略系统消息"
}
}
rule_engine_rules {
desc {
en: """The rules"""
zh: "规则"
}
label: {
en: "Rules"
zh: "规则"
}
}
}

View File

@ -3,6 +3,7 @@
-behaviour(hocon_schema).
-include_lib("typerefl/include/types.hrl").
-include_lib("hocon/include/hoconsc.hrl").
-include_lib("emqx/include/logger.hrl").
-export([ check_params/2
@ -30,10 +31,10 @@ check_params(Params, Tag) ->
%% Hocon Schema Definitions
roots() ->
[ {"rule_creation", sc(ref("rule_creation"), #{desc => "Schema for creating rules"})}
, {"rule_info", sc(ref("rule_info"), #{desc => "Schema for rule info"})}
, {"rule_events", sc(ref("rule_events"), #{desc => "Schema for rule events"})}
, {"rule_test", sc(ref("rule_test"), #{desc => "Schema for testing rules"})}
[ {"rule_creation", sc(ref("rule_creation"), #{desc => ?DESC("root_rule_creation")})}
, {"rule_info", sc(ref("rule_info"), #{desc => ?DESC("root_rule_info")})}
, {"rule_events", sc(ref("rule_events"), #{desc => ?DESC("root_rule_events")})}
, {"rule_test", sc(ref("rule_test"), #{desc => ?DESC("root_rule_test")})}
].
fields("rule_creation") ->
@ -41,14 +42,14 @@ fields("rule_creation") ->
fields("rule_info") ->
[ rule_id()
, {"metrics", sc(ref("metrics"), #{desc => "The metrics of the rule"})}
, {"metrics", sc(ref("metrics"), #{desc => ?DESC("ri_metrics")})}
, {"node_metrics", sc(hoconsc:array(ref("node_metrics")),
#{ desc => "The metrics of the rule for each node"
#{ desc => ?DESC("ri_node_metrics")
})}
, {"from", sc(hoconsc:array(binary()),
#{desc => "The topics of the rule", example => "t/#"})}
#{desc => ?DESC("ri_from"), example => "t/#"})}
, {"created_at", sc(binary(),
#{ desc => "The created time of the rule"
#{ desc => ?DESC("ri_created_at")
, example => "2021-12-01T15:00:43.153+08:00"
})}
] ++ fields("rule_creation");
@ -56,12 +57,12 @@ fields("rule_info") ->
%% TODO: we can delete this API if the Dashboard not depends on it
fields("rule_events") ->
ETopics = [binary_to_atom(emqx_rule_events:event_topic(E)) || E <- emqx_rule_events:event_names()],
[ {"event", sc(hoconsc:enum(ETopics), #{desc => "The event topics", required => true})}
, {"title", sc(binary(), #{desc => "The title", example => "some title"})}
, {"description", sc(binary(), #{desc => "The description", example => "some desc"})}
, {"columns", sc(map(), #{desc => "The columns"})}
, {"test_columns", sc(map(), #{desc => "The test columns"})}
, {"sql_example", sc(binary(), #{desc => "The sql_example"})}
[ {"event", sc(hoconsc:enum(ETopics), #{desc => ?DESC("rs_event"), required => true})}
, {"title", sc(binary(), #{desc => ?DESC("rs_title"), example => "some title"})}
, {"description", sc(binary(), #{desc => ?DESC("rs_description"), example => "some desc"})}
, {"columns", sc(map(), #{desc => ?DESC("rs_columns")})}
, {"test_columns", sc(map(), #{desc => ?DESC("rs_test_columns")})}
, {"sql_example", sc(binary(), #{desc => ?DESC("rs_sql_example")})}
];
fields("rule_test") ->
@ -77,183 +78,177 @@ fields("rule_test") ->
, ref("ctx_check_authz_complete")
, ref("ctx_bridge_mqtt")
]),
#{desc => "The context of the event for testing",
#{desc => ?DESC("test_context"),
default => #{}})}
, {"sql", sc(binary(), #{desc => "The SQL of the rule for testing", required => true})}
, {"sql", sc(binary(), #{desc => ?DESC("test_sql"), required => true})}
];
fields("metrics") ->
[ {"sql.matched", sc(non_neg_integer(), #{
desc => "How much times the FROM clause of the SQL is matched."
desc => ?DESC("metrics_sql_matched")
})}
, {"sql.matched.rate", sc(float(), #{desc => "The rate of matched, times/second"})}
, {"sql.matched.rate.max", sc(float(), #{desc => "The max rate of matched, times/second"})}
, {"sql.matched.rate", sc(float(), #{desc => ?DESC("metrics_sql_matched_rate") })}
, {"sql.matched.rate.max", sc(float(), #{desc => ?DESC("metrics_sql_matched_rate_max") })}
, {"sql.matched.rate.last5m", sc(float(),
#{desc => "The average rate of matched in last 5 minutes, times/second"})}
, {"sql.passed", sc(non_neg_integer(), #{desc => "How much times the SQL is passed"})}
, {"sql.failed", sc(non_neg_integer(), #{desc => "How much times the SQL is failed"})}
#{desc => ?DESC("metrics_sql_matched_rate_last5m") })}
, {"sql.passed", sc(non_neg_integer(), #{desc => ?DESC("metrics_sql_passed") })}
, {"sql.failed", sc(non_neg_integer(), #{desc => ?DESC("metrics_sql_failed") })}
, {"sql.failed.exception", sc(non_neg_integer(), #{
desc => "How much times the SQL is failed due to exceptions. "
"This may because of a crash when calling a SQL function, or "
"trying to do arithmetic operation on undefined variables"
desc => ?DESC("metrics_sql_failed_exception")
})}
, {"sql.failed.unknown", sc(non_neg_integer(), #{
desc => "How much times the SQL is failed due to an unknown error."
desc => ?DESC("metrics_sql_failed_unknown")
})}
, {"outputs.total", sc(non_neg_integer(), #{
desc => "How much times the outputs are called by the rule. "
"This value may several times of 'sql.matched', depending on the "
"number of the outputs of the rule."
desc => ?DESC("metrics_outputs_total")
})}
, {"outputs.success", sc(non_neg_integer(), #{
desc => "How much times the rule success to call the outputs."
desc => ?DESC("metrics_outputs_success")
})}
, {"outputs.failed", sc(non_neg_integer(), #{
desc => "How much times the rule failed to call the outputs."
desc => ?DESC("metrics_outputs_failed")
})}
, {"outputs.failed.out_of_service", sc(non_neg_integer(), #{
desc => "How much times the rule failed to call outputs due to the output is "
"out of service. For example, a bridge is disabled or stopped."
desc => ?DESC("metrics_outputs_failed_out_of_service")
})}
, {"outputs.failed.unknown", sc(non_neg_integer(), #{
desc => "How much times the rule failed to call outputs due to to an unknown error."
desc => ?DESC("metrics_outputs_failed_unknown")
})}
];
fields("node_metrics") ->
[ {"node", sc(binary(), #{desc => "The node name", example => "emqx@127.0.0.1"})}
[ {"node", sc(binary(), #{desc => ?DESC("node_node"), example => "emqx@127.0.0.1"})}
] ++ fields("metrics");
fields("ctx_pub") ->
[ {"event_type", sc(message_publish, #{desc => "Event Type", required => true})}
, {"id", sc(binary(), #{desc => "Message ID"})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"payload", sc(binary(), #{desc => "The Message Payload"})}
, {"peerhost", sc(binary(), #{desc => "The IP Address of the Peer Client"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
[ {"event_type", sc(message_publish, #{desc => ?DESC("event_event_type"), required => true})}
, {"id", sc(binary(), #{desc => ?DESC("event_id")})}
, {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})}
, {"username", sc(binary(), #{desc => ?DESC("event_username")})}
, {"payload", sc(binary(), #{desc => ?DESC("event_payload")})}
, {"peerhost", sc(binary(), #{desc => ?DESC("event_peerhost")})}
, {"topic", sc(binary(), #{desc => ?DESC("event_topic")})}
, {"publish_received_at", sc(integer(), #{
desc => "The Time that this Message is Received"})}
desc => ?DESC("event_publish_received_at")})}
] ++ [qos()];
fields("ctx_sub") ->
[ {"event_type", sc(session_subscribed, #{desc => "Event Type", required => true})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"payload", sc(binary(), #{desc => "The Message Payload"})}
, {"peerhost", sc(binary(), #{desc => "The IP Address of the Peer Client"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
[ {"event_type", sc(session_subscribed, #{desc => ?DESC("event_event_type"), required => true})}
, {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})}
, {"username", sc(binary(), #{desc => ?DESC("event_username")})}
, {"payload", sc(binary(), #{desc => ?DESC("event_payload")})}
, {"peerhost", sc(binary(), #{desc => ?DESC("event_peerhost")})}
, {"topic", sc(binary(), #{desc => ?DESC("event_topic")})}
, {"publish_received_at", sc(integer(), #{
desc => "The Time that this Message is Received"})}
desc => ?DESC("event_publish_received_at")})}
] ++ [qos()];
fields("ctx_unsub") ->
[{"event_type", sc(session_unsubscribed, #{desc => "Event Type", required => true})}] ++
[{"event_type", sc(session_unsubscribed, #{desc => ?DESC("event_event_type"), required => true})}] ++
proplists:delete("event_type", fields("ctx_sub"));
fields("ctx_delivered") ->
[ {"event_type", sc(message_delivered, #{desc => "Event Type", required => true})}
, {"id", sc(binary(), #{desc => "Message ID"})}
, {"from_clientid", sc(binary(), #{desc => "The Client ID"})}
, {"from_username", sc(binary(), #{desc => "The User Name"})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"payload", sc(binary(), #{desc => "The Message Payload"})}
, {"peerhost", sc(binary(), #{desc => "The IP Address of the Peer Client"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
[ {"event_type", sc(message_delivered, #{desc => ?DESC("event_event_type"), required => true})}
, {"id", sc(binary(), #{desc => ?DESC("event_id")})}
, {"from_clientid", sc(binary(), #{desc => ?DESC("event_from_clientid")})}
, {"from_username", sc(binary(), #{desc => ?DESC("event_from_username")})}
, {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})}
, {"username", sc(binary(), #{desc => ?DESC("event_username")})}
, {"payload", sc(binary(), #{desc => ?DESC("event_payload")})}
, {"peerhost", sc(binary(), #{desc => ?DESC("event_peerhost")})}
, {"topic", sc(binary(), #{desc => ?DESC("event_topic")})}
, {"publish_received_at", sc(integer(), #{
desc => "The Time that this Message is Received"})}
desc => ?DESC("event_publish_received_at")})}
] ++ [qos()];
fields("ctx_acked") ->
[{"event_type", sc(message_acked, #{desc => "Event Type", required => true})}] ++
[{"event_type", sc(message_acked, #{desc => ?DESC("event_event_type"), required => true})}] ++
proplists:delete("event_type", fields("ctx_delivered"));
fields("ctx_dropped") ->
[ {"event_type", sc(message_dropped, #{desc => "Event Type", required => true})}
, {"id", sc(binary(), #{desc => "Message ID"})}
, {"reason", sc(binary(), #{desc => "The Reason for Dropping"})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"payload", sc(binary(), #{desc => "The Message Payload"})}
, {"peerhost", sc(binary(), #{desc => "The IP Address of the Peer Client"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
[ {"event_type", sc(message_dropped, #{desc => ?DESC("event_event_type"), required => true})}
, {"id", sc(binary(), #{desc => ?DESC("event_id")})}
, {"reason", sc(binary(), #{desc => ?DESC("event_ctx_dropped")})}
, {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})}
, {"username", sc(binary(), #{desc => ?DESC("event_username")})}
, {"payload", sc(binary(), #{desc => ?DESC("event_payload")})}
, {"peerhost", sc(binary(), #{desc => ?DESC("event_peerhost")})}
, {"topic", sc(binary(), #{desc => ?DESC("event_topic")})}
, {"publish_received_at", sc(integer(), #{
desc => "The Time that this Message is Received"})}
desc => ?DESC("event_publish_received_at")})}
] ++ [qos()];
fields("ctx_connected") ->
[ {"event_type", sc(client_connected, #{desc => "Event Type", required => true})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"mountpoint", sc(binary(), #{desc => "The Mountpoint"})}
, {"peername", sc(binary(), #{desc => "The IP Address and Port of the Peer Client"})}
, {"sockname", sc(binary(), #{desc => "The IP Address and Port of the Local Listener"})}
, {"proto_name", sc(binary(), #{desc => "Protocol Name"})}
, {"proto_ver", sc(binary(), #{desc => "Protocol Version"})}
, {"keepalive", sc(integer(), #{desc => "KeepAlive"})}
, {"clean_start", sc(boolean(), #{desc => "Clean Start", default => true})}
, {"expiry_interval", sc(integer(), #{desc => "Expiry Interval"})}
, {"is_bridge", sc(boolean(), #{desc => "Is Bridge", default => false})}
[ {"event_type", sc(client_connected, #{desc => ?DESC("event_event_type"), required => true})}
, {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})}
, {"username", sc(binary(), #{desc => ?DESC("event_username")})}
, {"mountpoint", sc(binary(), #{desc => ?DESC("event_mountpoint")})}
, {"peername", sc(binary(), #{desc => ?DESC("event_peername")})}
, {"sockname", sc(binary(), #{desc => ?DESC("event_sockname")})}
, {"proto_name", sc(binary(), #{desc => ?DESC("event_proto_name")})}
, {"proto_ver", sc(binary(), #{desc => ?DESC("event_proto_ver")})}
, {"keepalive", sc(integer(), #{desc => ?DESC("event_keepalive")})}
, {"clean_start", sc(boolean(), #{desc => ?DESC("event_clean_start"), default => true})}
, {"expiry_interval", sc(integer(), #{desc => ?DESC("event_expiry_interval")})}
, {"is_bridge", sc(boolean(), #{desc => ?DESC("event_is_bridge"), default => false})}
, {"connected_at", sc(integer(), #{
desc => "The Time that this Client is Connected"})}
desc => ?DESC("event_connected_at")})}
];
fields("ctx_disconnected") ->
[ {"event_type", sc(client_disconnected, #{desc => "Event Type", required => true})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"reason", sc(binary(), #{desc => "The Reason for Disconnect"})}
, {"peername", sc(binary(), #{desc => "The IP Address and Port of the Peer Client"})}
, {"sockname", sc(binary(), #{desc => "The IP Address and Port of the Local Listener"})}
[ {"event_type", sc(client_disconnected, #{desc => ?DESC("event_event_type"), required => true})}
, {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})}
, {"username", sc(binary(), #{desc => ?DESC("event_username")})}
, {"reason", sc(binary(), #{desc => ?DESC("event_ctx_disconnected_reason")})}
, {"peername", sc(binary(), #{desc => ?DESC("event_peername")})}
, {"sockname", sc(binary(), #{desc => ?DESC("event_sockname")})}
, {"disconnected_at", sc(integer(), #{
desc => "The Time that this Client is Disconnected"})}
desc => ?DESC("event_ctx_disconnected_da")})}
];
fields("ctx_connack") ->
[ {"event_type", sc(client_connack, #{desc => "Event Type", required => true})}
, {"reason_code", sc(binary(), #{desc => "The reason code"})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"clean_start", sc(boolean(), #{desc => "Clean Start", default => true})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"peername", sc(binary(), #{desc => "The IP Address and Port of the Peer Client"})}
, {"sockname", sc(binary(), #{desc => "The IP Address and Port of the Local Listener"})}
, {"proto_name", sc(binary(), #{desc => "Protocol Name"})}
, {"proto_ver", sc(binary(), #{desc => "Protocol Version"})}
, {"keepalive", sc(integer(), #{desc => "KeepAlive"})}
, {"expiry_interval", sc(integer(), #{desc => "Expiry Interval"})}
[ {"event_type", sc(client_connack, #{desc => ?DESC("event_event_type"), required => true})}
, {"reason_code", sc(binary(), #{desc => ?DESC("event_ctx_connack_reason_code")})}
, {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})}
, {"clean_start", sc(boolean(), #{desc => ?DESC("event_clean_start"), default => true})}
, {"username", sc(binary(), #{desc => ?DESC("event_username")})}
, {"peername", sc(binary(), #{desc => ?DESC("event_peername")})}
, {"sockname", sc(binary(), #{desc => ?DESC("event_sockname")})}
, {"proto_name", sc(binary(), #{desc => ?DESC("event_proto_name")})}
, {"proto_ver", sc(binary(), #{desc => ?DESC("event_proto_ver")})}
, {"keepalive", sc(integer(), #{desc => ?DESC("event_keepalive")})}
, {"expiry_interval", sc(integer(), #{desc => ?DESC("event_expiry_interval")})}
, {"connected_at", sc(integer(), #{
desc => "The Time that this Client is Connected"})}
desc => ?DESC("event_connected_at")})}
];
fields("ctx_check_authz_complete") ->
[ {"event_type", sc(client_check_authz_complete, #{desc => "Event Type", required => true})}
, {"clientid", sc(binary(), #{desc => "The Client ID"})}
, {"username", sc(binary(), #{desc => "The User Name"})}
, {"peerhost", sc(binary(), #{desc => "The IP Address of the Peer Client"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
, {"action", sc(binary(), #{desc => "Publish or Subscribe"})}
, {"authz_source", sc(binary(), #{desc => "Cache, Plugs or Default"})}
, {"result", sc(binary(), #{desc => "Allow or Deny"})}
[ {"event_type", sc(client_check_authz_complete, #{desc => ?DESC("event_event_type"), required => true})}
, {"clientid", sc(binary(), #{desc => ?DESC("event_clientid")})}
, {"username", sc(binary(), #{desc => ?DESC("event_username")})}
, {"peerhost", sc(binary(), #{desc => ?DESC("event_peerhost")})}
, {"topic", sc(binary(), #{desc => ?DESC("event_topic")})}
, {"action", sc(binary(), #{desc => ?DESC("event_action")})}
, {"authz_source", sc(binary(), #{desc => ?DESC("event_authz_source")})}
, {"result", sc(binary(), #{desc => ?DESC("event_result")})}
];
fields("ctx_bridge_mqtt") ->
[ {"event_type", sc('$bridges/mqtt:*', #{desc => "Event Type", required => true})}
, {"id", sc(binary(), #{desc => "Message ID"})}
, {"payload", sc(binary(), #{desc => "The Message Payload"})}
, {"topic", sc(binary(), #{desc => "Message Topic"})}
, {"server", sc(binary(), #{desc => "The IP address (or hostname) and port of the MQTT broker,"
" in IP:Port format"})}
, {"dup", sc(binary(), #{desc => "The DUP flag of the MQTT message"})}
, {"retain", sc(binary(), #{desc => "If is a retain message"})}
[ {"event_type", sc('$bridges/mqtt:*', #{desc => ?DESC("event_event_type"), required => true})}
, {"id", sc(binary(), #{desc => ?DESC("event_id")})}
, {"payload", sc(binary(), #{desc => ?DESC("event_payload")})}
, {"topic", sc(binary(), #{desc => ?DESC("event_topic")})}
, {"server", sc(binary(), #{desc => ?DESC("event_server")})}
, {"dup", sc(binary(), #{desc => ?DESC("event_dup")})}
, {"retain", sc(binary(), #{desc => ?DESC("event_retain")})}
, {"message_received_at", sc(integer(), #{
desc => "The Time that this Message is Received"})}
desc => ?DESC("event_publish_received_at")})}
] ++ [qos()].
qos() ->
{"qos", sc(emqx_schema:qos(), #{desc => "The Message QoS"})}.
{"qos", sc(emqx_schema:qos(), #{desc => ?DESC("event_qos")})}.
rule_id() ->
{"id", sc(binary(),
#{ desc => "The ID of the rule", required => true
#{ desc => ?DESC("rule_id"), required => true
, example => "293fb66f"
})}.

View File

@ -18,6 +18,7 @@
-include("rule_engine.hrl").
-include_lib("emqx/include/logger.hrl").
-include_lib("hocon/include/hoconsc.hrl").
-include_lib("typerefl/include/types.hrl").
-behaviour(minirest_api).
@ -102,14 +103,14 @@ schema("/rules") ->
'operationId' => '/rules',
get => #{
tags => [<<"rules">>],
description => <<"List all rules">>,
description => ?DESC("api1"),
summary => <<"List Rules">>,
responses => #{
200 => mk(array(rule_info_schema()), #{desc => "List of rules"})
200 => mk(array(rule_info_schema()), #{desc => ?DESC("desc9")})
}},
post => #{
tags => [<<"rules">>],
description => <<"Create a new rule using given Id">>,
description => ?DESC("api2"),
summary => <<"Create a Rule">>,
'requestBody' => rule_creation_schema(),
responses => #{
@ -123,7 +124,7 @@ schema("/rule_events") ->
'operationId' => '/rule_events',
get => #{
tags => [<<"rules">>],
description => <<"List all events can be used in rules">>,
description => ?DESC("api3"),
summary => <<"List Events">>,
responses => #{
200 => mk(ref(emqx_rule_api_schema, "rule_events"), #{})
@ -136,7 +137,7 @@ schema("/rules/:id") ->
'operationId' => '/rules/:id',
get => #{
tags => [<<"rules">>],
description => <<"Get a rule by given Id">>,
description => ?DESC("api4"),
summary => <<"Get a Rule">>,
parameters => param_path_id(),
responses => #{
@ -146,7 +147,7 @@ schema("/rules/:id") ->
},
put => #{
tags => [<<"rules">>],
description => <<"Update a rule by given Id to all nodes in the cluster">>,
description => ?DESC("api5"),
summary => <<"Update a Rule">>,
parameters => param_path_id(),
'requestBody' => rule_creation_schema(),
@ -157,7 +158,7 @@ schema("/rules/:id") ->
},
delete => #{
tags => [<<"rules">>],
description => <<"Delete a rule by given Id from all nodes in the cluster">>,
description => ?DESC("api6"),
summary => <<"Delete a Rule">>,
parameters => param_path_id(),
responses => #{
@ -171,7 +172,7 @@ schema("/rules/:id/reset_metrics") ->
'operationId' => '/rules/:id/reset_metrics',
put => #{
tags => [<<"rules">>],
description => <<"Reset a rule metrics">>,
description => ?DESC("api7"),
summary => <<"Reset a Rule Metrics">>,
parameters => param_path_id(),
responses => #{
@ -186,7 +187,7 @@ schema("/rule_test") ->
'operationId' => '/rule_test',
post => #{
tags => [<<"rules">>],
description => <<"Test a rule">>,
description => ?DESC("api8"),
summary => <<"Test a Rule">>,
'requestBody' => rule_test_schema(),
responses => #{

View File

@ -17,6 +17,7 @@
-module(emqx_rule_engine_schema).
-include_lib("typerefl/include/types.hrl").
-include_lib("hocon/include/hoconsc.hrl").
-behaviour(hocon_schema).
@ -34,38 +35,21 @@ namespace() -> rule_engine.
roots() -> ["rule_engine"].
fields("rule_engine") ->
[ {ignore_sys_message, sc(boolean(), #{default => true, desc =>
"When set to 'true' (default), rule-engine will ignore messages published to $SYS topics."
[ {ignore_sys_message, sc(boolean(), #{default => true, desc => ?DESC("rule_engine_ignore_sys_message")
})}
, {rules, sc(hoconsc:map("id", ref("rules")), #{desc => "The rules", default => #{}})}
, {rules, sc(hoconsc:map("id", ref("rules")), #{desc => ?DESC("rule_engine_rules"), default => #{}})}
];
fields("rules") ->
[ rule_name()
, {"sql", sc(binary(),
#{ desc => "
SQL query to transform the messages.<br>
Example: <code>SELECT * FROM \"test/topic\" WHERE payload.x = 1</code><br>
"
#{ desc => ?DESC("rules_sql")
, example => "SELECT * FROM \"test/topic\" WHERE payload.x = 1"
, required => true
, validator => fun ?MODULE:validate_sql/1
})}
, {"outputs", sc(hoconsc:array(hoconsc:union(outputs())),
#{ desc => "
A list of outputs of the rule.<br>
An output can be a string that refers to the channel ID of an EMQX bridge, or an object
that refers to a function.<br>
There a some built-in functions like \"republish\" and \"console\", and we also support user
provided functions in the format: \"{module}:{function}\".<br>
The outputs in the list are executed sequentially.
This means that if one of the output is executing slowly, all the following outputs will not
be executed until it returns.<br>
If one of the output crashed, all other outputs come after it will still be executed, in the
original order.<br>
If there's any error when running an output, there will be an error message, and the 'failure'
counter of the function output or the bridge channel will increase.
"
#{ desc => ?DESC("rules_outputs")
, default => []
, example => [
<<"http:my_http_bridge">>,
@ -74,21 +58,21 @@ counter of the function output or the bridge channel will increase.
#{function => console}
]
})}
, {"enable", sc(boolean(), #{desc => "Enable or disable the rule", default => true})}
, {"enable", sc(boolean(), #{desc => ?DESC("rules_enable"), default => true})}
, {"description", sc(binary(),
#{ desc => "The description of the rule"
#{ desc => ?DESC("rules_description")
, example => "Some description"
, default => <<>>
})}
];
fields("builtin_output_republish") ->
[ {function, sc(republish, #{desc => "Republish the message as a new MQTT message"})}
[ {function, sc(republish, #{desc => ?DESC("republish_function")})}
, {args, sc(ref("republish_args"), #{default => #{}})}
];
fields("builtin_output_console") ->
[ {function, sc(console, #{desc => "Print the outputs to the console"})}
[ {function, sc(console, #{desc => ?DESC("console_function")})}
%% we may support some args for the console output in the future
%, {args, sc(map(), #{desc => "The arguments of the built-in 'console' output",
% default => #{}})}
@ -96,62 +80,33 @@ fields("builtin_output_console") ->
fields("user_provided_function") ->
[ {function, sc(binary(),
#{ desc => "
The user provided function. Should be in the format: '{module}:{function}'.<br>
Where {module} is the Erlang callback module and {function} is the Erlang function.
<br>
To write your own function, checkout the function <code>console</code> and
<code>republish</code> in the source file:
<code>apps/emqx_rule_engine/src/emqx_rule_outputs.erl</code> as an example.
"
#{ desc => ?DESC("user_provided_function_function")
, example => "module:function"
})}
, {args, sc(map(),
#{ desc => "
The args will be passed as the 3rd argument to module:function/3,
checkout the function <code>console</code> and <code>republish</code> in the source file:
<code>apps/emqx_rule_engine/src/emqx_rule_outputs.erl</code> as an example.
"
#{ desc => ?DESC("user_provided_function_args")
, default => #{}
})}
];
fields("republish_args") ->
[ {topic, sc(binary(),
#{ desc =>"
The target topic of message to be re-published.<br>
Template with variables is allowed, see description of the 'republish_args'.
"
#{ desc => ?DESC("republish_args_topic")
, required => true
, example => <<"a/1">>
})}
, {qos, sc(qos(),
#{ desc => "
The qos of the message to be re-published.
Template with variables is allowed, see description of the 'republish_args'.<br>
Defaults to ${qos}. If variable ${qos} is not found from the selected result of the rule,
0 is used.
"
#{ desc => ?DESC("republish_args_qos")
, default => <<"${qos}">>
, example => <<"${qos}">>
})}
, {retain, sc(hoconsc:union([binary(), boolean()]),
#{ desc => "
The 'retain' flag of the message to be re-published.
Template with variables is allowed, see description of the 'republish_args'.<br>
Defaults to ${retain}. If variable ${retain} is not found from the selected result
of the rule, false is used.
"
#{ desc => ?DESC("republish_args_retain")
, default => <<"${retain}">>
, example => <<"${retain}">>
})}
, {payload, sc(binary(),
#{ desc => "
The payload of the message to be re-published.
Template with variables is allowed, see description of the 'republish_args'.<br>.
Defaults to ${payload}. If variable ${payload} is not found from the selected result
of the rule, then the string \"undefined\" is used.
"
#{ desc => ?DESC("republish_args_payload")
, default => <<"${payload}">>
, example => <<"${payload}">>
})}
@ -191,7 +146,7 @@ desc(_) ->
rule_name() ->
{"name", sc(binary(),
#{ desc => "The name of the rule"
#{ desc => ?DESC("rules_name")
, default => ""
, required => true
, example => "foo"