Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement memory metrics #652

Merged
merged 11 commits into from
Jan 14, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
import io.opentelemetry.contrib.jfr.metrics.internal.cpu.ContextSwitchRateHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.cpu.LongLockHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.cpu.OverallCPULoadHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.CodeCacheConfigurationHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.G1HeapSummaryHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.GCHeapConfigurationHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.GCHeapSummaryHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.MetaspaceSummaryHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.ObjectAllocationInNewTLABHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.ObjectAllocationOutsideTLABHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.ParallelHeapSummaryHandler;
Expand All @@ -41,7 +44,6 @@ private HandlerRegistry(List<? extends RecordedEventHandler> mappers) {

static HandlerRegistry createDefault(MeterProvider meterProvider) {
var handlers = new ArrayList<RecordedEventHandler>();

for (var bean : ManagementFactory.getGarbageCollectorMXBeans()) {
var name = bean.getName();
switch (name) {
Expand Down Expand Up @@ -90,6 +92,9 @@ static HandlerRegistry createDefault(MeterProvider meterProvider) {
new LongLockHandler(grouper),
new ThreadCountHandler(),
new ClassesLoadedHandler(),
new GCHeapConfigurationHandler(),
new MetaspaceSummaryHandler(),
new CodeCacheConfigurationHandler(),
new DirectBufferStatisticsHandler());
handlers.addAll(basicHandlers);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package io.opentelemetry.contrib.jfr.metrics.internal;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;

public final class Constants {
private Constants() {}
Expand Down Expand Up @@ -71,6 +72,25 @@ private Constants() {}
public static final AttributeKey<String> ATTR_GC = AttributeKey.stringKey("pool");
public static final AttributeKey<String> ATTR_ACTION = AttributeKey.stringKey("action");
public static final AttributeKey<Boolean> ATTR_DAEMON = AttributeKey.booleanKey(DAEMON);
public static final Attributes ATTR_PS_EDEN_SPACE =
Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "PS Eden Space");
public static final Attributes ATTR_PS_SURVIVOR_SPACE =
Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "PS Survivor Space");
public static final Attributes ATTR_PS_OLD_GEN =
Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "PS Old Gen");
public static final Attributes ATTR_G1_SURVIVOR_SPACE =
Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "G1 Survivor Space");
public static final Attributes ATTR_G1_EDEN_SPACE =
Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "G1 Eden Space");
public static final Attributes ATTR_JAVA_HEAP_SPACE =
Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "Java heap space");
public static final Attributes ATTR_METASPACE =
Attributes.of(ATTR_TYPE, NON_HEAP, ATTR_POOL, "Metaspace");
public static final Attributes ATTR_COMPRESSED_CLASS_SPACE =
Attributes.of(ATTR_TYPE, NON_HEAP, ATTR_POOL, "Compressed Class Space");
public static final Attributes ATTR_CODE_CACHE =
Attributes.of(ATTR_TYPE, NON_HEAP, ATTR_POOL, "CodeCache");

public static final String UNIT_CLASSES = "{classes}";
public static final String UNIT_THREADS = "{threads}";
public static final String UNIT_BUFFERS = "{buffers}";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.jfr.metrics.internal.memory;

import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_POOL;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_TYPE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.INITIAL_SIZE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_DESCRIPTION_MEMORY_INIT;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_MEMORY_INIT;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NON_HEAP;
import static io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler.defaultMeter;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler;
import java.time.Duration;
import java.util.Optional;
import jdk.jfr.consumer.RecordedEvent;

