22#include "util/Assert.hpp"
23#include "util/config/ConfigDefinition.hpp"
24#include "util/config/Error.hpp"
26#include <fmt/format.h>
38namespace util::config {
50 std::string_view value;
67 [[nodiscard]]
static constexpr std::string_view
68 get(std::string_view key)
71 std::ranges::find_if(kCONFIG_DESCRIPTION, [&](
auto const& v) {
return v.key == key; });
72 ASSERT(itr != kCONFIG_DESCRIPTION.end(),
"Key {} doesn't exist in config", key);
82 [[nodiscard]]
static std::expected<void, Error>
85 namespace fs = std::filesystem;
88 auto const dir = path.parent_path();
89 if (!dir.empty() && !fs::exists(dir)) {
90 return std::unexpected<Error>{fmt::format(
91 "Error: Directory '{}' does not exist or provided path is invalid", dir.string()
95 std::ofstream file(path.string());
96 if (!file.is_open()) {
97 return std::unexpected{
98 fmt::format(
"Failed to create file '{}': {}", path.string(), std::strerror(errno))
105 std::cout <<
"Markdown file generated successfully: " << path <<
"\n";
117 file << kCONFIG_DESCRIPTION_HEADER;
119 for (
auto const& [key, val] : kCONFIG_DESCRIPTION) {
120 file <<
"\n### " << key <<
"\n\n";
124 if (key.contains(
"[]")) {
125 file << getClioConfig().asArray(key);
127 file << getClioConfig().getValueView(key);
129 file <<
"- **Description**: " << val <<
"\n";
134 static constexpr auto kCONFIG_DESCRIPTION_HEADER =
135 R
"(# Clio Config Description
137This document provides a list of all available Clio configuration properties in detail.
140> Dot notation in configuration key names represents nested fields.
141> For example, **database.scylladb** refers to the _scylladb_ field inside the _database_ object.
142> If a key name includes "[]", it indicates that the nested field is an array (e.g., etl_sources.[]).
144## Configuration Details
147 static constexpr auto kCONFIG_DESCRIPTION = std::array{
148 KV{.key =
"database.type",
149 .value =
"Specifies the type of database used for storing and retrieving data required "
150 "by the Clio server. Both "
151 "ScyllaDB and Cassandra can serve as backends for Clio; however, this value "
152 "must be set to `cassandra`."},
153 KV{.key =
"database.cassandra.contact_points",
154 .value =
"A list of IP addresses or hostnames for the initial cluster nodes (Cassandra "
156 "the client connects to when establishing a database connection. If you're "
157 "running Clio locally, "
158 "set this value to `localhost` or `127.0.0.1`."},
159 KV{.key =
"database.cassandra.secure_connect_bundle",
160 .value =
"The configuration file that contains the necessary credentials and connection "
162 "securely connecting to a Cassandra database cluster."},
163 KV{.key =
"database.cassandra.port",
164 .value =
"The port number used to connect to the Cassandra database."},
165 KV{.key =
"database.cassandra.keyspace",
166 .value =
"The Cassandra keyspace to use for the database. If you don't provide a value, "
168 "`clio` by default."},
169 KV{.key =
"database.cassandra.replication_factor",
171 "Represents the number of replicated nodes for ScyllaDB. For more details see "
174 "Factor](https://university.scylladb.com/courses/scylla-essentials-overview/lessons/"
175 "high-availability/topic/fault-tolerance-replication-factor/)."},
176 KV{.key =
"database.cassandra.table_prefix",
178 "An optional field to specify a prefix for the Cassandra database table names."},
179 KV{.key =
"database.cassandra.max_write_requests_outstanding",
180 .value =
"Represents the maximum number of outstanding write requests. Write requests "
181 "are API calls that "
182 "write to the database."},
183 KV{.key =
"database.cassandra.max_read_requests_outstanding",
184 .value =
"Maximum number of outstanding read requests. Read requests are API calls that "
185 "read from the database."},
186 KV{.key =
"database.cassandra.threads",
187 .value =
"Represents the number of threads that will be used for database operations."},
188 KV{.key =
"database.cassandra.provider",
189 .value =
"The specific database backend provider we are using."},
190 KV{.key =
"database.cassandra.core_connections_per_host",
191 .value =
"The number of core connections per host for the Cassandra database."},
192 KV{.key =
"database.cassandra.queue_size_io",
193 .value =
"Defines the queue size of the input/output (I/O) operations in Cassandra."},
194 KV{.key =
"database.cassandra.write_batch_size",
195 .value =
"Represents the batch size for write operations in Cassandra."},
196 KV{.key =
"database.cassandra.connect_timeout",
197 .value =
"The maximum amount of time in seconds that the system waits for a database "
200 KV{.key =
"database.cassandra.request_timeout",
201 .value =
"The maximum amount of time in seconds that the system waits for a request to "
202 "be fetched from the "
204 KV{.key =
"database.cassandra.username",
205 .value =
"The username used for authenticating with the database."},
206 KV{.key =
"database.cassandra.password",
207 .value =
"The password used for authenticating with the database."},
208 KV{.key =
"database.cassandra.certfile",
209 .value =
"The path to the SSL/TLS certificate file used to establish a secure "
210 "connection between the client "
211 "and the Cassandra database."},
212 KV{.key =
"allow_no_etl",
213 .value =
"If set to `True`, allows Clio to start without any ETL source."},
214 KV{.key =
"etl_sources.[].ip", .value =
"The IP address of the ETL source."},
215 KV{.key =
"etl_sources.[].ws_port", .value =
"The WebSocket port of the ETL source."},
216 KV{.key =
"etl_sources.[].grpc_port", .value =
"The gRPC port of the ETL source."},
217 KV{.key =
"forwarding.cache_timeout",
218 .value =
"Specifies the timeout duration (in seconds) for the forwarding cache used in "
220 "communication. A value of `0` means disabling this feature."},
221 KV{.key =
"forwarding.request_timeout",
222 .value =
"Specifies the timeout duration (in seconds) for the forwarding request used "
225 KV{.key =
"rpc.cache_timeout",
226 .value =
"Specifies the timeout duration (in seconds) for RPC cache response to "
227 "timeout. A value of `0` "
228 "means disabling this feature."},
229 KV{.key =
"num_markers",
230 .value =
"Specifies the number of coroutines used to download the initial ledger."},
231 KV{.key =
"dos_guard.whitelist.[]",
232 .value =
"The list of IP addresses to whitelist for DOS protection."},
233 KV{.key =
"dos_guard.max_fetches",
234 .value =
"The maximum number of fetch operations allowed by DOS guard."},
235 KV{.key =
"dos_guard.max_connections",
236 .value =
"The maximum number of concurrent connections for a specific IP address."},
237 KV{.key =
"dos_guard.max_requests",
238 .value =
"The maximum number of requests allowed for a specific IP address."},
239 KV{.key =
"dos_guard.sweep_interval",
240 .value =
"Interval in seconds for DOS guard to sweep(clear) its state."},
241 KV{.key =
"workers", .value =
"The number of threads used to process RPC requests."},
242 KV{.key =
"server.ip", .value =
"The IP address of the Clio HTTP server."},
243 KV{.key =
"server.port", .value =
"The port number of the Clio HTTP server."},
244 KV{.key =
"server.max_queue_size",
245 .value =
"The maximum size of the server's request queue. If set to `0`, this means "
246 "there is no queue size "
248 KV{.key =
"server.local_admin",
249 .value =
"Indicates if requests from `localhost` are allowed to call Clio admin-only "
250 "APIs. Note that this "
251 "setting cannot be enabled "
252 "together with [server.admin_password](#serveradmin_password)."},
253 KV{.key =
"server.admin_password",
254 .value =
"The password for Clio admin-only APIs. Note that this setting cannot be "
255 "enabled together with "
256 "[server.local_admin](#serveradmin_password)."},
257 KV{.key =
"server.processing_policy",
258 .value =
"For the `sequent` policy, requests from a single client connection are "
259 "processed one by one, with "
260 "the next request read only after the previous one is processed. For the "
261 "`parallel` policy, Clio "
262 "will accept all requests and process them in parallel, sending a reply for "
263 "each request as soon "
265 KV{.key =
"server.parallel_requests_limit",
266 .value =
"This is an optional parameter, used only if the `processing_strategy` is "
267 "`parallel`. It limits "
268 "the number of requests processed in parallel for a single client connection. "
269 "If not specified, no "
270 "limit is enforced."},
271 KV{.key =
"server.ws_max_sending_queue_size",
272 .value =
"Maximum queue size for sending subscription data to clients. This queue "
273 "buffers data when a "
274 "client is slow to receive it, ensuring delivery once the client is ready."},
275 KV{.key =
"server.proxy.ips.[]",
277 "List of proxy ip addresses. When Clio receives a request from proxy it will use "
278 "`Forwarded` value (if any) as client ip. When this option is used together with "
279 "`server.proxy.tokens` Clio will identify proxy by ip or by token."},
280 KV{.key =
"server.proxy.tokens.[]",
281 .value =
"List of tokens in identifying request as a request from proxy. Token should "
283 "`X-Proxy-Token` header, e.g. "
284 "`X-Proxy-Token: <very_secret_token>'. When Clio receives a request from proxy "
285 "it will use 'Forwarded` value (if any) to get client ip. When this option is "
286 "used together with "
287 "'server.proxy.ips' Clio will identify proxy by ip or by token."},
288 KV{.key =
"prometheus.enabled", .value =
"Enables or disables Prometheus metrics."},
289 KV{.key =
"prometheus.compress_reply",
290 .value =
"Enables or disables compression of Prometheus responses."},
291 KV{.key =
"io_threads",
292 .value =
"The number of input/output (I/O) threads. The value cannot be less than `1`."},
293 KV{.key =
"subscription_workers",
294 .value =
"The number of worker threads or processes that are responsible for managing "
296 "subscription-based tasks from `rippled`."},
297 KV{.key =
"graceful_period",
298 .value =
"The number of seconds the server waits to shutdown gracefully. If Clio does "
300 "gracefully after the specified value, it will be killed instead."},
301 KV{.key =
"cache.num_diffs",
302 .value =
"The number of cursors generated is the number of changed (without counting "
303 "deleted) objects in "
304 "the latest `cache.num_diffs` number of ledgers. Cursors are workers that load "
306 "from the position of markers concurrently. For more information, please read "
307 "[README.md](../src/etl/README.md)."},
308 KV{.key =
"cache.num_markers",
309 .value =
"Specifies how many markers are placed randomly within the cache. These "
310 "markers define the "
311 "positions on the ledger that will be loaded concurrently by the workers. The "
312 "higher the number, "
313 "the more places within the cache we potentially cover."},
314 KV{.key =
"cache.num_cursors_from_diff",
315 .value =
"`cache.num_cursors_from_diff` number of cursors are generated by looking at "
316 "the number of changed "
317 "objects in the most recent ledger. If number of changed objects in current "
318 "ledger is not enough, "
319 "it will keep reading previous ledgers until it hit "
320 "`cache.num_cursors_from_diff`. If set to `0`, "
321 "the system defaults to generating cursors based on `cache.num_diffs`."},
322 KV{.key =
"cache.num_cursors_from_account",
323 .value =
"`cache.num_cursors_from_diff` of cursors are generated by reading accounts in "
324 "`account_tx` table. "
325 "If set to `0`, the system defaults to generating cursors based on "
326 "`cache.num_diffs`."},
327 KV{.key =
"cache.page_fetch_size",
328 .value =
"The number of ledger objects to fetch concurrently per marker."},
329 KV{.key =
"cache.limit_load_in_cluster",
330 .value =
"If enabled only one clio node in a cluster (sharing the same database) will "
331 "load cache at a time"},
332 KV{.key =
"cache.load", .value =
"The strategy used for Cache loading."},
333 KV{.key =
"cache.file.path",
334 .value =
"The path to a file where cache will be saved to on shutdown and loaded from "
336 "If the file couldn't be read Clio will load cache as usual (from DB or from "
338 KV{.key =
"cache.file.max_sequence_age",
339 .value =
"Max allowed difference between the latest sequence in DB and in cache file. "
340 "If the cache file is "
341 "too old (contains too low latest sequence) Clio will reject using it."},
342 KV{.key =
"cache.file.async_save",
344 "When false, Clio waits for cache saving to finish before shutting down. When true, "
345 "cache saving runs in parallel with other shutdown operations."},
346 KV{.key =
"log.channels.[].channel", .value =
"The name of the log channel."},
347 KV{.key =
"log.channels.[].level", .value =
"The log level for the specific log channel."},
348 KV{.key =
"log.level",
349 .value =
"The general logging level of Clio. This level is applied to all log channels "
350 "that do not have an "
351 "explicitly defined logging level."},
352 KV{.key =
"log.format",
353 .value = R
"(The format string for log messages using spdlog format patterns.
355Each of the variables expands like so:
357- `%Y-%m-%d %H:%M:%S.%f`: The full date and time of the log entry with microsecond precision
358- `%^`: Start color range
359- `%3!l`: The severity (aka log level) the entry was sent at stripped to 3 characters
360- `%n`: The logger name (channel) that this log entry was sent to
361- `%$`: End color range
362- `%v`: The actual log message
364Some additional variables that might be useful:
366- `%@`: A partial path to the C++ file and the line number in the said file (`src/file/path:linenumber`)
367- `%t`: The ID of the thread the log entry is written from
369Documentation can be found at: <https://github.com/gabime/spdlog/wiki/Custom-formatting>.)"},
370 KV{.key = "log.is_async", .value =
"Whether spdlog is asynchronous or not."},
371 KV{.key =
"log.enable_console", .value =
"Enables or disables logging to the console."},
372 KV{.key =
"log.directory", .value =
"The directory path for the log files."},
373 KV{.key =
"log.rotation_size",
374 .value =
"The log rotation size in megabytes. When the log file reaches this particular "
377 KV{.key =
"log.directory_max_files",
378 .value =
"The maximum number of log files in the directory."},
379 KV{.key =
"log.tag_style",
380 .value =
"Log tags are unique identifiers for log messages. `uint`/`int` starts logging "
381 "from 0 and increments, "
382 "making it faster. In contrast, `uuid` generates a random unique identifier, "
383 "which adds overhead."},
384 KV{.key =
"extractor_threads",
385 .value =
"Number of threads used to extract data from ETL source."},
386 KV{.key =
"read_only",
387 .value =
"Indicates if the server is allowed to write data to the database."},
388 KV{.key =
"start_sequence",
389 .value =
"If specified, the ledger index Clio will start writing to the database from."},
390 KV{.key =
"finish_sequence",
391 .value =
"If specified, the final ledger that Clio will write to the database."},
392 KV{.key =
"ssl_cert_file", .value =
"The path to the SSL certificate file."},
393 KV{.key =
"ssl_key_file", .value =
"The path to the SSL key file."},
394 KV{.key =
"api_version.default",
395 .value =
"The default API version that the Clio server will run on."},
396 KV{.key =
"api_version.min", .value =
"The minimum API version allowed to use."},
397 KV{.key =
"api_version.max", .value =
"The maximum API version allowed to use."},
398 KV{.key =
"migration.full_scan_threads",
399 .value =
"The number of threads used to scan the table."},
400 KV{.key =
"migration.full_scan_jobs",
401 .value =
"The number of coroutines used to scan the table."},
402 KV{.key =
"migration.cursors_per_job", .value =
"The number of cursors each job will scan."}
Struct to represent a key-value pair.
Definition ConfigDescription.hpp:48
static std::expected< void, Error > generateConfigDescriptionToFile(std::filesystem::path path)
Generate markdown file of all the clio config descriptions.
Definition ConfigDescription.hpp:83
static constexpr std::string_view get(std::string_view key)
Retrieves the description for a given key.
Definition ConfigDescription.hpp:68
static void writeConfigDescriptionToFile(std::ostream &file)
Writes to Config description to file.
Definition ConfigDescription.hpp:115
constexpr ClioConfigDescription()=default
Constructs a new Clio Config Description based on pre-existing descriptions.