diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java index 7a512fd75ea8f..d19f341f8323a 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java @@ -430,11 +430,11 @@ public void addNodeStats(NodeStats nodeStats) { return; } count++; - if (nodeStats.getProcess().cpu() != null) { + if (nodeStats.getProcess().getCpu() != null) { // with no sigar, this may not be available - cpuPercent += nodeStats.getProcess().cpu().getPercent(); + cpuPercent += nodeStats.getProcess().getCpu().getPercent(); } - long fd = nodeStats.getProcess().openFileDescriptors(); + long fd = nodeStats.getProcess().getOpenFileDescriptors(); if (fd > 0) { // fd can be -1 if not supported on platform totalOpenFileDescriptors += fd; diff --git a/core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java b/core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java index 006d55edaeeb0..d084e6315e8ae 100644 --- a/core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java +++ b/core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java @@ -40,7 +40,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.monitor.jvm.JvmInfo; -import org.elasticsearch.monitor.process.JmxProcessProbe; +import org.elasticsearch.monitor.process.ProcessProbe; import org.elasticsearch.node.Node; import org.elasticsearch.node.NodeBuilder; import org.elasticsearch.node.internal.InternalSettingsPreparer; @@ -143,14 +143,22 @@ public boolean handle(int code) { StringHelper.randomId(); } + static void initializeProbes() { + // Force probes to be loaded + ProcessProbe.getInstance(); + } + public static boolean isMemoryLocked() { return Natives.isMemoryLocked(); } private void setup(boolean addShutdownHook, Settings settings, Environment environment) throws Exception { - initializeNatives(settings.getAsBoolean("bootstrap.mlockall", false), + initializeNatives(settings.getAsBoolean("bootstrap.mlockall", false), settings.getAsBoolean("bootstrap.ctrlhandler", true)); + // initialize probes before the security manager is installed + initializeProbes(); + if (addShutdownHook) { Runtime.getRuntime().addShutdownHook(new Thread() { @Override @@ -167,7 +175,7 @@ public void run() { // look for jar hell JarHell.checkJarHell(); - + // install SM after natives, shutdown hooks, etc. setupSecurity(settings, environment); @@ -262,7 +270,7 @@ public static void main(String[] args) { if (System.getProperty("es.max-open-files", "false").equals("true")) { ESLogger logger = Loggers.getLogger(Bootstrap.class); - logger.info("max_open_files [{}]", JmxProcessProbe.getMaxFileDescriptorCount()); + logger.info("max_open_files [{}]", ProcessProbe.getInstance().getMaxFileDescriptorCount()); } // warn if running using the client VM diff --git a/core/src/main/java/org/elasticsearch/monitor/MonitorModule.java b/core/src/main/java/org/elasticsearch/monitor/MonitorModule.java index db876d9189325..2b08460210fc7 100644 --- a/core/src/main/java/org/elasticsearch/monitor/MonitorModule.java +++ b/core/src/main/java/org/elasticsearch/monitor/MonitorModule.java @@ -28,7 +28,6 @@ import org.elasticsearch.monitor.os.JmxOsProbe; import org.elasticsearch.monitor.os.OsProbe; import org.elasticsearch.monitor.os.OsService; -import org.elasticsearch.monitor.process.JmxProcessProbe; import org.elasticsearch.monitor.process.ProcessProbe; import org.elasticsearch.monitor.process.ProcessService; @@ -50,7 +49,7 @@ public MonitorModule(Settings settings) { @Override protected void configure() { // bind default implementations - bind(ProcessProbe.class).to(JmxProcessProbe.class).asEagerSingleton(); + bind(ProcessProbe.class).toInstance(ProcessProbe.getInstance()); bind(OsProbe.class).to(JmxOsProbe.class).asEagerSingleton(); bind(FsProbe.class).asEagerSingleton(); diff --git a/core/src/main/java/org/elasticsearch/monitor/process/JmxProcessProbe.java b/core/src/main/java/org/elasticsearch/monitor/process/JmxProcessProbe.java deleted file mode 100644 index f91d7823938d5..0000000000000 --- a/core/src/main/java/org/elasticsearch/monitor/process/JmxProcessProbe.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.elasticsearch.monitor.process; - -import org.elasticsearch.common.component.AbstractComponent; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.settings.Settings; - -import java.lang.management.ManagementFactory; -import java.lang.management.OperatingSystemMXBean; -import java.lang.reflect.Method; - -import static org.elasticsearch.monitor.jvm.JvmInfo.jvmInfo; - -/** - * - */ -public class JmxProcessProbe extends AbstractComponent implements ProcessProbe { - - private static final OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean(); - - private static final Method getMaxFileDescriptorCountField; - private static final Method getOpenFileDescriptorCountField; - - static { - Method method = null; - try { - method = osMxBean.getClass().getDeclaredMethod("getMaxFileDescriptorCount"); - method.setAccessible(true); - } catch (Exception e) { - // not available - } - getMaxFileDescriptorCountField = method; - - method = null; - try { - method = osMxBean.getClass().getDeclaredMethod("getOpenFileDescriptorCount"); - method.setAccessible(true); - } catch (Exception e) { - // not available - } - getOpenFileDescriptorCountField = method; - } - - public static long getMaxFileDescriptorCount() { - if (getMaxFileDescriptorCountField == null) { - return -1; - } - try { - return (Long) getMaxFileDescriptorCountField.invoke(osMxBean); - } catch (Exception e) { - return -1; - } - } - - public static long getOpenFileDescriptorCount() { - if (getOpenFileDescriptorCountField == null) { - return -1; - } - try { - return (Long) getOpenFileDescriptorCountField.invoke(osMxBean); - } catch (Exception e) { - return -1; - } - } - - @Inject - public JmxProcessProbe(Settings settings) { - super(settings); - } - - @Override - public ProcessInfo processInfo() { - return new ProcessInfo(jvmInfo().pid(), getMaxFileDescriptorCount()); - } - - @Override - public ProcessStats processStats() { - ProcessStats stats = new ProcessStats(); - stats.timestamp = System.currentTimeMillis(); - stats.openFileDescriptors = getOpenFileDescriptorCount(); - return stats; - } -} diff --git a/core/src/main/java/org/elasticsearch/monitor/process/ProcessInfo.java b/core/src/main/java/org/elasticsearch/monitor/process/ProcessInfo.java index 8fd16d528fb13..7d1ea03b085fd 100644 --- a/core/src/main/java/org/elasticsearch/monitor/process/ProcessInfo.java +++ b/core/src/main/java/org/elasticsearch/monitor/process/ProcessInfo.java @@ -19,7 +19,6 @@ package org.elasticsearch.monitor.process; -import org.elasticsearch.bootstrap.Bootstrap; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Streamable; @@ -29,27 +28,20 @@ import java.io.IOException; -/** - * - */ public class ProcessInfo implements Streamable, ToXContent { long refreshInterval; private long id; - private long maxFileDescriptors = -1; - private boolean mlockall; ProcessInfo() { - } - public ProcessInfo(long id, long maxFileDescriptors) { + public ProcessInfo(long id, boolean mlockall) { this.id = id; - this.maxFileDescriptors = maxFileDescriptors; - this.mlockall = Bootstrap.isMemoryLocked(); + this.mlockall = mlockall; } public long refreshInterval() { @@ -60,30 +52,11 @@ public long getRefreshInterval() { return this.refreshInterval; } - /** - * The process id. - */ - public long id() { - return this.id; - } - /** * The process id. */ public long getId() { - return id(); - } - - public long maxFileDescriptors() { - return this.maxFileDescriptors; - } - - public long getMaxFileDescriptors() { - return maxFileDescriptors; - } - - public boolean mlockAll() { - return mlockall; + return id; } public boolean isMlockall() { @@ -95,7 +68,6 @@ static final class Fields { static final XContentBuilderString REFRESH_INTERVAL = new XContentBuilderString("refresh_interval"); static final XContentBuilderString REFRESH_INTERVAL_IN_MILLIS = new XContentBuilderString("refresh_interval_in_millis"); static final XContentBuilderString ID = new XContentBuilderString("id"); - static final XContentBuilderString MAX_FILE_DESCRIPTORS = new XContentBuilderString("max_file_descriptors"); static final XContentBuilderString MLOCKALL = new XContentBuilderString("mlockall"); } @@ -104,7 +76,6 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.startObject(Fields.PROCESS); builder.timeValueField(Fields.REFRESH_INTERVAL_IN_MILLIS, Fields.REFRESH_INTERVAL, refreshInterval); builder.field(Fields.ID, id); - builder.field(Fields.MAX_FILE_DESCRIPTORS, maxFileDescriptors); builder.field(Fields.MLOCKALL, mlockall); builder.endObject(); return builder; @@ -120,7 +91,6 @@ public static ProcessInfo readProcessInfo(StreamInput in) throws IOException { public void readFrom(StreamInput in) throws IOException { refreshInterval = in.readLong(); id = in.readLong(); - maxFileDescriptors = in.readLong(); mlockall = in.readBoolean(); } @@ -128,7 +98,6 @@ public void readFrom(StreamInput in) throws IOException { public void writeTo(StreamOutput out) throws IOException { out.writeLong(refreshInterval); out.writeLong(id); - out.writeLong(maxFileDescriptors); out.writeBoolean(mlockall); } } diff --git a/core/src/main/java/org/elasticsearch/monitor/process/ProcessProbe.java b/core/src/main/java/org/elasticsearch/monitor/process/ProcessProbe.java index 89d56ed8131fd..b1d1c7f67970c 100644 --- a/core/src/main/java/org/elasticsearch/monitor/process/ProcessProbe.java +++ b/core/src/main/java/org/elasticsearch/monitor/process/ProcessProbe.java @@ -19,12 +19,156 @@ package org.elasticsearch.monitor.process; -/** - * - */ -public interface ProcessProbe { +import org.elasticsearch.bootstrap.Bootstrap; + +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; +import java.lang.reflect.Method; + +import static org.elasticsearch.monitor.jvm.JvmInfo.jvmInfo; + +public class ProcessProbe { + + private static final OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean(); + + private static final Method getMaxFileDescriptorCountField; + private static final Method getOpenFileDescriptorCountField; + private static final Method getProcessCpuLoad; + private static final Method getProcessCpuTime; + private static final Method getCommittedVirtualMemorySize; + + static { + getMaxFileDescriptorCountField = getMethod("getMaxFileDescriptorCount"); + getOpenFileDescriptorCountField = getMethod("getOpenFileDescriptorCount"); + getProcessCpuLoad = getMethod("getProcessCpuLoad"); + getProcessCpuTime = getMethod("getProcessCpuTime"); + getCommittedVirtualMemorySize = getMethod("getCommittedVirtualMemorySize"); + } + + private static class ProcessProbeHolder { + private final static ProcessProbe INSTANCE = new ProcessProbe(); + } + + public static ProcessProbe getInstance() { + return ProcessProbeHolder.INSTANCE; + } + + private ProcessProbe() { + } + + /** + * Returns the maximum number of file descriptors allowed on the system, or -1 if not supported. + */ + public long getMaxFileDescriptorCount() { + if (getMaxFileDescriptorCountField == null) { + return -1; + } + try { + return (Long) getMaxFileDescriptorCountField.invoke(osMxBean); + } catch (Throwable t) { + return -1; + } + } + + /** + * Returns the number of opened file descriptors associated with the current process, or -1 if not supported. + */ + public long getOpenFileDescriptorCount() { + if (getOpenFileDescriptorCountField == null) { + return -1; + } + try { + return (Long) getOpenFileDescriptorCountField.invoke(osMxBean); + } catch (Throwable t) { + return -1; + } + } + + /** + * Returns the process CPU usage in percent + */ + public short getProcessCpuPercent() { + if (getProcessCpuLoad != null) { + try { + double load = (double) getProcessCpuLoad.invoke(osMxBean); + if (load >= 0) { + return (short) (load * 100); + } + } catch (Throwable t) { + return -1; + } + } + return -1; + } + + /** + * Returns the CPU time (in milliseconds) used by the process on which the Java virtual machine is running, or -1 if not supported. + */ + public long getProcessCpuTotalTime() { + if (getProcessCpuTime != null) { + try { + long time = (long) getProcessCpuTime.invoke(osMxBean); + if (time >= 0) { + return (time / 1_000_000L); + } + } catch (Throwable t) { + return -1; + } + } + return -1; + } + + /** + * Returns the size (in bytes) of virtual memory that is guaranteed to be available to the running process + */ + public long getTotalVirtualMemorySize() { + if (getCommittedVirtualMemorySize != null) { + try { + long virtual = (long) getCommittedVirtualMemorySize.invoke(osMxBean); + if (virtual >= 0) { + return virtual; + } + } catch (Throwable t) { + return -1; + } + } + return -1; + } + + public ProcessInfo processInfo() { + return new ProcessInfo(jvmInfo().pid(), Bootstrap.isMemoryLocked()); + } + + public ProcessStats processStats() { + ProcessStats stats = new ProcessStats(); + stats.timestamp = System.currentTimeMillis(); + stats.openFileDescriptors = getOpenFileDescriptorCount(); + stats.maxFileDescriptors = getMaxFileDescriptorCount(); + + ProcessStats.Cpu cpu = new ProcessStats.Cpu(); + cpu.percent = getProcessCpuPercent(); + cpu.total = getProcessCpuTotalTime(); + stats.cpu = cpu; + + ProcessStats.Mem mem = new ProcessStats.Mem(); + mem.totalVirtual = getTotalVirtualMemorySize(); + stats.mem = mem; - ProcessInfo processInfo(); + return stats; + } - ProcessStats processStats(); + /** + * Returns a given method of the OperatingSystemMXBean, + * or null if the method is not found or unavailable. + */ + private static Method getMethod(String methodName) { + try { + Method method = osMxBean.getClass().getDeclaredMethod(methodName); + method.setAccessible(true); + return method; + } catch (Throwable t) { + // not available + } + return null; + } } diff --git a/core/src/main/java/org/elasticsearch/monitor/process/ProcessStats.java b/core/src/main/java/org/elasticsearch/monitor/process/ProcessStats.java index 9777864a89ae2..44ef7c7a81602 100644 --- a/core/src/main/java/org/elasticsearch/monitor/process/ProcessStats.java +++ b/core/src/main/java/org/elasticsearch/monitor/process/ProcessStats.java @@ -30,14 +30,12 @@ import java.io.IOException; -/** - * - */ public class ProcessStats implements Streamable, ToXContent { long timestamp = -1; - long openFileDescriptors; + long openFileDescriptors = -1; + long maxFileDescriptors = -1; Cpu cpu = null; @@ -46,57 +44,38 @@ public class ProcessStats implements Streamable, ToXContent { ProcessStats() { } - public long timestamp() { - return this.timestamp; - } - public long getTimestamp() { - return timestamp(); - } - - public long openFileDescriptors() { - return this.openFileDescriptors; + return timestamp; } public long getOpenFileDescriptors() { return openFileDescriptors; } - public Cpu cpu() { - return cpu; + public long getMaxFileDescriptors() { + return maxFileDescriptors; } public Cpu getCpu() { - return cpu(); - } - - public Mem mem() { - return mem; + return cpu; } public Mem getMem() { - return mem(); + return mem; } static final class Fields { static final XContentBuilderString PROCESS = new XContentBuilderString("process"); static final XContentBuilderString TIMESTAMP = new XContentBuilderString("timestamp"); static final XContentBuilderString OPEN_FILE_DESCRIPTORS = new XContentBuilderString("open_file_descriptors"); + static final XContentBuilderString MAX_FILE_DESCRIPTORS = new XContentBuilderString("max_file_descriptors"); static final XContentBuilderString CPU = new XContentBuilderString("cpu"); static final XContentBuilderString PERCENT = new XContentBuilderString("percent"); - static final XContentBuilderString SYS = new XContentBuilderString("sys"); - static final XContentBuilderString SYS_IN_MILLIS = new XContentBuilderString("sys_in_millis"); - static final XContentBuilderString USER = new XContentBuilderString("user"); - static final XContentBuilderString USER_IN_MILLIS = new XContentBuilderString("user_in_millis"); static final XContentBuilderString TOTAL = new XContentBuilderString("total"); static final XContentBuilderString TOTAL_IN_MILLIS = new XContentBuilderString("total_in_millis"); static final XContentBuilderString MEM = new XContentBuilderString("mem"); - static final XContentBuilderString RESIDENT = new XContentBuilderString("resident"); - static final XContentBuilderString RESIDENT_IN_BYTES = new XContentBuilderString("resident_in_bytes"); - static final XContentBuilderString SHARE = new XContentBuilderString("share"); - static final XContentBuilderString SHARE_IN_BYTES = new XContentBuilderString("share_in_bytes"); static final XContentBuilderString TOTAL_VIRTUAL = new XContentBuilderString("total_virtual"); static final XContentBuilderString TOTAL_VIRTUAL_IN_BYTES = new XContentBuilderString("total_virtual_in_bytes"); } @@ -106,18 +85,15 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.startObject(Fields.PROCESS); builder.field(Fields.TIMESTAMP, timestamp); builder.field(Fields.OPEN_FILE_DESCRIPTORS, openFileDescriptors); + builder.field(Fields.MAX_FILE_DESCRIPTORS, maxFileDescriptors); if (cpu != null) { builder.startObject(Fields.CPU); - builder.field(Fields.PERCENT, cpu.percent()); - builder.timeValueField(Fields.SYS_IN_MILLIS, Fields.SYS, cpu.sys); - builder.timeValueField(Fields.USER_IN_MILLIS, Fields.USER, cpu.user); + builder.field(Fields.PERCENT, cpu.percent); builder.timeValueField(Fields.TOTAL_IN_MILLIS, Fields.TOTAL, cpu.total); builder.endObject(); } if (mem != null) { builder.startObject(Fields.MEM); - builder.byteSizeField(Fields.RESIDENT_IN_BYTES, Fields.RESIDENT, mem.resident); - builder.byteSizeField(Fields.SHARE_IN_BYTES, Fields.SHARE, mem.share); builder.byteSizeField(Fields.TOTAL_VIRTUAL_IN_BYTES, Fields.TOTAL_VIRTUAL, mem.totalVirtual); builder.endObject(); } @@ -135,6 +111,7 @@ public static ProcessStats readProcessStats(StreamInput in) throws IOException { public void readFrom(StreamInput in) throws IOException { timestamp = in.readVLong(); openFileDescriptors = in.readLong(); + maxFileDescriptors = in.readLong(); if (in.readBoolean()) { cpu = Cpu.readCpu(in); } @@ -147,6 +124,7 @@ public void readFrom(StreamInput in) throws IOException { public void writeTo(StreamOutput out) throws IOException { out.writeVLong(timestamp); out.writeLong(openFileDescriptors); + out.writeLong(maxFileDescriptors); if (cpu == null) { out.writeBoolean(false); } else { @@ -164,8 +142,6 @@ public void writeTo(StreamOutput out) throws IOException { public static class Mem implements Streamable { long totalVirtual = -1; - long resident = -1; - long share = -1; Mem() { } @@ -179,47 +155,21 @@ public static Mem readMem(StreamInput in) throws IOException { @Override public void readFrom(StreamInput in) throws IOException { totalVirtual = in.readLong(); - resident = in.readLong(); - share = in.readLong(); } @Override public void writeTo(StreamOutput out) throws IOException { out.writeLong(totalVirtual); - out.writeLong(resident); - out.writeLong(share); - } - - public ByteSizeValue totalVirtual() { - return new ByteSizeValue(totalVirtual); } public ByteSizeValue getTotalVirtual() { - return totalVirtual(); - } - - public ByteSizeValue resident() { - return new ByteSizeValue(resident); - } - - public ByteSizeValue getResident() { - return resident(); - } - - public ByteSizeValue share() { - return new ByteSizeValue(share); - } - - public ByteSizeValue getShare() { - return share(); + return new ByteSizeValue(totalVirtual); } } public static class Cpu implements Streamable { short percent = -1; - long sys = -1; - long user = -1; long total = -1; Cpu() { @@ -235,90 +185,31 @@ public static Cpu readCpu(StreamInput in) throws IOException { @Override public void readFrom(StreamInput in) throws IOException { percent = in.readShort(); - sys = in.readLong(); - user = in.readLong(); total = in.readLong(); } @Override public void writeTo(StreamOutput out) throws IOException { out.writeShort(percent); - out.writeLong(sys); - out.writeLong(user); out.writeLong(total); } /** * Get the Process cpu usage. - *

- *

Supported Platforms: All. - */ - public short percent() { - return percent; - } - - /** - * Get the Process cpu usage. - *

+ *

*

Supported Platforms: All. */ public short getPercent() { - return percent(); - } - - /** - * Get the Process cpu kernel time. - *

- *

Supported Platforms: All. - */ - public TimeValue sys() { - return new TimeValue(sys); - } - - /** - * Get the Process cpu kernel time. - *

- *

Supported Platforms: All. - */ - public TimeValue getSys() { - return sys(); - } - - /** - * Get the Process cpu user time. - *

- *

Supported Platforms: All. - */ - public TimeValue user() { - return new TimeValue(user); - } - - /** - * Get the Process cpu time (sum of User and Sys). - *

- * Supported Platforms: All. - */ - public TimeValue total() { - return new TimeValue(total); + return percent; } /** * Get the Process cpu time (sum of User and Sys). - *

+ *

* Supported Platforms: All. */ public TimeValue getTotal() { - return total(); - } - - /** - * Get the Process cpu user time. - *

- *

Supported Platforms: All. - */ - public TimeValue getUser() { - return user(); + return new TimeValue(total); } - } } diff --git a/core/src/main/java/org/elasticsearch/rest/action/cat/RestNodesAction.java b/core/src/main/java/org/elasticsearch/rest/action/cat/RestNodesAction.java index 87fc5378fd14c..2e2e09c8e30dc 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/cat/RestNodesAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/cat/RestNodesAction.java @@ -53,7 +53,6 @@ import org.elasticsearch.monitor.jvm.JvmStats; import org.elasticsearch.monitor.os.OsInfo; import org.elasticsearch.monitor.os.OsStats; -import org.elasticsearch.monitor.process.ProcessInfo; import org.elasticsearch.monitor.process.ProcessStats; import org.elasticsearch.rest.*; import org.elasticsearch.rest.action.support.RestActionListener; @@ -221,7 +220,6 @@ private Table buildTable(RestRequest req, ClusterStateResponse state, NodesInfoR JvmInfo jvmInfo = info == null ? null : info.getJvm(); OsInfo osInfo = info == null ? null : info.getOs(); - ProcessInfo processInfo = info == null ? null : info.getProcess(); JvmStats jvmStats = stats == null ? null : stats.getJvm(); FsInfo fsInfo = stats == null ? null : stats.getFs(); @@ -232,7 +230,7 @@ private Table buildTable(RestRequest req, ClusterStateResponse state, NodesInfoR table.startRow(); table.addCell(fullId ? node.id() : Strings.substring(node.getId(), 0, 4)); - table.addCell(info == null ? null : info.getProcess().id()); + table.addCell(info == null ? null : info.getProcess().getId()); table.addCell(node.getHostName()); table.addCell(node.getHostAddress()); if (node.address() instanceof InetSocketTransportAddress) { @@ -252,9 +250,8 @@ private Table buildTable(RestRequest req, ClusterStateResponse state, NodesInfoR table.addCell(osStats == null ? null : osStats.getMem() == null ? null : osStats.getMem().usedPercent()); table.addCell(osInfo == null ? null : osInfo.getMem() == null ? null : osInfo.getMem().total()); // sigar fails to load in IntelliJ table.addCell(processStats == null ? null : processStats.getOpenFileDescriptors()); - table.addCell(processStats == null || processInfo == null ? null : - calculatePercentage(processStats.getOpenFileDescriptors(), processInfo.getMaxFileDescriptors())); - table.addCell(processInfo == null ? null : processInfo.getMaxFileDescriptors()); + table.addCell(processStats == null ? null : calculatePercentage(processStats.getOpenFileDescriptors(), processStats.getMaxFileDescriptors())); + table.addCell(processStats == null ? null : processStats.getMaxFileDescriptors()); table.addCell(osStats == null ? null : osStats.getLoadAverage().length < 1 ? null : String.format(Locale.ROOT, "%.2f", osStats.getLoadAverage()[0])); table.addCell(jvmStats == null ? null : jvmStats.getUptime()); diff --git a/core/src/main/java/org/elasticsearch/rest/action/cat/RestThreadPoolAction.java b/core/src/main/java/org/elasticsearch/rest/action/cat/RestThreadPoolAction.java index cdde7a109eb7f..b5848379a61dd 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/cat/RestThreadPoolAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/cat/RestThreadPoolAction.java @@ -229,7 +229,7 @@ private Table buildTable(RestRequest req, ClusterStateResponse state, NodesInfoR table.startRow(); table.addCell(fullId ? node.id() : Strings.substring(node.getId(), 0, 4)); - table.addCell(info == null ? null : info.getProcess().id()); + table.addCell(info == null ? null : info.getProcess().getId()); table.addCell(node.getHostName()); table.addCell(node.getHostAddress()); if (node.address() instanceof InetSocketTransportAddress) { diff --git a/core/src/test/java/org/elasticsearch/benchmark/monitor/process/ProcessProbeBenchmark.java b/core/src/test/java/org/elasticsearch/benchmark/monitor/process/ProcessProbeBenchmark.java new file mode 100644 index 0000000000000..43f495b6b2fd9 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/benchmark/monitor/process/ProcessProbeBenchmark.java @@ -0,0 +1,130 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.benchmark.monitor.process; + +import org.elasticsearch.common.logging.ESLogger; +import org.elasticsearch.common.logging.ESLoggerFactory; +import org.elasticsearch.monitor.process.ProcessProbe; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; + +public class ProcessProbeBenchmark { + + private static final int ITERATIONS = 100_000; + + public static void main(String[] args) { + System.setProperty("es.logger.prefix", ""); + final ESLogger logger = ESLoggerFactory.getLogger("benchmark"); + + logger.info("--> loading process probe"); + ProcessProbe probe = ProcessProbe.getInstance(); + + logger.info("--> warming up..."); + for (int i = 0; i < ITERATIONS; i++) { + probe.getOpenFileDescriptorCount(); + probe.getMaxFileDescriptorCount(); + probe.getTotalVirtualMemorySize(); + probe.getProcessCpuPercent(); + probe.getProcessCpuTotalTime(); + } + logger.info("--> warmed up"); + + + + + logger.info("--> testing 'getOpenFileDescriptorCount' method..."); + long start = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + probe.getOpenFileDescriptorCount(); + } + long elapsed = System.currentTimeMillis() - start; + logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS)); + + logger.info("--> testing 'getMaxFileDescriptorCount' method..."); + start = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + probe.getMaxFileDescriptorCount(); + } + elapsed = System.currentTimeMillis() - start; + logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS)); + + logger.info("--> testing 'getTotalVirtualMemorySize' method..."); + start = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + probe.getTotalVirtualMemorySize(); + } + elapsed = System.currentTimeMillis() - start; + logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS)); + + logger.info("--> testing 'getProcessCpuPercent' method..."); + start = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + probe.getProcessCpuPercent(); + } + elapsed = System.currentTimeMillis() - start; + logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS)); + + logger.info("--> testing 'getProcessCpuTotalTime' method..."); + start = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + probe.getProcessCpuTotalTime(); + } + elapsed = System.currentTimeMillis() - start; + logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS)); + + + + + logger.info("--> calculating process CPU user time with 'getAllThreadIds + getThreadUserTime' methods..."); + final ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean(); + final long[] threadIds = threadMxBean.getAllThreadIds(); + long sum = 0; + + start = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + for (long threadId : threadIds) { + sum += threadMxBean.getThreadUserTime(threadId); + } + } + elapsed = System.currentTimeMillis() - start; + logger.info("--> execution time [total: {} ms, avg: {} ms] for {} iterations with average result of {}", + elapsed, (elapsed / (double)ITERATIONS), ITERATIONS, (sum / (double)ITERATIONS)); + + /* Commented as com.sun.management is listed as forbidden usage + if (threadMxBean instanceof com.sun.management.ThreadMXBean) { + logger.info("--> calculating process CPU user time with 'getAllThreadIds + getThreadUserTime(long[])' methods..."); + final com.sun.management.ThreadMXBean threadMxBean2 = (com.sun.management.ThreadMXBean)threadMxBean; + sum = 0; + + start = System.currentTimeMillis(); + for (int i = 0; i < ITERATIONS; i++) { + long[] user = threadMxBean2.getThreadUserTime(threadIds); + for (int n = 0 ; n != threadIds.length; ++n) { + sum += user[n]; + } + } + elapsed = System.currentTimeMillis() - start; + logger.info("--> execution time [total: {} ms, avg: {} ms] for {} iterations with average result of {}", + elapsed, (elapsed / (double)ITERATIONS), ITERATIONS, (sum / (double)ITERATIONS)); + + }*/ + } +} diff --git a/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java b/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java index 083affa50b1ec..1ed5df3b75105 100644 --- a/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java +++ b/core/src/test/java/org/elasticsearch/bootstrap/BootstrapForTesting.java @@ -51,6 +51,9 @@ public class BootstrapForTesting { static { // just like bootstrap, initialize natives, then SM Bootstrap.initializeNatives(true, true); + + // initialize probes + Bootstrap.initializeProbes(); // check for jar hell try { diff --git a/core/src/test/java/org/elasticsearch/monitor/process/ProcessProbeTests.java b/core/src/test/java/org/elasticsearch/monitor/process/ProcessProbeTests.java new file mode 100644 index 0000000000000..4aa4e64dbd264 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/monitor/process/ProcessProbeTests.java @@ -0,0 +1,56 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.monitor.process; + +import org.elasticsearch.bootstrap.Bootstrap; +import org.elasticsearch.test.ElasticsearchTestCase; +import org.junit.Test; + +import static org.elasticsearch.monitor.jvm.JvmInfo.jvmInfo; +import static org.hamcrest.Matchers.*; + +public class ProcessProbeTests extends ElasticsearchTestCase { + + ProcessProbe probe = ProcessProbe.getInstance(); + + @Test + public void testProcessInfo() { + ProcessInfo info = probe.processInfo(); + assertNotNull(info); + assertThat(info.getRefreshInterval(), greaterThanOrEqualTo(0L)); + assertThat(info.getId(), equalTo(jvmInfo().pid())); + assertThat(info.isMlockall(), equalTo(Bootstrap.isMemoryLocked())); + } + + @Test + public void testProcessStats() { + ProcessStats stats = probe.processStats(); + assertNotNull(stats); + + ProcessStats.Cpu cpu = stats.getCpu(); + assertNotNull(cpu); + assertThat(cpu.getPercent(), greaterThanOrEqualTo((short) 0)); + assertThat(cpu.total, anyOf(equalTo(-1L), greaterThan(0L))); + + ProcessStats.Mem mem = stats.getMem(); + assertNotNull(mem); + assertThat(mem.totalVirtual, anyOf(equalTo(-1L), greaterThan(0L))); + } +} diff --git a/docs/reference/cluster/nodes-info.asciidoc b/docs/reference/cluster/nodes-info.asciidoc index 07a2360acbee2..73dbb488476cf 100644 --- a/docs/reference/cluster/nodes-info.asciidoc +++ b/docs/reference/cluster/nodes-info.asciidoc @@ -32,6 +32,28 @@ curl -XGET 'http://localhost:9200/_nodes/nodeId1,nodeId2/_all The `_all` flag can be set to return all the information - or you can simply omit it. + +[float] +[[process-info]] +==== Process information + +The `process` flag can be set to retrieve information that concern +the current running process: + +`process.refresh_interval_in_millis`:: + Refresh interval for the process statistics. + +`process.id`:: + Process identifier (PID) + +`process.mlockall`:: + Indicates if the process address space has been successfully locked in memory + + +[float] +[[plugins-info]] +==== Plugins information + `plugins` - if set, the result will contain details about the loaded plugins per node: diff --git a/docs/reference/cluster/nodes-stats.asciidoc b/docs/reference/cluster/nodes-stats.asciidoc index ce65c15153e82..47ef6ae87aa34 100644 --- a/docs/reference/cluster/nodes-stats.asciidoc +++ b/docs/reference/cluster/nodes-stats.asciidoc @@ -23,33 +23,33 @@ of `indices`, `os`, `process`, `jvm`, `transport`, `http`, `fs`, `breaker` and `thread_pool`. For example: [horizontal] -`indices`:: +`indices`:: Indices stats about size, document count, indexing and deletion times, search times, field cache size, merges and flushes -`fs`:: +`fs`:: File system information, data path, free disk space, read/write stats (see <>) -`http`:: +`http`:: HTTP connection information -`jvm`:: +`jvm`:: JVM stats, memory pool information, garbage collection, buffer pools -`os`:: +`os`:: Operating system stats, load average, cpu, mem, swap -`process`:: +`process`:: Process statistics, memory consumption, cpu usage, open - file descriptors + file descriptors (see <>) -`thread_pool`:: +`thread_pool`:: Statistics about each thread pool, including current size, queue and rejected tasks -`transport`:: +`transport`:: Transport statistics about sent and received bytes in cluster communication @@ -114,6 +114,31 @@ information that concern the file system: `null` means we could not determine it, `true` means the device possibly spins and `false` means it does not (ex: solid-state disks). +[float] +[[process-stats]] +==== Process statistics + +The `process` flag can be set to retrieve statistics that concern +the current running process: + +`process.timestamp`:: + Last time the process statistics have been refreshed + +`process.open_file_descriptors`:: + Number of opened file descriptors associated with the current process, or -1 if not supported + +`process.max_file_descriptors`:: + Maximum number of file descriptors allowed on the system, or -1 if not supported + +`process.cpu.percent`:: + CPU usage in percent + +`process.cpu.total_in_millis`:: + CPU time (in milliseconds) used by the process on which the Java virtual machine is running, or -1 if not supported + +`process.mem.total_virtual_in_bytes`:: + Size in bytes of virtual memory that is guaranteed to be available to the running process + [float] [[field-data]]