• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

knowledgepixels / nanopub-registry / 23976591988

04 Apr 2026 09:57AM UTC coverage: 31.828% (+0.5%) from 31.28%
23976591988

push

github

web-flow
Merge pull request #91 from knowledgepixels/perf/seqnum-batch-allocation

perf: batch seqNum allocation to reduce global counter contention

216 of 754 branches covered (28.65%)

Branch coverage included in aggregate %.

714 of 2168 relevant lines covered (32.93%)

5.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
src/main/java/com/knowledgepixels/registry/MetricsCollector.java
1
package com.knowledgepixels.registry;
2

3
import com.mongodb.client.ClientSession;
4
import io.micrometer.core.instrument.Gauge;
5
import io.micrometer.core.instrument.MeterRegistry;
6
import org.slf4j.Logger;
7
import org.slf4j.LoggerFactory;
8

9
import java.util.Map;
10
import java.util.Optional;
11
import java.util.concurrent.ConcurrentHashMap;
12
import java.util.concurrent.atomic.AtomicInteger;
13

14
import static com.knowledgepixels.registry.RegistryDB.*;
15

16
public final class MetricsCollector {
17

18
    private final Logger logger = LoggerFactory.getLogger(MetricsCollector.class);
×
19
    private final AtomicInteger seqNum = new AtomicInteger(0);
×
20
    private final AtomicInteger nanopubCount = new AtomicInteger(0);
×
21
    // TODO(transition): Remove loadCounter metric after dashboards updated
22
    private final AtomicInteger loadCounter = new AtomicInteger(0);
×
23
    private final AtomicInteger trustStateCounter = new AtomicInteger(0);
×
24
    private final AtomicInteger agentCount = new AtomicInteger(0);
×
25
    private final AtomicInteger accountCount = new AtomicInteger(0);
×
26

27
    private final Map<ServerStatus, AtomicInteger> statusStates = new ConcurrentHashMap<>();
×
28

29
    public MetricsCollector(MeterRegistry meterRegistry) {
×
30
        // Numeric metrics
31
        Gauge.builder("registry.seqnum", seqNum, AtomicInteger::get).register(meterRegistry);
×
32
        Gauge.builder("registry.nanopub.count", nanopubCount, AtomicInteger::get).register(meterRegistry);
×
33
        // TODO(transition): Remove after dashboards updated
34
        Gauge.builder("registry.load.counter", loadCounter, AtomicInteger::get).register(meterRegistry);
×
35
        Gauge.builder("registry.trust.state.counter", trustStateCounter, AtomicInteger::get).register(meterRegistry);
×
36
        Gauge.builder("registry.agent.count", agentCount, AtomicInteger::get).register(meterRegistry);
×
37
        Gauge.builder("registry.account.count", accountCount, AtomicInteger::get).register(meterRegistry);
×
38

39
        // Status label metrics
40
        for (final var status : ServerStatus.values()) {
×
41
            AtomicInteger stateGauge = new AtomicInteger(0);
×
42
            statusStates.put(status, stateGauge);
×
43
            Gauge.builder("registry.server.status", stateGauge, AtomicInteger::get)
×
44
                    .description("Server status (1 if current)")
×
45
                    .tag("status", status.name())
×
46
                    .register(meterRegistry);
×
47
        }
48
    }
×
49

50
    public void updateMetrics() {
51
        try (final var session = RegistryDB.getClient().startSession()) {
×
52
            // Update numeric metrics
53
            extractMaximalIntegerValueFromField(session, Collection.NANOPUBS.toString(), "seqNum")
×
54
                    .ifPresent(val -> {
×
55
                        seqNum.set(val);
×
56
                        loadCounter.set(val); // TODO(transition): Remove after dashboards updated
×
57
                    });
×
58
            nanopubCount.set((int) collection(Collection.NANOPUBS.toString()).estimatedDocumentCount());
×
59

60
            extractIntegerValueFromField(session, Collection.SERVER_INFO.toString(), "trustStateCounter")
×
61
                    .ifPresent(trustStateCounter::set);
×
62

63
            agentCount.set(countDocumentsInCollection(session, Collection.AGENTS.toString()));
×
64
            accountCount.set(countDocumentsInCollection(session, Collection.ACCOUNTS.toString()));
×
65

66
            // Update status gauge
67
            final var currentStatus = extractStringValueFromField(session, Collection.SERVER_INFO.toString(), "status")
×
68
                    .map(ServerStatus::valueOf)
×
69
                    .orElse(null);
×
70
            for (final var status : ServerStatus.values()) {
×
71
                statusStates.get(status).set(status.equals(currentStatus) ? 1 : 0);
×
72
            }
73
        } catch (Exception e) {
×
74
            logger.error("Error updating metrics: {}", e.getMessage());
×
75
        }
×
76
    }
×
77

78
    private Optional<Integer> extractMaximalIntegerValueFromField(
79
            ClientSession session,
80
            String collectionName,
81
            String fieldName
82
    ) {
83
        return Optional
×
84
                .ofNullable(getMaxValue(session, collectionName, fieldName))
×
85
                .filter(Number.class::isInstance)
×
86
                .map(Number.class::cast)
×
87
                .map(Number::intValue);
×
88
    }
89

90
    private Optional<Integer> extractIntegerValueFromField(
91
            ClientSession session,
92
            String collectionName,
93
            String fieldName
94
    ) {
95
        return Optional
×
96
                .ofNullable(getValue(session, collectionName, fieldName))
×
97
                .filter(Number.class::isInstance)
×
98
                .map(Number.class::cast)
×
99
                .map(Number::intValue);
×
100
    }
101

102
    private Optional<String> extractStringValueFromField(
103
            ClientSession session,
104
            String collectionName,
105
            String fieldName
106
    ) {
107
        return Optional
×
108
                .ofNullable(getValue(session, collectionName, fieldName))
×
109
                .filter(String.class::isInstance)
×
110
                .map(String.class::cast);
×
111
    }
112

113
    private int countDocumentsInCollection(ClientSession session, String collectionName) {
114
        return (int) collection(collectionName).countDocuments(session);
×
115
    }
116
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc