Skip to content

Commit 4b7c14a

Browse files
authored
OAK-11609 : add support for metrics export to Prometheus via pushgateway for VersionGarbageCollector (#2216)
1 parent a72e127 commit 4b7c14a

File tree

7 files changed

+226
-16
lines changed

7 files changed

+226
-16
lines changed

oak-run-commons/src/main/java/org/apache/jackrabbit/oak/run/cli/NodeStoreFixtureProvider.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,19 @@ private static boolean oldSegmentStore(Options options) {
100100
return !manifest.exists();
101101
}
102102

103+
public static StatisticsProvider createStatsProvider(Whiteboard wb, Closer closer) {
104+
ScheduledExecutorService executorService =
105+
MoreExecutors.getExitingScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
106+
MetricStatisticsProvider statsProvider = new MetricStatisticsProvider(getPlatformMBeanServer(), executorService);
107+
closer.register(statsProvider);
108+
closer.register(() -> reportMetrics(statsProvider));
109+
wb.register(MetricRegistry.class, statsProvider.getRegistry(), emptyMap());
110+
return statsProvider;
111+
}
112+
103113
private static StatisticsProvider createStatsProvider(Options options, Whiteboard wb, Closer closer) {
104114
if (options.getCommonOpts().isMetricsEnabled()) {
105-
ScheduledExecutorService executorService =
106-
MoreExecutors.getExitingScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
107-
MetricStatisticsProvider statsProvider = new MetricStatisticsProvider(getPlatformMBeanServer(), executorService);
108-
closer.register(statsProvider);
109-
closer.register(() -> reportMetrics(statsProvider));
110-
wb.register(MetricRegistry.class, statsProvider.getRegistry(), emptyMap());
111-
return statsProvider;
115+
return createStatsProvider(wb, closer);
112116
}
113117
return StatisticsProvider.NOOP;
114118
}
@@ -163,7 +167,7 @@ public void close() throws IOException {
163167
}
164168
}
165169

