diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/HandlerRegistry.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/HandlerRegistry.java index ea139c9d0..485bc29c7 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/HandlerRegistry.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/HandlerRegistry.java @@ -19,10 +19,8 @@ import io.opentelemetry.contrib.jfr.metrics.internal.network.NetworkReadHandler; import io.opentelemetry.contrib.jfr.metrics.internal.network.NetworkWriteHandler; import java.util.*; -import java.util.stream.Stream; final class HandlerRegistry { - private static final String SCHEMA_URL = "https://opentelemetry.io/schemas/1.6.1"; private static final String INSTRUMENTATION_NAME = "io.opentelemetry.contrib.jfr"; private static final String INSTRUMENTATION_VERSION = "1.7.0-SNAPSHOT"; @@ -33,28 +31,31 @@ private HandlerRegistry(List mappers) { } static HandlerRegistry createDefault(MeterProvider meterProvider) { - var otelMeter = meterProvider.get(INSTRUMENTATION_NAME, INSTRUMENTATION_VERSION, null); - + var meter = + meterProvider + .meterBuilder(INSTRUMENTATION_NAME) + .setInstrumentationVersion(INSTRUMENTATION_VERSION) + .build(); var grouper = new ThreadGrouper(); - var filtered = + var handlers = List.of( - new ObjectAllocationInNewTLABHandler(otelMeter, grouper), - new ObjectAllocationOutsideTLABHandler(otelMeter, grouper), - new NetworkReadHandler(otelMeter, grouper), - new NetworkWriteHandler(otelMeter, grouper), - new G1GarbageCollectionHandler(otelMeter), - new GCHeapSummaryHandler(otelMeter), - new ContextSwitchRateHandler(otelMeter), - new OverallCPULoadHandler(otelMeter), - new ContainerConfigurationHandler(otelMeter), - new LongLockHandler(otelMeter, grouper)); - filtered.forEach(RecordedEventHandler::init); - - return new HandlerRegistry(filtered); + new ObjectAllocationInNewTLABHandler(grouper), + new ObjectAllocationOutsideTLABHandler(grouper), + new NetworkReadHandler(grouper), + new NetworkWriteHandler(grouper), + new G1GarbageCollectionHandler(), + new GCHeapSummaryHandler(), + new ContextSwitchRateHandler(), + new OverallCPULoadHandler(), + new ContainerConfigurationHandler(), + new LongLockHandler(grouper)); + handlers.forEach(handler -> handler.initializeMeter(meter)); + + return new HandlerRegistry(handlers); } - /** @return a stream of all entries in this registry. */ - Stream all() { - return mappers.stream(); + /** @return all entries in this registry. */ + List all() { + return mappers; } } diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/JfrMetrics.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/JfrMetrics.java index 9dc23a394..4d12e422f 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/JfrMetrics.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/JfrMetrics.java @@ -8,10 +8,8 @@ import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import java.util.concurrent.Executors; -import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; -import jdk.jfr.EventSettings; import jdk.jfr.consumer.RecordingStream; /** The entry point class for the JFR-over-OpenTelemetry support. */ @@ -34,8 +32,7 @@ public static void enable(MeterProvider meterProvider) { jfrMonitorService.submit( () -> { try (var recordingStream = new RecordingStream()) { - var enableMappedEvent = eventEnablerFor(recordingStream); - toMetricRegistry.all().forEach(enableMappedEvent); + toMetricRegistry.all().forEach(handler -> enableHandler(recordingStream, handler)); recordingStream.setReuse(false); logger.log(Level.FINE, "Starting recording stream..."); recordingStream.start(); // run forever @@ -43,12 +40,10 @@ public static void enable(MeterProvider meterProvider) { }); } - private static Consumer eventEnablerFor(RecordingStream recordingStream) { - return handler -> { - EventSettings eventSettings = recordingStream.enable(handler.getEventName()); - handler.getPollingDuration().ifPresent(eventSettings::withPeriod); - handler.getThreshold().ifPresent(eventSettings::withThreshold); - recordingStream.onEvent(handler.getEventName(), handler); - }; + private static void enableHandler(RecordingStream recordingStream, RecordedEventHandler handler) { + var eventSettings = recordingStream.enable(handler.getEventName()); + handler.getPollingDuration().ifPresent(eventSettings::withPeriod); + handler.getThreshold().ifPresent(eventSettings::withThreshold); + recordingStream.onEvent(handler.getEventName(), handler); } } diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/AbstractThreadDispatchingHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/AbstractThreadDispatchingHandler.java index 768625793..d78baa486 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/AbstractThreadDispatchingHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/AbstractThreadDispatchingHandler.java @@ -7,33 +7,30 @@ import java.util.HashMap; import java.util.Map; -import java.util.Optional; +import java.util.function.Consumer; import jdk.jfr.consumer.RecordedEvent; public abstract class AbstractThreadDispatchingHandler implements RecordedEventHandler { // Will need pruning code for fast-cycling thread frameworks to prevent memory leaks - protected final Map perThread = new HashMap<>(); - protected final ThreadGrouper grouper; + private final Map> perThread = new HashMap<>(); + private final ThreadGrouper grouper; public AbstractThreadDispatchingHandler(ThreadGrouper grouper) { this.grouper = grouper; } - public void reset() { - perThread.clear(); - } - public abstract String getEventName(); - public abstract RecordedEventHandler createPerThreadSummarizer(String threadName); + public abstract Consumer createPerThreadSummarizer(String threadName); @Override public void accept(RecordedEvent ev) { - final Optional possibleGroupedThreadName = grouper.groupedName(ev); - possibleGroupedThreadName.ifPresent( - groupedThreadName -> { - perThread.computeIfAbsent(groupedThreadName, name -> createPerThreadSummarizer(name)); - perThread.get(groupedThreadName).accept(ev); - }); + grouper + .groupedName(ev) + .ifPresent( + groupedThreadName -> + perThread + .computeIfAbsent(groupedThreadName, this::createPerThreadSummarizer) + .accept(ev)); } } diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/Constants.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/Constants.java index 792e38a7b..0244e33ed 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/Constants.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/Constants.java @@ -15,8 +15,6 @@ private Constants() {} public static final String BYTES = "B"; public static final String MILLISECONDS = "ms"; public static final String PERCENTAGE = "%age"; - public static final String READ = "read"; - public static final String WRITE = "write"; public static final String USER = "user"; public static final String SYSTEM = "system"; public static final String MACHINE = "machine.total"; @@ -24,6 +22,13 @@ private Constants() {} public static final String USED = "used"; public static final String COMMITTED = "committed"; + public static final String NETWORK_BYTES_NAME = "runtime.jvm.network.io"; + public static final String NETWORK_BYTES_DESCRIPTION = "Network read/write bytes"; + public static final String NETWORK_DURATION_NAME = "runtime.jvm.network.duration"; + public static final String NETWORK_DURATION_DESCRIPTION = "Network read/write duration"; + public static final String NETWORK_MODE_READ = "read"; + public static final String NETWORK_MODE_WRITE = "write"; + public static final AttributeKey ATTR_THREAD_NAME = AttributeKey.stringKey("thread.name"); public static final AttributeKey ATTR_ARENA_NAME = AttributeKey.stringKey("arena"); public static final AttributeKey ATTR_NETWORK_MODE = AttributeKey.stringKey("mode"); diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/RecordedEventHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/RecordedEventHandler.java index c1def3052..fa6d3a566 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/RecordedEventHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/RecordedEventHandler.java @@ -5,6 +5,8 @@ package io.opentelemetry.contrib.jfr.metrics.internal; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.internal.NoopMeter; import java.time.Duration; import java.util.Optional; import java.util.function.Consumer; @@ -31,6 +33,14 @@ default boolean test(RecordedEvent event) { return event.getEventType().getName().equalsIgnoreCase(getEventName()); } + /** + * Set the OpenTelemetry {@link Meter} after the SDK has been initialized. Until called, + * implementations should use instruments from {@link NoopMeter}. + * + * @param meter the meter + */ + void initializeMeter(Meter meter); + /** * Optionally returns a polling duration for JFR events, if present * @@ -50,13 +60,4 @@ default Optional getPollingDuration() { default Optional getThreshold() { return Optional.empty(); } - - /** - * Initialize the handler. Default implementation is a no-op - * - * @return - */ - default RecordedEventHandler init() { - return this; - } } diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/ThreadGrouper.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/ThreadGrouper.java index df260b8e1..cca9c1268 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/ThreadGrouper.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/ThreadGrouper.java @@ -9,11 +9,11 @@ import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordedThread; -public class ThreadGrouper { +public final class ThreadGrouper { // FIXME doesn't actually do any grouping, but should be safe for now public Optional groupedName(RecordedEvent ev) { Object thisField = ev.getValue("eventThread"); - if (thisField != null && thisField instanceof RecordedThread) { + if (thisField instanceof RecordedThread) { return Optional.of(((RecordedThread) thisField).getJavaName()); } return Optional.empty(); diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/container/ContainerConfigurationHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/container/ContainerConfigurationHandler.java index 15c89a9d9..53ab19a83 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/container/ContainerConfigurationHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/container/ContainerConfigurationHandler.java @@ -8,6 +8,7 @@ import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ONE; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.internal.NoopMeter; import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import jdk.jfr.consumer.RecordedEvent; @@ -17,21 +18,19 @@ public final class ContainerConfigurationHandler implements RecordedEventHandler private static final String EFFECTIVE_CPU_COUNT = "effectiveCpuCount"; - private final Meter otelMeter; private volatile long value = 0L; - public ContainerConfigurationHandler(Meter otelMeter) { - this.otelMeter = otelMeter; + public ContainerConfigurationHandler() { + initializeMeter(NoopMeter.getInstance()); } - public ContainerConfigurationHandler init() { - otelMeter + @Override + public void initializeMeter(Meter meter) { + meter .upDownCounterBuilder(METRIC_NAME) .ofDoubles() .setUnit(ONE) .buildWithCallback(codm -> codm.observe(value)); - - return this; } @Override diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/ContextSwitchRateHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/ContextSwitchRateHandler.java index 64465ee12..df9e1f007 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/ContextSwitchRateHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/ContextSwitchRateHandler.java @@ -8,6 +8,7 @@ import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.HERTZ; import io.opentelemetry.api.metrics.*; +import io.opentelemetry.api.metrics.internal.NoopMeter; import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import java.time.Duration; import java.util.Optional; @@ -17,20 +18,10 @@ public final class ContextSwitchRateHandler implements RecordedEventHandler { private static final String EVENT_NAME = "jdk.ThreadContextSwitchRate"; private static final String METRIC_NAME = "runtime.jvm.cpu.context_switch"; - private final Meter otelMeter; private volatile double value = 0; - public ContextSwitchRateHandler(Meter otelMeter) { - this.otelMeter = otelMeter; - } - - public ContextSwitchRateHandler init() { - otelMeter - .upDownCounterBuilder(METRIC_NAME) - .ofDoubles() - .setUnit(HERTZ) - .buildWithCallback(codm -> codm.observe(value)); - return this; + public ContextSwitchRateHandler() { + initializeMeter(NoopMeter.getInstance()); } @Override @@ -42,6 +33,15 @@ public String getEventName() { return EVENT_NAME; } + @Override + public void initializeMeter(Meter meter) { + meter + .upDownCounterBuilder(METRIC_NAME) + .ofDoubles() + .setUnit(HERTZ) + .buildWithCallback(codm -> codm.observe(value)); + } + @Override public Optional getPollingDuration() { return Optional.of(Duration.ofSeconds(1)); diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/LongLockHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/LongLockHandler.java index 34187ee3c..91115453c 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/LongLockHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/LongLockHandler.java @@ -8,23 +8,38 @@ import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_THREAD_NAME; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.BoundDoubleHistogram; +import io.opentelemetry.api.metrics.DoubleHistogram; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.internal.NoopMeter; import io.opentelemetry.contrib.jfr.metrics.internal.AbstractThreadDispatchingHandler; import io.opentelemetry.contrib.jfr.metrics.internal.Constants; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import io.opentelemetry.contrib.jfr.metrics.internal.ThreadGrouper; import java.time.Duration; import java.util.Optional; +import java.util.function.Consumer; +import jdk.jfr.consumer.RecordedEvent; public final class LongLockHandler extends AbstractThreadDispatchingHandler { - static final String EVENT_NAME = "jdk.JavaMonitorWait"; - private final Meter otelMeter; + private static final String EVENT_NAME = "jdk.JavaMonitorWait"; private static final String METRIC_NAME = "runtime.jvm.cpu.longlock.time"; private static final String DESCRIPTION = "Long lock times"; - public LongLockHandler(Meter otelMeter, ThreadGrouper grouper) { + private DoubleHistogram histogram; + + public LongLockHandler(ThreadGrouper grouper) { super(grouper); - this.otelMeter = otelMeter; + initializeMeter(NoopMeter.getInstance()); + } + + @Override + public void initializeMeter(Meter meter) { + histogram = + meter + .histogramBuilder(METRIC_NAME) + .setDescription(DESCRIPTION) + .setUnit(Constants.MILLISECONDS) + .build(); } @Override @@ -33,18 +48,32 @@ public String getEventName() { } @Override - public RecordedEventHandler createPerThreadSummarizer(String threadName) { - var attr = Attributes.of(ATTR_THREAD_NAME, threadName); - var builder = otelMeter.histogramBuilder(METRIC_NAME); - builder.setDescription(DESCRIPTION); - builder.setUnit(Constants.MILLISECONDS); - var histogram = builder.build().bind(attr); - var ret = new PerThreadLongLockHandler(histogram, threadName); - return ret.init(); + public Consumer createPerThreadSummarizer(String threadName) { + return new PerThreadLongLockHandler(histogram, threadName); } @Override public Optional getThreshold() { return Optional.empty(); } + + private static class PerThreadLongLockHandler implements Consumer { + private static final String EVENT_THREAD = "eventThread"; + + private final BoundDoubleHistogram boundHistogram; + + public PerThreadLongLockHandler(DoubleHistogram histogram, String threadName) { + this.boundHistogram = histogram.bind(Attributes.of(ATTR_THREAD_NAME, threadName)); + } + + @Override + public void accept(RecordedEvent recordedEvent) { + if (recordedEvent.hasField(EVENT_THREAD)) { + boundHistogram.record(recordedEvent.getDuration().toMillis()); + } + // What about the class name in MONITOR_CLASS ? + // We can get a stack trace from the thread on the event + // var eventThread = recordedEvent.getThread(EVENT_THREAD); + } + } } diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/OverallCPULoadHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/OverallCPULoadHandler.java index fd7f84b29..2fa832ed0 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/OverallCPULoadHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/OverallCPULoadHandler.java @@ -15,13 +15,13 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.BoundDoubleHistogram; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.internal.NoopMeter; import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import java.time.Duration; import java.util.Optional; import jdk.jfr.consumer.RecordedEvent; public final class OverallCPULoadHandler implements RecordedEventHandler { - private static final String SIMPLE_CLASS_NAME = OverallCPULoadHandler.class.getSimpleName(); private static final String EVENT_NAME = "jdk.CPULoad"; private static final String JVM_USER = "jvmUser"; private static final String JVM_SYSTEM = "jvmSystem"; @@ -30,36 +30,37 @@ public final class OverallCPULoadHandler implements RecordedEventHandler { private static final String METRIC_NAME = "runtime.jvm.cpu.utilization"; private static final String DESCRIPTION = "CPU Utilization"; - private final Meter otelMeter; private BoundDoubleHistogram userHistogram; private BoundDoubleHistogram systemHistogram; private BoundDoubleHistogram machineHistogram; - public OverallCPULoadHandler(Meter otelMeter) { - this.otelMeter = otelMeter; + public OverallCPULoadHandler() { + initializeMeter(NoopMeter.getInstance()); } @Override - public OverallCPULoadHandler init() { - var attr = Attributes.of(ATTR_CPU_USAGE, USER); - var builder = otelMeter.histogramBuilder(METRIC_NAME); - builder.setDescription(DESCRIPTION); - builder.setUnit(PERCENTAGE); - userHistogram = builder.build().bind(attr); - - attr = Attributes.of(ATTR_CPU_USAGE, SYSTEM); - builder = otelMeter.histogramBuilder(METRIC_NAME); - builder.setDescription(DESCRIPTION); - builder.setUnit(ONE); - systemHistogram = builder.build().bind(attr); - - attr = Attributes.of(ATTR_CPU_USAGE, MACHINE); - builder = otelMeter.histogramBuilder(METRIC_NAME); - builder.setDescription(DESCRIPTION); - builder.setUnit(ONE); - machineHistogram = builder.build().bind(attr); - - return this; + public void initializeMeter(Meter meter) { + userHistogram = + meter + .histogramBuilder(METRIC_NAME) + .setDescription(DESCRIPTION) + .setUnit(PERCENTAGE) + .build() + .bind(Attributes.of(ATTR_CPU_USAGE, USER)); + systemHistogram = + meter + .histogramBuilder(METRIC_NAME) + .setDescription(DESCRIPTION) + .setUnit(ONE) + .build() + .bind(Attributes.of(ATTR_CPU_USAGE, SYSTEM)); + machineHistogram = + meter + .histogramBuilder(METRIC_NAME) + .setDescription(DESCRIPTION) + .setUnit(ONE) + .build() + .bind(Attributes.of(ATTR_CPU_USAGE, MACHINE)); } @Override diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/PerThreadLongLockHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/PerThreadLongLockHandler.java deleted file mode 100644 index 2b9a0a858..000000000 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/PerThreadLongLockHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.jfr.metrics.internal.cpu; - -import io.opentelemetry.api.metrics.BoundDoubleHistogram; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; -import jdk.jfr.consumer.RecordedEvent; - -public final class PerThreadLongLockHandler implements RecordedEventHandler { - private static final String SIMPLE_CLASS_NAME = PerThreadLongLockHandler.class.getSimpleName(); - private static final String MONITOR_CLASS = "monitorClass"; - private static final String CLASS = "class"; - private static final String EVENT_THREAD = "eventThread"; - private static final String DURATION = "duration"; - private static final String STACK_TRACE = "stackTrace"; - private static final String JFR_JAVA_MONITOR_WAIT = "JfrJavaMonitorWait"; - - private final String threadName; - private final BoundDoubleHistogram histogram; - - public PerThreadLongLockHandler(BoundDoubleHistogram histogram, String threadName) { - this.threadName = threadName; - this.histogram = histogram; - } - - @Override - public String getEventName() { - return LongLockHandler.EVENT_NAME; - } - - @Override - public void accept(RecordedEvent recordedEvent) { - if (recordedEvent.hasField(EVENT_THREAD)) { - histogram.record(recordedEvent.getDuration().toMillis()); - } - // What about the class name in MONITOR_CLASS ? - // We can get a stack trace from the thread on the event - // var eventThread = recordedEvent.getThread(EVENT_THREAD); - } -} diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/G1GarbageCollectionHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/G1GarbageCollectionHandler.java index a03845d3b..4f3ee7990 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/G1GarbageCollectionHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/G1GarbageCollectionHandler.java @@ -11,6 +11,7 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.metrics.BoundDoubleHistogram; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.internal.NoopMeter; import io.opentelemetry.contrib.jfr.metrics.internal.Constants; import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import jdk.jfr.consumer.RecordedEvent; @@ -21,20 +22,21 @@ public final class G1GarbageCollectionHandler implements RecordedEventHandler { private static final String METRIC_NAME = "runtime.jvm.gc.duration"; private static final String DESCRIPTION = "GC Duration"; - private final Meter otelMeter; private BoundDoubleHistogram gcHistogram; - public G1GarbageCollectionHandler(Meter otelMeter) { - this.otelMeter = otelMeter; + public G1GarbageCollectionHandler() { + initializeMeter(NoopMeter.getInstance()); } - public G1GarbageCollectionHandler init() { - var attr = Attributes.of(ATTR_GC_COLLECTOR, G1); - var builder = otelMeter.histogramBuilder(METRIC_NAME); - builder.setDescription(DESCRIPTION); - builder.setUnit(Constants.MILLISECONDS); - gcHistogram = builder.build().bind(attr); - return this; + @Override + public void initializeMeter(Meter meter) { + gcHistogram = + meter + .histogramBuilder(METRIC_NAME) + .setDescription(DESCRIPTION) + .setUnit(Constants.MILLISECONDS) + .build() + .bind(Attributes.of(ATTR_GC_COLLECTOR, G1)); } @Override diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/GCHeapSummaryHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/GCHeapSummaryHandler.java index 9ded4594a..a8099cfab 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/GCHeapSummaryHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/GCHeapSummaryHandler.java @@ -14,7 +14,7 @@ import io.opentelemetry.api.metrics.BoundDoubleHistogram; import io.opentelemetry.api.metrics.DoubleHistogram; import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.contrib.jfr.metrics.internal.Constants; +import io.opentelemetry.api.metrics.internal.NoopMeter; import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import java.util.HashMap; import java.util.Map; @@ -23,7 +23,6 @@ /** This class handles GCHeapSummary JFR events. For GC purposes they come in pairs. */ public final class GCHeapSummaryHandler implements RecordedEventHandler { - private static final String SIMPLE_CLASS_NAME = GCHeapSummaryHandler.class.getSimpleName(); private static final String METRIC_NAME_DURATION = "runtime.jvm.gc.duration"; private static final String METRIC_NAME_MEMORY = "runtime.jvm.memory.utilization"; @@ -39,34 +38,30 @@ public final class GCHeapSummaryHandler implements RecordedEventHandler { private final Map awaitingPairs = new HashMap<>(); - private final Meter otelMeter; private DoubleHistogram durationHistogram; private BoundDoubleHistogram usedHistogram; private BoundDoubleHistogram committedHistogram; - public GCHeapSummaryHandler(Meter otelMeter) { - this.otelMeter = otelMeter; + public GCHeapSummaryHandler() { + initializeMeter(NoopMeter.getInstance()); } - public GCHeapSummaryHandler init() { - var builder = otelMeter.histogramBuilder(METRIC_NAME_DURATION); - builder.setDescription(DESCRIPTION); - builder.setUnit(Constants.MILLISECONDS); - durationHistogram = builder.build(); - - var attr = Attributes.of(ATTR_MEMORY_USAGE, USED); - builder = otelMeter.histogramBuilder(METRIC_NAME_MEMORY); - builder.setDescription(DESCRIPTION); - builder.setUnit(BYTES); - usedHistogram = builder.build().bind(attr); - - attr = Attributes.of(ATTR_MEMORY_USAGE, COMMITTED); - builder = otelMeter.histogramBuilder(METRIC_NAME_MEMORY); - builder.setDescription(DESCRIPTION); - builder.setUnit(BYTES); - committedHistogram = builder.build().bind(attr); - - return this; + @Override + public void initializeMeter(Meter meter) { + durationHistogram = + meter + .histogramBuilder(METRIC_NAME_DURATION) + .setDescription(DESCRIPTION) + .setUnit(BYTES) + .build(); + var memoryHistogram = + meter + .histogramBuilder(METRIC_NAME_MEMORY) + .setDescription(DESCRIPTION) + .setUnit(BYTES) + .build(); + usedHistogram = memoryHistogram.bind(Attributes.of(ATTR_MEMORY_USAGE, USED)); + committedHistogram = memoryHistogram.bind(Attributes.of(ATTR_MEMORY_USAGE, COMMITTED)); } @Override @@ -86,12 +81,10 @@ public void accept(RecordedEvent ev) { } } - long gcId = 0; - if (ev.hasField(GC_ID)) { - gcId = ev.getLong(GC_ID); - } else { + if (!ev.hasField(GC_ID)) { return; } + long gcId = ev.getLong(GC_ID); var pair = awaitingPairs.get(gcId); if (pair == null) { diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/ObjectAllocationInNewTLABHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/ObjectAllocationInNewTLABHandler.java index 73b95dae4..28d40d30a 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/ObjectAllocationInNewTLABHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/ObjectAllocationInNewTLABHandler.java @@ -5,22 +5,44 @@ package io.opentelemetry.contrib.jfr.metrics.internal.memory; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_ARENA_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_THREAD_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_MEMORY_ALLOCATION; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.BoundDoubleHistogram; +import io.opentelemetry.api.metrics.DoubleHistogram; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.internal.NoopMeter; import io.opentelemetry.contrib.jfr.metrics.internal.AbstractThreadDispatchingHandler; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import io.opentelemetry.contrib.jfr.metrics.internal.ThreadGrouper; +import java.util.function.Consumer; +import jdk.jfr.consumer.RecordedEvent; /** * This class handles TLAB allocation JFR events, and delegates them to the actual per-thread * aggregators */ public final class ObjectAllocationInNewTLABHandler extends AbstractThreadDispatchingHandler { - static final String EVENT_NAME = "jdk.ObjectAllocationInNewTLAB"; - private final Meter otelMeter; + private static final String EVENT_NAME = "jdk.ObjectAllocationInNewTLAB"; + private static final String DESCRIPTION = "Allocation"; + + private DoubleHistogram histogram; - public ObjectAllocationInNewTLABHandler(Meter otelMeter, ThreadGrouper grouper) { + public ObjectAllocationInNewTLABHandler(ThreadGrouper grouper) { super(grouper); - this.otelMeter = otelMeter; + initializeMeter(NoopMeter.getInstance()); + } + + @Override + public void initializeMeter(Meter meter) { + histogram = + meter + .histogramBuilder(METRIC_NAME_MEMORY_ALLOCATION) + .setDescription(DESCRIPTION) + .setUnit(BYTES) + .build(); } @Override @@ -29,8 +51,28 @@ public String getEventName() { } @Override - public RecordedEventHandler createPerThreadSummarizer(String threadName) { - var ret = new PerThreadObjectAllocationInNewTLABHandler(otelMeter, threadName); - return ret.init(); + public Consumer createPerThreadSummarizer(String threadName) { + return new PerThreadObjectAllocationInNewTLABHandler(histogram, threadName); + } + + /** This class aggregates all TLAB allocation JFR events for a single thread */ + private static class PerThreadObjectAllocationInNewTLABHandler + implements Consumer { + private static final String TLAB_SIZE = "tlabSize"; + private static final String TLAB = "TLAB"; + + private final BoundDoubleHistogram boundHistogram; + + public PerThreadObjectAllocationInNewTLABHandler(DoubleHistogram histogram, String threadName) { + boundHistogram = + histogram.bind(Attributes.of(ATTR_THREAD_NAME, threadName, ATTR_ARENA_NAME, TLAB)); + } + + @Override + public void accept(RecordedEvent ev) { + boundHistogram.record(ev.getLong(TLAB_SIZE)); + // Probably too high a cardinality + // ev.getClass("objectClass").getName(); + } } } diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/ObjectAllocationOutsideTLABHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/ObjectAllocationOutsideTLABHandler.java index d64f7bc3c..5c01272ff 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/ObjectAllocationOutsideTLABHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/ObjectAllocationOutsideTLABHandler.java @@ -5,22 +5,44 @@ package io.opentelemetry.contrib.jfr.metrics.internal.memory; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_ARENA_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_THREAD_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_MEMORY_ALLOCATION; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.BoundDoubleHistogram; +import io.opentelemetry.api.metrics.DoubleHistogram; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.internal.NoopMeter; import io.opentelemetry.contrib.jfr.metrics.internal.AbstractThreadDispatchingHandler; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import io.opentelemetry.contrib.jfr.metrics.internal.ThreadGrouper; +import java.util.function.Consumer; +import jdk.jfr.consumer.RecordedEvent; /** * This class handles all non-TLAB allocation JFR events, and delegates them to the actual * per-thread aggregators */ public final class ObjectAllocationOutsideTLABHandler extends AbstractThreadDispatchingHandler { - static final String EVENT_NAME = "jdk.ObjectAllocationOutsideTLAB"; - private final Meter otelMeter; + private static final String EVENT_NAME = "jdk.ObjectAllocationOutsideTLAB"; + private static final String DESCRIPTION = "Allocation"; + + private DoubleHistogram histogram; - public ObjectAllocationOutsideTLABHandler(Meter otelMeter, ThreadGrouper grouper) { + public ObjectAllocationOutsideTLABHandler(ThreadGrouper grouper) { super(grouper); - this.otelMeter = otelMeter; + initializeMeter(NoopMeter.getInstance()); + } + + @Override + public void initializeMeter(Meter meter) { + histogram = + meter + .histogramBuilder(METRIC_NAME_MEMORY_ALLOCATION) + .setDescription(DESCRIPTION) + .setUnit(BYTES) + .build(); } @Override @@ -28,8 +50,29 @@ public String getEventName() { return EVENT_NAME; } - public RecordedEventHandler createPerThreadSummarizer(String threadName) { - var ret = new PerThreadObjectAllocationOutsideTLABHandler(otelMeter, threadName); - return ret.init(); + public Consumer createPerThreadSummarizer(String threadName) { + return new PerThreadObjectAllocationOutsideTLABHandler(histogram, threadName); + } + + /** This class aggregates all non-TLAB allocation JFR events for a single thread */ + private static class PerThreadObjectAllocationOutsideTLABHandler + implements Consumer { + private static final String ALLOCATION_SIZE = "allocationSize"; + private static final String MAIN = "Main"; + + private final BoundDoubleHistogram boundHistogram; + + public PerThreadObjectAllocationOutsideTLABHandler( + DoubleHistogram histogram, String threadName) { + boundHistogram = + histogram.bind(Attributes.of(ATTR_THREAD_NAME, threadName, ATTR_ARENA_NAME, MAIN)); + } + + @Override + public void accept(RecordedEvent ev) { + boundHistogram.record(ev.getLong(ALLOCATION_SIZE)); + // Probably too high a cardinality + // ev.getClass("objectClass").getName(); + } } } diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/PerThreadObjectAllocationInNewTLABHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/PerThreadObjectAllocationInNewTLABHandler.java deleted file mode 100644 index e1760b06f..000000000 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/PerThreadObjectAllocationInNewTLABHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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_ARENA_NAME; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_THREAD_NAME; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_MEMORY_ALLOCATION; - -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.metrics.BoundDoubleHistogram; -import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; -import jdk.jfr.consumer.RecordedEvent; - -/** This class aggregates all TLAB allocation JFR events for a single thread */ -public final class PerThreadObjectAllocationInNewTLABHandler implements RecordedEventHandler { - private static final String TLAB_SIZE = "tlabSize"; - private static final String DESCRIPTION = "Allocation"; - private static final String TLAB = "TLAB"; - - private final String threadName; - private final Meter otelMeter; - private BoundDoubleHistogram histogram; - - public PerThreadObjectAllocationInNewTLABHandler(Meter otelMeter, String threadName) { - this.threadName = threadName; - this.otelMeter = otelMeter; - } - - public PerThreadObjectAllocationInNewTLABHandler init() { - var attr = Attributes.of(ATTR_THREAD_NAME, threadName, ATTR_ARENA_NAME, TLAB); - var builder = otelMeter.histogramBuilder(METRIC_NAME_MEMORY_ALLOCATION); - builder.setDescription(DESCRIPTION); - builder.setUnit(BYTES); - histogram = builder.build().bind(attr); - return this; - } - - @Override - public String getEventName() { - return ObjectAllocationInNewTLABHandler.EVENT_NAME; - } - - @Override - public void accept(RecordedEvent ev) { - histogram.record(ev.getLong(TLAB_SIZE)); - // Probably too high a cardinality - // ev.getClass("objectClass").getName(); - } -} diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/PerThreadObjectAllocationOutsideTLABHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/PerThreadObjectAllocationOutsideTLABHandler.java deleted file mode 100644 index 7359b6c9e..000000000 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/PerThreadObjectAllocationOutsideTLABHandler.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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_ARENA_NAME; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_THREAD_NAME; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.METRIC_NAME_MEMORY_ALLOCATION; - -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.metrics.BoundDoubleHistogram; -import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; -import jdk.jfr.consumer.RecordedEvent; - -/** This class aggregates all non-TLAB allocation JFR events for a single thread */ -public final class PerThreadObjectAllocationOutsideTLABHandler implements RecordedEventHandler { - private static final String ALLOCATION_SIZE = "allocationSize"; - private static final String DESCRIPTION = "Allocation"; - private static final String MAIN = "Main"; - - private final String threadName; - private final Meter otelMeter; - private BoundDoubleHistogram histogram; - - public PerThreadObjectAllocationOutsideTLABHandler(Meter otelMeter, String threadName) { - this.otelMeter = otelMeter; - this.threadName = threadName; - } - - public PerThreadObjectAllocationOutsideTLABHandler init() { - var attr = Attributes.of(ATTR_THREAD_NAME, threadName, ATTR_ARENA_NAME, MAIN); - var builder = otelMeter.histogramBuilder(METRIC_NAME_MEMORY_ALLOCATION); - builder.setDescription(DESCRIPTION); - builder.setUnit(BYTES); - histogram = builder.build().bind(attr); - return this; - } - - @Override - public String getEventName() { - return ObjectAllocationOutsideTLABHandler.EVENT_NAME; - } - - @Override - public void accept(RecordedEvent ev) { - histogram.record(ev.getLong(ALLOCATION_SIZE)); - // Probably too high a cardinality - // ev.getClass("objectClass").getName(); - } -} diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/NetworkReadHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/NetworkReadHandler.java index f592ec400..56b9b44e9 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/NetworkReadHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/NetworkReadHandler.java @@ -5,18 +5,51 @@ package io.opentelemetry.contrib.jfr.metrics.internal.network; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_NETWORK_MODE; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_THREAD_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.MILLISECONDS; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_BYTES_DESCRIPTION; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_BYTES_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_DURATION_DESCRIPTION; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_DURATION_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_MODE_READ; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.BoundDoubleHistogram; +import io.opentelemetry.api.metrics.DoubleHistogram; import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.internal.NoopMeter; import io.opentelemetry.contrib.jfr.metrics.internal.AbstractThreadDispatchingHandler; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; import io.opentelemetry.contrib.jfr.metrics.internal.ThreadGrouper; +import java.util.function.Consumer; +import jdk.jfr.consumer.RecordedEvent; public final class NetworkReadHandler extends AbstractThreadDispatchingHandler { - static final String EVENT_NAME = "jdk.SocketRead"; - private final Meter otelMeter; + private static final String EVENT_NAME = "jdk.SocketRead"; + + private DoubleHistogram bytesHistogram; + private DoubleHistogram durationHistogram; - public NetworkReadHandler(Meter otelMeter, ThreadGrouper nameNormalizer) { + public NetworkReadHandler(ThreadGrouper nameNormalizer) { super(nameNormalizer); - this.otelMeter = otelMeter; + initializeMeter(NoopMeter.getInstance()); + } + + @Override + public void initializeMeter(Meter meter) { + bytesHistogram = + meter + .histogramBuilder(NETWORK_BYTES_NAME) + .setDescription(NETWORK_BYTES_DESCRIPTION) + .setUnit(BYTES) + .build(); + durationHistogram = + meter + .histogramBuilder(NETWORK_DURATION_NAME) + .setDescription(NETWORK_DURATION_DESCRIPTION) + .setUnit(MILLISECONDS) + .build(); } @Override @@ -25,8 +58,27 @@ public String getEventName() { } @Override - public RecordedEventHandler createPerThreadSummarizer(String threadName) { - var ret = new PerThreadNetworkReadHandler(otelMeter, threadName); - return ret.init(); + public Consumer createPerThreadSummarizer(String threadName) { + return new PerThreadNetworkReadHandler(bytesHistogram, durationHistogram, threadName); + } + + private static class PerThreadNetworkReadHandler implements Consumer { + private static final String BYTES_READ = "bytesRead"; + + private final BoundDoubleHistogram boundBytesHistogram; + private final BoundDoubleHistogram boundDurationHistogram; + + public PerThreadNetworkReadHandler( + DoubleHistogram bytesHistogram, DoubleHistogram durationHistogram, String threadName) { + var attr = Attributes.of(ATTR_THREAD_NAME, threadName, ATTR_NETWORK_MODE, NETWORK_MODE_READ); + this.boundBytesHistogram = bytesHistogram.bind(attr); + this.boundDurationHistogram = durationHistogram.bind(attr); + } + + @Override + public void accept(RecordedEvent ev) { + boundBytesHistogram.record(ev.getLong(BYTES_READ)); + boundDurationHistogram.record(ev.getDuration().toMillis()); + } } } diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/NetworkWriteHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/NetworkWriteHandler.java index 4152b758b..03cc95922 100644 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/NetworkWriteHandler.java +++ b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/NetworkWriteHandler.java @@ -5,6 +5,26 @@ package io.opentelemetry.contrib.jfr.metrics.internal.network; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_NETWORK_MODE; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_THREAD_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.MILLISECONDS; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_BYTES_DESCRIPTION; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_BYTES_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_DURATION_DESCRIPTION; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_DURATION_NAME; +import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.NETWORK_MODE_WRITE; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.BoundDoubleHistogram; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.internal.NoopMeter; +import io.opentelemetry.contrib.jfr.metrics.internal.AbstractThreadDispatchingHandler; +import io.opentelemetry.contrib.jfr.metrics.internal.ThreadGrouper; +import java.util.function.Consumer; +import jdk.jfr.consumer.RecordedEvent; + // jdk.SocketWrite { // startTime = 20:22:57.161 // duration = 87.4 ms @@ -23,18 +43,15 @@ // ] // } -import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.contrib.jfr.metrics.internal.AbstractThreadDispatchingHandler; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; -import io.opentelemetry.contrib.jfr.metrics.internal.ThreadGrouper; - public final class NetworkWriteHandler extends AbstractThreadDispatchingHandler { - static final String EVENT_NAME = "jdk.SocketWrite"; - private final Meter otelMeter; + private static final String EVENT_NAME = "jdk.SocketWrite"; - public NetworkWriteHandler(Meter otelMeter, ThreadGrouper nameNormalizer) { + private DoubleHistogram bytesHistogram; + private DoubleHistogram durationHistogram; + + public NetworkWriteHandler(ThreadGrouper nameNormalizer) { super(nameNormalizer); - this.otelMeter = otelMeter; + initializeMeter(NoopMeter.getInstance()); } @Override @@ -43,8 +60,43 @@ public String getEventName() { } @Override - public RecordedEventHandler createPerThreadSummarizer(String threadName) { - var ret = new PerThreadNetworkWriteHandler(otelMeter, threadName); - return ret.init(); + public void initializeMeter(Meter meter) { + bytesHistogram = + meter + .histogramBuilder(NETWORK_BYTES_NAME) + .setDescription(NETWORK_BYTES_DESCRIPTION) + .setUnit(BYTES) + .build(); + durationHistogram = + meter + .histogramBuilder(NETWORK_DURATION_NAME) + .setDescription(NETWORK_DURATION_DESCRIPTION) + .setUnit(MILLISECONDS) + .build(); + } + + @Override + public Consumer createPerThreadSummarizer(String threadName) { + return new PerThreadNetworkWriteHandler(bytesHistogram, durationHistogram, threadName); + } + + private static final class PerThreadNetworkWriteHandler implements Consumer { + private static final String BYTES_WRITTEN = "bytesWritten"; + + private final BoundDoubleHistogram boundBytesHistogram; + private final BoundDoubleHistogram boundDurationHistogram; + + private PerThreadNetworkWriteHandler( + DoubleHistogram bytesHistogram, DoubleHistogram durationHistogram, String threadName) { + var attr = Attributes.of(ATTR_THREAD_NAME, threadName, ATTR_NETWORK_MODE, NETWORK_MODE_WRITE); + boundBytesHistogram = bytesHistogram.bind(attr); + boundDurationHistogram = durationHistogram.bind(attr); + } + + @Override + public void accept(RecordedEvent ev) { + boundBytesHistogram.record(ev.getLong(BYTES_WRITTEN)); + boundDurationHistogram.record(ev.getDuration().toMillis()); + } } } diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/PerThreadNetworkReadHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/PerThreadNetworkReadHandler.java deleted file mode 100644 index 0762c4b65..000000000 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/PerThreadNetworkReadHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.jfr.metrics.internal.network; - -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_NETWORK_MODE; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_THREAD_NAME; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.READ; - -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.metrics.BoundDoubleHistogram; -import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.contrib.jfr.metrics.internal.Constants; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; -import jdk.jfr.consumer.RecordedEvent; - -public final class PerThreadNetworkReadHandler implements RecordedEventHandler { - private static final String DESCRIPTION_BYTES = "Bytes Read"; - private static final String DESCRIPTION_DURATION = "Read Duration"; - private final String threadName; - - private static final String METRIC_NAME_DURATION = "runtime.jvm.network.duration"; - private static final String METRIC_NAME_BYTES = "runtime.jvm.network.io"; - private static final String BYTES_READ = "bytesRead"; - private final Meter otelMeter; - private BoundDoubleHistogram bytesHistogram; - private BoundDoubleHistogram durationHistogram; - - public PerThreadNetworkReadHandler(Meter otelMeter, String threadName) { - this.threadName = threadName; - this.otelMeter = otelMeter; - } - - public PerThreadNetworkReadHandler init() { - var attr = Attributes.of(ATTR_THREAD_NAME, threadName, ATTR_NETWORK_MODE, READ); - - var builder = otelMeter.histogramBuilder(METRIC_NAME_BYTES); - builder.setDescription(DESCRIPTION_BYTES); - builder.setUnit(Constants.BYTES); - bytesHistogram = builder.build().bind(attr); - - builder = otelMeter.histogramBuilder(METRIC_NAME_DURATION); - builder.setDescription(DESCRIPTION_DURATION); - builder.setUnit(Constants.MILLISECONDS); - durationHistogram = builder.build().bind(attr); - - return this; - } - - @Override - public String getEventName() { - return NetworkReadHandler.EVENT_NAME; - } - - @Override - public void accept(RecordedEvent ev) { - bytesHistogram.record(ev.getLong(BYTES_READ)); - durationHistogram.record(ev.getDuration().toMillis()); - } -} diff --git a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/PerThreadNetworkWriteHandler.java b/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/PerThreadNetworkWriteHandler.java deleted file mode 100644 index 1859e9457..000000000 --- a/jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/network/PerThreadNetworkWriteHandler.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.contrib.jfr.metrics.internal.network; - -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_NETWORK_MODE; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_THREAD_NAME; -import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.WRITE; - -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.metrics.BoundDoubleHistogram; -import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.contrib.jfr.metrics.internal.Constants; -import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler; -import jdk.jfr.consumer.RecordedEvent; - -public final class PerThreadNetworkWriteHandler implements RecordedEventHandler { - private static final String SIMPLE_CLASS_NAME = - PerThreadNetworkWriteHandler.class.getSimpleName(); - private static final String BYTES_WRITTEN = "bytesWritten"; - private static final String METRIC_NAME_DURATION = "runtime.jvm.network.duration"; - private static final String METRIC_NAME_BYTES = "runtime.jvm.network.io"; - - private static final String DESCRIPTION_BYTES = "Bytes Written"; - private static final String DESCRIPTION_DURATION = "Write Duration"; - - private final String threadName; - private final Meter otelMeter; - - private BoundDoubleHistogram bytesHistogram; - private BoundDoubleHistogram durationHistogram; - - public PerThreadNetworkWriteHandler(Meter otelMeter, String threadName) { - this.threadName = threadName; - this.otelMeter = otelMeter; - } - - public PerThreadNetworkWriteHandler init() { - var attr = Attributes.of(ATTR_THREAD_NAME, threadName, ATTR_NETWORK_MODE, WRITE); - - var builder = otelMeter.histogramBuilder(METRIC_NAME_BYTES); - builder.setDescription(DESCRIPTION_BYTES); - builder.setUnit(Constants.BYTES); - bytesHistogram = builder.build().bind(attr); - - builder = otelMeter.histogramBuilder(METRIC_NAME_DURATION); - builder.setDescription(DESCRIPTION_DURATION); - builder.setUnit(Constants.MILLISECONDS); - durationHistogram = builder.build().bind(attr); - - return this; - } - - @Override - public String getEventName() { - return NetworkWriteHandler.EVENT_NAME; - } - - @Override - public void accept(RecordedEvent ev) { - bytesHistogram.record(ev.getLong(BYTES_WRITTEN)); - durationHistogram.record(ev.getDuration().toMillis()); - } -}