Skip to content

Commit

Permalink
Add jvm threads instrumentation (open-telemetry#6070)
Browse files Browse the repository at this point in the history
* Add jvm threads instrumentation

* Use up down counter
  • Loading branch information
jack-berg authored and RashmiRam committed May 23, 2022
1 parent fcf5fb5 commit 6b53153
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.opentelemetry.instrumentation.runtimemetrics.Classes;
import io.opentelemetry.instrumentation.runtimemetrics.GarbageCollector;
import io.opentelemetry.instrumentation.runtimemetrics.MemoryPools;
import io.opentelemetry.instrumentation.runtimemetrics.Threads;
import io.opentelemetry.javaagent.extension.AgentListener;
import io.opentelemetry.javaagent.tooling.config.AgentConfig;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
Expand All @@ -28,8 +29,9 @@ public void afterAgent(Config config, AutoConfiguredOpenTelemetrySdk unused) {
if (new AgentConfig(config)
.isInstrumentationEnabled(Collections.singleton("runtime-metrics"), DEFAULT_ENABLED)) {

MemoryPools.registerObservers(GlobalOpenTelemetry.get());
Classes.registerObservers(GlobalOpenTelemetry.get());
MemoryPools.registerObservers(GlobalOpenTelemetry.get());
Threads.registerObservers(GlobalOpenTelemetry.get());

if (config.getBoolean(
"otel.instrumentation.runtime-metrics.experimental-metrics.enabled", false)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ class RuntimeMetricsTest extends AgentInstrumentationSpecification {

then:
conditions.eventually {
assert getMetrics().any { it.name == "process.runtime.jvm.classes.loaded" }
assert getMetrics().any { it.name == "process.runtime.jvm.classes.unloaded" }
assert getMetrics().any { it.name == "process.runtime.jvm.classes.current_loaded" }
assert getMetrics().any { it.name == "runtime.jvm.gc.time" }
assert getMetrics().any { it.name == "runtime.jvm.gc.count" }
assert getMetrics().any { it.name == "process.runtime.jvm.memory.init" }
assert getMetrics().any { it.name == "process.runtime.jvm.memory.usage" }
assert getMetrics().any { it.name == "process.runtime.jvm.memory.committed" }
assert getMetrics().any { it.name == "process.runtime.jvm.memory.max" }
assert getMetrics().any { it.name == "process.runtime.jvm.classes.loaded" }
assert getMetrics().any { it.name == "process.runtime.jvm.classes.unloaded" }
assert getMetrics().any { it.name == "process.runtime.jvm.classes.current_loaded" }
assert getMetrics().any { it.name == "process.runtime.jvm.threads.count" }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.runtimemetrics;

import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.metrics.Meter;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;

/**
* Registers measurements that generate metrics about JVM threads.
*
* <p>Example usage:
*
* <pre>{@code
* Classes.registerObservers(GlobalOpenTelemetry.get());
* }</pre>
*
* <p>Example metrics being exported:
*
* <pre>
* process.runtime.jvm.threads.count 4
* </pre>
*/
public final class Threads {

// Visible for testing
static final Threads INSTANCE = new Threads();

/** Register observers for java runtime class metrics. */
public static void registerObservers(OpenTelemetry openTelemetry) {
INSTANCE.registerObservers(openTelemetry, ManagementFactory.getThreadMXBean());
}

// Visible for testing
void registerObservers(OpenTelemetry openTelemetry, ThreadMXBean threadBean) {
Meter meter = openTelemetry.getMeter("io.opentelemetry.runtime-metrics");

meter
.upDownCounterBuilder("process.runtime.jvm.threads.count")
.setDescription("Number of executing threads")
.setUnit("1")
.buildWithCallback(
observableMeasurement -> observableMeasurement.record(threadBean.getThreadCount()));
}

private Threads() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.runtimemetrics;

import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static org.mockito.Mockito.when;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension;
import java.lang.management.ThreadMXBean;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class ThreadsTest {

@RegisterExtension
static final InstrumentationExtension testing = LibraryInstrumentationExtension.create();

@Mock private ThreadMXBean threadBean;

@Test
void registerObservers() {
when(threadBean.getThreadCount()).thenReturn(3);

Threads.INSTANCE.registerObservers(testing.getOpenTelemetry(), threadBean);

testing.waitAndAssertMetrics(
"io.opentelemetry.runtime-metrics",
"process.runtime.jvm.threads.count",
metrics ->
metrics.anySatisfy(
metricData ->
assertThat(metricData)
.hasDescription("Number of executing threads")
.hasUnit("1")
.hasLongSumSatisfying(
sum ->
sum.isNotMonotonic()
.hasPointsSatisfying(
point ->
point.hasValue(3).hasAttributes(Attributes.empty())))));
}
}

0 comments on commit 6b53153

Please sign in to comment.