From 255db81e538e983d0be7bb94a13cd41ea72b9a93 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Wed, 30 Sep 2026 22:36:47 +0100 Subject: [PATCH] fix(telemetry): Name the key when a [telemetry] on/off value is invalid The seven on/off keys were read as integers, so a value such as enabled=true threw boost::bad_lexical_cast with no key in the message. They now go through readFlag, which accepts 0, 1, true and false in any case and otherwise throws a message naming the key. Startup still stops on a bad value, so the operator has to fix it. --- cfg/xrpld-example.cfg | 2 + src/libxrpl/telemetry/TelemetryConfig.cpp | 47 +++++++++++++++++++---- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/cfg/xrpld-example.cfg b/cfg/xrpld-example.cfg index 4aa150af76..c1ca59e8d8 100644 --- a/cfg/xrpld-example.cfg +++ b/cfg/xrpld-example.cfg @@ -1698,6 +1698,8 @@ validators.txt # enabled=0 # # Enable or disable telemetry at runtime. Default: 0 (disabled). +# This key, use_tls and the trace_* keys take 0, 1, true or false, in +# any case. Any other value is a startup error that names the key. # # service_name=xrpld # diff --git a/src/libxrpl/telemetry/TelemetryConfig.cpp b/src/libxrpl/telemetry/TelemetryConfig.cpp index 4f3698383c..a73351308a 100644 --- a/src/libxrpl/telemetry/TelemetryConfig.cpp +++ b/src/libxrpl/telemetry/TelemetryConfig.cpp @@ -9,6 +9,7 @@ */ #include +#include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include namespace xrpl::telemetry { @@ -129,6 +131,37 @@ readBounded( return static_cast(*parsed); } +/** + * Read an on/off key. Accepts 0, 1, true or false, in any case. + * + * Reading it as a number would throw boost::bad_lexical_cast for "true", + * naming no key. This reads the text and names the key instead. + * + * @param section The [telemetry] section to read from. + * @param name Key to read, as documented in cfg/xrpld-example.cfg. + * @param absentValue Value returned when the key is absent. + * @return The configured value, or absentValue if the key is absent. + * @throws std::runtime_error For any other value, with a message naming the + * key. + */ +[[nodiscard]] bool +readFlag(Section const& section, std::string_view name, bool absentValue) +{ + std::string const keyName{name}; + auto const text = section.get(keyName); + if (!text) + return absentValue; + + bool flag = false; + if (!beast::lexicalCastChecked(flag, *text)) + { + Throw( + "Invalid value '" + keyName + "' in " + kSectionLabel + + ": must be 0, 1, true or false."); + } + return flag; +} + /** * Derive a human-readable network type label from the numeric network ID. * @param networkId The network identifier from [network_id] config. @@ -161,14 +194,14 @@ makeTelemetrySetup( { Telemetry::Setup setup; - setup.enabled = section.valueOr(key::enabled, 0) != 0; + setup.enabled = readFlag(section, key::enabled, false); setup.serviceName = section.valueOr(key::serviceName, dflt::serviceName); setup.serviceVersion = version; setup.serviceInstanceId = section.valueOr(key::serviceInstanceId, nodePublicKey); setup.tracesEndpoint = section.valueOr(key::tracesEndpoint, dflt::tracesEndpoint); - setup.useTls = section.valueOr(key::useTls, 0) != 0; + setup.useTls = readFlag(section, key::useTls, false); setup.tlsCertPath = section.valueOr(key::tlsCaCert, ""); // Head sampling is intentionally fixed at 1.0 (sample everything) and is @@ -197,11 +230,11 @@ makeTelemetrySetup( setup.networkId = networkId; setup.networkType = networkTypeFromId(networkId); - setup.traceTransactions = section.valueOr(key::traceTransactions, 1) != 0; - setup.traceConsensus = section.valueOr(key::traceConsensus, 1) != 0; - setup.traceRpc = section.valueOr(key::traceRpc, 1) != 0; - setup.tracePeer = section.valueOr(key::tracePeer, 1) != 0; - setup.traceLedger = section.valueOr(key::traceLedger, 1) != 0; + setup.traceTransactions = readFlag(section, key::traceTransactions, true); + setup.traceConsensus = readFlag(section, key::traceConsensus, true); + setup.traceRpc = readFlag(section, key::traceRpc, true); + setup.tracePeer = readFlag(section, key::tracePeer, true); + setup.traceLedger = readFlag(section, key::traceLedger, true); return setup; }