Skip to content

Commit

Permalink
Merge pull request #80 from gastaldi/all_process
Browse files Browse the repository at this point in the history
Introduce Process.getAllProcess
  • Loading branch information
dmlloyd authored Mar 8, 2021
2 parents 642edeb + 7fd3616 commit 26661c1
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 14 deletions.
122 changes: 122 additions & 0 deletions os/src/main/java/io/smallrye/common/os/GetAllProcessesInfoAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package io.smallrye.common.os;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.function.Predicate;
import java.util.regex.Pattern;

final class GetAllProcessesInfoAction implements PrivilegedAction<List<ProcessInfo>> {

private final static Predicate<String> IS_NUMBER = Pattern.compile("\\d+").asPredicate();

@Override
public List<ProcessInfo> run() {
// The ProcessHandle API does not exist, so we have to rely on external processes to get this information
switch (OS.current()) {
case LINUX:
return readLinuxProcesses();
case MAC:
return readMacProcesses();
case WINDOWS:
return readWindowsProcesses();
default:
throw new UnsupportedOperationException(
"Listing all processes is not supported in JDK 8 in " + OS.current().name());
}
}

private List<ProcessInfo> readLinuxProcesses() {
List<ProcessInfo> processes = new ArrayList<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(Paths.get("/proc"))) {
for (Path procPath : stream) {
String name = procPath.getFileName().toString();
if (IS_NUMBER.test(name)) {
long pid = Long.parseLong(name);
try (BufferedReader reader = Files
.newBufferedReader(procPath.resolve("cmdline"), StandardCharsets.UTF_8)) {
String line = reader.readLine();
if (line != null) {
int idx = line.indexOf(0);
String cmdLine = idx == -1 ? line : line.substring(0, idx);
processes.add(new ProcessInfo(pid, cmdLine));
}
} catch (IOException ignored) {
// ignore case where process exits right before we read cmdline
}
}
}
} catch (IOException ignored) {
// ignore
}
return processes;
}

private List<ProcessInfo> readMacProcesses() {
List<ProcessInfo> processes = new ArrayList<>();
java.lang.Process process = null;
try {
ProcessBuilder processBuilder = new ProcessBuilder("ps", "-ax", "-o", "pid=,comm=");
String thisCmd = String.join(" ", processBuilder.command());
process = processBuilder.start();
try (Scanner scanner = new Scanner(process.getInputStream())) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
int separator = line.indexOf(" ");
String cmd = line.substring(separator + 1);
if (!thisCmd.equals(cmd)) {
long pid = Long.parseLong(line.substring(0, separator));
processes.add(new ProcessInfo(pid, cmd));
}
}
}
} catch (IOException e) {
// ignored
} finally {
if (process != null) {
process.destroy();
}
}
return processes;
}