/** Handles attributes with pool value CodeCache */
public final class CodeCacheConfigurationHandler implements RecordedEventHandler {
private static final String EVENT_NAME = "jdk.CodeCacheConfiguration";

private static final Attributes ATTR = Attributes.of(ATTR_TYPE, NON_HEAP, ATTR_POOL, "CodeCache");

private volatile long initialSize = 0;

public CodeCacheConfigurationHandler() {
initializeMeter(defaultMeter());
}

@Override
public void initializeMeter(Meter meter) {
meter
.upDownCounterBuilder(METRIC_NAME_MEMORY_INIT)
.setDescription(METRIC_DESCRIPTION_MEMORY_INIT)
.setUnit(BYTES)
.buildWithCallback(measurement -> measurement.record(initialSize, ATTR));
}

@Override
public String getEventName() {
return EVENT_NAME;
}

@Override
public void accept(RecordedEvent event) {
if (event.hasField(INITIAL_SIZE)) {
initialSize = event.getLong(INITIAL_SIZE);
}
}

@Override
public Optional<Duration> getPollingDuration() {
return Optional.of(Duration.ofSeconds(1));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_TYPE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.HEAP;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_DESCRIPTION_COMMITTED;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_DESCRIPTION_MEMORY;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_DESCRIPTION_MEMORY_AFTER;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_COMMITTED;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_MEMORY;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_MEMORY_AFTER;
import static io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler.defaultMeter;
Expand All @@ -33,11 +35,12 @@ public final class G1HeapSummaryHandler implements RecordedEventHandler {
private static final String AFTER = "After GC";
private static final String GC_ID = "gcId";
private static final String EDEN_USED_SIZE = "edenUsedSize";
private static final String EDEN_TOTAL_SIZE = "edenTotalSize";
private static final String SURVIVOR_USED_SIZE = "survivorUsedSize";
private static final String WHEN = "when";
private static final Attributes ATTR_MEMORY_EDEN_USED =
private static final Attributes ATTR_MEMORY_EDEN =
Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "G1 Eden Space");
private static final Attributes ATTR_MEMORY_SURVIVOR_USED =
private static final Attributes ATTR_MEMORY_SURVIVOR =
Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "G1 Survivor Space");
// private static final Attributes ATTR_MEMORY_OLD_USED =
// Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "G1 Old Gen"); // TODO needs jdk JFR support
Expand All @@ -46,6 +49,7 @@ public final class G1HeapSummaryHandler implements RecordedEventHandler {
private volatile long usageEdenAfter = 0;
private volatile long usageSurvivor = 0;
private volatile long usageSurvivorAfter = 0;
private volatile long committedEden = 0;

public G1HeapSummaryHandler() {
initializeMeter(defaultMeter());
Expand All @@ -59,18 +63,23 @@ public void initializeMeter(Meter meter) {
.setUnit(BYTES)
.buildWithCallback(
measurement -> {
measurement.record(usageEden, ATTR_MEMORY_EDEN_USED);
measurement.record(usageSurvivor, ATTR_MEMORY_SURVIVOR_USED);
measurement.record(usageEden, ATTR_MEMORY_EDEN);
measurement.record(usageSurvivor, ATTR_MEMORY_SURVIVOR);
});
meter
.upDownCounterBuilder(METRIC_NAME_MEMORY_AFTER)
.setDescription(METRIC_DESCRIPTION_MEMORY_AFTER)
.setUnit(BYTES)
.buildWithCallback(
measurement -> {
measurement.record(usageEdenAfter, ATTR_MEMORY_EDEN_USED);
measurement.record(usageSurvivorAfter, ATTR_MEMORY_SURVIVOR_USED);
measurement.record(usageEdenAfter, ATTR_MEMORY_EDEN);
measurement.record(usageSurvivorAfter, ATTR_MEMORY_SURVIVOR);
});
meter
.upDownCounterBuilder(METRIC_NAME_COMMITTED)
.setDescription(METRIC_DESCRIPTION_COMMITTED)
.setUnit(BYTES)
.buildWithCallback(measurement -> measurement.record(committedEden, ATTR_MEMORY_EDEN));
}

@Override
Expand Down Expand Up @@ -115,5 +124,9 @@ private void recordValues(RecordedEvent event, boolean before) {
usageSurvivorAfter = event.getLong(SURVIVOR_USED_SIZE);
}
}

if (event.hasField(EDEN_TOTAL_SIZE)) {
committedEden = event.getLong(EDEN_TOTAL_SIZE);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.jfr.metrics.internal.memory;

import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_POOL;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_TYPE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.HEAP;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.INITIAL_SIZE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_DESCRIPTION_MEMORY_INIT;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_DESCRIPTION_MEMORY_LIMIT;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_MEMORY_INIT;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_MEMORY_LIMIT;
import static io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler.defaultMeter;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler;
import java.time.Duration;
import java.util.Optional;
import jdk.jfr.consumer.RecordedEvent;

/** This class handles GCHeapConfiguration JFR events. */
public final class GCHeapConfigurationHandler implements RecordedEventHandler {
private static final String EVENT_NAME = "jdk.GCHeapConfiguration";

private static final String MAX_SIZE = "maxSize";
private static final Attributes ATTR =
Attributes.of(ATTR_TYPE, HEAP, ATTR_POOL, "Java heap space");
roberttoyonaga marked this conversation as resolved.
Show resolved Hide resolved

private volatile long init = 0;
private volatile long limit = 0;

public GCHeapConfigurationHandler() {
initializeMeter(defaultMeter());
}

@Override
public void initializeMeter(Meter meter) {
meter
.upDownCounterBuilder(METRIC_NAME_MEMORY_INIT)
.setDescription(METRIC_DESCRIPTION_MEMORY_INIT)
.setUnit(BYTES)
.buildWithCallback(measurement -> measurement.record(init, ATTR));
meter
.upDownCounterBuilder(METRIC_NAME_MEMORY_LIMIT)
.setDescription(METRIC_DESCRIPTION_MEMORY_LIMIT)
.setUnit(BYTES)
.buildWithCallback(measurement -> measurement.record(limit, ATTR));
}

@Override
public String getEventName() {
return EVENT_NAME;
}

@Override
public void accept(RecordedEvent event) {
if (event.hasField(INITIAL_SIZE)) {
init = event.getLong(INITIAL_SIZE);
}
if (event.hasField(MAX_SIZE)) {
limit = event.getLong(MAX_SIZE);
}
}

@Override
public Optional<Duration> getPollingDuration() {
return Optional.of(Duration.ofSeconds(1));
}
}
Loading