merge: bring the metrics_endpoint key forward from phase-8

Telemetry.cpp conflicted. Phase-9 rewrote the metrics pipeline into
makeTracerResource()/makeMetricsResource()/initMetrics() further down the
class, so its side of the region is empty and phase-8's private helper
block does not apply. Resolved to phase-9's structure; phase-8's own
hunks outside the region (the deleted kTracesPath/kMetricsPath, the
verbatim traces URL, the two-endpoint startup log) merged in.

Phase-9's initMetrics() still derives the metrics URL by suffix-swap.
That is fixed in the next commit, not here.
This commit is contained in:
Pratik Mankawde
2026-09-03 16:45:09 +01:00
7 changed files with 25 additions and 15 deletions

View File

@@ -572,13 +572,14 @@ graph LR
server=otel # NEW: uses OTel OTLP metrics exporter
# No prefix: it applies on the StatsD path only, not this one.
# Endpoint and auth inherited from [telemetry] section:
# Endpoints and auth come from the [telemetry] section:
[telemetry]
enabled=1
endpoint=http://localhost:4318/v1/traces
traces_endpoint=http://localhost:4318/v1/traces
metrics_endpoint=http://localhost:4318/v1/metrics
```
The `OTelCollector` reads the OTLP endpoint from `[telemetry]` config (replacing `/v1/traces` with `/v1/metrics` for the metrics exporter). No additional config keys needed.
Each signal has its own key and each URL is used verbatim, so an operator can send traces and metrics to different collectors, or to one whose OTLP paths are not the defaults.
**Backward compatibility**: `server=statsd` continues to work exactly as before.

View File

@@ -615,9 +615,9 @@ name and maps `.` and space to `_`, and the only place the class reads `prefix_`
is its startup log line. Exported names are therefore the lowercased raw names
(`jobq_job_count`, `rpc_requests_total`) and the service is identified by the OTel
resource `service.name`, not by a name prefix. `endpoint` is read from this section
but likewise reaches only that log line — the real exporter URL is derived inside
`Telemetry::initMetrics()` from `[telemetry] endpoint`, by swapping the trailing
`/v1/traces` for `/v1/metrics`.
but likewise reaches only that log line — the exporter URL comes from
`[telemetry] metrics_endpoint`, which `Telemetry::initMetrics()` uses verbatim. No
endpoint is derived from another.
Fallback (StatsD). `StatsDCollector` is still selected by this value, but the
stack in `docker/telemetry/` no longer receives it: using this path also requires

View File

@@ -385,7 +385,7 @@ ${IPS_FIXED}
enabled=1
service_instance_id=Node-${i}
traces_endpoint=http://localhost:4318/v1/traces
exporter=otlp_http
metrics_endpoint=http://localhost:4318/v1/metrics
batch_size=512
batch_delay_ms=2000
max_queue_size=2048

View File

@@ -210,6 +210,14 @@ public:
*/
std::string tracesEndpoint = "http://localhost:4318/v1/traces";
/**
* Full OTLP/HTTP URL where metrics are sent, including the signal path.
* Used verbatim and independent of tracesEndpoint, so an operator can
* point the two signals at different collectors, or at one whose OTLP
* paths are not the defaults.
*/
std::string metricsEndpoint = "http://localhost:4318/v1/metrics";
/**
* Whether to use TLS for the exporter connection.
*/

View File

@@ -83,12 +83,6 @@ namespace xrpl::telemetry {
static_assert(kMeterName == beast::insight::kOTelMeterName);
static_assert(kMeterVersion == beast::insight::kOTelMeterVersion);
/**
* OTLP/HTTP path per signal, appended by signalEndpoint().
*/
constexpr std::string_view kTracesPath{"/v1/traces"};
constexpr std::string_view kMetricsPath{"/v1/metrics"};
/**
* Metric export cadence. The interval matches the 1 s scrape the dashboards
* assume; the timeout bounds a stalled collector.
@@ -390,11 +384,12 @@ public:
start() override
{
JLOG(journal_.info()) << "Telemetry starting: traces_endpoint=" << setup_.tracesEndpoint
<< " metrics_endpoint=" << setup_.metricsEndpoint
<< " sampling=" << setup_.samplingRatio;
// Configure OTLP HTTP exporter
otlp_http::OtlpHttpExporterOptions exporterOpts;
exporterOpts.url = signalEndpoint(setup_.tracesEndpoint, kTracesPath);
exporterOpts.url = setup_.tracesEndpoint;
if (setup_.useTls)
{
exporterOpts.ssl_ca_cert_path = setup_.tlsCertPath;

View File

@@ -36,6 +36,7 @@ constexpr char const* enabled = "enabled";
constexpr char const* serviceName = "service_name";
constexpr char const* serviceInstanceId = "service_instance_id";
constexpr char const* tracesEndpoint = "traces_endpoint";
constexpr char const* metricsEndpoint = "metrics_endpoint";
constexpr char const* useTls = "use_tls";
constexpr char const* tlsCaCert = "tls_ca_cert";
constexpr char const* tlsClientCert = "tls_client_cert";
@@ -61,6 +62,7 @@ constexpr char const* traceLedger = "trace_ledger";
namespace dflt {
constexpr char const* serviceName = "xrpld";
constexpr char const* tracesEndpoint = "http://localhost:4318/v1/traces";
constexpr char const* metricsEndpoint = "http://localhost:4318/v1/metrics";
constexpr std::uint32_t batchSize = 512u;
constexpr std::uint32_t batchDelayMs = 5000u;
constexpr std::uint32_t maxQueueSize = 2048u;
@@ -137,6 +139,8 @@ makeTelemetrySetup(
setup.serviceInstanceId = section.valueOr<std::string>(key::serviceInstanceId, nodePublicKey);
setup.tracesEndpoint = section.valueOr<std::string>(key::tracesEndpoint, dflt::tracesEndpoint);
setup.metricsEndpoint =
section.valueOr<std::string>(key::metricsEndpoint, dflt::metricsEndpoint);
setup.useTls = section.valueOr<int>(key::useTls, 0) != 0;
setup.tlsCertPath = section.valueOr<std::string>(key::tlsCaCert, "");

View File

@@ -117,6 +117,7 @@ TEST(TelemetryConfig, setup_defaults)
EXPECT_TRUE(s.serviceInstanceId.empty());
EXPECT_TRUE(s.nodeId.empty());
EXPECT_EQ(s.tracesEndpoint, "http://localhost:4318/v1/traces");
EXPECT_EQ(s.metricsEndpoint, "http://localhost:4318/v1/metrics");
EXPECT_FALSE(s.useTls);
EXPECT_TRUE(s.tlsCertPath.empty());
EXPECT_DOUBLE_EQ(s.samplingRatio, 1.0);
@@ -159,8 +160,8 @@ TEST(TelemetryConfig, parse_full_section)
section.set("enabled", "1");
section.set("service_name", "my-rippled");
section.set("service_instance_id", "custom-id");
section.set("exporter", "otlp_http");
section.set("traces_endpoint", "http://collector:4318/v1/traces");
section.set("metrics_endpoint", "http://collector:4318/v1/metrics");
section.set("use_tls", "1");
section.set("tls_ca_cert", caCert);
section.set("batch_size", "256");
@@ -178,6 +179,7 @@ TEST(TelemetryConfig, parse_full_section)
EXPECT_EQ(setup.serviceName, "my-rippled");
EXPECT_EQ(setup.serviceInstanceId, "custom-id");
EXPECT_EQ(setup.tracesEndpoint, "http://collector:4318/v1/traces");
EXPECT_EQ(setup.metricsEndpoint, "http://collector:4318/v1/metrics");
EXPECT_TRUE(setup.useTls);
EXPECT_EQ(setup.tlsCertPath, caCert);
EXPECT_EQ(setup.batchSize, 256u);