Skip to content

Commit

Permalink
chore: add metrics docs generation
Browse files Browse the repository at this point in the history
  • Loading branch information
jeqo committed Oct 14, 2024
1 parent 7a96610 commit 1e055c9
Show file tree
Hide file tree
Showing 7 changed files with 575 additions and 7 deletions.
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ all: clean build test

clean:
./gradlew clean
rm config.rst metrics.rst

checkstyle:
./gradlew checkstyleMain checkstyleTest checkstyleIntegrationTest
Expand All @@ -43,9 +44,14 @@ storage/azure/build/distributions/azure-$(VERSION).tgz:
./gradlew build :storage:azure:distTar -x test -x integrationTest -x e2e:test

.PHONY: docs
docs:
docs: config.rst metrics.rst

config.rst:
./gradlew :docs:genConfigDocs

metrics.rst:
./gradlew :docs:genMetricsDocs

test: build
./gradlew test -x e2e:test

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
import com.github.benmanes.caffeine.cache.Weigher;

public abstract class ChunkCache<T> implements ChunkManager, Configurable {
private static final String METRIC_GROUP = "chunk-cache-metrics";
private static final String THREAD_POOL_METRIC_GROUP = "chunk-cache-thread-pool-metrics";
public static final String METRIC_GROUP = "chunk-cache-metrics";
public static final String THREAD_POOL_METRIC_GROUP = "chunk-cache-thread-pool-metrics";

private final ChunkManager chunkManager;
private ExecutorService executor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public class MemorySegmentIndexesCache implements SegmentIndexesCache {
private static final Logger log = LoggerFactory.getLogger(MemorySegmentIndexesCache.class);

private static final long DEFAULT_MAX_SIZE_BYTES = 10 * 1024 * 1024;
private static final String METRIC_GROUP = "segment-indexes-cache-metrics";
private static final String THREAD_POOL_METRIC_GROUP = "segment-indexes-cache-thread-pool-metrics";
public static final String METRIC_GROUP = "segment-indexes-cache-metrics";
public static final String THREAD_POOL_METRIC_GROUP = "segment-indexes-cache-thread-pool-metrics";

private final CaffeineStatsCounter statsCounter = new CaffeineStatsCounter(METRIC_GROUP);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@

public class MemorySegmentManifestCache implements SegmentManifestCache {
private static final Logger log = LoggerFactory.getLogger(MemorySegmentManifestCache.class);
private static final String METRIC_GROUP = "segment-manifest-cache-metrics";
private static final String THREAD_POOL_METRIC_GROUP = "segment-manifest-cache-thread-pool-metrics";
public static final String METRIC_GROUP = "segment-manifest-cache-metrics";
public static final String THREAD_POOL_METRIC_GROUP = "segment-manifest-cache-thread-pool-metrics";
private static final long DEFAULT_MAX_SIZE = 1000L;
private static final long DEFAULT_RETENTION_MS = 3_600_000;

Expand Down
6 changes: 6 additions & 0 deletions docs/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ tasks.register('genConfigDocs', JavaExec) {
mainClass = 'io.aiven.kafka.tieredstorage.misc.ConfigDocs'
standardOutput = new File("config.rst").newOutputStream()
}

tasks.register('genMetricsDocs', JavaExec) {
classpath = sourceSets.main.runtimeClasspath
mainClass = 'io.aiven.kafka.tieredstorage.misc.MetricDocs'
standardOutput = new File("metrics.rst").newOutputStream()
}
189 changes: 189 additions & 0 deletions docs/src/main/java/io/aiven/kafka/tieredstorage/misc/MetricDocs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright 2024 Aiven Oy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.aiven.kafka.tieredstorage.misc;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

import org.apache.kafka.common.MetricName;
import org.apache.kafka.common.MetricNameTemplate;
import org.apache.kafka.common.metrics.Metrics;
import org.apache.kafka.common.utils.Sanitizer;

import io.aiven.kafka.tieredstorage.fetch.cache.ChunkCache;
import io.aiven.kafka.tieredstorage.fetch.index.MemorySegmentIndexesCache;
import io.aiven.kafka.tieredstorage.fetch.manifest.MemorySegmentManifestCache;
import io.aiven.kafka.tieredstorage.metrics.CaffeineMetricsRegistry;
import io.aiven.kafka.tieredstorage.metrics.MetricsRegistry;
import io.aiven.kafka.tieredstorage.metrics.ThreadPoolMonitorMetricsRegistry;

public class MetricDocs {
public static void main(final String[] args) {
printSectionTitle("Core components metrics");
System.out.println();
printSubsectionTitle("RemoteStorageManager metrics");
System.out.println();
System.out.println(toRstTable("test", new MetricsRegistry().all()));

System.out.println();
printSubsectionTitle("SegmentManifestCache metrics");
System.out.println();
System.out.println(toRstTable(
"test",
new CaffeineMetricsRegistry(MemorySegmentManifestCache.METRIC_GROUP).all()));
System.out.println();
System.out.println(toRstTable(
"test",
new ThreadPoolMonitorMetricsRegistry(MemorySegmentManifestCache.THREAD_POOL_METRIC_GROUP).all()));

System.out.println();
printSubsectionTitle("SegmentIndexesCache metrics");
System.out.println(toRstTable(
"test",
new CaffeineMetricsRegistry(MemorySegmentIndexesCache.METRIC_GROUP).all()));
System.out.println(toRstTable(
"test",
new ThreadPoolMonitorMetricsRegistry(MemorySegmentIndexesCache.THREAD_POOL_METRIC_GROUP).all()));
System.out.println();
printSubsectionTitle("ChunkCache metrics");
System.out.println();
System.out.println(toRstTable(
"test",
new CaffeineMetricsRegistry(ChunkCache.METRIC_GROUP).all()));
System.out.println();
System.out.println(toRstTable(
"test",
new ThreadPoolMonitorMetricsRegistry(ChunkCache.THREAD_POOL_METRIC_GROUP).all()));

System.out.println();
printSectionTitle("Storage Backend metrics");
System.out.println();
printSubsectionTitle("AzureBlobStorage metrics");
System.out.println();
System.out.println(toRstTable(
"test",
new io.aiven.kafka.tieredstorage.storage.azure.MetricRegistry().all()));
System.out.println();
printSubsectionTitle("GcsStorage metrics");
System.out.println();
System.out.println(toRstTable(
"test",
new io.aiven.kafka.tieredstorage.storage.gcs.MetricRegistry().all()));
System.out.println();
printSubsectionTitle("S3Storage metrics");
System.out.println();
System.out.println(toRstTable(
"test",
new io.aiven.kafka.tieredstorage.storage.s3.MetricRegistry().all()));
}

public static String toRstTable(final String domain, final Iterable<MetricNameTemplate> allMetrics) {
final Map<String, Map<String, String>> beansAndAttributes = new TreeMap<>();

try (final Metrics metrics = new Metrics()) {
for (final MetricNameTemplate template : allMetrics) {
final Map<String, String> tags = new LinkedHashMap<>();
for (final String s : template.tags()) {
tags.put(s, "{" + s + "}");
}

final MetricName metricName = metrics.metricName(
template.name(),
template.group(),
template.description(),
tags
);
final String beanName = getMBeanName(domain, metricName);
beansAndAttributes.computeIfAbsent(beanName, k -> new TreeMap<>());
final Map<String, String> attrAndDesc = beansAndAttributes.get(beanName);
if (!attrAndDesc.containsKey(template.name())) {
attrAndDesc.put(template.name(), template.description());
} else {
throw new IllegalArgumentException(
"mBean '" + beanName
+ "' attribute '"
+ template.name()
+ "' is defined twice."
);
}
}
}

final StringBuilder b = new StringBuilder();

for (final Map.Entry<String, Map<String, String>> e : beansAndAttributes.entrySet()) {
// Add mBean name as a section title
b.append(e.getKey()).append("\n");
b.append("=".repeat(e.getKey().length())).append("\n\n");

// Determine the maximum lengths for each column
final int maxAttrLength = Math.max("Attribute name".length(),
e.getValue().keySet().stream().mapToInt(String::length).max().orElse(0));
final int maxDescLength = Math.max("Description".length(),
e.getValue().values().stream().mapToInt(String::length).max().orElse(0));

// Create the table header
final String headerFormat = "%-" + maxAttrLength + "s %-" + maxDescLength + "s\n";
final String separatorLine = "=" + "=".repeat(maxAttrLength) + " " + "=".repeat(maxDescLength) + "\n";

b.append(separatorLine);
b.append(String.format(headerFormat, "Attribute name", "Description"));
b.append(separatorLine);

// Add table rows
for (final Map.Entry<String, String> e2 : e.getValue().entrySet()) {
b.append(String.format(headerFormat, e2.getKey(), e2.getValue()));
}

// Close the table
b.append(separatorLine);
b.append("\n"); // Add an empty line between tables
}

return b.toString();
}

static String getMBeanName(final String prefix, final MetricName metricName) {
final StringBuilder beanName = new StringBuilder();
beanName.append(prefix);
beanName.append(":type=");
beanName.append(metricName.group());
for (final Map.Entry<String, String> entry : metricName.tags().entrySet()) {
if (entry.getKey().length() <= 0 || entry.getValue().length() <= 0) {
continue;
}
beanName.append(",");
beanName.append(entry.getKey());
beanName.append("=");
beanName.append(Sanitizer.jmxSanitize(entry.getValue()));
}
return beanName.toString();
}

static void printSectionTitle(final String title) {
System.out.println("=================\n"
+ title + "\n"
+ "=================");
}

static void printSubsectionTitle(final String title) {
System.out.println("-----------------\n"
+ title + "\n"
+ "-----------------");
}
}
Loading

0 comments on commit 1e055c9

Please sign in to comment.