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

feat(oshi): oshi metrics observables #10364

Merged
merged 4 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import io.opentelemetry.instrumentation.oshi.ProcessMetrics;
import io.opentelemetry.instrumentation.oshi.SystemMetrics;
import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public final class MetricsRegistration {
Expand All @@ -17,13 +19,28 @@ public final class MetricsRegistration {

public static void register() {
laurit marked this conversation as resolved.
Show resolved Hide resolved
if (registered.compareAndSet(false, true)) {
SystemMetrics.registerObservers(GlobalOpenTelemetry.get());
List<AutoCloseable> observables = new ArrayList<>();
observables.addAll(SystemMetrics.registerObservers(GlobalOpenTelemetry.get()));

// ProcessMetrics don't follow the spec
if (InstrumentationConfig.get()
.getBoolean("otel.instrumentation.oshi.experimental-metrics.enabled", false)) {
ProcessMetrics.registerObservers(GlobalOpenTelemetry.get());
observables.addAll(ProcessMetrics.registerObservers(GlobalOpenTelemetry.get()));
}
Thread cleanupTelemetry = new Thread(() -> MetricsRegistration.closeObservables(observables));
Runtime.getRuntime().addShutdownHook(cleanupTelemetry);
}
}

private static void closeObservables(List<AutoCloseable> observables) {
observables.forEach(MetricsRegistration::closeObservable);
}

private static void closeObservable(AutoCloseable observable) {
try {
observable.close();
} catch (Exception e) {
throw new IllegalStateException("Error occurred closing observable", e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import io.opentelemetry.instrumentation.oshi.AbstractProcessMetricsTest;
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.extension.RegisterExtension;

class ProcessMetricsTest extends AbstractProcessMetricsTest {
Expand All @@ -16,7 +18,9 @@ class ProcessMetricsTest extends AbstractProcessMetricsTest {
public static final InstrumentationExtension testing = AgentInstrumentationExtension.create();

@Override
protected void registerMetrics() {}
protected List<AutoCloseable> registerMetrics() {
return Collections.emptyList();
}

@Override
protected InstrumentationExtension testing() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import io.opentelemetry.instrumentation.oshi.AbstractSystemMetricsTest;
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.extension.RegisterExtension;

class SystemMetricsTest extends AbstractSystemMetricsTest {
Expand All @@ -16,7 +18,9 @@ class SystemMetricsTest extends AbstractSystemMetricsTest {
public static final InstrumentationExtension testing = AgentInstrumentationExtension.create();

@Override
protected void registerMetrics() {}
protected List<AutoCloseable> registerMetrics() {
return Collections.emptyList();
}

@Override
protected InstrumentationExtension testing() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.Meter;
import java.util.ArrayList;
import java.util.List;
import oshi.SystemInfo;
import oshi.software.os.OSProcess;
import oshi.software.os.OperatingSystem;
Expand All @@ -20,33 +22,36 @@ public class ProcessMetrics {
private ProcessMetrics() {}

/** Register observers for java runtime metrics. */
public static void registerObservers(OpenTelemetry openTelemetry) {
public static List<AutoCloseable> registerObservers(OpenTelemetry openTelemetry) {
Meter meter = openTelemetry.getMeterProvider().get("io.opentelemetry.oshi");
SystemInfo systemInfo = new SystemInfo();
OperatingSystem osInfo = systemInfo.getOperatingSystem();
OSProcess processInfo = osInfo.getProcess(osInfo.getProcessId());
List<AutoCloseable> observables = new ArrayList<>();
observables.add(
meter
.upDownCounterBuilder("runtime.java.memory")
.setDescription("Runtime Java memory")
.setUnit("By")
.buildWithCallback(
r -> {
processInfo.updateAttributes();
r.record(processInfo.getResidentSetSize(), Attributes.of(TYPE_KEY, "rss"));
r.record(processInfo.getVirtualSize(), Attributes.of(TYPE_KEY, "vms"));
}));

meter
.upDownCounterBuilder("runtime.java.memory")
.setDescription("Runtime Java memory")
.setUnit("By")
.buildWithCallback(
r -> {
processInfo.updateAttributes();
r.record(processInfo.getResidentSetSize(), Attributes.of(TYPE_KEY, "rss"));
r.record(processInfo.getVirtualSize(), Attributes.of(TYPE_KEY, "vms"));
});

meter
.gaugeBuilder("runtime.java.cpu_time")
.setDescription("Runtime Java CPU time")
.setUnit("ms")
.ofLongs()
.buildWithCallback(
r -> {
processInfo.updateAttributes();
r.record(processInfo.getUserTime(), Attributes.of(TYPE_KEY, "user"));
r.record(processInfo.getKernelTime(), Attributes.of(TYPE_KEY, "system"));
});
observables.add(
meter
.gaugeBuilder("runtime.java.cpu_time")
.setDescription("Runtime Java CPU time")
.setUnit("ms")
.ofLongs()
.buildWithCallback(
r -> {
processInfo.updateAttributes();
r.record(processInfo.getUserTime(), Attributes.of(TYPE_KEY, "user"));
r.record(processInfo.getKernelTime(), Attributes.of(TYPE_KEY, "system"));
}));
return observables;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.Meter;
import java.util.ArrayList;
import java.util.List;
import oshi.SystemInfo;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HWDiskStore;
Expand All @@ -28,111 +30,121 @@ public class SystemMetrics {
private SystemMetrics() {}

/** Register observers for system metrics. */
public static void registerObservers(OpenTelemetry openTelemetry) {
public static List<AutoCloseable> registerObservers(OpenTelemetry openTelemetry) {
Meter meter = openTelemetry.getMeterProvider().get("io.opentelemetry.oshi");
SystemInfo systemInfo = new SystemInfo();
HardwareAbstractionLayer hal = systemInfo.getHardware();
List<AutoCloseable> observables = new ArrayList<>();

meter
.upDownCounterBuilder("system.memory.usage")
.setDescription("System memory usage")
.setUnit("By")
.buildWithCallback(
r -> {
GlobalMemory mem = hal.getMemory();
r.record(mem.getTotal() - mem.getAvailable(), ATTRIBUTES_USED);
r.record(mem.getAvailable(), ATTRIBUTES_FREE);
});
observables.add(
meter
.upDownCounterBuilder("system.memory.usage")
.setDescription("System memory usage")
.setUnit("By")
.buildWithCallback(
r -> {
GlobalMemory mem = hal.getMemory();
r.record(mem.getTotal() - mem.getAvailable(), ATTRIBUTES_USED);
r.record(mem.getAvailable(), ATTRIBUTES_FREE);
}));

meter
.gaugeBuilder("system.memory.utilization")
.setDescription("System memory utilization")
.setUnit("1")
.buildWithCallback(
r -> {
GlobalMemory mem = hal.getMemory();
r.record(
((double) (mem.getTotal() - mem.getAvailable())) / mem.getTotal(),
ATTRIBUTES_USED);
r.record(((double) mem.getAvailable()) / mem.getTotal(), ATTRIBUTES_FREE);
});
observables.add(
meter
.gaugeBuilder("system.memory.utilization")
.setDescription("System memory utilization")
.setUnit("1")
.buildWithCallback(
r -> {
GlobalMemory mem = hal.getMemory();
r.record(
((double) (mem.getTotal() - mem.getAvailable())) / mem.getTotal(),
ATTRIBUTES_USED);
r.record(((double) mem.getAvailable()) / mem.getTotal(), ATTRIBUTES_FREE);
}));

meter
.counterBuilder("system.network.io")
.setDescription("System network IO")
.setUnit("By")
.buildWithCallback(
r -> {
for (NetworkIF networkIf : hal.getNetworkIFs()) {
networkIf.updateAttributes();
long recv = networkIf.getBytesRecv();
long sent = networkIf.getBytesSent();
String device = networkIf.getName();
r.record(recv, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "receive"));
r.record(sent, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "transmit"));
}
});
observables.add(
meter
.counterBuilder("system.network.io")
.setDescription("System network IO")
.setUnit("By")
.buildWithCallback(
r -> {
for (NetworkIF networkIf : hal.getNetworkIFs()) {
networkIf.updateAttributes();
long recv = networkIf.getBytesRecv();
long sent = networkIf.getBytesSent();
String device = networkIf.getName();
r.record(recv, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "receive"));
r.record(sent, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "transmit"));
}
}));

meter
.counterBuilder("system.network.packets")
.setDescription("System network packets")
.setUnit("{packets}")
.buildWithCallback(
r -> {
for (NetworkIF networkIf : hal.getNetworkIFs()) {
networkIf.updateAttributes();
long recv = networkIf.getPacketsRecv();
long sent = networkIf.getPacketsSent();
String device = networkIf.getName();
r.record(recv, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "receive"));
r.record(sent, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "transmit"));
}
});
observables.add(
meter
.counterBuilder("system.network.packets")
.setDescription("System network packets")
.setUnit("{packets}")
.buildWithCallback(
r -> {
for (NetworkIF networkIf : hal.getNetworkIFs()) {
networkIf.updateAttributes();
long recv = networkIf.getPacketsRecv();
long sent = networkIf.getPacketsSent();
String device = networkIf.getName();
r.record(recv, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "receive"));
r.record(sent, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "transmit"));
}
}));

meter
.counterBuilder("system.network.errors")
.setDescription("System network errors")
.setUnit("{errors}")
.buildWithCallback(
r -> {
for (NetworkIF networkIf : hal.getNetworkIFs()) {
networkIf.updateAttributes();
long recv = networkIf.getInErrors();
long sent = networkIf.getOutErrors();
String device = networkIf.getName();
r.record(recv, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "receive"));
r.record(sent, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "transmit"));
}
});
observables.add(
meter
.counterBuilder("system.network.errors")
.setDescription("System network errors")
.setUnit("{errors}")
.buildWithCallback(
r -> {
for (NetworkIF networkIf : hal.getNetworkIFs()) {
networkIf.updateAttributes();
long recv = networkIf.getInErrors();
long sent = networkIf.getOutErrors();
String device = networkIf.getName();
r.record(recv, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "receive"));
r.record(sent, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "transmit"));
}
}));

meter
.counterBuilder("system.disk.io")
.setDescription("System disk IO")
.setUnit("By")
.buildWithCallback(
r -> {
for (HWDiskStore diskStore : hal.getDiskStores()) {
long read = diskStore.getReadBytes();
long write = diskStore.getWriteBytes();
String device = diskStore.getName();
r.record(read, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "read"));
r.record(write, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "write"));
}
});
observables.add(
meter
.counterBuilder("system.disk.io")
.setDescription("System disk IO")
.setUnit("By")
.buildWithCallback(
r -> {
for (HWDiskStore diskStore : hal.getDiskStores()) {
long read = diskStore.getReadBytes();
long write = diskStore.getWriteBytes();
String device = diskStore.getName();
r.record(read, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "read"));
r.record(write, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "write"));
}
}));

meter
.counterBuilder("system.disk.operations")
.setDescription("System disk operations")
.setUnit("{operations}")
.buildWithCallback(
r -> {
for (HWDiskStore diskStore : hal.getDiskStores()) {
long read = diskStore.getReads();
long write = diskStore.getWrites();
String device = diskStore.getName();
r.record(read, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "read"));
r.record(write, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "write"));
}
});
observables.add(
meter
.counterBuilder("system.disk.operations")
.setDescription("System disk operations")
.setUnit("{operations}")
.buildWithCallback(
r -> {
for (HWDiskStore diskStore : hal.getDiskStores()) {
long read = diskStore.getReads();
long write = diskStore.getWrites();
String device = diskStore.getName();
r.record(read, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "read"));
r.record(write, Attributes.of(DEVICE_KEY, device, DIRECTION_KEY, "write"));
}
}));

return observables;
}
}
Loading
Loading