feat: add emqx_conf_schema i18n conf

This commit is contained in:
Zhongwen Deng 2022-04-21 22:17:59 +08:00
parent d0d356ec12
commit 05b4ed58e0
3 changed files with 1459 additions and 1407 deletions

File diff suppressed because it is too large Load Diff

View File

@ -105,28 +105,27 @@ fields("cluster") ->
sc(atom(), sc(atom(),
#{ mapping => "ekka.cluster_name" #{ mapping => "ekka.cluster_name"
, default => emqxcl , default => emqxcl
, desc => "Human-friendly name of the EMQX cluster." , desc => ?DESC(cluster_name)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"discovery_strategy", , {"discovery_strategy",
sc(hoconsc:enum([manual, static, mcast, dns, etcd, k8s]), sc(hoconsc:enum([manual, static, mcast, dns, etcd, k8s]),
#{ default => manual #{ default => manual
, desc => "Service discovery method for the cluster nodes." , desc => ?DESC(cluster_discovery_strategy)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"autoclean", , {"autoclean",
sc(emqx_schema:duration(), sc(emqx_schema:duration(),
#{ mapping => "ekka.cluster_autoclean" #{ mapping => "ekka.cluster_autoclean"
, default => "5m" , default => "5m"
, desc => "Remove disconnected nodes from the cluster after this interval." , desc => ?DESC(cluster_autoclean)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"autoheal", , {"autoheal",
sc(boolean(), sc(boolean(),
#{ mapping => "ekka.cluster_autoheal" #{ mapping => "ekka.cluster_autoheal"
, default => true , default => true
, desc => "If <code>true</code>, the node will try to heal network partitions , desc => ?DESC(cluster_autoheal)
automatically."
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"proto_dist", , {"proto_dist",
@ -134,7 +133,7 @@ fields("cluster") ->
#{ mapping => "ekka.proto_dist" #{ mapping => "ekka.proto_dist"
, default => inet_tcp , default => inet_tcp
, 'readOnly' => true , 'readOnly' => true
, desc => "The Erlang distribution protocol for the cluster." , desc => ?DESC(cluster_proto_dist)
})} })}
, {"static", , {"static",
sc(ref(cluster_static), sc(ref(cluster_static),
@ -162,7 +161,7 @@ fields(cluster_static) ->
[ {"seeds", [ {"seeds",
sc(hoconsc:array(atom()), sc(hoconsc:array(atom()),
#{ default => [] #{ default => []
, desc => "List EMQX node names in the static cluster. See <code>node.name</code>." , desc => ?DESC(cluster_static_seeds)
, 'readOnly' => true , 'readOnly' => true
})} })}
]; ];
@ -171,50 +170,49 @@ fields(cluster_mcast) ->
[ {"addr", [ {"addr",
sc(string(), sc(string(),
#{ default => "239.192.0.1" #{ default => "239.192.0.1"
, desc => "Multicast IPv4 address." , desc => ?DESC(cluster_mcast_addr)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"ports", , {"ports",
sc(hoconsc:array(integer()), sc(hoconsc:array(integer()),
#{ default => [4369, 4370] #{ default => [4369, 4370]
, 'readOnly' => true , 'readOnly' => true
, desc => "List of UDP ports used for service discovery.<br/> , desc => ?DESC(cluster_mcast_ports)
Note: probe messages are broadcast to all the specified ports."
})} })}
, {"iface", , {"iface",
sc(string(), sc(string(),
#{ default => "0.0.0.0" #{ default => "0.0.0.0"
, desc => "Local IP address the node discovery service needs to bind to." , desc => ?DESC(cluster_mcast_iface)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"ttl", , {"ttl",
sc(range(0, 255), sc(range(0, 255),
#{ default => 255 #{ default => 255
, desc => "Time-to-live (TTL) for the outgoing UDP datagrams." , desc => ?DESC(cluster_mcast_ttl)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"loop", , {"loop",
sc(boolean(), sc(boolean(),
#{ default => true #{ default => true
, desc => "If <code>true</code>, loop UDP datagrams back to the local socket." , desc => ?DESC(cluster_mcast_loop)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"sndbuf", , {"sndbuf",
sc(emqx_schema:bytesize(), sc(emqx_schema:bytesize(),
#{ default => "16KB" #{ default => "16KB"
, desc => "Size of the kernel-level buffer for outgoing datagrams." , desc => ?DESC(cluster_mcast_sndbuf)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"recbuf", , {"recbuf",
sc(emqx_schema:bytesize(), sc(emqx_schema:bytesize(),
#{ default => "16KB" #{ default => "16KB"
, desc => "Size of the kernel-level buffer for incoming datagrams." , desc => ?DESC(cluster_mcast_recbuf)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"buffer", , {"buffer",
sc(emqx_schema:bytesize(), sc(emqx_schema:bytesize(),
#{ default =>"32KB" #{ default =>"32KB"
, desc => "Size of the user-level buffer." , desc => ?DESC(cluster_mcast_buffer)
, 'readOnly' => true , 'readOnly' => true
})} })}
]; ];
@ -223,13 +221,13 @@ fields(cluster_dns) ->
[ {"name", [ {"name",
sc(string(), sc(string(),
#{ default => "localhost" #{ default => "localhost"
, desc => "The domain name of the EMQX cluster." , desc => ?DESC(cluster_dns_name)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"app", , {"app",
sc(string(), sc(string(),
#{ default => "emqx" #{ default => "emqx"
, desc => "The symbolic name of the EMQX service." , desc => ?DESC(cluster_dns_app)
, 'readOnly' => true , 'readOnly' => true
})} })}
]; ];
@ -237,25 +235,24 @@ fields(cluster_dns) ->
fields(cluster_etcd) -> fields(cluster_etcd) ->
[ {"server", [ {"server",
sc(emqx_schema:comma_separated_list(), sc(emqx_schema:comma_separated_list(),
#{ desc => "List of endpoint URLs of the etcd cluster" #{ desc => ?DESC(cluster_etcd_server)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"prefix", , {"prefix",
sc(string(), sc(string(),
#{ default => "emqxcl" #{ default => "emqxcl"
, desc => "Key prefix used for EMQX service discovery." , desc => ?DESC(cluster_etcd_prefix)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"node_ttl", , {"node_ttl",
sc(emqx_schema:duration(), sc(emqx_schema:duration(),
#{ default => "1m" #{ default => "1m"
, 'readOnly' => true , 'readOnly' => true
, desc => "Expiration time of the etcd key associated with the node. , desc => ?DESC(cluster_etcd_node_ttl)
It is refreshed automatically, as long as the node is alive."
})} })}
, {"ssl", , {"ssl",
sc(hoconsc:ref(emqx_schema, ssl_client_opts), sc(hoconsc:ref(emqx_schema, ssl_client_opts),
#{ desc => "Options for the TLS connection to the etcd cluster." #{ desc => ?DESC(cluster_etcd_ssl)
, 'readOnly' => true , 'readOnly' => true
})} })}
]; ];
@ -263,42 +260,37 @@ It is refreshed automatically, as long as the node is alive."
fields(cluster_k8s) -> fields(cluster_k8s) ->
[ {"apiserver", [ {"apiserver",
sc(string(), sc(string(),
#{ desc => "Kubernetes API endpoint URL." #{ desc => ?DESC(cluster_k8s_apiserver)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"service_name", , {"service_name",
sc(string(), sc(string(),
#{ default => "emqx" #{ default => "emqx"
, desc => "EMQX broker service name." , desc => ?DESC(cluster_k8s_service_name)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"address_type", , {"address_type",
sc(hoconsc:enum([ip, dns, hostname]), sc(hoconsc:enum([ip, dns, hostname]),
#{ desc => "Address type used for connecting to the discovered nodes." #{ desc => ?DESC(cluster_k8s_address_type)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"app_name", , {"app_name",
sc(string(), sc(string(),
#{ default => "emqx" #{ default => "emqx"
, 'readOnly' => true , 'readOnly' => true
, desc => "This parameter should be set to the part of the <code>node.name</code> , desc => ?DESC(cluster_k8s_app_name)
before the '@'.<br/>
For example, if the <code>node.name</code> is <code>emqx@127.0.0.1</code>, then this parameter
should be set to <code>emqx</code>."
})} })}
, {"namespace", , {"namespace",
sc(string(), sc(string(),
#{ default => "default" #{ default => "default"
, desc => "Kubernetes namespace." , desc => ?DESC(cluster_k8s_namespace)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"suffix", , {"suffix",
sc(string(), sc(string(),
#{ default => "pod.local" #{ default => "pod.local"
, 'readOnly' => true , 'readOnly' => true
, desc => "Node name suffix.<br/> , desc => ?DESC(cluster_k8s_suffix)
Note: this parameter is only relevant when <code>address_type</code> is <code>dns</code>
or <code>hostname</code>."
})} })}
]; ];
@ -307,8 +299,7 @@ fields("node") ->
sc(string(), sc(string(),
#{ default => "emqx@127.0.0.1" #{ default => "emqx@127.0.0.1"
, 'readOnly' => true , 'readOnly' => true
, desc => "Unique name of the EMQX node. It must follow <code>%name%@FQDN</code> or , desc => ?DESC(node_name)
<code>%name%@IPv4</code> format."
})} })}
, {"cookie", , {"cookie",
sc(string(), sc(string(),
@ -316,65 +307,47 @@ fields("node") ->
default => "emqxsecretcookie", default => "emqxsecretcookie",
'readOnly' => true, 'readOnly' => true,
sensitive => true, sensitive => true,
desc => "Secret cookie is a random string that should be the same on all nodes in desc => ?DESC(node_cookie)
the given EMQX cluster, but unique per EMQX cluster. It is used to prevent EMQX nodes that
belong to different clusters from accidentally connecting to each other."
})} })}
, {"data_dir", , {"data_dir",
sc(string(), sc(string(),
#{ required => true, #{ required => true,
'readOnly' => true, 'readOnly' => true,
mapping => "emqx.data_dir", mapping => "emqx.data_dir",
desc => desc => ?DESC(node_data_dir)
"""
Path to the persistent data directory.
Possible auto-created subdirectories are:
- `mnesia/\<node_name>`: EMQX's built-in database directory.
For example, `mnesia/emqx@127.0.0.1`.
There should be only one such subdirectory.
Meaning, in case the node is to be renamed (to e.g. `emqx@10.0.1.1`),
the old dir should be deleted first.
- `configs`: Generated configs at boot time, and cluster/local override configs.
- `patches`: Hot-patch beam files are to be placed here.
- `trace`: Trace log files.
**NOTE**: One data dir cannot be shared by two or more EMQX nodes.
"""
})} })}
, {"config_files", , {"config_files",
sc(list(string()), sc(list(string()),
#{ mapping => "emqx.config_files" #{ mapping => "emqx.config_files"
, default => undefined , default => undefined
, 'readOnly' => true , 'readOnly' => true
, desc => "List of configuration files that are read during startup. The order is , desc => ?DESC(node_config_files)
significant: later configuration files override the previous ones."
})} })}
, {"global_gc_interval", , {"global_gc_interval",
sc(emqx_schema:duration(), sc(emqx_schema:duration(),
#{ mapping => "emqx_machine.global_gc_interval" #{ mapping => "emqx_machine.global_gc_interval"
, default => "15m" , default => "15m"
, desc => "Periodic garbage collection interval." , desc => ?DESC(node_global_gc_interval)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"crash_dump_file", , {"crash_dump_file",
sc(file(), sc(file(),
#{ mapping => "vm_args.-env ERL_CRASH_DUMP" #{ mapping => "vm_args.-env ERL_CRASH_DUMP"
, desc => "Location of the crash dump file" , desc => ?DESC(node_crash_dump_file)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"crash_dump_seconds", , {"crash_dump_seconds",
sc(emqx_schema:duration_s(), sc(emqx_schema:duration_s(),
#{ mapping => "vm_args.-env ERL_CRASH_DUMP_SECONDS" #{ mapping => "vm_args.-env ERL_CRASH_DUMP_SECONDS"
, default => "30s" , default => "30s"
, desc => "The number of seconds that the broker is allowed to spend writing , desc => ?DESC(node_crash_dump_seconds)
a crash dump"
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"crash_dump_bytes", , {"crash_dump_bytes",
sc(emqx_schema:bytesize(), sc(emqx_schema:bytesize(),
#{ mapping => "vm_args.-env ERL_CRASH_DUMP_BYTES" #{ mapping => "vm_args.-env ERL_CRASH_DUMP_BYTES"
, default => "100MB" , default => "100MB"
, desc => "The maximum size of a crash dump file in bytes." , desc => ?DESC(node_crash_dump_bytes)
, 'readOnly' => true , 'readOnly' => true
})} })}
, {"dist_net_ticktime", , {"dist_net_ticktime",
@ -382,28 +355,25 @@ a crash dump"
#{ mapping => "vm_args.-kernel net_ticktime" #{ mapping => "vm_args.-kernel net_ticktime"
, default => "2m" , default => "2m"
, 'readOnly' => true , 'readOnly' => true
, desc => "This is the approximate time an EMQX node may be unresponsive " , desc => ?DESC(node_dist_net_ticktime)
"until it is considered down and thereby disconnected."
})} })}
, {"backtrace_depth", , {"backtrace_depth",
sc(integer(), sc(integer(),
#{ mapping => "emqx_machine.backtrace_depth" #{ mapping => "emqx_machine.backtrace_depth"
, default => 23 , default => 23
, 'readOnly' => true , 'readOnly' => true
, desc => "Maximum depth of the call stack printed in error messages and , desc => ?DESC(node_backtrace_depth)
<code>process_info</code>."
})} })}
, {"applications", , {"applications",
sc(emqx_schema:comma_separated_atoms(), sc(emqx_schema:comma_separated_atoms(),
#{ mapping => "emqx_machine.applications" #{ mapping => "emqx_machine.applications"
, default => [] , default => []
, 'readOnly' => true , 'readOnly' => true
, desc => "List of Erlang applications that shall be rebooted when the EMQX broker joins , desc => ?DESC(node_applications)
the cluster."
})} })}
, {"etc_dir", , {"etc_dir",
sc(string(), sc(string(),
#{ desc => "<code>etc</code> dir for the node" #{ desc => ?DESC(node_etc_dir)
, 'readOnly' => true , 'readOnly' => true
} }
)} )}
@ -420,81 +390,45 @@ fields("db") ->
#{ mapping => "mria.db_backend" #{ mapping => "mria.db_backend"
, default => rlog , default => rlog
, 'readOnly' => true , 'readOnly' => true
, desc => """ , desc => ?DESC(db_backend)
Select the backend for the embedded database.<br/>
<code>rlog</code> is the default backend,
that is suitable for very large clusters.<br/>
<code>mnesia</code> is a backend that offers decent performance in small clusters.
"""
})} })}
, {"role", , {"role",
sc(hoconsc:enum([core, replicant]), sc(hoconsc:enum([core, replicant]),
#{ mapping => "mria.node_role" #{ mapping => "mria.node_role"
, default => core , default => core
, 'readOnly' => true , 'readOnly' => true
, desc => """ , desc => ?DESC(db_role)
Select a node role.<br/>
<code>core</code> nodes provide durability of the data, and take care of writes.
It is recommended to place core nodes in different racks or different availability zones.<br/>
<code>replicant</code> nodes are ephemeral worker nodes. Removing them from the cluster
doesn't affect database redundancy<br/>
It is recommended to have more replicant nodes than core nodes.<br/>
Note: this parameter only takes effect when the <code>backend</code> is set
to <code>rlog</code>.
"""
})} })}
, {"core_nodes", , {"core_nodes",
sc(emqx_schema:comma_separated_atoms(), sc(emqx_schema:comma_separated_atoms(),
#{ mapping => "mria.core_nodes" #{ mapping => "mria.core_nodes"
, default => [] , default => []
, 'readOnly' => true , 'readOnly' => true
, desc => """ , desc => ?DESC(db_core_nodes)
List of core nodes that the replicant will connect to.<br/>
Note: this parameter only takes effect when the <code>backend</code> is set
to <code>rlog</code> and the <code>role</code> is set to <code>replicant</code>.<br/>
This value needs to be defined for manual or static cluster discovery mechanisms.<br/>
If an automatic cluster discovery mechanism is being used (such as <code>etcd</code>),
there is no need to set this value.
"""
})} })}
, {"rpc_module", , {"rpc_module",
sc(hoconsc:enum([gen_rpc, rpc]), sc(hoconsc:enum([gen_rpc, rpc]),
#{ mapping => "mria.rlog_rpc_module" #{ mapping => "mria.rlog_rpc_module"
, default => gen_rpc , default => gen_rpc
, 'readOnly' => true , 'readOnly' => true
, desc => """ , desc => ?DESC(db_rpc_module)
Protocol used for pushing transaction logs to the replicant nodes.
"""
})} })}
, {"tlog_push_mode", , {"tlog_push_mode",
sc(hoconsc:enum([sync, async]), sc(hoconsc:enum([sync, async]),
#{ mapping => "mria.tlog_push_mode" #{ mapping => "mria.tlog_push_mode"
, default => async , default => async
, 'readOnly' => true , 'readOnly' => true
, desc => """ , desc => ?DESC(db_tlog_push_mode)
In sync mode the core node waits for an ack from the replicant nodes before sending the next
transaction log entry.
"""
})} })}
, {"default_shard_transport", , {"default_shard_transport",
sc(hoconsc:enum([gen_rpc, distr]), sc(hoconsc:enum([gen_rpc, distr]),
#{ mapping => "mria.shard_transport" #{ mapping => "mria.shard_transport"
, default => gen_rpc , default => gen_rpc
, desc => , desc => ?DESC(db_default_shard_transport)
"Defines the default transport for pushing transaction logs.<br/>"
"This may be overridden on a per-shard basis in <code>db.shard_transports</code>."
"<code>gen_rpc</code> uses the <code>gen_rpc</code> library, "
"<code>distr</code> uses the Erlang distribution.<br/>"
})} })}
, {"shard_transports", , {"shard_transports",
sc(map(shard, hoconsc:enum([gen_rpc, distr])), sc(map(shard, hoconsc:enum([gen_rpc, distr])),
#{ desc => #{ desc => ?DESC(db_shard_transports)
"Allows to tune the transport method used for transaction log replication, "
"on a per-shard basis.<br/>"
"<code>gen_rpc</code> uses the <code>gen_rpc</code> library, "
"<code>distr</code> uses the Erlang distribution.<br/>"
"If not specified, the default is to use the value "
"set in <code>db.default_shard_transport</code>."
, mapping => "emqx_machine.custom_shard_transports" , mapping => "emqx_machine.custom_shard_transports"
, default => #{} , default => #{}
})} })}
@ -503,19 +437,17 @@ transaction log entry.
fields("cluster_call") -> fields("cluster_call") ->
[ {"retry_interval", [ {"retry_interval",
sc(emqx_schema:duration(), sc(emqx_schema:duration(),
#{ desc => "Time interval to retry after a failed call." #{ desc => ?DESC(cluster_call_retry_interval)
, default => "1s" , default => "1s"
})} })}
, {"max_history", , {"max_history",
sc(range(1, 500), sc(range(1, 500),
#{ desc => "Retain the maximum number of completed transactions (for queries)." #{ desc => ?DESC(cluster_call_max_history)
, default => 100 , default => 100
})} })}
, {"cleanup_interval", , {"cleanup_interval",
sc(emqx_schema:duration(), sc(emqx_schema:duration(),
#{ desc => #{ desc => ?DESC(cluster_call_cleanup_interval)
"Time interval to clear completed but stale transactions.
Ensure that the number of completed transactions is less than the <code>max_history</code>."
, default => "5m" , default => "5m"
})} })}
]; ];
@ -524,136 +456,118 @@ fields("rpc") ->
[ {"mode", [ {"mode",
sc(hoconsc:enum([sync, async]), sc(hoconsc:enum([sync, async]),
#{ default => async #{ default => async
, desc => "In <code>sync</code> mode the sending side waits for the ack from the " , desc => ?DESC(rpc_mode)
"receiving side."
})} })}
, {"driver", , {"driver",
sc(hoconsc:enum([tcp, ssl]), sc(hoconsc:enum([tcp, ssl]),
#{ mapping => "gen_rpc.driver" #{ mapping => "gen_rpc.driver"
, default => tcp , default => tcp
, desc => "Transport protocol used for inter-broker communication" , desc => ?DESC(rpc_driver)
})} })}
, {"async_batch_size", , {"async_batch_size",
sc(integer(), sc(integer(),
#{ mapping => "gen_rpc.max_batch_size" #{ mapping => "gen_rpc.max_batch_size"
, default => 256 , default => 256
, desc => "The maximum number of batch messages sent in asynchronous mode. " , desc => ?DESC(rpc_async_batch_size)
"Note that this configuration does not work in synchronous mode."
})} })}
, {"port_discovery", , {"port_discovery",
sc(hoconsc:enum([manual, stateless]), sc(hoconsc:enum([manual, stateless]),
#{ mapping => "gen_rpc.port_discovery" #{ mapping => "gen_rpc.port_discovery"
, default => stateless , default => stateless
, desc => "<code>manual</code>: discover ports by <code>tcp_server_port</code>.<br/>" , desc => ?DESC(rpc_port_discovery)
"<code>stateless</code>: discover ports in a stateless manner, "
"using the following algorithm. "
"If node name is <code>emqxN@127.0.0.1</code>, where the N is an integer, "
"then the listening port will be 5370 + N."
})} })}
, {"tcp_server_port", , {"tcp_server_port",
sc(integer(), sc(integer(),
#{ mapping => "gen_rpc.tcp_server_port" #{ mapping => "gen_rpc.tcp_server_port"
, default => 5369 , default => 5369
, desc => "Listening port used by RPC local service.<br/> " , desc => ?DESC(rpc_tcp_server_port)
"Note that this config only takes effect when rpc.port_discovery "
"is set to manual."
})} })}
, {"ssl_server_port", , {"ssl_server_port",
sc(integer(), sc(integer(),
#{ mapping => "gen_rpc.ssl_server_port" #{ mapping => "gen_rpc.ssl_server_port"
, default => 5369 , default => 5369
, desc => "Listening port used by RPC local service.<br/> " , desc => ?DESC(rpc_ssl_server_port)
"Note that this config only takes effect when rpc.port_discovery "
"is set to manual and <code>driver</code> is set to <code>ssl</code>."
})} })}
, {"tcp_client_num", , {"tcp_client_num",
sc(range(1, 256), sc(range(1, 256),
#{ default => 10 #{ default => 10
, desc => "Set the maximum number of RPC communication channels initiated by this node " , desc => ?DESC(rpc_tcp_client_num)
"to each remote node."
})} })}
, {"connect_timeout", , {"connect_timeout",
sc(emqx_schema:duration(), sc(emqx_schema:duration(),
#{ mapping => "gen_rpc.connect_timeout" #{ mapping => "gen_rpc.connect_timeout"
, default => "5s" , default => "5s"
, desc => "Timeout for establishing an RPC connection." , desc => ?DESC(rpc_connect_timeout)
})} })}
, {"certfile", , {"certfile",
sc(file(), sc(file(),
#{ mapping => "gen_rpc.certfile" #{ mapping => "gen_rpc.certfile"
, desc => "Path to TLS certificate file used to validate identity of the cluster nodes. " , desc => ?DESC(rpc_certfile)
"Note that this config only takes effect when <code>rpc.driver</code> "
"is set to <code>ssl</code>."
})} })}
, {"keyfile", , {"keyfile",
sc(file(), sc(file(),
#{ mapping => "gen_rpc.keyfile" #{ mapping => "gen_rpc.keyfile"
, desc => "Path to the private key file for the <code>rpc.certfile</code>.<br/>" , desc => ?DESC(rpc_keyfile)
"Note: contents of this file are secret, so "
"it's necessary to set permissions to 600."
})} })}
, {"cacertfile", , {"cacertfile",
sc(file(), sc(file(),
#{ mapping => "gen_rpc.cacertfile" #{ mapping => "gen_rpc.cacertfile"
, desc => "Path to certification authority TLS certificate file used to validate " , desc => ?DESC(rpc_cacertfile)
"<code>rpc.certfile</code>.<br/>"
"Note: certificates of all nodes in the cluster must be signed by the same CA."
})} })}
, {"send_timeout", , {"send_timeout",
sc(emqx_schema:duration(), sc(emqx_schema:duration(),
#{ mapping => "gen_rpc.send_timeout" #{ mapping => "gen_rpc.send_timeout"
, default => "5s" , default => "5s"
, desc => "Timeout for sending the RPC request." , desc => ?DESC(rpc_send_timeout)
})} })}
, {"authentication_timeout", , {"authentication_timeout",
sc(emqx_schema:duration(), sc(emqx_schema:duration(),
#{ mapping=> "gen_rpc.authentication_timeout" #{ mapping=> "gen_rpc.authentication_timeout"
, default => "5s" , default => "5s"
, desc => "Timeout for the remote node authentication." , desc => ?DESC(rpc_authentication_timeout)
})} })}
, {"call_receive_timeout", , {"call_receive_timeout",
sc(emqx_schema:duration(), sc(emqx_schema:duration(),
#{ mapping => "gen_rpc.call_receive_timeout" #{ mapping => "gen_rpc.call_receive_timeout"
, default => "15s" , default => "15s"
, desc => "Timeout for the reply to a synchronous RPC." , desc => ?DESC(rpc_call_receive_timeout)
})} })}
, {"socket_keepalive_idle", , {"socket_keepalive_idle",
sc(emqx_schema:duration_s(), sc(emqx_schema:duration_s(),
#{ mapping => "gen_rpc.socket_keepalive_idle" #{ mapping => "gen_rpc.socket_keepalive_idle"
, default => "7200s" , default => "7200s"
, desc => "How long the connections between the brokers " , desc => ?DESC(rpc_socket_keepalive_idle)
"should remain open after the last message is sent."
})} })}
, {"socket_keepalive_interval", , {"socket_keepalive_interval",
sc(emqx_schema:duration_s(), sc(emqx_schema:duration_s(),
#{ mapping => "gen_rpc.socket_keepalive_interval" #{ mapping => "gen_rpc.socket_keepalive_interval"
, default => "75s" , default => "75s"
, desc => "The interval between keepalive messages." , desc => ?DESC(rpc_socket_keepalive_interval)
})} })}
, {"socket_keepalive_count", , {"socket_keepalive_count",
sc(integer(), sc(integer(),
#{ mapping => "gen_rpc.socket_keepalive_count" #{ mapping => "gen_rpc.socket_keepalive_count"
, default => 9 , default => 9
, desc => "How many times the keepalive probe message can fail to receive a reply " , desc => ?DESC(rpc_socket_keepalive_count)
"until the RPC connection is considered lost."
})} })}
, {"socket_sndbuf", , {"socket_sndbuf",
sc(emqx_schema:bytesize(), sc(emqx_schema:bytesize(),
#{ mapping => "gen_rpc.socket_sndbuf" #{ mapping => "gen_rpc.socket_sndbuf"
, default => "1MB" , default => "1MB"
, desc => "TCP tuning parameters. TCP sending buffer size." , desc => ?DESC(rpc_socket_sndbuf)
})} })}
, {"socket_recbuf", , {"socket_recbuf",
sc(emqx_schema:bytesize(), sc(emqx_schema:bytesize(),
#{ mapping => "gen_rpc.socket_recbuf" #{ mapping => "gen_rpc.socket_recbuf"
, default => "1MB" , default => "1MB"
, desc => "TCP tuning parameters. TCP receiving buffer size." , desc => ?DESC(rpc_socket_recbuf)
})} })}
, {"socket_buffer", , {"socket_buffer",
sc(emqx_schema:bytesize(), sc(emqx_schema:bytesize(),
#{ mapping => "gen_rpc.socket_buffer" #{ mapping => "gen_rpc.socket_buffer"
, default => "1MB" , default => "1MB"
, desc => "TCP tuning parameters. Socket buffer size in user mode." , desc => ?DESC(rpc_socket_buffer)
})} })}
]; ];
@ -1094,15 +1008,5 @@ emqx_schema_high_prio_roots() ->
Roots = emqx_schema:roots(high), Roots = emqx_schema:roots(high),
Authz = {"authorization", Authz = {"authorization",
sc(hoconsc:ref(?MODULE, "authorization"), sc(hoconsc:ref(?MODULE, "authorization"),
#{ desc => """ #{ desc => ?DESC(authorization)})},
Authorization a.k.a. ACL.<br>
In EMQX, MQTT client access control is extremely flexible.<br>
An out-of-the-box set of authorization data sources are supported.
For example,<br>
'file' source is to support concise and yet generic ACL rules in a file;<br>
'built_in_database' source can be used to store per-client customizable rule sets,
natively in the EMQX node;<br>
'http' source to make EMQX call an external HTTP API to make the decision;<br>
'PostgreSQL' etc. to look up clients or rules from external databases;<br>
""" })},
lists:keyreplace("authorization", 1, Roots, Authz). lists:keyreplace("authorization", 1, Roots, Authz).

View File

@ -313,7 +313,7 @@ next_interval() ->
sample(Time) -> sample(Time) ->
Fun = Fun =
fun(Key, Res) -> fun(Key, Res) ->
maps:put(Key, value(Key), Res) maps:put(Key, getstats(Key), Res)
end, end,
Data = lists:foldl(Fun, #{}, ?SAMPLER_LIST), Data = lists:foldl(Fun, #{}, ?SAMPLER_LIST),
#emqx_monit{time = Time, data = Data}. #emqx_monit{time = Time, data = Data}.
@ -362,11 +362,17 @@ count_map(M1, M2) ->
end, end,
lists:foldl(Fun, #{}, ?SAMPLER_LIST). lists:foldl(Fun, #{}, ?SAMPLER_LIST).
value(connections) -> emqx_stats:getstat('connections.count'); getstats(Key) ->
value(topics) -> emqx_stats:getstat('topics.count'); %% Stats ets maybe not exist when ekka join.
value(subscriptions) -> emqx_stats:getstat('subscriptions.count'); try stats(Key)
value(received) -> emqx_metrics:val('messages.received'); catch _: _ -> 0
value(received_bytes) -> emqx_metrics:val('bytes.received'); end.
value(sent) -> emqx_metrics:val('messages.sent');
value(sent_bytes) -> emqx_metrics:val('bytes.sent'); stats(connections) -> emqx_stats:getstat('connections.count');
value(dropped) -> emqx_metrics:val('messages.dropped'). stats(topics) -> emqx_stats:getstat('topics.count');
stats(subscriptions) -> emqx_stats:getstat('subscriptions.count');
stats(received) -> emqx_metrics:val('messages.received');
stats(received_bytes) -> emqx_metrics:val('bytes.received');
stats(sent) -> emqx_metrics:val('messages.sent');
stats(sent_bytes) -> emqx_metrics:val('bytes.sent');
stats(dropped) -> emqx_metrics:val('messages.dropped').