org.neo4j.kernel.diagnostics.providers.SystemDiagnostics Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-kernel Show documentation
Show all versions of neo4j-kernel Show documentation
Neo4j kernel is a lightweight, embedded Java database designed to
store data structured as graphs rather than tables. For more
information, see http://neo4j.org.
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.kernel.diagnostics.providers;
import static java.lang.String.format;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static org.neo4j.io.ByteUnit.bytesToString;
import java.io.File;
import java.io.UncheckedIOException;
import java.lang.management.CompilationMXBean;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.ByteOrder;
import java.nio.file.Path;
import java.time.ZoneId;
import java.time.zone.ZoneRulesProvider;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.neo4j.internal.diagnostics.DiagnosticsLogger;
import org.neo4j.internal.diagnostics.DiagnosticsProvider;
import org.neo4j.internal.nativeimpl.NativeAccess;
import org.neo4j.internal.nativeimpl.NativeAccessProvider;
import org.neo4j.internal.unsafe.UnsafeUtil;
import org.neo4j.io.fs.FileUtils;
import org.neo4j.io.os.OsBeanUtil;
import org.neo4j.util.VisibleForTesting;
public enum SystemDiagnostics implements DiagnosticsProvider {
SYSTEM_MEMORY("System memory information") {
@Override
public void dump(DiagnosticsLogger logger) {
logBytes(logger, "Total Physical memory: ", OsBeanUtil.getTotalPhysicalMemory());
logBytes(logger, "Free Physical memory: ", OsBeanUtil.getFreePhysicalMemory());
logBytes(logger, "Committed virtual memory: ", OsBeanUtil.getCommittedVirtualMemory());
logBytes(logger, "Total swap space: ", OsBeanUtil.getTotalSwapSpace());
logBytes(logger, "Free swap space: ", OsBeanUtil.getFreeSwapSpace());
}
},
JAVA_MEMORY("JVM memory information") {
@Override
public void dump(DiagnosticsLogger logger) {
logger.log("Free memory: " + bytesToString(Runtime.getRuntime().freeMemory()));
logger.log("Total memory: " + bytesToString(Runtime.getRuntime().totalMemory()));
logger.log("Max memory: " + bytesToString(Runtime.getRuntime().maxMemory()));
for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
logger.log("Garbage Collector: " + gc.getName() + ": " + Arrays.toString(gc.getMemoryPoolNames()));
}
for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
MemoryUsage usage = pool.getUsage();
logger.log(format(
"Memory Pool: %s (%s): committed=%s, used=%s, max=%s, threshold=%s",
pool.getName(),
pool.getType(),
usage == null ? "?" : bytesToString(usage.getCommitted()),
usage == null ? "?" : bytesToString(usage.getUsed()),
usage == null ? "?" : bytesToString(usage.getMax()),
pool.isUsageThresholdSupported() ? bytesToString(pool.getUsageThreshold()) : "?"));
}
}
},
OPERATING_SYSTEM("Operating system information") {
@Override
public void dump(DiagnosticsLogger logger) {
OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
logger.log(format(
"Operating System: %s; version: %s; arch: %s; cpus: %s",
os.getName(), os.getVersion(), os.getArch(), os.getAvailableProcessors()));
logLong(logger, "Max number of file descriptors: ", OsBeanUtil.getMaxFileDescriptors());
logLong(logger, "Number of open file descriptors: ", OsBeanUtil.getOpenFileDescriptors());
logger.log("Process id: " + ProcessHandle.current().pid());
logger.log("Byte order: " + ByteOrder.nativeOrder());
logger.log("Local timezone: " + getLocalTimeZone());
logger.log("Memory page size: " + UnsafeUtil.pageSize());
logger.log("Unaligned memory access allowed: " + UnsafeUtil.allowUnalignedMemoryAccess);
}
private String getLocalTimeZone() {
return ZoneId.systemDefault().getId();
}
},
JAVA_VIRTUAL_MACHINE("JVM information") {
@Override
public void dump(DiagnosticsLogger logger) {
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
logger.log("VM Name: " + runtime.getVmName());
logger.log("VM Vendor: " + runtime.getVmVendor());
logger.log("VM Version: " + runtime.getVmVersion());
CompilationMXBean compiler = ManagementFactory.getCompilationMXBean();
logger.log("JIT compiler: " + ((compiler == null) ? "unknown" : compiler.getName()));
logger.log("VM Arguments: " + runtime.getInputArguments());
}
},
CLASSPATH("Java classpath") {
@Override
public void dump(DiagnosticsLogger logger) {
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
Collection classpath;
if (runtime.isBootClassPathSupported()) {
classpath = buildClassPath(
getClass().getClassLoader(),
Map.of("bootstrap", runtime.getBootClassPath(), "classpath", runtime.getClassPath()));
} else {
classpath = buildClassPath(getClass().getClassLoader(), Map.of("classpath", runtime.getClassPath()));
}
for (String path : classpath) {
logger.log(path);
}
}
private Collection buildClassPath(ClassLoader loader, Map classPaths) {
Map paths = new HashMap<>();
Set> entries = classPaths.entrySet();
for (Entry classPathEntry : entries) {
String classPathType = classPathEntry.getKey();
String[] splittedClassPath = classPathEntry.getValue().split(File.pathSeparator);
for (String entry : splittedClassPath) {
String canonicalEntry = canonicalize(entry);
paths.merge(canonicalEntry, classPathType, (k, v) -> v + " + " + classPathType);
}
}
for (int level = 0; loader != null; level++) {
if (loader instanceof URLClassLoader urls) {
URL[] classLoaderUrls = urls.getURLs();
if (classLoaderUrls != null) {
for (URL url : classLoaderUrls) {
if ("file".equalsIgnoreCase(url.getProtocol())) {
String type = "loader." + level;
paths.merge(url.toString(), type, (k, v) -> k + " + " + type);
}
}
} else {
paths.put(loader.toString(), "");
}
}
loader = loader.getParent();
}
List result = new ArrayList<>(paths.size());
for (Entry path : paths.entrySet()) {
result.add(" [" + path.getValue() + "] " + path.getKey());
}
return result;
}
},
LIBRARY_PATH("Library path") {
@Override
public void dump(DiagnosticsLogger logger) {
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
for (String path : runtime.getLibraryPath().split(File.pathSeparator)) {
logger.log(canonicalize(path));
}
}
},
SYSTEM_PROPERTIES("System properties") {
@Override
public void dump(DiagnosticsLogger logger) {
for (Object property : System.getProperties().keySet()) {
if (property instanceof String key) {
if (key.startsWith("java.")
|| key.startsWith("os.")
|| key.endsWith(".boot.class.path")
|| key.equals("line.separator")) {
continue;
}
logger.log(key + " = " + System.getProperty(key));
}
}
}
},
TIMEZONE_DATABASE("(IANA) TimeZone database version") {
@Override
public void dump(DiagnosticsLogger logger) {
Map versions = new HashMap<>();
for (String tz : ZoneRulesProvider.getAvailableZoneIds()) {
for (String version : ZoneRulesProvider.getVersions(tz).keySet()) {
versions.compute(version, (key, value) -> value == null ? 1 : (value + 1));
}
}
String[] sorted = versions.keySet().toArray(new String[0]);
Arrays.sort(sorted);
for (String tz : sorted) {
logger.log(format(" TimeZone version: %s (available for %d zone identifiers)", tz, versions.get(tz)));
}
}
},
NETWORK("Network information") {
@Override
public void dump(DiagnosticsLogger logger) {
try {
Enumeration networkInterfaces = getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface iface = networkInterfaces.nextElement();
logger.log(format("Interface %s:", iface.getDisplayName()));
Enumeration addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
String hostAddress = address.getHostAddress();
logger.log(format(" address: %s", hostAddress));
}
}
} catch (SocketException e) {
logger.log("ERROR: failed to inspect network interfaces and addresses: " + e.getMessage());
}
}
},
NATIVE_ACCESSOR("Native access information") {
@Override
public void dump(DiagnosticsLogger logger) {
NativeAccess nativeAccess = NativeAccessProvider.getNativeAccess();
logger.log("Native access details: " + nativeAccess.describe());
}
};
private final String name;
SystemDiagnostics(String name) {
this.name = name;
}
@Override
public String getDiagnosticsName() {
return name;
}
@VisibleForTesting
static String canonicalize(String path) {
try {
boolean hasWildcard = path.endsWith("*");
if (hasWildcard) {
path = path.substring(0, path.length() - 1);
}
String result =
FileUtils.getCanonicalFile(Path.of(path)).toAbsolutePath().toString();
if (hasWildcard) {
result += File.separator + "*";
}
return result;
} catch (UncheckedIOException e) {
return Path.of(path).toAbsolutePath().toString();
}
}
private static void logBytes(DiagnosticsLogger logger, String message, long value) {
if (value != OsBeanUtil.VALUE_UNAVAILABLE) {
logger.log(message + bytesToString(value));
}
}
private static void logLong(DiagnosticsLogger logger, String message, long value) {
if (value != OsBeanUtil.VALUE_UNAVAILABLE) {
logger.log(message + value);
}
}
}