166-
private static class ClosingWhiteboard implements Whiteboard {
170+
public static class ClosingWhiteboard implements Whiteboard {
167171
private final Whiteboard delegate;
168172
private final Closer closer;
169173

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.jackrabbit.oak.run;
20+
21+
import org.apache.jackrabbit.oak.plugins.document.FullGCMetricsExporter;
22+
23+
/**
24+
* Fixture encapsulating FullGC metrics exporter instance of T
25+
* @param <T>
26+
*/
27+
public interface FullGCMetricsExporterFixture<T> extends FullGCMetricsExporter<T>, MetricsExporterFixture<T> {
28+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.jackrabbit.oak.run;
20+
21+
import com.codahale.metrics.MetricRegistry;
22+
import io.prometheus.client.CollectorRegistry;
23+
import io.prometheus.client.dropwizard.DropwizardExports;
24+
import io.prometheus.client.exporter.PushGateway;
25+
import org.apache.jackrabbit.oak.run.MetricsExporterFixtureProvider.ExportMetricsArgs;
26+
import org.apache.jackrabbit.oak.run.MetricsExporterFixtureProvider.ExporterType;
27+
import org.apache.jackrabbit.oak.run.cli.NodeStoreFixtureProvider;
28+
import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
29+
import org.jetbrains.annotations.Nullable;
30+
import org.slf4j.Logger;
31+
import org.slf4j.LoggerFactory;
32+
33+
import java.io.IOException;
34+
35+
import static java.util.Collections.emptyMap;
36+
import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.getService;
37+
38+
/**
39+
* Initializes metrics exported fixture for fullGC. For use in oak-run RevisionsCommand.
40+
*/
41+
class FullGCMetricsExporterFixtureProvider {
42+
43+
private static final Logger log = LoggerFactory.getLogger(NodeStoreFixtureProvider.class);
44+
45+
@Nullable
46+
static FullGCMetricsExporterFixture<PushGateway> create(RevisionsCommand.RevisionsOptions options, Whiteboard wb) {
47+
if (options.exportMetrics()) {
48+
CollectorRegistry collectorRegistry = new CollectorRegistry();
49+
wb.register(CollectorRegistry.class, collectorRegistry, emptyMap());
50+
51+
MetricRegistry metricRegistry = getService(wb, MetricRegistry.class);
52+
53+
ExportMetricsArgs metricsArgs = new ExportMetricsArgs(options.exportMetricsArgs());
54+
if (metricsArgs.getExporterType() == ExporterType.pushgateway) {
55+
PushGateway pg = new PushGateway(metricsArgs.getPushUri());
56+
new DropwizardExports(metricRegistry).register(collectorRegistry);
57+
58+
wb.register(PushGateway.class, pg, emptyMap());
59+
return new FullGCMetricsExporterFixture<>() {
60+
public ExporterType getExporterType() {
61+
return ExporterType.pushgateway;
62+
}
63+
64+
public PushGateway getMetricsExporter() {
65+
return pg;
66+
}
67+
68+
@Override
69+
public void close() {
70+
pushMetrics(collectorRegistry, pg, metricsArgs);
71+
}
72+
73+
/**
74+
* Push the metricsMap that is passed from VersionGarbageCollector to pushgateway.
75+
*/
76+
@Override
77+
public void onIterationComplete() {
78+
pushMetrics(collectorRegistry, pg, metricsArgs);
79+
}
80+
};
81+
}
82+
}
83+
return null;
84+
}
85+
86+
private static void pushMetrics(CollectorRegistry collectorRegistry, PushGateway pg, ExportMetricsArgs metricsArgs) {
87+
try {
88+
log.info("Pushing metrics to pushgateway: ", metricsArgs.getPushMap());
89+
pg.pushAdd(collectorRegistry, PushGateway.class.getName(), metricsArgs.getPushMap());
90+
} catch (IOException e) {
91+
log.error("Error pushing metrics to pushgateway", e);
92+
}
93+
}
94+
}

oak-run/src/main/java/org/apache/jackrabbit/oak/run/RevisionsCommand.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import java.util.Arrays;
21+
import java.util.Collections;
2122
import java.util.List;
2223
import java.util.Locale;
2324
import java.util.Optional;
@@ -42,6 +43,7 @@
4243
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreBuilder;
4344
import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
4445
import org.apache.jackrabbit.oak.plugins.document.FormatVersion;
46+
import org.apache.jackrabbit.oak.plugins.document.FullGCMetricsExporter;
4547
import org.apache.jackrabbit.oak.plugins.document.MissingLastRevSeeker;
4648
import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
4749
import org.apache.jackrabbit.oak.plugins.document.RevisionContextWrapper;
@@ -50,12 +52,16 @@
5052
import org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCInfo;
5153
import org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats;
5254
import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
55+
import org.apache.jackrabbit.oak.run.cli.NodeStoreFixtureProvider;
5356
import org.apache.jackrabbit.oak.run.commons.Command;
5457
import org.apache.jackrabbit.oak.plugins.document.VersionGCOptions;
5558
import org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector;
5659
import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore;
5760
import org.apache.jackrabbit.oak.spi.gc.LoggingGCMonitor;
61+
import org.apache.jackrabbit.oak.spi.whiteboard.DefaultWhiteboard;
62+
import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
5863
import org.apache.jackrabbit.oak.stats.DefaultStatisticsProvider;
64+
import org.apache.jackrabbit.oak.stats.StatisticsProvider;
5965
import org.bson.Document;
6066
import org.slf4j.Logger;
6167
import org.slf4j.LoggerFactory;
@@ -75,6 +81,7 @@
7581
import static org.apache.jackrabbit.oak.run.Utils.asCloseable;
7682
import static org.apache.jackrabbit.oak.run.Utils.createDocumentMKBuilder;
7783
import static org.apache.jackrabbit.oak.run.Utils.getMongoConnection;
84+
import static org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils.getService;
7885

7986
/**
8087
* Gives information about current node revisions state.
@@ -118,7 +125,7 @@ public RevisionsCommand(boolean exitWhenDone) {
118125
this.exitWhenDone = exitWhenDone;
119126
}
120127

121-
private static class RevisionsOptions extends Utils.NodeStoreOptions {
128+
static class RevisionsOptions extends Utils.NodeStoreOptions {
122129

123130
static final String CMD_INFO = "info";
124131
static final String CMD_COLLECT = "collect";
@@ -148,6 +155,7 @@ private static class RevisionsOptions extends Utils.NodeStoreOptions {
148155
final OptionSpec<Boolean> embeddedVerification;
149156
final OptionSpec<Integer> fullGcMode;
150157
final OptionSpec<Boolean> fullGCAuditLoggingEnabled;
158+
final OptionSpec<String> exportMetrics;
151159

152160
RevisionsOptions(String usage) {
153161
super(usage);
@@ -211,6 +219,8 @@ private static class RevisionsOptions extends Utils.NodeStoreOptions {
211219
.withOptionalArg().ofType(Long.class).defaultsTo(TimeUnit.DAYS.toSeconds(1));
212220
fullGCAuditLoggingEnabled = parser.accepts("fullGCAuditLoggingEnabled", "Enable audit logging for Full GC")
213221
.withOptionalArg().ofType(Boolean.class).defaultsTo(FALSE);
222+
exportMetrics = parser.accepts("exportMetrics",
223+
"type, URI to export the metrics and optional metadata all delimeted by semi-colon(;)").withRequiredArg();
214224
}
215225

216226
public RevisionsOptions parse(String[] args) {
@@ -313,6 +323,14 @@ boolean doCompaction() {
313323
Boolean isFullGCAuditLoggingEnabled() {
314324
return options.has(fullGCAuditLoggingEnabled);
315325
}
326+
327+
boolean exportMetrics() {
328+
return options.has(exportMetrics);
329+
}
330+
331+
String exportMetricsArgs() {
332+
return exportMetrics.value(options);
333+
}
316334
}
317335

318336
@Override
@@ -382,7 +400,6 @@ private VersionGarbageCollector bootstrapVGC(RevisionsOptions options, Closer cl
382400
builder.setFullGCBatchSize(options.getFullGcBatchSize());
383401
builder.setFullGCProgressSize(options.getFullGcProgressSize());
384402
builder.setFullGcMaxAgeMillis(SECONDS.toMillis(options.getFullGcMaxAge()));
385-
builder.setFullGCAuditLoggingEnabled(options.isFullGCAuditLoggingEnabled());
386403

387404
// create a VersionGCSupport while builder is read-write
388405
VersionGCSupport gcSupport = builder.createVersionGCSupport();
@@ -416,7 +433,6 @@ private VersionGarbageCollector bootstrapVGC(RevisionsOptions options, Closer cl
416433
System.out.println("FullGcProgressSize is : " + options.getFullGcProgressSize());
417434
System.out.println("FullGcMaxAgeInSecs is : " + options.getFullGcMaxAge());
418435
System.out.println("FullGcMaxAgeMillis is : " + builder.getFullGcMaxAgeMillis());
419-
System.out.println("FullGCAuditLoggingEnabled is : " + options.isFullGCAuditLoggingEnabled());
420436
VersionGarbageCollector gc = createVersionGC(builder.build(), gcSupport, options.isDryRun(), builder);
421437

422438
VersionGCOptions gcOptions = gc.getOptions();
@@ -460,11 +476,22 @@ private void printInfo(VersionGarbageCollector gc, RevisionsOptions options) thr
460476

461477
private void collect(final RevisionsOptions options, Closer closer, boolean fullGCEnabled) throws IOException {
462478
VersionGarbageCollector gc = bootstrapVGC(options, closer, fullGCEnabled);
463-
// Set a default statistics provider
464-
gc.setStatisticsProvider(new DefaultStatisticsProvider(Executors.newSingleThreadScheduledExecutor()));
479+
480+
// setup metrics exporter
481+
Whiteboard whiteboard = new NodeStoreFixtureProvider.ClosingWhiteboard(new DefaultWhiteboard(), closer);
482+
StatisticsProvider statsProvider = NodeStoreFixtureProvider.createStatsProvider(whiteboard, closer);
483+
whiteboard.register(StatisticsProvider.class, statsProvider, Collections.emptyMap());
484+
gc.setStatisticsProvider(statsProvider, true);
485+
486+
FullGCMetricsExporter metricsExporter = FullGCMetricsExporterFixtureProvider.create(options, whiteboard);
487+
gc.setFullGCMetricsExporter(metricsExporter);
488+
465489
ExecutorService executor = Executors.newSingleThreadExecutor();
466490
final Semaphore finished = new Semaphore(0);
467491
try {
492+
// register metrics exporter to closer
493+
closer.register(metricsExporter);
494+
468495
// collect until shutdown hook is called
469496
final AtomicBoolean running = new AtomicBoolean(true);
470497
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
@@ -490,6 +517,7 @@ private void collect(final RevisionsOptions options, Closer closer, boolean full
490517
}
491518
System.out.println("retrieving gc info");
492519
printInfo(gc, options);
520+
} catch (Exception e) {
493521
} finally {
494522
finished.release();
495523
if (options.isDryRun()) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.jackrabbit.oak.plugins.document;
20+
21+
import java.io.Closeable;
22+
import java.util.Map;
23+
24+
/**
25+
* Exporter interface for setting dependency for VersionGarbageCollector that allows
26+
* for export of fullGC metrics to Prometheus via pushgateway.
27+
* @param <T>
28+
*/
29+
public interface FullGCMetricsExporter<T> extends Closeable {
30+
31+
/**
32+
* Called from VersionGarbageCollector when a fullGC iteration completes.
33+
*/
34+
void onIterationComplete();
35+
}

oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/FullGCStatsCollectorImpl.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
*/
3838
class FullGCStatsCollectorImpl implements FullGCStatsCollector {
3939

40+
static final String OAK_RUN_METRICS_PREFIX = "oak_FullGC";
4041
static final String FULL_GC = "FullGC";
4142
static final String READ_DOC = "READ_DOC";
4243
static final String DELETED_ORPHAN_NODE = "DELETED_ORPHAN_NODE";
@@ -83,9 +84,15 @@ class FullGCStatsCollectorImpl implements FullGCStatsCollector {
8384

8485
private final CounterStats counter;
8586
private final CounterStats failureCounter;
87+
private static String METRICS_QUALIFIED_NAME_PREFIX;
8688

8789
FullGCStatsCollectorImpl(StatisticsProvider provider) {
90+
this(provider, false);
91+
}
92+
93+
FullGCStatsCollectorImpl(StatisticsProvider provider, boolean isOakRunJob) {
8894
this.provider = provider;
95+
this.METRICS_QUALIFIED_NAME_PREFIX = isOakRunJob ? OAK_RUN_METRICS_PREFIX : FULL_GC;
8996

9097
readDoc = meter(provider, READ_DOC);
9198
deletedOrphanNode = meter(provider, DELETED_ORPHAN_NODE);
@@ -232,11 +239,10 @@ private static CounterStats counter(StatisticsProvider provider, String name) {
232239
}
233240

234241
private static String qualifiedName(String metricName) {
235-
return FULL_GC + "." + metricName;
242+
return METRICS_QUALIFIED_NAME_PREFIX + "." + metricName;
236243
}
237244

238245
private MeterStats getMeter(Map<GCPhase, MeterStats> map, GCPhase phase, String name) {
239246
return map.computeIfAbsent(phase, p -> meter(provider, name + "." + p.name()));
240247
}
241-
242248
}

0 commit comments

Comments
 (0)