Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
ConfigDescription.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2024, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "util/Assert.hpp"
23#include "util/config/ConfigDefinition.hpp"
24#include "util/config/Error.hpp"
25
26#include <fmt/format.h>
27
28#include <algorithm>
29#include <array>
30#include <cerrno>
31#include <cstring>
32#include <expected>
33#include <filesystem>
34#include <fstream>
35#include <iostream>
36#include <string_view>
37
38namespace util::config {
39
46public:
48 struct KV {
49 std::string_view key;
50 std::string_view value;
51 };
52
58 constexpr ClioConfigDescription() = default;
59
66 [[nodiscard]] static constexpr std::string_view
67 get(std::string_view key)
68 {
69 auto const itr = std::ranges::find_if(kCONFIG_DESCRIPTION, [&](auto const& v) { return v.key == key; });
70 ASSERT(itr != kCONFIG_DESCRIPTION.end(), "Key {} doesn't exist in config", key);
71 return itr->value;
72 }
73
80 [[nodiscard]] static std::expected<void, Error>
81 generateConfigDescriptionToFile(std::filesystem::path path)
82 {
83 namespace fs = std::filesystem;
84
85 // Validate the directory exists
86 auto const dir = path.parent_path();
87 if (!dir.empty() && !fs::exists(dir)) {
88 return std::unexpected<Error>{
89 fmt::format("Error: Directory '{}' does not exist or provided path is invalid", dir.string())
90 };
91 }
92
93 std::ofstream file(path.string());
94 if (!file.is_open()) {
95 return std::unexpected{fmt::format("Failed to create file '{}': {}", path.string(), std::strerror(errno))};
96 }
97
99 file.close();
100
101 std::cout << "Markdown file generated successfully: " << path << "\n";
102 return {};
103 }
104
110 static void
112 {
113 file << kCONFIG_DESCRIPTION_HEADER;
114
115 for (auto const& [key, val] : kCONFIG_DESCRIPTION) {
116 file << "\n### " << key << "\n\n";
117
118 // Every type of value is directed to operator<< in ConfigValue.hpp
119 // as ConfigValue is the one that holds all the info regarding the config values
120 if (key.contains("[]")) {
121 file << getClioConfig().asArray(key);
122 } else {
123 file << getClioConfig().getValueView(key);
124 }
125 file << "- **Description**: " << val << "\n";
126 }
127 }
128
129private:
130 static constexpr auto kCONFIG_DESCRIPTION_HEADER =
131 R"(# Clio Config Description
132
133This document provides a list of all available Clio configuration properties in detail.
134
135> [!NOTE]
136> Dot notation in configuration key names represents nested fields.
137> For example, **database.scylladb** refers to the _scylladb_ field inside the _database_ object.
138> If a key name includes "[]", it indicates that the nested field is an array (e.g., etl_sources.[]).
139
140## Configuration Details
141)";
142
143 static constexpr auto kCONFIG_DESCRIPTION = std::array{
144 KV{
145 .key = "database.type",
146 .value =
147 "Specifies the type of database used for storing and retrieving data required by the Clio server. Both "
148 "ScyllaDB and Cassandra can serve as backends for Clio; however, this value must be set to `cassandra`."
149 },
150 KV{.key = "database.cassandra.contact_points",
151 .value = "A list of IP addresses or hostnames for the initial cluster nodes (Cassandra or ScyllaDB) that "
152 "the client connects to when establishing a database connection. If you're running Clio locally, "
153 "set this value to `localhost` or `127.0.0.1`."},
154 KV{.key = "database.cassandra.secure_connect_bundle",
155 .value = "The configuration file that contains the necessary credentials and connection details for "
156 "securely connecting to a Cassandra database cluster."},
157 KV{.key = "database.cassandra.port", .value = "The port number used to connect to the Cassandra database."},
158 KV{.key = "database.cassandra.keyspace",
159 .value = "The Cassandra keyspace to use for the database. If you don't provide a value, this is set to "
160 "`clio` by default."},
161 KV{.key = "database.cassandra.replication_factor",
162 .value = "Represents the number of replicated nodes for ScyllaDB. For more details see [Fault Tolerance "
163 "Replication "
164 "Factor](https://university.scylladb.com/courses/scylla-essentials-overview/lessons/"
165 "high-availability/topic/fault-tolerance-replication-factor/)."},
166 KV{.key = "database.cassandra.table_prefix",
167 .value = "An optional field to specify a prefix for the Cassandra database table names."},
168 KV{.key = "database.cassandra.max_write_requests_outstanding",
169 .value = "Represents the maximum number of outstanding write requests. Write requests are API calls that "
170 "write to the database."},
171 KV{.key = "database.cassandra.max_read_requests_outstanding",
172 .value =
173 "Maximum number of outstanding read requests. Read requests are API calls that read from the database."},
174 KV{.key = "database.cassandra.threads",
175 .value = "Represents the number of threads that will be used for database operations."},
176 KV{.key = "database.cassandra.core_connections_per_host",
177 .value = "The number of core connections per host for the Cassandra database."},
178 KV{.key = "database.cassandra.queue_size_io",
179 .value = "Defines the queue size of the input/output (I/O) operations in Cassandra."},
180 KV{.key = "database.cassandra.write_batch_size",
181 .value = "Represents the batch size for write operations in Cassandra."},
182 KV{.key = "database.cassandra.connect_timeout",
183 .value = "The maximum amount of time in seconds that the system waits for a database connection to be "
184 "established."},
185 KV{.key = "database.cassandra.request_timeout",
186 .value = "The maximum amount of time in seconds that the system waits for a request to be fetched from the "
187 "database."},
188 KV{.key = "database.cassandra.username", .value = "The username used for authenticating with the database."},
189 KV{.key = "database.cassandra.password", .value = "The password used for authenticating with the database."},
190 KV{.key = "database.cassandra.certfile",
191 .value = "The path to the SSL/TLS certificate file used to establish a secure connection between the client "
192 "and the Cassandra database."},
193 KV{.key = "allow_no_etl", .value = "If set to `True`, allows Clio to start without any ETL source."},
194 KV{.key = "etl_sources.[].ip", .value = "The IP address of the ETL source."},
195 KV{.key = "etl_sources.[].ws_port", .value = "The WebSocket port of the ETL source."},
196 KV{.key = "etl_sources.[].grpc_port", .value = "The gRPC port of the ETL source."},
197 KV{.key = "forwarding.cache_timeout",
198 .value = "Specifies the timeout duration (in seconds) for the forwarding cache used in `rippled` "
199 "communication. A value of `0` means disabling this feature."},
200 KV{.key = "forwarding.request_timeout",
201 .value = "Specifies the timeout duration (in seconds) for the forwarding request used in `rippled` "
202 "communication."},
203 KV{.key = "rpc.cache_timeout",
204 .value = "Specifies the timeout duration (in seconds) for RPC cache response to timeout. A value of `0` "
205 "means disabling this feature."},
206 KV{.key = "num_markers", .value = "Specifies the number of coroutines used to download the initial ledger."},
207 KV{.key = "dos_guard.whitelist.[]", .value = "The list of IP addresses to whitelist for DOS protection."},
208 KV{.key = "dos_guard.max_fetches", .value = "The maximum number of fetch operations allowed by DOS guard."},
209 KV{.key = "dos_guard.max_connections",
210 .value = "The maximum number of concurrent connections for a specific IP address."},
211 KV{.key = "dos_guard.max_requests",
212 .value = "The maximum number of requests allowed for a specific IP address."},
213 KV{.key = "dos_guard.sweep_interval", .value = "Interval in seconds for DOS guard to sweep(clear) its state."},
214 KV{.key = "workers", .value = "The number of threads used to process RPC requests."},
215 KV{.key = "server.ip", .value = "The IP address of the Clio HTTP server."},
216 KV{.key = "server.port", .value = "The port number of the Clio HTTP server."},
217 KV{.key = "server.max_queue_size",
218 .value = "The maximum size of the server's request queue. If set to `0`, this means there is no queue size "
219 "limit."},
220 KV{.key = "server.local_admin",
221 .value = "Indicates if requests from `localhost` are allowed to call Clio admin-only APIs. Note that this "
222 "setting cannot be enabled "
223 "together with [server.admin_password](#serveradmin_password)."},
224 KV{.key = "server.admin_password",
225 .value = "The password for Clio admin-only APIs. Note that this setting cannot be enabled together with "
226 "[server.local_admin](#serveradmin_password)."},
227 KV{.key = "server.processing_policy",
228 .value = "For the `sequent` policy, requests from a single client connection are processed one by one, with "
229 "the next request read only after the previous one is processed. For the `parallel` policy, Clio "
230 "will accept all requests and process them in parallel, sending a reply for each request as soon "
231 "as it is ready."},
232 KV{.key = "server.parallel_requests_limit",
233 .value = "This is an optional parameter, used only if the `processing_strategy` is `parallel`. It limits "
234 "the number of requests processed in parallel for a single client connection. If not specified, no "
235 "limit is enforced."},
236 KV{.key = "server.ws_max_sending_queue_size",
237 .value = "Maximum queue size for sending subscription data to clients. This queue buffers data when a "
238 "client is slow to receive it, ensuring delivery once the client is ready."},
239 KV{.key = "server.proxy.ips.[]",
240 .value = "List of proxy ip addresses. When Clio receives a request from proxy it will use "
241 "`Forwarded` value (if any) as client ip. When this option is used together with "
242 "`server.proxy.tokens` Clio will identify proxy by ip or by token."},
243 KV{.key = "server.proxy.tokens.[]",
244 .value = "List of tokens in identifying request as a request from proxy. Token should be provided in "
245 "`X-Proxy-Token` header, e.g. "
246 "`X-Proxy-Token: <very_secret_token>'. When Clio receives a request from proxy "
247 "it will use 'Forwarded` value (if any) to get client ip. When this option is used together with "
248 "'server.proxy.ips' Clio will identify proxy by ip or by token."},
249 KV{.key = "prometheus.enabled", .value = "Enables or disables Prometheus metrics."},
250 KV{.key = "prometheus.compress_reply", .value = "Enables or disables compression of Prometheus responses."},
251 KV{.key = "io_threads",
252 .value = "The number of input/output (I/O) threads. The value cannot be less than `1`."},
253 KV{.key = "subscription_workers",
254 .value = "The number of worker threads or processes that are responsible for managing and processing "
255 "subscription-based tasks from `rippled`."},
256 KV{.key = "graceful_period",
257 .value = "The number of milliseconds the server waits to shutdown gracefully. If Clio does not shutdown "
258 "gracefully after the specified value, it will be killed instead."},
259 KV{.key = "cache.num_diffs",
260 .value = "The number of cursors generated is the number of changed (without counting deleted) objects in "
261 "the latest `cache.num_diffs` number of ledgers. Cursors are workers that load the ledger cache "
262 "from the position of markers concurrently. For more information, please read "
263 "[README.md](../src/etl/README.md)."},
264 KV{.key = "cache.num_markers",
265 .value = "Specifies how many markers are placed randomly within the cache. These markers define the "
266 "positions on the ledger that will be loaded concurrently by the workers. The higher the number, "
267 "the more places within the cache we potentially cover."},
268 KV{.key = "cache.num_cursors_from_diff",
269 .value = "`cache.num_cursors_from_diff` number of cursors are generated by looking at the number of changed "
270 "objects in the most recent ledger. If number of changed objects in current ledger is not enough, "
271 "it will keep reading previous ledgers until it hit `cache.num_cursors_from_diff`. If set to `0`, "
272 "the system defaults to generating cursors based on `cache.num_diffs`."},
273 KV{.key = "cache.num_cursors_from_account",
274 .value = "`cache.num_cursors_from_diff` of cursors are generated by reading accounts in `account_tx` table. "
275 "If set to `0`, the system defaults to generating cursors based on `cache.num_diffs`."},
276 KV{.key = "cache.page_fetch_size", .value = "The number of ledger objects to fetch concurrently per marker."},
277 KV{.key = "cache.load", .value = "The strategy used for Cache loading."},
278 KV{.key = "log.channels.[].channel", .value = "The name of the log channel."},
279 KV{.key = "log.channels.[].level", .value = "The log level for the specific log channel."},
280 KV{.key = "log.level",
281 .value = "The general logging level of Clio. This level is applied to all log channels that do not have an "
282 "explicitly defined logging level."},
283 KV{.key = "log.format", .value = R"(The format string for log messages using spdlog format patterns.
284
285Each of the variables expands like so:
286
287- `%Y-%m-%d %H:%M:%S.%f`: The full date and time of the log entry with microsecond precision
288- `%^`: Start color range
289- `%3!l`: The severity (aka log level) the entry was sent at stripped to 3 characters
290- `%n`: The logger name (channel) that this log entry was sent to
291- `%$`: End color range
292- `%v`: The actual log message
293
294Some additional variables that might be useful:
295
296- `%@`: A partial path to the C++ file and the line number in the said file (`src/file/path:linenumber`)
297- `%t`: The ID of the thread the log entry is written from
298
299Documentation can be found at: <https://github.com/gabime/spdlog/wiki/Custom-formatting>.)"},
300 KV{.key = "log.is_async", .value = "Whether spdlog is asynchronous or not."},
301 KV{.key = "log.enable_console", .value = "Enables or disables logging to the console."},
302 KV{.key = "log.directory", .value = "The directory path for the log files."},
303 KV{.key = "log.rotation_size",
304 .value = "The log rotation size in megabytes. When the log file reaches this particular size, a new log "
305 "file starts."},
306 KV{.key = "log.directory_max_files", .value = "The maximum number of log files in the directory."},
307 KV{.key = "log.tag_style",
308 .value =
309 "Log tags are unique identifiers for log messages. `uint`/`int` starts logging from 0 and increments, "
310 "making it faster. In contrast, `uuid` generates a random unique identifier, which adds overhead."},
311 KV{.key = "extractor_threads", .value = "Number of threads used to extract data from ETL source."},
312 KV{.key = "read_only", .value = "Indicates if the server is allowed to write data to the database."},
313 KV{.key = "start_sequence",
314 .value = "If specified, the ledger index Clio will start writing to the database from."},
315 KV{.key = "finish_sequence", .value = "If specified, the final ledger that Clio will write to the database."},
316 KV{.key = "ssl_cert_file", .value = "The path to the SSL certificate file."},
317 KV{.key = "ssl_key_file", .value = "The path to the SSL key file."},
318 KV{.key = "api_version.default", .value = "The default API version that the Clio server will run on."},
319 KV{.key = "api_version.min", .value = "The minimum API version allowed to use."},
320 KV{.key = "api_version.max", .value = "The maximum API version allowed to use."},
321 KV{.key = "migration.full_scan_threads", .value = "The number of threads used to scan the table."},
322 KV{.key = "migration.full_scan_jobs", .value = "The number of coroutines used to scan the table."},
323 KV{.key = "migration.cursors_per_job", .value = "The number of cursors each job will scan."}
324 };
325};
326
327} // namespace util::config
Array const & asArray(std::string_view key) const
Returns the Array object associated with the specified key.
Definition ConfigDefinition.cpp:138
ValueView getValueView(std::string_view fullKey) const
Returns the specified ValueView object associated with the key.
Definition ConfigDefinition.cpp:113
Struct to represent a key-value pair.
Definition ConfigDescription.hpp:48
All the config description are stored and extracted from this class.
Definition ConfigDescription.hpp:45
static std::expected< void, Error > generateConfigDescriptionToFile(std::filesystem::path path)
Generate markdown file of all the clio config descriptions.
Definition ConfigDescription.hpp:81
static constexpr std::string_view get(std::string_view key)
Retrieves the description for a given key.
Definition ConfigDescription.hpp:67
static void writeConfigDescriptionToFile(std::ostream &file)
Writes to Config description to file.
Definition ConfigDescription.hpp:111
constexpr ClioConfigDescription()=default
Constructs a new Clio Config Description based on pre-existing descriptions.