Skip to content

Commit

Permalink
Merge pull request #15302 from jasontedor/return-of-the-cpu-percent-b…
Browse files Browse the repository at this point in the history
…ackport

Add system CPU percent to OS stats
  • Loading branch information
jasontedor committed Dec 8, 2015
2 parents 1c06386 + 7a819b7 commit 8be31e7
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 16 deletions.
39 changes: 39 additions & 0 deletions core/src/main/java/org/elasticsearch/monitor/Probes.java
@@ -0,0 +1,39 @@
/*
* 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;

import java.lang.management.OperatingSystemMXBean;
import java.lang.reflect.Method;

public class Probes {
public static short getLoadAndScaleToPercent(Method method, OperatingSystemMXBean osMxBean) {
if (method != null) {
try {
double load = (double) method.invoke(osMxBean);
if (load >= 0) {
return (short) (load * 100);
}
} catch (Throwable t) {
return -1;
}
}
return -1;
}
}
8 changes: 8 additions & 0 deletions core/src/main/java/org/elasticsearch/monitor/os/OsProbe.java
Expand Up @@ -20,6 +20,7 @@
package org.elasticsearch.monitor.os;

import org.apache.lucene.util.Constants;
import org.elasticsearch.monitor.Probes;

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
Expand All @@ -34,13 +35,15 @@ public class OsProbe {
private static final Method getFreeSwapSpaceSize;
private static final Method getTotalSwapSpaceSize;
private static final Method getSystemLoadAverage;
private static final Method getSystemCpuLoad;

static {
getFreePhysicalMemorySize = getMethod("getFreePhysicalMemorySize");
getTotalPhysicalMemorySize = getMethod("getTotalPhysicalMemorySize");
getFreeSwapSpaceSize = getMethod("getFreeSwapSpaceSize");
getTotalSwapSpaceSize = getMethod("getTotalSwapSpaceSize");
getSystemLoadAverage = getMethod("getSystemLoadAverage");
getSystemCpuLoad = getMethod("getSystemCpuLoad");
}

/**
Expand Down Expand Up @@ -113,6 +116,10 @@ public double getSystemLoadAverage() {
}
}

public short getSystemCpuPercent() {
return Probes.getLoadAndScaleToPercent(getSystemCpuLoad, osMxBean);
}

private static class OsProbeHolder {
private final static OsProbe INSTANCE = new OsProbe();
}
Expand All @@ -136,6 +143,7 @@ public OsInfo osInfo() {
public OsStats osStats() {
OsStats stats = new OsStats();
stats.timestamp = System.currentTimeMillis();
stats.cpuPercent = getSystemCpuPercent();
stats.loadAverage = getSystemLoadAverage();

OsStats.Mem mem = new OsStats.Mem();
Expand Down
24 changes: 22 additions & 2 deletions core/src/main/java/org/elasticsearch/monitor/os/OsStats.java
Expand Up @@ -19,6 +19,7 @@

package org.elasticsearch.monitor.os;

import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Streamable;
Expand All @@ -36,6 +37,8 @@ public class OsStats implements Streamable, ToXContent {

long timestamp;

Short cpuPercent = null;

double loadAverage = -1;

Mem mem = null;
Expand All @@ -49,11 +52,14 @@ public long getTimestamp() {
return timestamp;
}

public Short getCpuPercent() {
return cpuPercent;
}

public double getLoadAverage() {
return loadAverage;
}


public Mem getMem() {
return mem;
}
Expand All @@ -65,6 +71,7 @@ public Swap getSwap() {
static final class Fields {
static final XContentBuilderString OS = new XContentBuilderString("os");
static final XContentBuilderString TIMESTAMP = new XContentBuilderString("timestamp");
static final XContentBuilderString PERCENT = new XContentBuilderString("cpu_percent");
static final XContentBuilderString LOAD_AVERAGE = new XContentBuilderString("load_average");

static final XContentBuilderString MEM = new XContentBuilderString("mem");
Expand All @@ -85,6 +92,9 @@ static final class Fields {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(Fields.OS);
builder.field(Fields.TIMESTAMP, getTimestamp());
if (getCpuPercent() != null) {
builder.field(Fields.PERCENT, getCpuPercent());
}
builder.field(Fields.LOAD_AVERAGE, getLoadAverage());

if (mem != null) {
Expand Down Expand Up @@ -120,6 +130,11 @@ public static OsStats readOsStats(StreamInput in) throws IOException {
@Override
public void readFrom(StreamInput in) throws IOException {
timestamp = in.readVLong();
if (in.getVersion().onOrAfter(Version.V_2_2_0)) {
if (in.readBoolean()) {
cpuPercent = in.readShort();
}
}
loadAverage = in.readDouble();
if (in.readBoolean()) {
mem = Mem.readMem(in);
Expand All @@ -132,6 +147,12 @@ public void readFrom(StreamInput in) throws IOException {
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeVLong(timestamp);
if (out.getVersion().onOrAfter(Version.V_2_2_0)) {
out.writeBoolean(cpuPercent != null);
if (cpuPercent != null) {
out.writeShort(cpuPercent);
}
}
out.writeDouble(loadAverage);
if (mem == null) {
out.writeBoolean(false);
Expand Down Expand Up @@ -230,5 +251,4 @@ public short getFreePercent() {
private static short calculatePercentage(long used, long max) {
return max <= 0 ? 0 : (short) (Math.round((100d * used) / max));
}

}
Expand Up @@ -20,6 +20,7 @@
package org.elasticsearch.monitor.process;

import org.elasticsearch.bootstrap.BootstrapInfo;
import org.elasticsearch.monitor.Probes;

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
Expand Down Expand Up @@ -88,17 +89,7 @@ public long getOpenFileDescriptorCount() {
* 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;
return Probes.getLoadAndScaleToPercent(getProcessCpuLoad, osMxBean);
}

/**
Expand Down
Expand Up @@ -130,6 +130,7 @@ protected Table getTableWithHeader(final RestRequest request) {
table.addCell("file_desc.percent", "default:false;alias:fdp,fileDescriptorPercent;text-align:right;desc:used file descriptor ratio");
table.addCell("file_desc.max", "default:false;alias:fdm,fileDescriptorMax;text-align:right;desc:max file descriptors");

table.addCell("cpu", "default:false;alias:cpu;text-align:right;desc:recent cpu usage");
table.addCell("load", "alias:l;text-align:right;desc:most recent load avg");
table.addCell("uptime", "default:false;alias:u;text-align:right;desc:node uptime");
table.addCell("node.role", "alias:r,role,dc,nodeRole;desc:d:data node, c:client node");
Expand Down Expand Up @@ -258,6 +259,7 @@ private Table buildTable(RestRequest req, ClusterStateResponse state, NodesInfoR
table.addCell(processStats == null ? null : calculatePercentage(processStats.getOpenFileDescriptors(), processStats.getMaxFileDescriptors()));
table.addCell(processStats == null ? null : processStats.getMaxFileDescriptors());

table.addCell(osStats == null || osStats.getCpuPercent() == null ? null : Short.toString(osStats.getCpuPercent()));
table.addCell(osStats == null ? null : String.format(Locale.ROOT, "%.2f", osStats.getLoadAverage()));
table.addCell(jvmStats == null ? null : jvmStats.getUptime());
table.addCell(node.clientNode() ? "c" : node.dataNode() ? "d" : "-");
Expand Down
Expand Up @@ -41,12 +41,10 @@ public static void main(String[] args) {
probe.getTotalSwapSpaceSize();
probe.getFreeSwapSpaceSize();
probe.getSystemLoadAverage();
probe.getSystemCpuPercent();
}
logger.info("--> warmed up");




logger.info("--> testing 'getTotalPhysicalMemorySize' method...");
long start = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) {
Expand Down Expand Up @@ -86,5 +84,13 @@ public static void main(String[] args) {
}
elapsed = System.currentTimeMillis() - start;
logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS));

logger.info("--> testing 'getSystemCpuPercent' method...");
start = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) {
probe.getSystemCpuPercent();
}
elapsed = System.currentTimeMillis() - start;
logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS));
}
}
Expand Up @@ -45,6 +45,7 @@ public void testOsStats() {
OsStats stats = probe.osStats();
assertNotNull(stats);
assertThat(stats.getTimestamp(), greaterThan(0L));
assertThat(stats.getCpuPercent(), anyOf(equalTo((short) -1), is(both(greaterThanOrEqualTo((short) 0)).and(lessThanOrEqualTo((short) 100)))));
if (Constants.WINDOWS) {
// Load average is always -1 on Windows platforms
assertThat(stats.getLoadAverage(), equalTo((double) -1));
Expand Down
3 changes: 3 additions & 0 deletions docs/reference/cluster/nodes-stats.asciidoc
Expand Up @@ -125,6 +125,9 @@ the operating system:
`os.timestamp`::
Last time the operating system statistics have been refreshed

`os.percent`::
Recent CPU usage for the whole system, or -1 if not supported

`os.load_average`::
System load average for the last minute, or -1 if not supported

Expand Down
13 changes: 13 additions & 0 deletions docs/reference/migration/migrate_2_2.asciidoc
Expand Up @@ -14,3 +14,16 @@ your application to Elasticsearch 2.2.
The field stats response format has been changed for number based and date fields. The `min_value` and
`max_value` elements now return values as number and the new `min_value_as_string` and `max_value_as_string`
return the values as string.

==== Adding system CPU percent to OS stats

The recent CPU usage (as a percent) has been added to the OS stats reported under the node stats API and the cat nodes
API. If you send an appropriate nodes stats request to a node running version 2.2.0 or later of Elasticsearch, the CPU
usage will be shown for any nodes in the response that are also running version 2.2.0 or later of Elasticsearch. Do
note that if you send a node stats request to a node running a version of Elasticsearch earlier than 2.2.0, the CPU
usage will not be shown for any nodes. The "cpu" field in the cat nodes API is not output by default. If you send an
appropriate cat nodes request to a node running version 2.2.0 or later of Elasticsearch, the CPU usage will be shown
for any nodes in the response that are also running version 2.2.0 or later of Elasticsearch and will be null for any
other node in the response. Do note that if you send a cat nodes request to a node running a version of Elasticsearch
earlier than 2.2.0, the CPU usage will not be shown for any nodes. Finally, the API for
org.elasticsearch.monitor.os.OsStats has an additional method `OsStats#getCpuPercent`.
Expand Up @@ -18,6 +18,16 @@
/^ host \s+ ip \s+ heap\.percent \s+ ram\.percent \s+ load \s+ node\.role \s+ master \s+ name \s+ \n
(\S+ \s+ (\d{1,3}\.){3}\d{1,3} \s+ \d+ \s+ \d* \s+ (-)?\d*(\.\d+)? \s+ [-dc] \s+ [-*mx] \s+ (\S+\s?)+ \s+ \n)+ $/
- do:
cat.nodes:
h: cpu
v: true

- match:
$body: |
/^cpu\s+ \n
(\s+(-1|\d+)*\s+ \n)+ $/
- do:
cat.nodes:
h: heap.current,heap.percent,heap.max
Expand Down

0 comments on commit 8be31e7

Please sign in to comment.