Skip to content

Commit 18e545f

Browse files
authored
Add topology export trigger for party metrics (#2497)
The trigger is disabled by default. [ci] Signed-off-by: Simon Meier <[email protected]>
1 parent dfe17c9 commit 18e545f

File tree

7 files changed

+100
-4
lines changed

7 files changed

+100
-4
lines changed

apps/app/src/test/scala/org/lfdecentralizedtrust/splice/integration/tests/ValidatorIntegrationTest.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.lfdecentralizedtrust.splice.integration.tests.SpliceTests.Integration
1212
import org.lfdecentralizedtrust.splice.util.WalletTestUtil
1313
import org.lfdecentralizedtrust.splice.validator.config.ValidatorAppBackendConfig
1414
import com.digitalasset.canton.config.CantonRequireTypes.InstanceName
15+
import com.digitalasset.canton.config.NonNegativeFiniteDuration
1516
import com.digitalasset.canton.config.RequireTypes.PositiveInt
1617
import com.digitalasset.canton.logging.SuppressionRule
1718
import com.digitalasset.canton.sequencing.SubmissionRequestAmplification
@@ -21,6 +22,7 @@ import org.apache.pekko.http.scaladsl.Http
2122
import org.apache.pekko.http.scaladsl.client.RequestBuilding.{Get, Post}
2223
import org.apache.pekko.http.scaladsl.model.StatusCodes
2324
import org.apache.pekko.http.scaladsl.model.headers.{Authorization, OAuth2BearerToken}
25+
import org.lfdecentralizedtrust.splice.config.ConfigTransforms
2426
import org.slf4j.event.Level
2527

2628
import scala.concurrent.Future
@@ -70,6 +72,13 @@ class ValidatorIntegrationTest extends IntegrationTest with WalletTestUtil {
7072
)
7173
})
7274
})
75+
// The topology metrics trigger is disabled by default.
76+
// Enable it here to check that it starts and runs without errors
77+
.addConfigTransform((_, config) =>
78+
ConfigTransforms.updateAllAutomationConfigs(
79+
_.copy(topologyMetricsPollingInterval = Some(NonNegativeFiniteDuration.ofSeconds(1)))
80+
)(config)
81+
)
7382

