diff --git a/apps/emqx/etc/emqx.conf b/apps/emqx/etc/emqx.conf
index e6249a039..286be934f 100644
--- a/apps/emqx/etc/emqx.conf
+++ b/apps/emqx/etc/emqx.conf
@@ -1016,7 +1016,7 @@ broker {
## - local: only lock the session locally on the current node
## - one: select only one remove node to lock the session
## - quorum: select some nodes to lock the session
- ## - all: lock the session on all of the nodes in the cluster
+ ## - all: lock the session on all the nodes in the cluster
## Default: quorum
session_locking_strategy = quorum
@@ -1027,7 +1027,7 @@ broker {
## - random: dispatch the message to a random selected subscriber
## - round_robin: select the subscribers in a round-robin manner
## - sticky: always use the last selected subscriber to dispatch,
- ## until the susbcriber disconnected.
+ ## until the subscriber disconnected.
## - hash: select the subscribers by the hash of clientIds
## Default: round_robin
shared_subscription_strategy = round_robin
diff --git a/apps/emqx/src/emqx_limiter/src/emqx_limiter_schema.erl b/apps/emqx/src/emqx_limiter/src/emqx_limiter_schema.erl
index f4c403b56..8421a7399 100644
--- a/apps/emqx/src/emqx_limiter/src/emqx_limiter_schema.erl
+++ b/apps/emqx/src/emqx_limiter/src/emqx_limiter_schema.erl
@@ -107,8 +107,8 @@ fields(limiter_opts) ->
[ {rate, sc(rate(), #{default => "infinity", desc => "The rate"})}
, {burst, sc(burst_rate(),
#{default => "0/0s",
- desc => "The burst, This value is based on rate."
- " This value + rate = the maximum limit that can be achieved when limiter burst"
+ desc => "The burst, This value is based on rate.
+ This value + rate = the maximum limit that can be achieved when limiter burst."
})}
, {bucket, sc(map("bucket name", ref(bucket_opts)), #{desc => "Buckets config"})}
];
@@ -121,7 +121,7 @@ fields(bucket_opts) ->
, {per_client, sc(ref(client_bucket),
#{default => #{},
desc => "The rate limit for each user of the bucket,"
- "this field is not required"
+ " this field is not required"
})}
];
diff --git a/apps/emqx/src/emqx_schema.erl b/apps/emqx/src/emqx_schema.erl
index 022ab3664..b54ff2356 100644
--- a/apps/emqx/src/emqx_schema.erl
+++ b/apps/emqx/src/emqx_schema.erl
@@ -936,7 +936,12 @@ fields("ws_opts") ->
{"mqtt_path",
sc(
string(),
- #{default => "/mqtt"}
+ #{
+ default => "/mqtt",
+ desc =>
+ "WebSocket's MQTT protocol path. So the address of\n"
+ " EMQX Broker's WebSocket is: ws://{ip}:{port}/mqtt
"
+ }
)},
{"mqtt_piggyback",
sc(
@@ -946,52 +951,99 @@ fields("ws_opts") ->
{"compress",
sc(
boolean(),
- #{default => false}
+ #{
+ default => false,
+ desc =>
+ "If true
, compress WebSocket messages using zlib
.
\n"
+ " The configuration items under deflate_opts
belong to the compression-related parameter configuration."
+ }
)},
{"idle_timeout",
sc(
duration(),
- #{default => "15s"}
+ #{
+ default => "15s",
+ desc =>
+ "The idle time after the TCP connection is established
\n"
+ " If no packets are received within this time, the connection will be closed."
+ }
)},
{"max_frame_size",
sc(
hoconsc:union([infinity, integer()]),
- #{default => infinity}
+ #{
+ default => infinity,
+ desc => "The maximum length of a single MQTT packet."
+ }
)},
{"fail_if_no_subprotocol",
sc(
boolean(),
- #{default => true}
+ #{
+ default => true,
+ desc =>
+ "If true
, the server will return an error when\n"
+ " the client does not carry the Sec-WebSocket-Protocol
field.\n"
+ "
Note: WeChat applet needs to disable this verification."
+ }
)},
{"supported_subprotocols",
sc(
comma_separated_list(),
- #{default => "mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5"}
+ #{
+ default => "mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5",
+ desc => "Comma-separated list of supported subprotocols."
+ }
)},
{"check_origin_enable",
sc(
boolean(),
- #{default => false}
+ #{
+ default => false,
+ desc =>
+ "If true
, origin
HTTP header will be\n"
+ " validated against the list of allowed origins configured in check_origins
\n"
+ " parameter."
+ }
)},
{"allow_origin_absence",
sc(
boolean(),
- #{default => true}
+ #{
+ default => true,
+ desc =>
+ "If false
and check_origin_enable
is\n"
+ " true
, the server will reject requests that don't have origin
\n"
+ " HTTP header."
+ }
)},
{"check_origins",
sc(
hoconsc:array(binary()),
- #{default => []}
+ #{
+ default => [],
+ desc => "List of allowed origins.
See check_origin_enable
."
+ }
)},
{"proxy_address_header",
sc(
string(),
- #{default => "x-forwarded-for"}
+ #{
+ default => "x-forwarded-for",
+ desc =>
+ "HTTP header used to pass information about the client IP address.\n"
+ " Relevant when the EMQX cluster is deployed behind a load-balancer."
+ }
)},
{"proxy_port_header",
sc(
string(),
- #{default => "x-forwarded-port"}
+ #{
+ default => "x-forwarded-port",
+ desc =>
+ "HTTP header used to pass information about the client port.\n"
+ " Relevant when the EMQX cluster is deployed behind a load-balancer."
+ }
)},
{"deflate_opts",
sc(
@@ -1004,52 +1056,79 @@ fields("tcp_opts") ->
{"active_n",
sc(
integer(),
- #{default => 100}
+ #{
+ default => 100,
+ desc =>
+ "Specify the {active, N} option for this Socket.
\n"
+ " See: https://erlang.org/doc/man/inet.html#setopts-2"
+ }
)},
{"backlog",
sc(
integer(),
- #{default => 1024}
+ #{
+ default => 1024,
+ desc =>
+ "TCP backlog defines the maximum length that the queue of\n"
+ " pending connections can grow to."
+ }
)},
{"send_timeout",
sc(
duration(),
- #{default => "15s"}
+ #{
+ default => "15s",
+ desc => "The TCP send timeout for the connections."
+ }
)},
{"send_timeout_close",
sc(
boolean(),
- #{default => true}
+ #{
+ default => true,
+ desc => "Close the connection if send timeout."
+ }
)},
{"recbuf",
sc(
bytesize(),
- #{}
+ #{desc => "The TCP receive buffer (OS kernel) for the connections."}
)},
{"sndbuf",
sc(
bytesize(),
- #{}
+ #{desc => "The TCP send buffer (OS kernel) for the connections."}
)},
{"buffer",
sc(
bytesize(),
- #{}
+ #{desc => "The size of the user-space buffer used by the driver."}
)},
{"high_watermark",
sc(
bytesize(),
- #{default => "1MB"}
+ #{
+ default => "1MB",
+ desc =>
+ "The socket is set to a busy state when the amount of data queued internally\n"
+ " by the VM socket implementation reaches this limit."
+ }
)},
{"nodelay",
sc(
boolean(),
- #{default => false}
+ #{
+ default => false,
+ desc => "The TCP_NODELAY flag for the connections."
+ }
)},
{"reuseaddr",
sc(
boolean(),
- #{default => true}
+ #{
+ default => true,
+ desc => "The SO_REUSEADDR flag for the connections."
+ }
)}
];
fields("listener_ssl_opts") ->
@@ -1079,37 +1158,56 @@ fields("deflate_opts") ->
{"level",
sc(
hoconsc:enum([none, default, best_compression, best_speed]),
- #{}
+ #{desc => "Compression level."}
)},
{"mem_level",
sc(
range(1, 9),
- #{default => 8}
+ #{
+ default => 8,
+ desc =>
+ "Specifies the size of the compression state.
\n"
+ " Lower values decrease memory usage per connection."
+ }
)},
{"strategy",
sc(
hoconsc:enum([default, filtered, huffman_only, rle]),
- #{}
+ #{desc => "Specifies the compression strategy."}
)},
{"server_context_takeover",
sc(
hoconsc:enum([takeover, no_takeover]),
- #{}
+ #{
+ desc =>
+ "Takeover means the compression state is retained\n"
+ " between server messages."
+ }
)},
{"client_context_takeover",
sc(
hoconsc:enum([takeover, no_takeover]),
- #{}
+ #{
+ desc =>
+ "Takeover means the compression state is retained\n"
+ " between client messages."
+ }
)},
{"server_max_window_bits",
sc(
range(8, 15),
- #{default => 15}
+ #{
+ default => 15,
+ desc => "Specifies the size of the compression context for the server."
+ }
)},
{"client_max_window_bits",
sc(
range(8, 15),
- #{default => 15}
+ #{
+ default => 15,
+ desc => "Specifies the size of the compression context for the client."
+ }
)}
];
fields("broker") ->
@@ -1117,27 +1215,57 @@ fields("broker") ->
{"enable_session_registry",
sc(
boolean(),
- #{default => true}
+ #{
+ default => true,
+ desc => "Enable session registry"
+ }
)},
{"session_locking_strategy",
sc(
hoconsc:enum([local, leader, quorum, all]),
- #{default => quorum}
+ #{
+ default => quorum,
+ desc =>
+ "Session locking strategy in a cluster.
\n"
+ " - `local`: only lock the session on the current node\n"
+ " - `one`: select only one remove node to lock the session\n"
+ " - `quorum`: select some nodes to lock the session\n"
+ " - `all`: lock the session on all the nodes in the cluster"
+ }
)},
{"shared_subscription_strategy",
sc(
hoconsc:enum([random, round_robin, sticky, hash_topic, hash_clientid]),
- #{default => round_robin}
+ #{
+ default => round_robin,
+ desc =>
+ "Dispatch strategy for shared subscription.
\n"
+ " - `random`: dispatch the message to a random selected subscriber\n"
+ " - `round_robin`: select the subscribers in a round-robin manner\n"
+ " - `sticky`: always use the last selected subscriber to dispatch,\n"
+ " until the subscriber disconnected.\n"
+ " - `hash`: select the subscribers by the hash of `clientIds`"
+ }
)},
{"shared_dispatch_ack_enabled",
sc(
boolean(),
- #{default => false}
+ #{
+ default => false,
+ desc =>
+ "Enable/disable shared dispatch acknowledgement for QoS1 and QoS2 messages.
\n"
+ " This should allow messages to be dispatched to a different subscriber in\n"
+ " the group in case the picked (based on `shared_subscription_strategy`) subscriber\n"
+ " is offline."
+ }
)},
{"route_batch_clean",
sc(
boolean(),
- #{default => true}
+ #{
+ default => true,
+ desc => "Enable batch clean for deleted routes."
+ }
)},
{"perf",
sc(
@@ -1248,42 +1376,74 @@ fields("sysmon_vm") ->
{"process_check_interval",
sc(
duration(),
- #{default => "30s"}
+ #{
+ default => "30s",
+ desc => "The time interval for the periodic process limit check."
+ }
)},
{"process_high_watermark",
sc(
percent(),
- #{default => "80%"}
+ #{
+ default => "80%",
+ desc =>
+ "The threshold, as percentage of processes, for how many\n"
+ " processes can simultaneously exist at the local node before the corresponding\n"
+ " alarm is set."
+ }
)},
{"process_low_watermark",
sc(
percent(),
- #{default => "60%"}
+ #{
+ default => "60%",
+ desc =>
+ "The threshold, as percentage of processes, for how many\n"
+ " processes can simultaneously exist at the local node before the corresponding\n"
+ " alarm is cleared."
+ }
)},
{"long_gc",
sc(
hoconsc:union([disabled, duration()]),
- #{}
+ #{
+ desc =>
+ "Enable Long GC monitoring.
\n"
+ " Notice: don't enable the monitor in production for:
\n"
+ " https://github.com/erlang/otp/blob/feb45017da36be78d4c5784d758ede619fa7bfd3/erts/emulator/beam/erl_gc.c#L421"
+ }
)},
{"long_schedule",
sc(
hoconsc:union([disabled, duration()]),
- #{default => "240ms"}
+ #{
+ default => "240ms",
+ desc => "Enable Long Schedule(ms) monitoring."
+ }
)},
{"large_heap",
sc(
hoconsc:union([disabled, bytesize()]),
- #{default => "32MB"}
+ #{
+ default => "32MB",
+ desc => "Enable Large Heap monitoring."
+ }
)},
{"busy_dist_port",
sc(
boolean(),
- #{default => true}
+ #{
+ default => true,
+ desc => "Enable Busy Distribution Port monitoring."
+ }
)},
{"busy_port",
sc(
boolean(),
- #{default => true}
+ #{
+ default => true,
+ desc => "Enable Busy Port monitoring."
+ }
)}
];
fields("sysmon_os") ->
@@ -1291,32 +1451,59 @@ fields("sysmon_os") ->
{"cpu_check_interval",
sc(
duration(),
- #{default => "60s"}
+ #{
+ default => "60s",
+ desc => "The time interval for the periodic CPU check."
+ }
)},
{"cpu_high_watermark",
sc(
percent(),
- #{default => "80%"}
+ #{
+ default => "80%",
+ desc =>
+ "The threshold, as percentage of system CPU load,\n"
+ " for how much system cpu can be used before the corresponding alarm is set."
+ }
)},
{"cpu_low_watermark",
sc(
percent(),
- #{default => "60%"}
+ #{
+ default => "60%",
+ desc =>
+ "The threshold, as percentage of system CPU load,\n"
+ " for how much system cpu can be used before the corresponding alarm is cleared."
+ }
)},
{"mem_check_interval",
sc(
hoconsc:union([disabled, duration()]),
- #{default => "60s"}
+ #{
+ default => "60s",
+ desc => "The time interval for the periodic memory check."
+ }
)},
{"sysmem_high_watermark",
sc(
percent(),
- #{default => "70%"}
+ #{
+ default => "70%",
+ desc =>
+ "The threshold, as percentage of system memory,\n"
+ " for how much system memory can be allocated before the corresponding alarm is set."
+ }
)},
{"procmem_high_watermark",
sc(
percent(),
- #{default => "5%"}
+ #{
+ default => "5%",
+ desc =>
+ "The threshold, as percentage of system memory,\n"
+ " for how much system memory can be allocated by one Erlang process before\n"
+ " the corresponding alarm is set."
+ }
)}
];
fields("sysmon_top") ->
@@ -1488,27 +1675,57 @@ base_listener() ->
{"bind",
sc(
hoconsc:union([ip_port(), integer()]),
- #{required => true}
+ #{
+ required => true,
+ desc => "IP address and port for the listening socket."
+ }
)},
{"acceptors",
sc(
integer(),
- #{default => 16}
+ #{
+ default => 16,
+ desc => "The size of the listener's receiving pool."
+ }
)},
{"max_connections",
sc(
hoconsc:union([infinity, integer()]),
- #{default => infinity}
+ #{
+ default => infinity,
+ desc => "The maximum number of concurrent connections allowed by the listener."
+ }
)},
{"mountpoint",
sc(
binary(),
- #{default => <<>>}
+ #{
+ default => <<>>,
+ desc =>
+ "When publishing or subscribing, prefix all topics with a mountpoint string.\n"
+ " The prefixed string will be removed from the topic name when the message\n"
+ " is delivered to the subscriber. The mountpoint is a way that users can use\n"
+ " to implement isolation of message routing between different listeners.\n"
+ " For example if a client A subscribes to `t` with `listeners.tcp..mountpoint`\n"
+ " set to `some_tenant`, then the client actually subscribes to the topic\n"
+ " `some_tenant/t`. Similarly, if another client B (connected to the same listener\n"
+ " as the client A) sends a message to topic `t`, the message is routed\n"
+ " to all the clients subscribed `some_tenant/t`, so client A will receive the\n"
+ " message, with topic name `t`.
\n"
+ " Set to `\"\"` to disable the feature.
\n"
+ "\n"
+ " Variables in mountpoint string:\n"
+ " - ${clientid}
: clientid\n"
+ " - ${username}
: username"
+ }
)},
{"zone",
sc(
atom(),
- #{default => 'default'}
+ #{
+ default => 'default',
+ desc => "The configuration zone to which the listener belongs."
+ }
)},
{"limiter",
sc(map("ratelimit's type", emqx_limiter_schema:bucket_name()), #{default => #{}})}
diff --git a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl
index f112fc852..a2c5b3c26 100644
--- a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl
+++ b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl
@@ -49,22 +49,39 @@ fields("http") ->
hoconsc:enum([http, https]),
#{ desc => "HTTP/HTTPS protocol."
, required => true
- , default => http})}
+ , default => http
+ })}
, {"bind", fun bind/1}
, {"num_acceptors", sc(
integer(),
#{ default => 4
- , desc => "Socket acceptor pool for TCP protocols."
+ , desc => "Socket acceptor pool size for TCP protocols."
})}
- , {"max_connections", sc(integer(), #{default => 512})}
- , {"backlog", sc(
- integer(),
- #{ default => 1024
- , desc => "Defines the maximum length that the queue of pending connections can grow to."
- })}
- , {"send_timeout", sc(emqx_schema:duration(), #{default => "5s"})}
- , {"inet6", sc(boolean(), #{default => false})}
- , {"ipv6_v6only", sc(boolean(), #{default => false})}
+ , {"max_connections",
+ sc(integer(),
+ #{ default => 512
+ , desc => "Maximum number of simultaneous connections."
+ })}
+ , {"backlog",
+ sc(integer(),
+ #{ default => 1024
+ , desc => "Defines the maximum length that the queue of pending connections can grow to."
+ })}
+ , {"send_timeout",
+ sc(emqx_schema:duration(),
+ #{ default => "5s"
+ , desc => "Send timeout for the socket."
+ })}
+ , {"inet6",
+ sc(boolean(),
+ #{ default => false
+ , desc => "Sets up the listener for IPv6."
+ })}
+ , {"ipv6_v6only",
+ sc(boolean(),
+ #{ default => false
+ , desc => "Disable IPv4-to-IPv6 mapping for the listener."
+ })}
];
fields("https") ->
@@ -81,6 +98,7 @@ bind(_) -> undefined.
default_username(type) -> string();
default_username(default) -> "admin";
default_username(required) -> true;
+default_username(desc) -> "The default username of the automatically created dashboard user.";
default_username(_) -> undefined.
default_password(type) -> string();
diff --git a/apps/emqx_modules/src/emqx_modules_schema.erl b/apps/emqx_modules/src/emqx_modules_schema.erl
index 58272a54a..90dc85088 100644
--- a/apps/emqx_modules/src/emqx_modules_schema.erl
+++ b/apps/emqx_modules/src/emqx_modules_schema.erl
@@ -123,18 +123,15 @@ fields("event_message") ->
}
)}
],
- #{
- fields => Fields,
- desc =>
- ""
- "\n"
- "Enable/Disable system event messages.\n"
- "The messages are published to '$event' prefixed topics.\n"
- "For example, if `client_disconnected` is set to `true`,\n"
- "a message is published to `$event/client_connected` topic\n"
- "whenever a client is connected.\n"
- ""
- };
+ #{fields => Fields,
+ desc => """
+Enable/Disable system event messages.
+The messages are published to $event
prefixed topics.
+For example, if `client_disconnected` is set to `true`,
+a message is published to $event/client_connected
topic
+whenever a client is connected.
+"""};
+
fields("topic_metrics") ->
[{topic, sc(binary(), #{})}].