private List<ProcessInfo> readWindowsProcesses() {
List<ProcessInfo> processes = new ArrayList<>();
java.lang.Process process = null;
try {
ProcessBuilder processBuilder = new ProcessBuilder("tasklist.exe", "/fo", "csv", "/nh");
String thisCmd = String.join(" ", processBuilder.command());
process = processBuilder.start();
try (Scanner sc = new Scanner(process.getInputStream())) {
// Skip first line
if (sc.hasNextLine()) {
sc.nextLine();
}
while (sc.hasNextLine()) {
String line = sc.nextLine().trim();
String[] parts = line.split(",");
String cmdLine = parts[0].substring(1).replaceFirst(".$", "");
if (!thisCmd.equals(cmdLine)) {
long pid = Long.parseLong(parts[1].substring(1).replaceFirst(".$", ""));
processes.add(new ProcessInfo(pid, cmdLine));
}
}
}
} catch (IOException e) {
// ignored
} finally {
if (process != null) {
process.destroy();
}
}
return processes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,19 @@

/**
*/
final class GetProcessInfoAction implements PrivilegedAction<Object[]> {
final class GetProcessInfoAction implements PrivilegedAction<ProcessInfo> {
GetProcessInfoAction() {
}

public Object[] run() {
@Override
public ProcessInfo run() {
long pid = -1L;
String processName = "<unknown>";
final RuntimeMXBean runtime;
try {
runtime = ManagementFactory.getPlatformMXBean(RuntimeMXBean.class);
} catch (Exception ignored) {
return new Object[] { pid, processName };
return new ProcessInfo(pid, processName);
}
// TODO: on Java 9, use ProcessHandle.current().pid()
// Process ID
Expand Down Expand Up @@ -101,6 +102,6 @@ public Object[] run() {
if (processName == null) {
processName = "<unknown>";
}
return new Object[] { pid, processName };
return new ProcessInfo(pid, processName);
}
}
32 changes: 25 additions & 7 deletions os/src/main/java/io/smallrye/common/os/Process.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,18 @@

import static java.security.AccessController.doPrivileged;

import java.util.List;

/**
* Utilities for getting information about the current process.
*
* @author <a href="mailto:[email protected]">David M. Lloyd</a>
*/
public final class Process {
private static final long processId;
private static final String processName;
private static final ProcessInfo currentProcess;

static {
Object[] array = doPrivileged(new GetProcessInfoAction());
processId = (Long) array[0];
processName = (String) array[1];
currentProcess = doPrivileged(new GetProcessInfoAction());
}

private Process() {
Expand All @@ -44,7 +43,7 @@ private Process() {
* @return the process name (not {@code null})
*/
public static String getProcessName() {
return processName;
return currentProcess.getCommand();
}

/**
Expand All @@ -54,6 +53,25 @@ public static String getProcessName() {
* @return the ID of this process, or -1 if it cannot be determined
*/
public static long getProcessId() {
return processId;
return currentProcess.getId();
}

/**
* Returns information about the current process
*
* @return the current process
*/
public static ProcessInfo getCurrentProcess() {
return currentProcess;
}

/**
* Returns all the running processes.
*
* @return a list of all the running processes. May throw an exception if running on an unsupported JDK
* @throws UnsupportedOperationException if running on JDK 8
*/
public static List<ProcessInfo> getAllProcesses() {
return doPrivileged(new GetAllProcessesInfoAction());
}
}
22 changes: 22 additions & 0 deletions os/src/main/java/io/smallrye/common/os/ProcessInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.smallrye.common.os;

/**
* Returns information about a Process
*/
public class ProcessInfo {
private final long id;
private final String command;

public ProcessInfo(long id, String command) {
this.id = id;
this.command = command;
}

public long getId() {
return id;
}

public String getCommand() {
return command;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.smallrye.common.os;

import java.security.PrivilegedAction;
import java.util.List;
import java.util.stream.Collectors;

final class GetAllProcessesInfoAction implements PrivilegedAction<List<ProcessInfo>> {

@Override
public List<ProcessInfo> run() {
return ProcessHandle.allProcesses()
.map(processHandle -> new ProcessInfo(processHandle.pid(), processHandle.info().command().orElse(null)))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@

/**
*/
final class GetProcessInfoAction implements PrivilegedAction<Object[]> {
final class GetProcessInfoAction implements PrivilegedAction<ProcessInfo> {
GetProcessInfoAction() {
}

public Object[] run() {
public ProcessInfo run() {
final ProcessHandle processHandle = ProcessHandle.current();
final long pid = processHandle.pid();
String processName = System.getProperty("jboss.process.name");
Expand Down Expand Up @@ -82,6 +82,6 @@ public Object[] run() {
if (processName == null) {
processName = "<unknown>";
}
return new Object[] { pid, processName };
return new ProcessInfo(pid, processName);
}
}
7 changes: 7 additions & 0 deletions os/src/test/java/io/smallrye/common/os/ProcessTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.smallrye.common.os;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

Expand All @@ -11,6 +12,12 @@ class ProcessTest {
public void testProcessInfo() {
assertNotEquals(0L, Process.getProcessId());
assertNotNull(Process.getProcessName());
assertNotNull(Process.getCurrentProcess());
}

@Test
public void testAllProcessInfo() {
assertFalse(Process.getAllProcesses().isEmpty());
}

}

0 comments on commit 26661c1

Please sign in to comment.