7483
"start and restart cleanly" in { implicit env =>
7584
initDsoWithSv1Only()

apps/common/src/main/scala/org/lfdecentralizedtrust/splice/config/AutomationConfig.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ case class AutomationConfig(
4646
*/
4747
domainIngestionPollingInterval: NonNegativeFiniteDuration =
4848
NonNegativeFiniteDuration ofSeconds 30,
49+
/** Polling interval to recompute and export topology metrics.
50+
*
51+
* Set to None to disable the topology metrics trigger.
52+
*/
53+
topologyMetricsPollingInterval: Option[NonNegativeFiniteDuration] = None,
4954
/** Maximal number of retries that the time-based triggers retry transient failures w/o raising a warning.
5055
*/
5156
maxNumSilentPollingRetries: Int = 3,

apps/validator/src/main/scala/org/lfdecentralizedtrust/splice/validator/ValidatorApp.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ class ValidatorApp(
853853
config.maxVettingDelay,
854854
config.parameters,
855855
config.latestPackagesOnly,
856+
metrics,
856857
loggerFactory,
857858
)
858859
_ <- MonadUtil.sequentialTraverse_(config.appInstances.toList)({ case (name, instance) =>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) 2024 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package org.lfdecentralizedtrust.splice.validator.automation
5+
6+
import com.digitalasset.canton.topology.store.TopologyStoreId
7+
import com.digitalasset.canton.topology.transaction.PartyToParticipant
8+
import com.digitalasset.canton.tracing.TraceContext
9+
import io.opentelemetry.api.trace.Tracer
10+
import org.lfdecentralizedtrust.splice.automation.{PollingTrigger, TriggerContext}
11+
import org.lfdecentralizedtrust.splice.environment.ParticipantAdminConnection
12+
import org.lfdecentralizedtrust.splice.environment.TopologyAdminConnection.TopologyResult
13+
import org.lfdecentralizedtrust.splice.scan.admin.api.client.ScanConnection
14+
import org.lfdecentralizedtrust.splice.validator.metrics.ValidatorAppMetrics
15+
16+
import scala.concurrent.{ExecutionContext, Future}
17+
18+
class TopologyMetricsTrigger(
19+
override protected val context: TriggerContext,
20+
metrics: ValidatorAppMetrics,
21+
scanConnection: ScanConnection,
22+
participantAdminConnection: ParticipantAdminConnection,
23+
)(implicit
24+
override val ec: ExecutionContext,
25+
override val tracer: Tracer,
26+
) extends PollingTrigger {
27+
28+
override def performWorkIfAvailable()(implicit
29+
tc: TraceContext
30+
): Future[Boolean] =
31+
for {
32+
synchronizerId <- scanConnection.getAmuletRulesDomain()(tc)
33+
partyMappings <- participantAdminConnection.listPartyToParticipant(
34+
store = Some(TopologyStoreId.SynchronizerStore(synchronizerId))
35+
)
36+
} yield {
37+
updateMetrics(partyMappings)
38+
false
39+
}
40+
41+
private def updateMetrics(
42+
partyMappings: Seq[TopologyResult[PartyToParticipant]]
43+
) = {
44+
metrics.numberOfPartiesGauge.updateValue(partyMappings.size.toDouble)
45+
}
46+
}

apps/validator/src/main/scala/org/lfdecentralizedtrust/splice/validator/automation/ValidatorAutomationService.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import io.opentelemetry.api.trace.Tracer
4242
import monocle.Monocle.toAppliedFocusOps
4343
import org.apache.pekko.stream.Materializer
4444
import org.lfdecentralizedtrust.splice.store.AppStoreWithIngestion.SpliceLedgerConnectionPriority
45+
import org.lfdecentralizedtrust.splice.validator.metrics.ValidatorAppMetrics
4546

4647
import java.nio.file.Path
4748
import scala.concurrent.ExecutionContextExecutor
@@ -77,6 +78,7 @@ class ValidatorAutomationService(
7778
maxVettingDelay: NonNegativeFiniteDuration,
7879
params: SpliceParametersConfig,
7980
latestPackagesOnly: Boolean,
81+
metrics: ValidatorAppMetrics,
8082
override protected val loggerFactory: NamedLoggerFactory,
8183
)(implicit
8284
ec: ExecutionContextExecutor,
@@ -98,6 +100,19 @@ class ValidatorAutomationService(
98100
: org.lfdecentralizedtrust.splice.validator.automation.ValidatorAutomationService.type =
99101
ValidatorAutomationService
100102

103+
automationConfig.topologyMetricsPollingInterval.foreach(topologyPollingInterval =>
104+
registerTrigger(
105+
new TopologyMetricsTrigger(
106+
triggerContext
107+
.focus(_.config.pollingInterval)
108+
.replace(topologyPollingInterval),
109+
metrics,
110+
scanConnection,
111+
participantAdminConnection,
112+
)
113+
)
114+
)
115+
101116
walletManagerOpt.foreach { walletManager =>
102117
registerTrigger(
103118
new WalletAppInstallTrigger(

apps/validator/src/main/scala/org/lfdecentralizedtrust/splice/validator/metrics/ValidatorAppMetrics.scala

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,28 @@
33

44
package org.lfdecentralizedtrust.splice.validator.metrics
55

6-
import com.daml.metrics.api.MetricHandle.LabeledMetricsFactory
6+
import com.daml.metrics.api.MetricHandle.{Gauge, LabeledMetricsFactory}
7+
import com.daml.metrics.api.{MetricInfo, MetricsContext}
8+
import com.daml.metrics.api.MetricQualification.Saturation
79
import org.lfdecentralizedtrust.splice.BaseSpliceMetrics
810
import com.digitalasset.canton.metrics.DbStorageHistograms
911

1012
/** Modelled after [[com.digitalasset.canton.synchronizer.metrics.DomainMetrics]].
11-
*
12-
* This is only a bare-bones implementation so the code compiles so far.
1313
*/
1414
class ValidatorAppMetrics(
1515
metricsFactory: LabeledMetricsFactory,
1616
storageHistograms: DbStorageHistograms,
17-
) extends BaseSpliceMetrics("validator", metricsFactory, storageHistograms) {}
17+
) extends BaseSpliceMetrics("validator", metricsFactory, storageHistograms) {
18+
19+
val numberOfPartiesGauge: Gauge[Double] =
20+
metricsFactory.gauge[Double](
21+
MetricInfo(
22+
prefix :+ "synchronizer-topology-num-parties",
23+
summary = "Total number of parties",
24+
description = "The total number of parties allocated on the global synchronizer.",
25+
qualification = Saturation,
26+
),
27+
Double.NaN,
28+
)(MetricsContext.Empty)
29+
30+
}

docs/src/release_notes.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ Upcoming
1515

1616
- All app & UI images now use a non-root user.
1717

18+
- Validator
19+
20+
- Add a trigger to export the metric ``validator_synchronizer_topology_num_parties``
21+
that counts the number of parties allocated on the Global Synchronizer.
22+
The trigger does not run by default. To enable it, add the following to your validator app config:
23+
``canton.validator-apps.<your-validator-name>.automation.topology-metrics-polling-interval = 5m``.
24+
1825
- SV
1926

2027
- Deployment

0 commit comments

Comments
 (0)