Browse Source

Update OS stats

Tanguy Leroux 10 years ago
parent
commit
19e348a82c

+ 1 - 36
core/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java

@@ -304,27 +304,16 @@ public class ClusterStatsNodes implements ToXContent, Streamable {
         int availableProcessors;
         long availableMemory;
         final ObjectIntHashMap<String> names;
-        final ObjectIntHashMap<OsInfo.Cpu> cpus;
 
         public OsStats() {
-            cpus = new ObjectIntHashMap<>();
             names = new ObjectIntHashMap<>();
         }
 
         public void addNodeInfo(NodeInfo nodeInfo) {
-            availableProcessors += nodeInfo.getOs().availableProcessors();
-            if (nodeInfo.getOs() == null) {
-                return;
-            }
+            availableProcessors += nodeInfo.getOs().getAvailableProcessors();
             if (nodeInfo.getOs().getName() != null) {
                 names.addTo(nodeInfo.getOs().getName(), 1);
             }
-            if (nodeInfo.getOs().cpu() != null) {
-                cpus.addTo(nodeInfo.getOs().cpu(), 1);
-            }
-            if (nodeInfo.getOs().getMem() != null && nodeInfo.getOs().getMem().getTotal().bytes() != -1) {
-                availableMemory += nodeInfo.getOs().getMem().getTotal().bytes();
-            }
         }
 
         public int getAvailableProcessors() {
@@ -335,10 +324,6 @@ public class ClusterStatsNodes implements ToXContent, Streamable {
             return new ByteSizeValue(availableMemory);
         }
 
-        public ObjectIntHashMap<OsInfo.Cpu> getCpus() {
-            return cpus;
-        }
-
         @Override
         public void readFrom(StreamInput in) throws IOException {
             availableProcessors = in.readVInt();
@@ -348,11 +333,6 @@ public class ClusterStatsNodes implements ToXContent, Streamable {
             for (int i = 0; i < size; i++) {
                 names.addTo(in.readString(), in.readVInt());
             }
-            size = in.readVInt();
-            cpus.clear();
-            for (int i = 0; i < size; i++) {
-                cpus.addTo(OsInfo.Cpu.readCpu(in), in.readVInt());
-            }
         }
 
         @Override
@@ -364,11 +344,6 @@ public class ClusterStatsNodes implements ToXContent, Streamable {
                 out.writeString(name.key);
                 out.writeVInt(name.value);
             }
-            out.writeVInt(cpus.size());
-            for (ObjectIntCursor<OsInfo.Cpu> c : cpus) {
-                c.key.writeTo(out);
-                out.writeVInt(c.value);
-            }
         }
 
         public static OsStats readOsStats(StreamInput in) throws IOException {
@@ -384,7 +359,6 @@ public class ClusterStatsNodes implements ToXContent, Streamable {
             static final XContentBuilderString MEM = new XContentBuilderString("mem");
             static final XContentBuilderString TOTAL = new XContentBuilderString("total");
             static final XContentBuilderString TOTAL_IN_BYTES = new XContentBuilderString("total_in_bytes");
-            static final XContentBuilderString CPU = new XContentBuilderString("cpu");
             static final XContentBuilderString COUNT = new XContentBuilderString("count");
         }
 
@@ -404,15 +378,6 @@ public class ClusterStatsNodes implements ToXContent, Streamable {
             }
             builder.endArray();
 
-            builder.startArray(Fields.CPU);
-            for (ObjectIntCursor<OsInfo.Cpu> cpu : cpus) {
-                builder.startObject();
-                cpu.key.toXContent(builder, params);
-                builder.field(Fields.COUNT, cpu.value);
-                builder.endObject();
-            }
-            builder.endArray();
-
             return builder;
         }
     }

+ 2 - 0
core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java

@@ -40,6 +40,7 @@ import org.elasticsearch.common.logging.log4j.LogConfigurator;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.env.Environment;
 import org.elasticsearch.monitor.jvm.JvmInfo;
+import org.elasticsearch.monitor.os.OsProbe;
 import org.elasticsearch.monitor.process.ProcessProbe;
 import org.elasticsearch.node.Node;
 import org.elasticsearch.node.NodeBuilder;
@@ -146,6 +147,7 @@ public class Bootstrap {
     static void initializeProbes() {
         // Force probes to be loaded
         ProcessProbe.getInstance();
+        OsProbe.getInstance();
     }
 
     public static boolean isMemoryLocked() {

+ 1 - 2
core/src/main/java/org/elasticsearch/monitor/MonitorModule.java

@@ -25,7 +25,6 @@ import org.elasticsearch.monitor.fs.FsProbe;
 import org.elasticsearch.monitor.fs.FsService;
 import org.elasticsearch.monitor.jvm.JvmMonitorService;
 import org.elasticsearch.monitor.jvm.JvmService;
-import org.elasticsearch.monitor.os.JmxOsProbe;
 import org.elasticsearch.monitor.os.OsProbe;
 import org.elasticsearch.monitor.os.OsService;
 import org.elasticsearch.monitor.process.ProcessProbe;
@@ -50,7 +49,7 @@ public class MonitorModule extends AbstractModule {
     protected void configure() {
         // bind default implementations
         bind(ProcessProbe.class).toInstance(ProcessProbe.getInstance());
-        bind(OsProbe.class).to(JmxOsProbe.class).asEagerSingleton();
+        bind(OsProbe.class).toInstance(OsProbe.getInstance());
         bind(FsProbe.class).asEagerSingleton();
 
         // bind other services

+ 0 - 47
core/src/main/java/org/elasticsearch/monitor/os/JmxOsProbe.java

@@ -1,47 +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.os;
-
-import org.elasticsearch.common.component.AbstractComponent;
-import org.elasticsearch.common.inject.Inject;
-import org.elasticsearch.common.settings.Settings;
-
-/**
- *
- */
-public class JmxOsProbe extends AbstractComponent implements OsProbe {
-
-    @Inject
-    public JmxOsProbe(Settings settings) {
-        super(settings);
-    }
-
-    @Override
-    public OsInfo osInfo() {
-        return new OsInfo();
-    }
-
-    @Override
-    public OsStats osStats() {
-        OsStats stats = new OsStats();
-        stats.timestamp = System.currentTimeMillis();
-        return stats;
-    }
-}

+ 16 - 294
core/src/main/java/org/elasticsearch/monitor/os/OsInfo.java

@@ -22,16 +22,12 @@ package org.elasticsearch.monitor.os;
 import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.io.stream.Streamable;
-import org.elasticsearch.common.unit.ByteSizeValue;
 import org.elasticsearch.common.xcontent.ToXContent;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentBuilderString;
 
 import java.io.IOException;
 
-/**
- *
- */
 public class OsInfo implements Streamable, ToXContent {
 
     long refreshInterval;
@@ -39,105 +35,56 @@ public class OsInfo implements Streamable, ToXContent {
     int availableProcessors;
 
     String name = null;
-
-    Cpu cpu = null;
-
-    Mem mem = null;
-
-    Swap swap = null;
+    String arch = null;
+    String version = null;
 
     OsInfo() {
     }
 
-    public long refreshInterval() {
-        return this.refreshInterval;
-    }
-
     public long getRefreshInterval() {
         return this.refreshInterval;
     }
 
-    public int availableProcessors() {
-        return this.availableProcessors;
-    }
-
     public int getAvailableProcessors() {
         return this.availableProcessors;
     }
 
-    public Cpu cpu() {
-        return this.cpu;
-    }
-
-    public Cpu getCpu() {
-        return cpu();
-    }
-
-    public Mem mem() {
-        return this.mem;
-    }
-
-    public Mem getMem() {
-        return mem();
-    }
-
-    public Swap swap() {
-        return this.swap;
+    public String getName() {
+        return name;
     }
 
-    public Swap getSwap() {
-        return swap();
+    public String getArch() {
+        return arch;
     }
 
-    public String getName() {
-        return name;
+    public String getVersion() {
+        return version;
     }
 
     static final class Fields {
         static final XContentBuilderString OS = new XContentBuilderString("os");
         static final XContentBuilderString NAME = new XContentBuilderString("name");
+        static final XContentBuilderString ARCH = new XContentBuilderString("arch");
+        static final XContentBuilderString VERSION = new XContentBuilderString("version");
         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 AVAILABLE_PROCESSORS = new XContentBuilderString("available_processors");
-        static final XContentBuilderString CPU = new XContentBuilderString("cpu");
-        static final XContentBuilderString VENDOR = new XContentBuilderString("vendor");
-        static final XContentBuilderString MODEL = new XContentBuilderString("model");
-        static final XContentBuilderString MHZ = new XContentBuilderString("mhz");
-        static final XContentBuilderString TOTAL_CORES = new XContentBuilderString("total_cores");
-        static final XContentBuilderString TOTAL_SOCKETS = new XContentBuilderString("total_sockets");
-        static final XContentBuilderString CORES_PER_SOCKET = new XContentBuilderString("cores_per_socket");
-        static final XContentBuilderString CACHE_SIZE = new XContentBuilderString("cache_size");
-        static final XContentBuilderString CACHE_SIZE_IN_BYTES = new XContentBuilderString("cache_size_in_bytes");
-
-        static final XContentBuilderString MEM = new XContentBuilderString("mem");
-        static final XContentBuilderString SWAP = new XContentBuilderString("swap");
-        static final XContentBuilderString TOTAL = new XContentBuilderString("total");
-        static final XContentBuilderString TOTAL_IN_BYTES = new XContentBuilderString("total_in_bytes");
     }
 
     @Override
     public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
         builder.startObject(Fields.OS);
+        builder.timeValueField(Fields.REFRESH_INTERVAL_IN_MILLIS, Fields.REFRESH_INTERVAL, refreshInterval);
         if (name != null) {
             builder.field(Fields.NAME, name);
         }
-        builder.timeValueField(Fields.REFRESH_INTERVAL_IN_MILLIS, Fields.REFRESH_INTERVAL, refreshInterval);
-        builder.field(Fields.AVAILABLE_PROCESSORS, availableProcessors);
-        if (cpu != null) {
-            builder.startObject(Fields.CPU);
-            cpu.toXContent(builder, params);
-            builder.endObject();
+        if (arch != null) {
+            builder.field(Fields.ARCH, arch);
         }
-        if (mem != null) {
-            builder.startObject(Fields.MEM);
-            builder.byteSizeField(Fields.TOTAL_IN_BYTES, Fields.TOTAL, mem.total);
-            builder.endObject();
-        }
-        if (swap != null) {
-            builder.startObject(Fields.SWAP);
-            builder.byteSizeField(Fields.TOTAL_IN_BYTES, Fields.TOTAL, swap.total);
-            builder.endObject();
+        if (version != null) {
+            builder.field(Fields.VERSION, version);
         }
+        builder.field(Fields.AVAILABLE_PROCESSORS, availableProcessors);
         builder.endObject();
         return builder;
     }
@@ -152,236 +99,11 @@ public class OsInfo implements Streamable, ToXContent {
     public void readFrom(StreamInput in) throws IOException {
         refreshInterval = in.readLong();
         availableProcessors = in.readInt();
-        if (in.readBoolean()) {
-            cpu = Cpu.readCpu(in);
-        }
-        if (in.readBoolean()) {
-            mem = Mem.readMem(in);
-        }
-        if (in.readBoolean()) {
-            swap = Swap.readSwap(in);
-        }
     }
 
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeLong(refreshInterval);
         out.writeInt(availableProcessors);
-        if (cpu == null) {
-            out.writeBoolean(false);
-        } else {
-            out.writeBoolean(true);
-            cpu.writeTo(out);
-        }
-        if (mem == null) {
-            out.writeBoolean(false);
-        } else {
-            out.writeBoolean(true);
-            mem.writeTo(out);
-        }
-        if (swap == null) {
-            out.writeBoolean(false);
-        } else {
-            out.writeBoolean(true);
-            swap.writeTo(out);
-        }
-    }
-
-    public static class Swap implements Streamable {
-
-        long total = -1;
-
-        Swap() {
-
-        }
-
-        public static Swap readSwap(StreamInput in) throws IOException {
-            Swap swap = new Swap();
-            swap.readFrom(in);
-            return swap;
-        }
-
-        @Override
-        public void readFrom(StreamInput in) throws IOException {
-            total = in.readLong();
-        }
-
-        @Override
-        public void writeTo(StreamOutput out) throws IOException {
-            out.writeLong(total);
-        }
-
-        public ByteSizeValue total() {
-            return new ByteSizeValue(total);
-        }
-
-        public ByteSizeValue getTotal() {
-            return total();
-        }
-
-    }
-
-    public static class Mem implements Streamable {
-
-        long total = -1;
-
-        Mem() {
-
-        }
-
-        public static Mem readMem(StreamInput in) throws IOException {
-            Mem mem = new Mem();
-            mem.readFrom(in);
-            return mem;
-        }
-
-        @Override
-        public void readFrom(StreamInput in) throws IOException {
-            total = in.readLong();
-        }
-
-        @Override
-        public void writeTo(StreamOutput out) throws IOException {
-            out.writeLong(total);
-        }
-
-        public ByteSizeValue total() {
-            return new ByteSizeValue(total);
-        }
-
-        public ByteSizeValue getTotal() {
-            return total();
-        }
-
-    }
-
-    public static class Cpu implements Streamable, ToXContent {
-
-        String vendor = "";
-        String model = "";
-        int mhz = -1;
-        int totalCores = -1;
-        int totalSockets = -1;
-        int coresPerSocket = -1;
-        long cacheSize = -1;
-
-        Cpu() {
-
-        }
-
-        public String vendor() {
-            return this.vendor;
-        }
-
-        public String getVendor() {
-            return vendor();
-        }
-
-        public String model() {
-            return model;
-        }
-
-        public String getModel() {
-            return model;
-        }
-
-        public int mhz() {
-            return mhz;
-        }
-
-        public int getMhz() {
-            return mhz;
-        }
-
-        public int totalCores() {
-            return totalCores;
-        }
-
-        public int getTotalCores() {
-            return totalCores();
-        }
-
-        public int totalSockets() {
-            return totalSockets;
-        }
-
-        public int getTotalSockets() {
-            return totalSockets();
-        }
-
-        public int coresPerSocket() {
-            return coresPerSocket;
-        }
-
-        public int getCoresPerSocket() {
-            return coresPerSocket();
-        }
-
-        public ByteSizeValue cacheSize() {
-            return new ByteSizeValue(cacheSize);
-        }
-
-        public ByteSizeValue getCacheSize() {
-            return cacheSize();
-        }
-
-        public static Cpu readCpu(StreamInput in) throws IOException {
-            Cpu cpu = new Cpu();
-            cpu.readFrom(in);
-            return cpu;
-        }
-
-        @Override
-        public void readFrom(StreamInput in) throws IOException {
-            vendor = in.readString();
-            model = in.readString();
-            mhz = in.readInt();
-            totalCores = in.readInt();
-            totalSockets = in.readInt();
-            coresPerSocket = in.readInt();
-            cacheSize = in.readLong();
-        }
-
-        @Override
-        public void writeTo(StreamOutput out) throws IOException {
-            out.writeString(vendor);
-            out.writeString(model);
-            out.writeInt(mhz);
-            out.writeInt(totalCores);
-            out.writeInt(totalSockets);
-            out.writeInt(coresPerSocket);
-            out.writeLong(cacheSize);
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-
-            Cpu cpu = (Cpu) o;
-
-            return model.equals(cpu.model) && vendor.equals(cpu.vendor);
-        }
-
-        @Override
-        public int hashCode() {
-            return model.hashCode();
-        }
-
-        @Override
-        public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
-            builder.field(Fields.VENDOR, vendor);
-            builder.field(Fields.MODEL, model);
-            builder.field(Fields.MHZ, mhz);
-            builder.field(Fields.TOTAL_CORES, totalCores);
-            builder.field(Fields.TOTAL_SOCKETS, totalSockets);
-            builder.field(Fields.CORES_PER_SOCKET, coresPerSocket);
-            builder.byteSizeField(Fields.CACHE_SIZE_IN_BYTES, Fields.CACHE_SIZE, cacheSize);
-            return builder;
-        }
     }
 }

+ 144 - 6
core/src/main/java/org/elasticsearch/monitor/os/OsProbe.java

@@ -19,12 +19,150 @@
 
 package org.elasticsearch.monitor.os;
 
-/**
- *
- */
-public interface OsProbe {
+import org.apache.lucene.util.Constants;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.reflect.Method;
+
+public class OsProbe {
+
+    private static final OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean();
+
+    private static final Method getFreePhysicalMemorySize;
+    private static final Method getTotalPhysicalMemorySize;
+    private static final Method getFreeSwapSpaceSize;
+    private static final Method getTotalSwapSpaceSize;
+    private static final Method getSystemLoadAverage;
+
+    static {
+        getFreePhysicalMemorySize = getMethod("getFreePhysicalMemorySize");
+        getTotalPhysicalMemorySize = getMethod("getTotalPhysicalMemorySize");
+        getFreeSwapSpaceSize = getMethod("getFreeSwapSpaceSize");
+        getTotalSwapSpaceSize = getMethod("getTotalSwapSpaceSize");
+        getSystemLoadAverage = getMethod("getSystemLoadAverage");
+    }
+
+    /**
+     * Returns the amount of free physical memory in bytes.
+     */
+    public long getFreePhysicalMemorySize() {
+        if (getFreePhysicalMemorySize == null) {
+            return -1;
+        }
+        try {
+            return (long) getFreePhysicalMemorySize.invoke(osMxBean);
+        } catch (Throwable t) {
+            return -1;
+        }
+    }
+
+    /**
+     * Returns the total amount of physical memory in bytes.
+     */
+    public long getTotalPhysicalMemorySize() {
+        if (getTotalPhysicalMemorySize == null) {
+            return -1;
+        }
+        try {
+            return (long) getTotalPhysicalMemorySize.invoke(osMxBean);
+        } catch (Throwable t) {
+            return -1;
+        }
+    }
+
+    /**
+     * Returns the amount of free swap space in bytes.
+     */
+    public long getFreeSwapSpaceSize() {
+        if (getFreeSwapSpaceSize == null) {
+            return -1;
+        }
+        try {
+            return (long) getFreeSwapSpaceSize.invoke(osMxBean);
+        } catch (Throwable t) {
+            return -1;
+        }
+    }
+
+    /**
+     * Returns the total amount of swap space in bytes.
+     */
+    public long getTotalSwapSpaceSize() {
+        if (getTotalSwapSpaceSize == null) {
+            return -1;
+        }
+        try {
+            return (long) getTotalSwapSpaceSize.invoke(osMxBean);
+        } catch (Throwable t) {
+            return -1;
+        }
+    }
+
+    /**
+     * Returns the system load average for the last minute.
+     */
+    public double getSystemLoadAverage() {
+        if (getSystemLoadAverage == null) {
+            return -1;
+        }
+        try {
+            return (double) getSystemLoadAverage.invoke(osMxBean);
+        } catch (Throwable t) {
+            return -1;
+        }
+    }
+
+    private static class OsProbeHolder {
+        private final static OsProbe INSTANCE = new OsProbe();
+    }
+
+    public static OsProbe getInstance() {
+        return OsProbeHolder.INSTANCE;
+    }
+
+    private OsProbe() {
+    }
+
+    public OsInfo osInfo() {
+        OsInfo info = new OsInfo();
+        info.availableProcessors = Runtime.getRuntime().availableProcessors();
+        info.name = Constants.OS_NAME;
+        info.arch = Constants.OS_ARCH;
+        info.version = Constants.OS_VERSION;
+        return info;
+    }
+
+    public OsStats osStats() {
+        OsStats stats = new OsStats();
+        stats.timestamp = System.currentTimeMillis();
+        stats.loadAverage = getSystemLoadAverage();
+
+        OsStats.Mem mem = new OsStats.Mem();
+        mem.total = getTotalPhysicalMemorySize();
+        mem.free = getFreePhysicalMemorySize();
+        stats.mem = mem;
+
+        OsStats.Swap swap = new OsStats.Swap();
+        swap.total = getTotalSwapSpaceSize();
+        swap.free = getFreeSwapSpaceSize();
+        stats.swap = swap;
 
-    OsInfo osInfo();
+        return stats;
+    }
 
-    OsStats osStats();
+    /**
+     * 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().getMethod(methodName);
+            method.setAccessible(true);
+            return method;
+        } catch (Throwable t) {
+            // not available
+        }
+        return null;
+    }
 }

+ 0 - 3
core/src/main/java/org/elasticsearch/monitor/os/OsService.java

@@ -19,7 +19,6 @@
 
 package org.elasticsearch.monitor.os;
 
-import org.apache.lucene.util.Constants;
 import org.elasticsearch.common.component.AbstractComponent;
 import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.settings.Settings;
@@ -46,8 +45,6 @@ public class OsService extends AbstractComponent {
 
         this.info = probe.osInfo();
         this.info.refreshInterval = refreshInterval.millis();
-        this.info.availableProcessors = Runtime.getRuntime().availableProcessors();
-        this.info.name = Constants.OS_NAME;
         osStatsCache = new OsStatsCache(refreshInterval, probe.osStats());
         logger.debug("Using probe [{}] with refresh_interval [{}]", probe, refreshInterval);
     }

+ 39 - 245
core/src/main/java/org/elasticsearch/monitor/os/OsStats.java

@@ -23,29 +23,20 @@ import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.common.io.stream.Streamable;
 import org.elasticsearch.common.unit.ByteSizeValue;
-import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.common.xcontent.ToXContent;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.elasticsearch.common.xcontent.XContentBuilderString;
 
 import java.io.IOException;
-import java.util.concurrent.TimeUnit;
 
 /**
  *
  */
 public class OsStats implements Streamable, ToXContent {
 
-    public static final double[] EMPTY_LOAD = new double[0];
-
-
     long timestamp;
 
-    double[] loadAverage = EMPTY_LOAD;
-
-    long uptime = -1;
-
-    Cpu cpu = null;
+    double loadAverage = -1;
 
     Mem mem = null;
 
@@ -54,70 +45,27 @@ public class OsStats implements Streamable, ToXContent {
     OsStats() {
     }
 
-    public long timestamp() {
-        return timestamp;
-    }
-
     public long getTimestamp() {
-        return timestamp();
+        return timestamp;
     }
 
-    public double[] loadAverage() {
+    public double getLoadAverage() {
         return loadAverage;
     }
 
-    public double[] getLoadAverage() {
-        return loadAverage();
-    }
-
-    public TimeValue uptime() {
-        return new TimeValue(uptime, TimeUnit.SECONDS);
-    }
-
-    public TimeValue getUptime() {
-        return uptime();
-    }
-
-    public Cpu cpu() {
-        return this.cpu;
-    }
-
-    public Cpu getCpu() {
-        return cpu();
-    }
-
-    public Mem mem() {
-        return this.mem;
-    }
 
     public Mem getMem() {
-        return mem();
-    }
-
-    public Swap swap() {
-        return this.swap;
+        return mem;
     }
 
     public Swap getSwap() {
-        return swap();
+        return swap;
     }
 
     static final class Fields {
         static final XContentBuilderString OS = new XContentBuilderString("os");
         static final XContentBuilderString TIMESTAMP = new XContentBuilderString("timestamp");
-        static final XContentBuilderString UPTIME = new XContentBuilderString("uptime");
-        static final XContentBuilderString UPTIME_IN_MILLIS = new XContentBuilderString("uptime_in_millis");
         static final XContentBuilderString LOAD_AVERAGE = new XContentBuilderString("load_average");
-        static final XContentBuilderString LOAD_AVERAGE_1m = new XContentBuilderString("1m");
-        static final XContentBuilderString LOAD_AVERAGE_5m = new XContentBuilderString("5m");
-        static final XContentBuilderString LOAD_AVERAGE_15m = new XContentBuilderString("15m");
-
-        static final XContentBuilderString CPU = new XContentBuilderString("cpu");
-        static final XContentBuilderString SYS = new XContentBuilderString("sys");
-        static final XContentBuilderString USER = new XContentBuilderString("user");
-        static final XContentBuilderString USAGE = new XContentBuilderString("usage");
-        static final XContentBuilderString IDLE = new XContentBuilderString("idle");
-        static final XContentBuilderString STOLEN = new XContentBuilderString("stolen");
 
         static final XContentBuilderString MEM = new XContentBuilderString("mem");
         static final XContentBuilderString SWAP = new XContentBuilderString("swap");
@@ -125,69 +73,37 @@ public class OsStats implements Streamable, ToXContent {
         static final XContentBuilderString FREE_IN_BYTES = new XContentBuilderString("free_in_bytes");
         static final XContentBuilderString USED = new XContentBuilderString("used");
         static final XContentBuilderString USED_IN_BYTES = new XContentBuilderString("used_in_bytes");
+        static final XContentBuilderString TOTAL = new XContentBuilderString("total");
+        static final XContentBuilderString TOTAL_IN_BYTES = new XContentBuilderString("total_in_bytes");
 
         static final XContentBuilderString FREE_PERCENT = new XContentBuilderString("free_percent");
         static final XContentBuilderString USED_PERCENT = new XContentBuilderString("used_percent");
 
-        static final XContentBuilderString ACTUAL_FREE = new XContentBuilderString("actual_free");
-        static final XContentBuilderString ACTUAL_FREE_IN_BYTES = new XContentBuilderString("actual_free_in_bytes");
-        static final XContentBuilderString ACTUAL_USED = new XContentBuilderString("actual_used");
-        static final XContentBuilderString ACTUAL_USED_IN_BYTES = new XContentBuilderString("actual_used_in_bytes");
     }
 
     @Override
     public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
         builder.startObject(Fields.OS);
-        builder.field(Fields.TIMESTAMP, timestamp);
-
-        if (uptime != -1) {
-            builder.timeValueField(Fields.UPTIME_IN_MILLIS, Fields.UPTIME, uptime);
-        }
-
-        if (loadAverage.length > 0) {
-            if (params.param("load_average_format", "array").equals("hash")) {
-                builder.startObject(Fields.LOAD_AVERAGE);
-                builder.field(Fields.LOAD_AVERAGE_1m, loadAverage[0]);
-                builder.field(Fields.LOAD_AVERAGE_5m, loadAverage[1]);
-                builder.field(Fields.LOAD_AVERAGE_15m, loadAverage[2]);
-                builder.endObject();
-            } else {
-                builder.startArray(Fields.LOAD_AVERAGE);
-                for (double value : loadAverage) {
-                    builder.value(value);
-                }
-                builder.endArray();
-            }
-        }
-
-        if (cpu != null) {
-            builder.startObject(Fields.CPU);
-            builder.field(Fields.SYS, cpu.sys());
-            builder.field(Fields.USER, cpu.user());
-            builder.field(Fields.IDLE, cpu.idle());
-            builder.field(Fields.USAGE, cpu.user() + cpu.sys());
-            builder.field(Fields.STOLEN, cpu.stolen());
-            builder.endObject();
-        }
+        builder.field(Fields.TIMESTAMP, getTimestamp());
+        builder.field(Fields.LOAD_AVERAGE, getLoadAverage());
 
         if (mem != null) {
             builder.startObject(Fields.MEM);
-            builder.byteSizeField(Fields.FREE_IN_BYTES, Fields.FREE, mem.free);
-            builder.byteSizeField(Fields.USED_IN_BYTES, Fields.USED, mem.used);
+            builder.byteSizeField(Fields.TOTAL_IN_BYTES, Fields.TOTAL, mem.getTotal());
+            builder.byteSizeField(Fields.FREE_IN_BYTES, Fields.FREE, mem.getFree());
+            builder.byteSizeField(Fields.USED_IN_BYTES, Fields.USED, mem.getUsed());
 
-            builder.field(Fields.FREE_PERCENT, mem.freePercent());
-            builder.field(Fields.USED_PERCENT, mem.usedPercent());
-
-            builder.byteSizeField(Fields.ACTUAL_FREE_IN_BYTES, Fields.ACTUAL_FREE, mem.actualFree);
-            builder.byteSizeField(Fields.ACTUAL_USED_IN_BYTES, Fields.ACTUAL_USED, mem.actualUsed);
+            builder.field(Fields.FREE_PERCENT, mem.getFreePercent());
+            builder.field(Fields.USED_PERCENT, mem.getUsedPercent());
 
             builder.endObject();
         }
 
         if (swap != null) {
             builder.startObject(Fields.SWAP);
-            builder.byteSizeField(Fields.USED_IN_BYTES, Fields.USED, swap.used);
-            builder.byteSizeField(Fields.FREE_IN_BYTES, Fields.FREE, swap.free);
+            builder.byteSizeField(Fields.TOTAL_IN_BYTES, Fields.TOTAL, swap.getTotal());
+            builder.byteSizeField(Fields.FREE_IN_BYTES, Fields.FREE, swap.getFree());
+            builder.byteSizeField(Fields.USED_IN_BYTES, Fields.USED, swap.getUsed());
             builder.endObject();
         }
 
@@ -204,14 +120,7 @@ public class OsStats implements Streamable, ToXContent {
     @Override
     public void readFrom(StreamInput in) throws IOException {
         timestamp = in.readVLong();
-        loadAverage = new double[in.readVInt()];
-        for (int i = 0; i < loadAverage.length; i++) {
-            loadAverage[i] = in.readDouble();
-        }
-        uptime = in.readLong();
-        if (in.readBoolean()) {
-            cpu = Cpu.readCpu(in);
-        }
+        loadAverage = in.readDouble();
         if (in.readBoolean()) {
             mem = Mem.readMem(in);
         }
@@ -223,17 +132,7 @@ public class OsStats implements Streamable, ToXContent {
     @Override
     public void writeTo(StreamOutput out) throws IOException {
         out.writeVLong(timestamp);
-        out.writeVInt(loadAverage.length);
-        for (double val : loadAverage) {
-            out.writeDouble(val);
-        }
-        out.writeLong(uptime);
-        if (cpu == null) {
-            out.writeBoolean(false);
-        } else {
-            out.writeBoolean(true);
-            cpu.writeTo(out);
-        }
+        out.writeDouble(loadAverage);
         if (mem == null) {
             out.writeBoolean(false);
         } else {
@@ -250,23 +149,19 @@ public class OsStats implements Streamable, ToXContent {
 
     public static class Swap implements Streamable {
 
+        long total = -1;
         long free = -1;
-        long used = -1;
-
-        public ByteSizeValue free() {
-            return new ByteSizeValue(free);
-        }
 
         public ByteSizeValue getFree() {
-            return free();
+            return new ByteSizeValue(free);
         }
 
-        public ByteSizeValue used() {
-            return new ByteSizeValue(used);
+        public ByteSizeValue getUsed() {
+            return new ByteSizeValue(total - free);
         }
 
-        public ByteSizeValue getUsed() {
-            return used();
+        public ByteSizeValue getTotal() {
+            return new ByteSizeValue(total);
         }
 
         public static Swap readSwap(StreamInput in) throws IOException {
@@ -277,25 +172,21 @@ public class OsStats implements Streamable, ToXContent {
 
         @Override
         public void readFrom(StreamInput in) throws IOException {
+            total = in.readLong();
             free = in.readLong();
-            used = in.readLong();
         }
 
         @Override
         public void writeTo(StreamOutput out) throws IOException {
+            out.writeLong(total);
             out.writeLong(free);
-            out.writeLong(used);
         }
     }
 
     public static class Mem implements Streamable {
 
+        long total = -1;
         long free = -1;
-        short freePercent = -1;
-        long used = -1;
-        short usedPercent = -1;
-        long actualFree = -1;
-        long actualUsed = -1;
 
         public static Mem readMem(StreamInput in) throws IOException {
             Mem mem = new Mem();
@@ -305,136 +196,39 @@ public class OsStats implements Streamable, ToXContent {
 
         @Override
         public void readFrom(StreamInput in) throws IOException {
+            total = in.readLong();
             free = in.readLong();
-            freePercent = in.readShort();
-            used = in.readLong();
-            usedPercent = in.readShort();
-            actualFree = in.readLong();
-            actualUsed = in.readLong();
         }
 
         @Override
         public void writeTo(StreamOutput out) throws IOException {
+            out.writeLong(total);
             out.writeLong(free);
-            out.writeShort(freePercent);
-            out.writeLong(used);
-            out.writeShort(usedPercent);
-            out.writeLong(actualFree);
-            out.writeLong(actualUsed);
         }
 
-        public ByteSizeValue used() {
-            return new ByteSizeValue(used);
+        public ByteSizeValue getTotal() {
+            return new ByteSizeValue(total);
         }
 
         public ByteSizeValue getUsed() {
-            return used();
-        }
-
-        public short usedPercent() {
-            return usedPercent;
+            return new ByteSizeValue(total - free);
         }
 
         public short getUsedPercent() {
-            return usedPercent();
-        }
-
-        public ByteSizeValue free() {
-            return new ByteSizeValue(free);
+            return calculatePercentage(getUsed().bytes(), getTotal().bytes());
         }
 
         public ByteSizeValue getFree() {
-            return free();
-        }
-
-        public short freePercent() {
-            return freePercent;
+            return new ByteSizeValue(free);
         }
 
         public short getFreePercent() {
-            return freePercent();
-        }
-
-        public ByteSizeValue actualFree() {
-            return new ByteSizeValue(actualFree);
-        }
-
-        public ByteSizeValue getActualFree() {
-            return actualFree();
-        }
-
-        public ByteSizeValue actualUsed() {
-            return new ByteSizeValue(actualUsed);
-        }
-
-        public ByteSizeValue getActualUsed() {
-            return actualUsed();
+            return calculatePercentage(getFree().bytes(), getTotal().bytes());
         }
     }
 
-    public static class Cpu implements Streamable {
-
-        short sys = -1;
-        short user = -1;
-        short idle = -1;
-        short stolen = -1;
-
-        Cpu() {
-
-        }
-
-        public static Cpu readCpu(StreamInput in) throws IOException {
-            Cpu cpu = new Cpu();
-            cpu.readFrom(in);
-            return cpu;
-        }
-
-        @Override
-        public void readFrom(StreamInput in) throws IOException {
-            sys = in.readShort();
-            user = in.readShort();
-            idle = in.readShort();
-            stolen = in.readShort();
-        }
-
-        @Override
-        public void writeTo(StreamOutput out) throws IOException {
-            out.writeShort(sys);
-            out.writeShort(user);
-            out.writeShort(idle);
-            out.writeShort(stolen);
-        }
-
-        public short sys() {
-            return sys;
-        }
-
-        public short getSys() {
-            return sys();
-        }
-
-        public short user() {
-            return user;
-        }
-
-        public short getUser() {
-            return user();
-        }
-
-        public short idle() {
-            return idle;
-        }
-
-        public short getIdle() {
-            return idle();
-        }
-
-        public short stolen() {
-            return stolen;
-        }
-
-        public short getStolen() {
-            return stolen();
-        }
+    private static short calculatePercentage(long used, long max) {
+        return max <= 0 ? 0 : (short) (Math.round((100d * used) / max));
     }
+
 }

+ 4 - 7
core/src/main/java/org/elasticsearch/rest/action/cat/RestNodesAction.java

@@ -51,7 +51,6 @@ import org.elasticsearch.indices.NodeIndicesStats;
 import org.elasticsearch.monitor.fs.FsInfo;
 import org.elasticsearch.monitor.jvm.JvmInfo;
 import org.elasticsearch.monitor.jvm.JvmStats;
-import org.elasticsearch.monitor.os.OsInfo;
 import org.elasticsearch.monitor.os.OsStats;
 import org.elasticsearch.monitor.process.ProcessStats;
 import org.elasticsearch.rest.*;
@@ -219,8 +218,6 @@ public class RestNodesAction extends AbstractCatAction {
             NodeStats stats = nodesStats.getNodesMap().get(node.id());
 
             JvmInfo jvmInfo = info == null ? null : info.getJvm();
-            OsInfo osInfo = info == null ? null : info.getOs();
-
             JvmStats jvmStats = stats == null ? null : stats.getJvm();
             FsInfo fsInfo = stats == null ? null : stats.getFs();
             OsStats osStats = stats == null ? null : stats.getOs();
@@ -246,14 +243,14 @@ public class RestNodesAction extends AbstractCatAction {
             table.addCell(jvmStats == null ? null : jvmStats.getMem().getHeapUsed());
             table.addCell(jvmStats == null ? null : jvmStats.getMem().getHeapUsedPercent());
             table.addCell(jvmInfo == null ? null : jvmInfo.getMem().getHeapMax());
-            table.addCell(osStats == null ? null : osStats.getMem() == null ? null : osStats.getMem().used());
-            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(osStats == null ? null : osStats.getMem() == null ? null : osStats.getMem().getUsed());
+            table.addCell(osStats == null ? null : osStats.getMem() == null ? null : osStats.getMem().getUsedPercent());
+            table.addCell(osStats == null ? null : osStats.getMem() == null ? null : osStats.getMem().getTotal());
             table.addCell(processStats == null ? null : processStats.getOpenFileDescriptors());
             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(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" : "-");
             table.addCell(masterId == null ? "x" : masterId.equals(node.id()) ? "*" : node.masterNode() ? "m" : "-");

+ 90 - 0
core/src/test/java/org/elasticsearch/benchmark/monitor/os/OsProbeBenchmark.java

@@ -0,0 +1,90 @@
+/*
+ * 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.os;
+
+import org.elasticsearch.common.logging.ESLogger;
+import org.elasticsearch.common.logging.ESLoggerFactory;
+import org.elasticsearch.monitor.os.OsProbe;
+
+public class OsProbeBenchmark {
+
+    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 OS probe");
+        OsProbe probe = OsProbe.getInstance();
+
+        logger.info("--> warming up...");
+        for (int i = 0; i < ITERATIONS; i++) {
+            probe.getTotalPhysicalMemorySize();
+            probe.getFreePhysicalMemorySize();
+            probe.getTotalSwapSpaceSize();
+            probe.getFreeSwapSpaceSize();
+            probe.getSystemLoadAverage();
+        }
+        logger.info("--> warmed up");
+
+
+
+
+        logger.info("--> testing 'getTotalPhysicalMemorySize' method...");
+        long start = System.currentTimeMillis();
+        for (int i = 0; i < ITERATIONS; i++) {
+            probe.getTotalPhysicalMemorySize();
+        }
+        long elapsed = System.currentTimeMillis() - start;
+        logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS));
+
+        logger.info("--> testing 'getFreePhysicalMemorySize' method...");
+        start = System.currentTimeMillis();
+        for (int i = 0; i < ITERATIONS; i++) {
+            probe.getFreePhysicalMemorySize();
+        }
+        elapsed = System.currentTimeMillis() - start;
+        logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS));
+
+        logger.info("--> testing 'getTotalSwapSpaceSize' method...");
+        start = System.currentTimeMillis();
+        for (int i = 0; i < ITERATIONS; i++) {
+            probe.getTotalSwapSpaceSize();
+        }
+        elapsed = System.currentTimeMillis() - start;
+        logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS));
+
+        logger.info("--> testing 'getFreeSwapSpaceSize' method...");
+        start = System.currentTimeMillis();
+        for (int i = 0; i < ITERATIONS; i++) {
+            probe.getFreeSwapSpaceSize();
+        }
+        elapsed = System.currentTimeMillis() - start;
+        logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS));
+
+        logger.info("--> testing 'getSystemLoadAverage' method...");
+        start = System.currentTimeMillis();
+        for (int i = 0; i < ITERATIONS; i++) {
+            probe.getSystemLoadAverage();
+        }
+        elapsed = System.currentTimeMillis() - start;
+        logger.info("--> total [{}] ms, avg [{}] ms", elapsed, (elapsed / (double)ITERATIONS));
+    }
+}

+ 3 - 2
core/src/test/java/org/elasticsearch/benchmark/monitor/process/ProcessProbeBenchmark.java

@@ -19,6 +19,7 @@
 
 package org.elasticsearch.benchmark.monitor.process;
 
+import org.elasticsearch.common.SuppressForbidden;
 import org.elasticsearch.common.logging.ESLogger;
 import org.elasticsearch.common.logging.ESLoggerFactory;
 import org.elasticsearch.monitor.process.ProcessProbe;
@@ -26,6 +27,7 @@ import org.elasticsearch.monitor.process.ProcessProbe;
 import java.lang.management.ManagementFactory;
 import java.lang.management.ThreadMXBean;
 
+@SuppressForbidden(reason = "use of om.sun.management.ThreadMXBean to compare performance")
 public class ProcessProbeBenchmark {
 
     private static final int ITERATIONS = 100_000;
@@ -108,7 +110,6 @@ public class ProcessProbeBenchmark {
         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;
@@ -125,6 +126,6 @@ public class ProcessProbeBenchmark {
             logger.info("--> execution time [total: {} ms, avg: {} ms] for {} iterations with average result of {}",
                     elapsed, (elapsed / (double)ITERATIONS), ITERATIONS, (sum / (double)ITERATIONS));
 
-        }*/
+        }
     }
 }

+ 63 - 0
core/src/test/java/org/elasticsearch/monitor/os/OsProbeTests.java

@@ -0,0 +1,63 @@
+/*
+ * 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.os;
+
+import org.apache.lucene.util.Constants;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.test.ElasticsearchTestCase;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.*;
+
+public class OsProbeTests extends ElasticsearchTestCase {
+
+    OsProbe probe = OsProbe.getInstance();
+
+    @Test
+    public void testOsInfo() {
+        OsInfo info = probe.osInfo();
+        assertNotNull(info);
+        assertThat(info.getRefreshInterval(), anyOf(equalTo(-1L), greaterThanOrEqualTo(0L)));
+        assertThat(info.getName(), equalTo(Constants.OS_NAME));
+        assertThat(info.getArch(), equalTo(Constants.OS_ARCH));
+        assertThat(info.getVersion(), equalTo(Constants.OS_VERSION));
+        assertThat(info.getAvailableProcessors(), equalTo(Runtime.getRuntime().availableProcessors()));
+    }
+
+    @Test
+    public void testOsStats() {
+        OsStats stats = probe.osStats();
+        assertNotNull(stats);
+        assertThat(stats.getTimestamp(), greaterThan(0L));
+        assertThat(stats.getLoadAverage(), anyOf(equalTo((double) -1), greaterThanOrEqualTo((double) 0)));
+
+        assertNotNull(stats.getMem());
+        assertThat(stats.getMem().getTotal().bytes(), anyOf(equalTo(-1L), greaterThan(0L)));
+        assertThat(stats.getMem().getFree().bytes(), anyOf(equalTo(-1L), greaterThan(0L)));
+        assertThat(stats.getMem().getFreePercent(), allOf(greaterThanOrEqualTo((short) 0), lessThanOrEqualTo((short) 100)));
+        assertThat(stats.getMem().getUsed().bytes(), anyOf(equalTo(-1L), greaterThanOrEqualTo(0L)));
+        assertThat(stats.getMem().getUsedPercent(), allOf(greaterThanOrEqualTo((short) 0), lessThanOrEqualTo((short) 100)));
+
+        assertNotNull(stats.getSwap());
+        assertThat(stats.getSwap().getTotal().bytes(), anyOf(equalTo(-1L), greaterThan(0L)));
+        assertThat(stats.getSwap().getFree().bytes(), anyOf(equalTo(-1L), greaterThan(0L)));
+        assertThat(stats.getSwap().getUsed().bytes(), anyOf(equalTo(-1L), greaterThanOrEqualTo(0L)));
+    }
+}

+ 22 - 2
docs/reference/cluster/nodes-info.asciidoc

@@ -32,6 +32,27 @@ 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]
+[[os-info]]
+==== Operating System information
+
+The `os` flag can be set to retrieve information that concern
+the operating system:
+
+`os.refresh_interval_in_millis`::
+	Refresh interval for the OS statistics
+
+`os.name`::
+	Name of the operating system (ex: Linux, Windows, Mac OS X)
+
+`os.arch`::
+	Name of the JVM architecture (ex: amd64, x86)
+
+`os.version`::
+	Version of the operating system
+
+`os.available_processors`::
+	Number of processors available to the Java virtual machine
 
 [float]
 [[process-info]]
@@ -41,7 +62,7 @@ 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.
+	Refresh interval for the process statistics
 
 `process.id`::
 	Process identifier (PID)
@@ -49,7 +70,6 @@ the current running process:
 `process.mlockall`::
 	Indicates if the process address space has been successfully locked in memory
 
-
 [float]
 [[plugins-info]]
 ==== Plugins information

+ 53 - 14
docs/reference/cluster/nodes-stats.asciidoc

@@ -40,6 +40,7 @@ of `indices`, `os`, `process`, `jvm`, `transport`, `http`,
 
 `os`::
 	Operating system stats, load average, cpu, mem, swap
+	(see <<os-stats,OS statistics>>)
 
 `process`::
 	Process statistics, memory consumption, cpu usage, open
@@ -79,41 +80,79 @@ information that concern the file system:
 `fs.timestamp`::
 	Last time the file stores statistics have been refreshed
 
-`os.total.total_in_bytes`::
+`fs.total.total_in_bytes`::
 	Total size (in bytes) of all file stores
 
-`os.total.free_in_bytes`::
+`fs.total.free_in_bytes`::
 	Total number of unallocated bytes in all file stores
 
-`os.total.available_in_bytes`::
-	Totalnumber of bytes available to this Java virtual machine on all file stores
+`fs.total.available_in_bytes`::
+	Total number of bytes available to this Java virtual machine on all file stores
 
-`os.data`::
+`fs.data`::
 	List of all file stores
 
-`os.data.path`::
+`fs.data.path`::
 	Path to the file store
 
-`os.data.mount`::
+`fs.data.mount`::
 	Mount point of the file store (ex: /dev/sda2)
 
-`os.data.type`::
+`fs.data.type`::
 	Type of the file store (ex: ext4)
 
-`os.data.total_in_bytes`::
-	Total size (in bytes) of thefile store
+`fs.data.total_in_bytes`::
+	Total size (in bytes) of the file store
 
-`os.data.free_in_bytes`::
+`fs.data.free_in_bytes`::
 	Total number of unallocated bytes in the file store
 
-`os.data.available_in_bytes`::
-	Totalnumber of bytes available to this Java virtual machine on this file store
+`fs.data.available_in_bytes`::
+	Total number of bytes available to this Java virtual machine on this file store
 
-`os.data.spins` (Linux only)::
+`fs.data.spins` (Linux only)::
 	Indicates if the file store is backed by spinning storage.
 	`null` means we could not determine it, `true` means the device possibly spins
 	 and `false` means it does not (ex: solid-state disks).
 
+[float]
+[[os-stats]]
+==== Operating System statistics
+
+The `os` flag can be set to retrieve statistics that concern
+the operating system:
+
+`os.timestamp`::
+	Last time the operating system statistics have been refreshed
+
+`os.load_average`::
+	System load average for the last minute
+
+`os.mem.total_in_bytes`::
+	Total amount of physical memory in bytes
+
+`os.mem.free_in_bytes`::
+	Amount of free physical memory in bytes
+
+`os.mem.free_percent`::
+	Percentage of free memory
+
+`os.mem.used_in_bytes`::
+	Amount of used physical memory in bytes
+
+`os.mem.used_percent`::
+	Percentage of used memory
+
+`os.swap.total_in_bytes`::
+	Total amount of swap space in bytes
+
+`os.swap.free_in_bytes`::
+	Amount of free swap space in bytes
+
+`os.swap.used_in_bytes`::
+	Amount of used swap space in bytes
+
+
 [float]
 [[process-stats]]
 ==== Process statistics