Copilot commented on code in PR #17290:
URL: https://github.com/apache/iotdb/pull/17290#discussion_r2923391718
##########
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/net/WindowsNetMetricManager.java:
##########
@@ -19,4 +19,191 @@
package org.apache.iotdb.metrics.metricsets.net;
-public class WindowsNetMetricManager implements INetMetricManager {}
+import org.apache.iotdb.metrics.MetricConstant;
+import org.apache.iotdb.metrics.config.MetricConfig;
+import org.apache.iotdb.metrics.config.MetricConfigDescriptor;
+import org.apache.iotdb.metrics.utils.MetricLevel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class WindowsNetMetricManager implements INetMetricManager {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(WindowsNetMetricManager.class);
+
+ private static final MetricConfig METRIC_CONFIG =
+ MetricConfigDescriptor.getInstance().getMetricConfig();
+
+ private long lastUpdateTime = 0L;
+
+ private Set<String> ifaceSet = new HashSet<>();
+
+ private final Map<String, Long> receivedBytesMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedBytesMapForIface = new
HashMap<>();
+
+ private final Map<String, Long> receivedPacketsMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedPacketsMapForIface = new
HashMap<>();
+
+ private int connectionNum = 0;
+
+ public WindowsNetMetricManager() {
+ checkUpdate();
+ }
+
+ @Override
+ public Set<String> getIfaceSet() {
+ checkUpdate();
+ return ifaceSet;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedByte() {
+ checkUpdate();
+ return receivedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedBytes() {
+ checkUpdate();
+ return transmittedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedPackets() {
+ checkUpdate();
+ return receivedPacketsMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedPackets() {
+ checkUpdate();
+ return transmittedPacketsMapForIface;
+ }
+
+ @Override
+ public int getConnectionNum() {
+ checkUpdate();
+ return connectionNum;
+ }
+
+ private void checkUpdate() {
+ if (System.currentTimeMillis() - lastUpdateTime >=
MetricConstant.UPDATE_INTERVAL) {
+ updateNetStatus();
+ }
+ }
+
+ private void updateNetStatus() {
+ lastUpdateTime = System.currentTimeMillis();
+ updateInterfaces();
+ updateStatistics();
+ if (MetricLevel.higherOrEqual(MetricLevel.NORMAL,
METRIC_CONFIG.getMetricLevel())) {
+ updateConnectionNum();
+ }
+ }
+
+ private void updateInterfaces() {
+ try {
+ ifaceSet.clear();
+ Process process =
+ Runtime.getRuntime()
+ .exec(
+ "cmd.exe /c chcp 65001 > nul & powershell.exe -Command
\"Get-NetAdapter -IncludeHidden | Select Name | Format-List \"");
+ BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("Name :")) {
+ ifaceSet.add(line.substring("Name : ".length()).trim());
+ }
+ }
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ LOGGER.error("Failed to get interfaces, exit code: {}", exitCode);
+ }
+ } catch (IOException | InterruptedException e) {
+ LOGGER.error("Error updating interfaces", e);
+ ifaceSet = Collections.emptySet();
+ }
+ }
+
+ private void updateStatistics() {
+ try {
+ receivedBytesMapForIface.clear();
+ transmittedBytesMapForIface.clear();
+ receivedPacketsMapForIface.clear();
+ transmittedPacketsMapForIface.clear();
+ Process process =
+ Runtime.getRuntime()
+ .exec(
+ "cmd.exe /c chcp 65001 > nul & powershell.exe -Command
\"Get-NetAdapterStatistics -IncludeHidden | Format-List
Name,ReceivedBytes,SentBytes,ReceivedUnicastPackets,SentUnicastPackets \"");
+ BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8));
+ String line;
+ String currentName = null;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("Name ")) {
+ currentName = line.substring(line.indexOf(": ") + 2).trim();
+ } else if (line.startsWith("ReceivedBytes ") && currentName != null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ receivedBytesMapForIface.put(currentName, value);
+ } else if (line.startsWith("SentBytes ") && currentName != null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ transmittedBytesMapForIface.put(currentName, value);
+ } else if (line.startsWith("ReceivedUnicastPackets ") && currentName
!= null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ receivedPacketsMapForIface.put(currentName, value);
+ } else if (line.startsWith("SentUnicastPackets ") && currentName !=
null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ transmittedPacketsMapForIface.put(currentName, value);
+ currentName = null; // Reset after processing an interface
+ }
+ }
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ LOGGER.error("Failed to get statistics, exit code: {}", exitCode);
+ }
+ } catch (IOException | InterruptedException | NumberFormatException e) {
+ LOGGER.error("Error updating statistics", e);
+ }
+ }
+
+ private void updateConnectionNum() {
+ try {
+ Process process = Runtime.getRuntime().exec("netstat -ano");
+ BufferedReader reader = new BufferedReader(new
InputStreamReader(process.getInputStream()));
+ int count = 0;
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (!line.isEmpty() && !line.startsWith("Active") &&
!line.startsWith("Proto")) {
+ String[] parts = line.split("\\s+");
+ if (parts.length >= 5 && parts[parts.length -
1].equals(METRIC_CONFIG.getPid())) {
Review Comment:
`netstat -ano` outputs UDP rows without a "State" column (typically 4
columns total), so the `parts.length >= 5` check skips all UDP sockets. This
makes the Windows `connectionNum` inconsistent with the Linux implementation
(which counts all sockets). Consider accepting `parts.length >= 4` and still
comparing the last column PID so UDP rows are counted too.
```suggestion
if (parts.length >= 4 && parts[parts.length -
1].equals(METRIC_CONFIG.getPid())) {
```
##########
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/disk/WindowsDiskMetricsManager.java:
##########
@@ -19,5 +19,483 @@
package org.apache.iotdb.metrics.metricsets.disk;
-/** Disk Metrics Manager for Windows system, not implemented yet. */
-public class WindowsDiskMetricsManager implements IDiskMetricsManager {}
+import org.apache.iotdb.metrics.config.MetricConfigDescriptor;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Disk metrics manager for Windows system.
+ *
+ * <p>Windows does not expose Linux-like cumulative counters through procfs,
so this implementation
+ * periodically samples Win32 performance counters and accumulates the
observed per-second values
+ * into totals that match the Linux manager contract as closely as possible.
+ */
+public class WindowsDiskMetricsManager implements IDiskMetricsManager {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(WindowsDiskMetricsManager.class);
+
+ private static final double BYTES_PER_KB = 1024.0;
+ private static final long UPDATE_SMALLEST_INTERVAL = 10000L;
+ private static final String POWER_SHELL = "powershell";
+ private static final String POWER_SHELL_NO_PROFILE = "-NoProfile";
+ private static final String POWER_SHELL_COMMAND = "-Command";
+ private static final String TOTAL_DISK_INSTANCE = "_Total";
+ private static final Charset WINDOWS_SHELL_CHARSET =
getWindowsShellCharset();
+ private static final String DISK_QUERY =
+ "Get-CimInstance Win32_PerfFormattedData_PerfDisk_PhysicalDisk | "
+ + "Where-Object { $_.Name -ne '_Total' } | "
+ + "ForEach-Object { "
+ + "[string]::Concat("
+ + "$_.Name, [char]9, "
+ + "$_.DiskReadsPerSec, [char]9, "
+ + "$_.DiskWritesPerSec, [char]9, "
+ + "$_.DiskReadBytesPerSec, [char]9, "
+ + "$_.DiskWriteBytesPerSec, [char]9, "
+ + "$_.AvgDisksecPerRead, [char]9, "
+ + "$_.AvgDisksecPerWrite, [char]9, "
+ + "$_.PercentIdleTime, [char]9, "
+ + "$_.AvgDiskQueueLength) }";
+ private static final String PROCESS_QUERY_TEMPLATE =
+ "Get-CimInstance Win32_PerfFormattedData_PerfProc_Process | "
+ + "Where-Object { $_.IDProcess -eq %s } | "
+ + "ForEach-Object { "
+ + "[string]::Concat("
+ + "$_.IOReadOperationsPerSec, [char]9, "
+ + "$_.IOWriteOperationsPerSec, [char]9, "
+ + "$_.IOReadBytesPerSec, [char]9, "
+ + "$_.IOWriteBytesPerSec) }";
+
+ private final String processId;
+ private final Set<String> diskIdSet = new HashSet<>();
+
+ private long lastUpdateTime = 0L;
+ private long updateInterval = 1L;
+
+ private final Map<String, Long> lastReadOperationCountForDisk = new
HashMap<>();
+ private final Map<String, Long> lastWriteOperationCountForDisk = new
HashMap<>();
+ private final Map<String, Long> lastReadTimeCostForDisk = new HashMap<>();
+ private final Map<String, Long> lastWriteTimeCostForDisk = new HashMap<>();
+ private final Map<String, Long> lastMergedReadCountForDisk = new HashMap<>();
+ private final Map<String, Long> lastMergedWriteCountForDisk = new
HashMap<>();
+ private final Map<String, Long> lastReadSizeForDisk = new HashMap<>();
+ private final Map<String, Long> lastWriteSizeForDisk = new HashMap<>();
+ private final Map<String, Double> lastIoUtilsPercentageForDisk = new
HashMap<>();
+ private final Map<String, Double> lastQueueSizeForDisk = new HashMap<>();
+ private final Map<String, Double> lastAvgReadCostTimeOfEachOpsForDisk = new
HashMap<>();
+ private final Map<String, Double> lastAvgWriteCostTimeOfEachOpsForDisk = new
HashMap<>();
+ private final Map<String, Double> lastAvgSizeOfEachReadForDisk = new
HashMap<>();
+ private final Map<String, Double> lastAvgSizeOfEachWriteForDisk = new
HashMap<>();
+
+ private long lastReallyReadSizeForProcess = 0L;
+ private long lastReallyWriteSizeForProcess = 0L;
+ private long lastAttemptReadSizeForProcess = 0L;
+ private long lastAttemptWriteSizeForProcess = 0L;
+ private long lastReadOpsCountForProcess = 0L;
+ private long lastWriteOpsCountForProcess = 0L;
+
+ public WindowsDiskMetricsManager() {
+ processId =
String.valueOf(MetricConfigDescriptor.getInstance().getMetricConfig().getPid());
+ collectDiskId();
+ }
+
+ @Override
+ public Map<String, Double> getReadDataSizeForDisk() {
+ checkUpdate();
+ return toKbMap(lastReadSizeForDisk);
+ }
+
+ @Override
+ public Map<String, Double> getWriteDataSizeForDisk() {
+ checkUpdate();
+ return toKbMap(lastWriteSizeForDisk);
+ }
+
+ @Override
+ public Map<String, Long> getReadOperationCountForDisk() {
+ checkUpdate();
+ return lastReadOperationCountForDisk;
+ }
+
+ @Override
+ public Map<String, Long> getWriteOperationCountForDisk() {
+ checkUpdate();
+ return lastWriteOperationCountForDisk;
+ }
+
+ @Override
+ public Map<String, Long> getReadCostTimeForDisk() {
+ checkUpdate();
+ return lastReadTimeCostForDisk;
+ }
+
+ @Override
+ public Map<String, Long> getWriteCostTimeForDisk() {
+ checkUpdate();
+ return lastWriteTimeCostForDisk;
+ }
+
+ @Override
+ public Map<String, Double> getIoUtilsPercentage() {
+ checkUpdate();
+ return lastIoUtilsPercentageForDisk;
+ }
+
+ @Override
+ public Map<String, Double> getAvgReadCostTimeOfEachOpsForDisk() {
+ checkUpdate();
+ return lastAvgReadCostTimeOfEachOpsForDisk;
+ }
+
+ @Override
+ public Map<String, Double> getAvgWriteCostTimeOfEachOpsForDisk() {
+ checkUpdate();
+ return lastAvgWriteCostTimeOfEachOpsForDisk;
+ }
+
+ @Override
+ public Map<String, Double> getAvgSizeOfEachReadForDisk() {
+ checkUpdate();
+ return lastAvgSizeOfEachReadForDisk;
+ }
+
+ @Override
+ public Map<String, Double> getAvgSizeOfEachWriteForDisk() {
+ checkUpdate();
+ return lastAvgSizeOfEachWriteForDisk;
+ }
+
+ @Override
+ public Map<String, Long> getMergedWriteOperationForDisk() {
+ checkUpdate();
+ return lastMergedWriteCountForDisk;
+ }
+
+ @Override
+ public Map<String, Long> getMergedReadOperationForDisk() {
+ checkUpdate();
+ return lastMergedReadCountForDisk;
+ }
+
+ @Override
+ public Map<String, Double> getQueueSizeForDisk() {
+ checkUpdate();
+ return lastQueueSizeForDisk;
+ }
+
+ @Override
+ public double getActualReadDataSizeForProcess() {
+ checkUpdate();
+ return lastReallyReadSizeForProcess / BYTES_PER_KB;
+ }
+
+ @Override
+ public double getActualWriteDataSizeForProcess() {
+ checkUpdate();
+ return lastReallyWriteSizeForProcess / BYTES_PER_KB;
+ }
+
+ @Override
+ public long getReadOpsCountForProcess() {
+ checkUpdate();
+ return lastReadOpsCountForProcess;
+ }
+
+ @Override
+ public long getWriteOpsCountForProcess() {
+ checkUpdate();
+ return lastWriteOpsCountForProcess;
+ }
+
+ @Override
+ public double getAttemptReadSizeForProcess() {
+ checkUpdate();
+ return lastAttemptReadSizeForProcess / BYTES_PER_KB;
+ }
+
+ @Override
+ public double getAttemptWriteSizeForProcess() {
+ checkUpdate();
+ return lastAttemptWriteSizeForProcess / BYTES_PER_KB;
+ }
+
+ @Override
+ public Set<String> getDiskIds() {
+ checkUpdate();
+ return diskIdSet;
+ }
+
+ private void collectDiskId() {
+ Map<String, String[]> diskInfoMap = queryDiskInfo();
+ if (diskInfoMap.isEmpty()) {
+ return;
+ }
+ diskIdSet.clear();
+ diskIdSet.addAll(diskInfoMap.keySet());
+ }
+
+ private Map<String, Double> toKbMap(Map<String, Long> source) {
+ Map<String, Double> result = new HashMap<>(source.size());
+ for (Map.Entry<String, Long> entry : source.entrySet()) {
+ result.put(entry.getKey(), entry.getValue() / BYTES_PER_KB);
+ }
+ return result;
+ }
+
+ private void updateInfo() {
+ long currentTime = System.currentTimeMillis();
+ updateInterval = lastUpdateTime == 0L ? 0L : currentTime - lastUpdateTime;
+ lastUpdateTime = currentTime;
+ updateDiskInfo();
+ updateProcessInfo();
+ }
+
+ private void updateDiskInfo() {
+ Map<String, String[]> diskInfoMap = queryDiskInfo();
+ if (diskInfoMap.isEmpty()) {
+ return;
+ }
+
+ diskIdSet.clear();
+ diskIdSet.addAll(diskInfoMap.keySet());
+
Review Comment:
`diskIdSet` is refreshed on every update, but the per-disk metric maps
(e.g., `lastReadOperationCountForDisk`, `lastReadSizeForDisk`, etc.) are never
pruned/cleared for disks that disappear. If the set of physical disks changes,
callers can keep seeing stale metrics for removed disk IDs and the maps can
grow over time. Consider removing entries not present in the new `diskIdSet`
(or clearing and rebuilding maps) when `diskInfoMap` is refreshed.
##########
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/net/WindowsNetMetricManager.java:
##########
@@ -19,4 +19,191 @@
package org.apache.iotdb.metrics.metricsets.net;
-public class WindowsNetMetricManager implements INetMetricManager {}
+import org.apache.iotdb.metrics.MetricConstant;
+import org.apache.iotdb.metrics.config.MetricConfig;
+import org.apache.iotdb.metrics.config.MetricConfigDescriptor;
+import org.apache.iotdb.metrics.utils.MetricLevel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class WindowsNetMetricManager implements INetMetricManager {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(WindowsNetMetricManager.class);
+
+ private static final MetricConfig METRIC_CONFIG =
+ MetricConfigDescriptor.getInstance().getMetricConfig();
+
+ private long lastUpdateTime = 0L;
+
+ private Set<String> ifaceSet = new HashSet<>();
+
+ private final Map<String, Long> receivedBytesMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedBytesMapForIface = new
HashMap<>();
+
+ private final Map<String, Long> receivedPacketsMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedPacketsMapForIface = new
HashMap<>();
+
+ private int connectionNum = 0;
+
+ public WindowsNetMetricManager() {
+ checkUpdate();
+ }
+
+ @Override
+ public Set<String> getIfaceSet() {
+ checkUpdate();
+ return ifaceSet;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedByte() {
+ checkUpdate();
+ return receivedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedBytes() {
+ checkUpdate();
+ return transmittedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedPackets() {
+ checkUpdate();
+ return receivedPacketsMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedPackets() {
+ checkUpdate();
+ return transmittedPacketsMapForIface;
+ }
+
+ @Override
+ public int getConnectionNum() {
+ checkUpdate();
+ return connectionNum;
+ }
+
+ private void checkUpdate() {
+ if (System.currentTimeMillis() - lastUpdateTime >=
MetricConstant.UPDATE_INTERVAL) {
+ updateNetStatus();
+ }
+ }
+
+ private void updateNetStatus() {
+ lastUpdateTime = System.currentTimeMillis();
+ updateInterfaces();
+ updateStatistics();
+ if (MetricLevel.higherOrEqual(MetricLevel.NORMAL,
METRIC_CONFIG.getMetricLevel())) {
+ updateConnectionNum();
+ }
+ }
+
+ private void updateInterfaces() {
+ try {
+ ifaceSet.clear();
+ Process process =
+ Runtime.getRuntime()
+ .exec(
+ "cmd.exe /c chcp 65001 > nul & powershell.exe -Command
\"Get-NetAdapter -IncludeHidden | Select Name | Format-List \"");
+ BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("Name :")) {
+ ifaceSet.add(line.substring("Name : ".length()).trim());
+ }
+ }
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ LOGGER.error("Failed to get interfaces, exit code: {}", exitCode);
+ }
+ } catch (IOException | InterruptedException e) {
+ LOGGER.error("Error updating interfaces", e);
+ ifaceSet = Collections.emptySet();
Review Comment:
In the catch block, `ifaceSet` is reassigned to `Collections.emptySet()`,
which is immutable. The next successful update will call `ifaceSet.clear()` and
throw `UnsupportedOperationException`, permanently breaking interface
collection after a single failure. Keep `ifaceSet` as a mutable set (e.g.,
clear and leave it empty, or assign a new `HashSet<>`) instead of using
`Collections.emptySet()` here.
```suggestion
```
##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/file/SystemRelatedFileMetrics.java:
##########
@@ -106,4 +120,10 @@ public void unbindFrom(AbstractMetricService
metricService) {
"open_file_handlers");
}
}
+
+ public interface Kernel32Ext extends Library {
+ Kernel32Ext INSTANCE = Native.load("kernel32", Kernel32Ext.class);
+
+ boolean GetProcessHandleCount(WinNT.HANDLE hProcess, IntByReference
pdwHandleCount);
Review Comment:
`Kernel32Ext` extends `com.sun.jna.Library`, which uses the default (cdecl)
calling convention. Win32 API functions in kernel32.dll use stdcall; using the
wrong convention can lead to incorrect results or crashes on 32-bit Windows.
Prefer extending `com.sun.jna.win32.StdCallLibrary` (or `Kernel32` if it
already exposes `GetProcessHandleCount`) so the calling convention matches
Windows APIs.
##########
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/net/WindowsNetMetricManager.java:
##########
@@ -19,4 +19,191 @@
package org.apache.iotdb.metrics.metricsets.net;
-public class WindowsNetMetricManager implements INetMetricManager {}
+import org.apache.iotdb.metrics.MetricConstant;
+import org.apache.iotdb.metrics.config.MetricConfig;
+import org.apache.iotdb.metrics.config.MetricConfigDescriptor;
+import org.apache.iotdb.metrics.utils.MetricLevel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class WindowsNetMetricManager implements INetMetricManager {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(WindowsNetMetricManager.class);
+
+ private static final MetricConfig METRIC_CONFIG =
+ MetricConfigDescriptor.getInstance().getMetricConfig();
+
+ private long lastUpdateTime = 0L;
+
+ private Set<String> ifaceSet = new HashSet<>();
+
+ private final Map<String, Long> receivedBytesMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedBytesMapForIface = new
HashMap<>();
+
+ private final Map<String, Long> receivedPacketsMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedPacketsMapForIface = new
HashMap<>();
+
+ private int connectionNum = 0;
+
+ public WindowsNetMetricManager() {
+ checkUpdate();
+ }
+
+ @Override
+ public Set<String> getIfaceSet() {
+ checkUpdate();
+ return ifaceSet;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedByte() {
+ checkUpdate();
+ return receivedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedBytes() {
+ checkUpdate();
+ return transmittedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedPackets() {
+ checkUpdate();
+ return receivedPacketsMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedPackets() {
+ checkUpdate();
+ return transmittedPacketsMapForIface;
+ }
+
+ @Override
+ public int getConnectionNum() {
+ checkUpdate();
+ return connectionNum;
+ }
+
+ private void checkUpdate() {
+ if (System.currentTimeMillis() - lastUpdateTime >=
MetricConstant.UPDATE_INTERVAL) {
+ updateNetStatus();
+ }
+ }
+
+ private void updateNetStatus() {
+ lastUpdateTime = System.currentTimeMillis();
+ updateInterfaces();
+ updateStatistics();
+ if (MetricLevel.higherOrEqual(MetricLevel.NORMAL,
METRIC_CONFIG.getMetricLevel())) {
+ updateConnectionNum();
+ }
+ }
+
+ private void updateInterfaces() {
+ try {
+ ifaceSet.clear();
+ Process process =
+ Runtime.getRuntime()
+ .exec(
+ "cmd.exe /c chcp 65001 > nul & powershell.exe -Command
\"Get-NetAdapter -IncludeHidden | Select Name | Format-List \"");
+ BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("Name :")) {
+ ifaceSet.add(line.substring("Name : ".length()).trim());
+ }
+ }
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ LOGGER.error("Failed to get interfaces, exit code: {}", exitCode);
+ }
+ } catch (IOException | InterruptedException e) {
+ LOGGER.error("Error updating interfaces", e);
+ ifaceSet = Collections.emptySet();
Review Comment:
The process/stream handling here can leak resources and potentially hang:
the `BufferedReader` is not closed, the process error stream is never consumed
(so the process can block if stderr fills), and `InterruptedException` is
swallowed without restoring the interrupt flag. Use `ProcessBuilder` with
`redirectErrorStream(true)` (or separately consume stderr), wrap the reader in
try-with-resources, and on interruption call
`Thread.currentThread().interrupt()` before returning.
```suggestion
Process process = null;
try {
ifaceSet.clear();
ProcessBuilder processBuilder =
new ProcessBuilder(
"cmd.exe",
"/c",
"chcp 65001 > nul & powershell.exe -Command \"Get-NetAdapter
-IncludeHidden | Select Name | Format-List \"");
processBuilder.redirectErrorStream(true);
process = processBuilder.start();
try (BufferedReader reader =
new BufferedReader(
new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.startsWith("Name :")) {
ifaceSet.add(line.substring("Name : ".length()).trim());
}
}
}
int exitCode = process.waitFor();
if (exitCode != 0) {
LOGGER.error("Failed to get interfaces, exit code: {}", exitCode);
}
} catch (InterruptedException e) {
LOGGER.error("Error updating interfaces", e);
ifaceSet = Collections.emptySet();
Thread.currentThread().interrupt();
} catch (IOException e) {
LOGGER.error("Error updating interfaces", e);
ifaceSet = Collections.emptySet();
```
##########
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/net/WindowsNetMetricManager.java:
##########
@@ -19,4 +19,191 @@
package org.apache.iotdb.metrics.metricsets.net;
-public class WindowsNetMetricManager implements INetMetricManager {}
+import org.apache.iotdb.metrics.MetricConstant;
+import org.apache.iotdb.metrics.config.MetricConfig;
+import org.apache.iotdb.metrics.config.MetricConfigDescriptor;
+import org.apache.iotdb.metrics.utils.MetricLevel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class WindowsNetMetricManager implements INetMetricManager {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(WindowsNetMetricManager.class);
+
+ private static final MetricConfig METRIC_CONFIG =
+ MetricConfigDescriptor.getInstance().getMetricConfig();
+
+ private long lastUpdateTime = 0L;
+
+ private Set<String> ifaceSet = new HashSet<>();
+
+ private final Map<String, Long> receivedBytesMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedBytesMapForIface = new
HashMap<>();
+
+ private final Map<String, Long> receivedPacketsMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedPacketsMapForIface = new
HashMap<>();
+
+ private int connectionNum = 0;
+
+ public WindowsNetMetricManager() {
+ checkUpdate();
+ }
+
+ @Override
+ public Set<String> getIfaceSet() {
+ checkUpdate();
+ return ifaceSet;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedByte() {
+ checkUpdate();
+ return receivedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedBytes() {
+ checkUpdate();
+ return transmittedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedPackets() {
+ checkUpdate();
+ return receivedPacketsMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedPackets() {
+ checkUpdate();
+ return transmittedPacketsMapForIface;
+ }
+
+ @Override
+ public int getConnectionNum() {
+ checkUpdate();
+ return connectionNum;
+ }
+
+ private void checkUpdate() {
+ if (System.currentTimeMillis() - lastUpdateTime >=
MetricConstant.UPDATE_INTERVAL) {
+ updateNetStatus();
+ }
+ }
+
+ private void updateNetStatus() {
+ lastUpdateTime = System.currentTimeMillis();
+ updateInterfaces();
+ updateStatistics();
+ if (MetricLevel.higherOrEqual(MetricLevel.NORMAL,
METRIC_CONFIG.getMetricLevel())) {
+ updateConnectionNum();
+ }
+ }
+
+ private void updateInterfaces() {
+ try {
+ ifaceSet.clear();
+ Process process =
+ Runtime.getRuntime()
+ .exec(
+ "cmd.exe /c chcp 65001 > nul & powershell.exe -Command
\"Get-NetAdapter -IncludeHidden | Select Name | Format-List \"");
+ BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("Name :")) {
+ ifaceSet.add(line.substring("Name : ".length()).trim());
+ }
+ }
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ LOGGER.error("Failed to get interfaces, exit code: {}", exitCode);
+ }
+ } catch (IOException | InterruptedException e) {
+ LOGGER.error("Error updating interfaces", e);
+ ifaceSet = Collections.emptySet();
+ }
+ }
+
+ private void updateStatistics() {
+ try {
+ receivedBytesMapForIface.clear();
+ transmittedBytesMapForIface.clear();
+ receivedPacketsMapForIface.clear();
+ transmittedPacketsMapForIface.clear();
+ Process process =
+ Runtime.getRuntime()
+ .exec(
+ "cmd.exe /c chcp 65001 > nul & powershell.exe -Command
\"Get-NetAdapterStatistics -IncludeHidden | Format-List
Name,ReceivedBytes,SentBytes,ReceivedUnicastPackets,SentUnicastPackets \"");
+ BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8));
+ String line;
+ String currentName = null;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("Name ")) {
+ currentName = line.substring(line.indexOf(": ") + 2).trim();
+ } else if (line.startsWith("ReceivedBytes ") && currentName != null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ receivedBytesMapForIface.put(currentName, value);
+ } else if (line.startsWith("SentBytes ") && currentName != null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ transmittedBytesMapForIface.put(currentName, value);
+ } else if (line.startsWith("ReceivedUnicastPackets ") && currentName
!= null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ receivedPacketsMapForIface.put(currentName, value);
+ } else if (line.startsWith("SentUnicastPackets ") && currentName !=
null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ transmittedPacketsMapForIface.put(currentName, value);
+ currentName = null; // Reset after processing an interface
+ }
+ }
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ LOGGER.error("Failed to get statistics, exit code: {}", exitCode);
+ }
+ } catch (IOException | InterruptedException | NumberFormatException e) {
+ LOGGER.error("Error updating statistics", e);
+ }
Review Comment:
Same resource/process handling issue as in `updateInterfaces()`: the
`BufferedReader` isn't closed, stderr isn't consumed, and
`InterruptedException` is caught without restoring the interrupt flag. Over
time this can leak handles and/or hang the update if PowerShell writes to
stderr. Prefer `ProcessBuilder` + `redirectErrorStream(true)`,
try-with-resources for the reader, and `Thread.currentThread().interrupt()` on
interruption.
##########
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/net/WindowsNetMetricManager.java:
##########
@@ -19,4 +19,191 @@
package org.apache.iotdb.metrics.metricsets.net;
-public class WindowsNetMetricManager implements INetMetricManager {}
+import org.apache.iotdb.metrics.MetricConstant;
+import org.apache.iotdb.metrics.config.MetricConfig;
+import org.apache.iotdb.metrics.config.MetricConfigDescriptor;
+import org.apache.iotdb.metrics.utils.MetricLevel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class WindowsNetMetricManager implements INetMetricManager {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(WindowsNetMetricManager.class);
+
+ private static final MetricConfig METRIC_CONFIG =
+ MetricConfigDescriptor.getInstance().getMetricConfig();
+
+ private long lastUpdateTime = 0L;
+
+ private Set<String> ifaceSet = new HashSet<>();
+
+ private final Map<String, Long> receivedBytesMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedBytesMapForIface = new
HashMap<>();
+
+ private final Map<String, Long> receivedPacketsMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedPacketsMapForIface = new
HashMap<>();
+
+ private int connectionNum = 0;
+
+ public WindowsNetMetricManager() {
+ checkUpdate();
+ }
+
+ @Override
+ public Set<String> getIfaceSet() {
+ checkUpdate();
+ return ifaceSet;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedByte() {
+ checkUpdate();
+ return receivedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedBytes() {
+ checkUpdate();
+ return transmittedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedPackets() {
+ checkUpdate();
+ return receivedPacketsMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedPackets() {
+ checkUpdate();
+ return transmittedPacketsMapForIface;
+ }
+
+ @Override
+ public int getConnectionNum() {
+ checkUpdate();
+ return connectionNum;
+ }
+
+ private void checkUpdate() {
+ if (System.currentTimeMillis() - lastUpdateTime >=
MetricConstant.UPDATE_INTERVAL) {
+ updateNetStatus();
+ }
+ }
+
+ private void updateNetStatus() {
+ lastUpdateTime = System.currentTimeMillis();
+ updateInterfaces();
+ updateStatistics();
+ if (MetricLevel.higherOrEqual(MetricLevel.NORMAL,
METRIC_CONFIG.getMetricLevel())) {
+ updateConnectionNum();
+ }
+ }
+
+ private void updateInterfaces() {
+ try {
+ ifaceSet.clear();
+ Process process =
+ Runtime.getRuntime()
+ .exec(
+ "cmd.exe /c chcp 65001 > nul & powershell.exe -Command
\"Get-NetAdapter -IncludeHidden | Select Name | Format-List \"");
+ BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("Name :")) {
+ ifaceSet.add(line.substring("Name : ".length()).trim());
+ }
+ }
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ LOGGER.error("Failed to get interfaces, exit code: {}", exitCode);
+ }
+ } catch (IOException | InterruptedException e) {
+ LOGGER.error("Error updating interfaces", e);
+ ifaceSet = Collections.emptySet();
+ }
+ }
+
+ private void updateStatistics() {
+ try {
+ receivedBytesMapForIface.clear();
+ transmittedBytesMapForIface.clear();
+ receivedPacketsMapForIface.clear();
+ transmittedPacketsMapForIface.clear();
+ Process process =
+ Runtime.getRuntime()
+ .exec(
+ "cmd.exe /c chcp 65001 > nul & powershell.exe -Command
\"Get-NetAdapterStatistics -IncludeHidden | Format-List
Name,ReceivedBytes,SentBytes,ReceivedUnicastPackets,SentUnicastPackets \"");
+ BufferedReader reader =
+ new BufferedReader(
+ new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8));
+ String line;
+ String currentName = null;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (line.startsWith("Name ")) {
+ currentName = line.substring(line.indexOf(": ") + 2).trim();
+ } else if (line.startsWith("ReceivedBytes ") && currentName != null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ receivedBytesMapForIface.put(currentName, value);
+ } else if (line.startsWith("SentBytes ") && currentName != null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ transmittedBytesMapForIface.put(currentName, value);
+ } else if (line.startsWith("ReceivedUnicastPackets ") && currentName
!= null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ receivedPacketsMapForIface.put(currentName, value);
+ } else if (line.startsWith("SentUnicastPackets ") && currentName !=
null) {
+ long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
+ transmittedPacketsMapForIface.put(currentName, value);
+ currentName = null; // Reset after processing an interface
+ }
+ }
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ LOGGER.error("Failed to get statistics, exit code: {}", exitCode);
+ }
+ } catch (IOException | InterruptedException | NumberFormatException e) {
+ LOGGER.error("Error updating statistics", e);
+ }
+ }
+
+ private void updateConnectionNum() {
+ try {
+ Process process = Runtime.getRuntime().exec("netstat -ano");
+ BufferedReader reader = new BufferedReader(new
InputStreamReader(process.getInputStream()));
+ int count = 0;
+ String line;
+ while ((line = reader.readLine()) != null) {
+ line = line.trim();
+ if (!line.isEmpty() && !line.startsWith("Active") &&
!line.startsWith("Proto")) {
+ String[] parts = line.split("\\s+");
+ if (parts.length >= 5 && parts[parts.length -
1].equals(METRIC_CONFIG.getPid())) {
+ count++;
+ }
+ }
+ }
+ this.connectionNum = count;
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ LOGGER.error("Failed to get connection num, exit code: {}", exitCode);
+ }
+ } catch (IOException | InterruptedException e) {
+ LOGGER.error("Error updating connection num", e);
Review Comment:
`netstat` process output is read without try-with-resources, and stderr
isn't consumed. Also, `InterruptedException` is swallowed without restoring the
interrupt flag. Please close the reader (try-with-resources), handle stderr
(redirect or consume), and call `Thread.currentThread().interrupt()` when
interrupted to avoid resource leaks and stuck metric collection threads.
```suggestion
try (BufferedReader reader =
new BufferedReader(
new InputStreamReader(process.getInputStream(),
StandardCharsets.UTF_8));
BufferedReader errorReader =
new BufferedReader(
new InputStreamReader(process.getErrorStream(),
StandardCharsets.UTF_8))) {
String line;
String currentName = null;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.startsWith("Name ")) {
currentName = line.substring(line.indexOf(": ") + 2).trim();
} else if (line.startsWith("ReceivedBytes ") && currentName !=
null) {
long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
receivedBytesMapForIface.put(currentName, value);
} else if (line.startsWith("SentBytes ") && currentName != null) {
long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
transmittedBytesMapForIface.put(currentName, value);
} else if (line.startsWith("ReceivedUnicastPackets ") &&
currentName != null) {
long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
receivedPacketsMapForIface.put(currentName, value);
} else if (line.startsWith("SentUnicastPackets ") && currentName
!= null) {
long value = Long.parseLong(line.substring(line.indexOf(": ") +
2).trim());
transmittedPacketsMapForIface.put(currentName, value);
currentName = null; // Reset after processing an interface
}
}
// Consume and discard any error output to avoid blocking on a full
stderr buffer.
while (errorReader.readLine() != null) {
// no-op
}
}
int exitCode = process.waitFor();
if (exitCode != 0) {
LOGGER.error("Failed to get statistics, exit code: {}", exitCode);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOGGER.error("Error updating statistics", e);
} catch (IOException | NumberFormatException e) {
LOGGER.error("Error updating statistics", e);
}
}
private void updateConnectionNum() {
try {
Process process = Runtime.getRuntime().exec("netstat -ano");
try (BufferedReader reader =
new BufferedReader(new
InputStreamReader(process.getInputStream()));
BufferedReader errorReader =
new BufferedReader(new
InputStreamReader(process.getErrorStream()))) {
int count = 0;
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (!line.isEmpty() && !line.startsWith("Active") &&
!line.startsWith("Proto")) {
String[] parts = line.split("\\s+");
if (parts.length >= 5 && parts[parts.length -
1].equals(METRIC_CONFIG.getPid())) {
count++;
}
}
}
// Consume and discard any error output to avoid blocking on a full
stderr buffer.
while (errorReader.readLine() != null) {
// no-op
}
this.connectionNum = count;
}
int exitCode = process.waitFor();
if (exitCode != 0) {
LOGGER.error("Failed to get connection num, exit code: {}",
exitCode);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOGGER.error("Error updating connection num", e);
} catch (IOException e) {
LOGGER.error("Error updating connection num", e);
```
##########
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/net/WindowsNetMetricManager.java:
##########
@@ -19,4 +19,191 @@
package org.apache.iotdb.metrics.metricsets.net;
-public class WindowsNetMetricManager implements INetMetricManager {}
+import org.apache.iotdb.metrics.MetricConstant;
+import org.apache.iotdb.metrics.config.MetricConfig;
+import org.apache.iotdb.metrics.config.MetricConfigDescriptor;
+import org.apache.iotdb.metrics.utils.MetricLevel;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class WindowsNetMetricManager implements INetMetricManager {
+ private static final Logger LOGGER =
LoggerFactory.getLogger(WindowsNetMetricManager.class);
+
+ private static final MetricConfig METRIC_CONFIG =
+ MetricConfigDescriptor.getInstance().getMetricConfig();
+
+ private long lastUpdateTime = 0L;
+
+ private Set<String> ifaceSet = new HashSet<>();
+
+ private final Map<String, Long> receivedBytesMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedBytesMapForIface = new
HashMap<>();
+
+ private final Map<String, Long> receivedPacketsMapForIface = new HashMap<>();
+
+ private final Map<String, Long> transmittedPacketsMapForIface = new
HashMap<>();
+
+ private int connectionNum = 0;
+
+ public WindowsNetMetricManager() {
+ checkUpdate();
+ }
+
+ @Override
+ public Set<String> getIfaceSet() {
+ checkUpdate();
+ return ifaceSet;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedByte() {
+ checkUpdate();
+ return receivedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedBytes() {
+ checkUpdate();
+ return transmittedBytesMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getReceivedPackets() {
+ checkUpdate();
+ return receivedPacketsMapForIface;
+ }
+
+ @Override
+ public Map<String, Long> getTransmittedPackets() {
+ checkUpdate();
+ return transmittedPacketsMapForIface;
+ }
+
+ @Override
+ public int getConnectionNum() {
+ checkUpdate();
+ return connectionNum;
+ }
+
+ private void checkUpdate() {
+ if (System.currentTimeMillis() - lastUpdateTime >=
MetricConstant.UPDATE_INTERVAL) {
+ updateNetStatus();
+ }
+ }
+
+ private void updateNetStatus() {
+ lastUpdateTime = System.currentTimeMillis();
+ updateInterfaces();
+ updateStatistics();
+ if (MetricLevel.higherOrEqual(MetricLevel.NORMAL,
METRIC_CONFIG.getMetricLevel())) {
+ updateConnectionNum();
+ }
+ }
+
+ private void updateInterfaces() {
+ try {
+ ifaceSet.clear();
+ Process process =
+ Runtime.getRuntime()
+ .exec(
+ "cmd.exe /c chcp 65001 > nul & powershell.exe -Command
\"Get-NetAdapter -IncludeHidden | Select Name | Format-List \"");
Review Comment:
`NetMetrics.bindTo()` registers gauges once using the current `ifaceSet`,
and `unbindFrom()` removes gauges using `getIfaceSet()` at unbind time. Because
this implementation clears and repopulates `ifaceSet` periodically, interface
list changes can cause gauges to be leaked (not removed) and new interfaces
will never get gauges. Consider keeping `ifaceSet` stable after construction
(like `LinuxNetMetricManager`), or change the higher-level `NetMetrics` binding
logic to support dynamic interface sets.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]