[ 
https://issues.apache.org/jira/browse/SCB-1017?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16691256#comment-16691256
 ] 

ASF GitHub Bot commented on SCB-1017:
-------------------------------------

liubao68 closed pull request #987: [SCB-1017]add os cpu net info in the metrics 
with linux os
URL: https://github.com/apache/servicecomb-java-chassis/pull/987
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
index ae545eb0e..e38080460 100644
--- 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
+++ 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
@@ -148,7 +148,7 @@ public static void run() {
         for (String metricLine : metricLines) {
           if (!metricLine.startsWith("#")) {
             String[] metricKeyAndValue = metricLine.split(" ");
-            if (!metricKeyAndValue[0].startsWith("jvm")) {
+            if (!metricKeyAndValue[0].startsWith("jvm") && 
!metricKeyAndValue[0].startsWith("os")) {
               if (Double.parseDouble(metricKeyAndValue[1]) < 0) {
                 TestMgr.check("true", "false");
                 break;
diff --git 
a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java
 
b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java
index 6024b6d29..c03061ab8 100644
--- 
a/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java
+++ 
b/foundations/foundation-common/src/main/java/org/apache/servicecomb/foundation/common/net/NetUtils.java
@@ -234,4 +234,14 @@ public static boolean canTcpListen(InetAddress address, 
int port) {
       return false;
     }
   }
+
+  public static String humanReadableBytes(long bytes) {
+    int unit = 1024;
+    if (bytes < unit) {
+      return bytes + " B";
+    }
+    int exp = (int) (Math.log(bytes) / Math.log(unit));
+    char pre = "KMGTPE".charAt(exp - 1);
+    return String.format("%.3f %cB", bytes / Math.pow(unit, exp), pre);
+  }
 }
diff --git 
a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java
 
b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java
index a9f8fba66..15c6a9ed5 100644
--- 
a/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java
+++ 
b/foundations/foundation-common/src/test/java/org/apache/servicecomb/foundation/common/net/TestNetUtils.java
@@ -108,6 +108,44 @@ public void testCanTcpListenYes() throws IOException {
     Assert.assertTrue(NetUtils.canTcpListen(address, port));
   }
 
+  @Test
+  public void humanReadableBytes() throws IOException {
+    Assert.assertEquals("0 B", NetUtils.humanReadableBytes(0L));
+    Assert.assertEquals("1 B", NetUtils.humanReadableBytes(1L));
+    Assert.assertEquals("1023 B", NetUtils.humanReadableBytes(1023L));
+
+    Assert.assertEquals("1.000 KB", NetUtils.humanReadableBytes(1024L));
+    Assert.assertEquals("1.001 KB", NetUtils.humanReadableBytes(1025L));
+    Assert.assertEquals("1023.999 KB", NetUtils.humanReadableBytes(1024L * 
1024 - 1));
+
+    Assert.assertEquals("1.000 MB", NetUtils.humanReadableBytes(1024L * 1024));
+    Assert.assertEquals("1.000 MB", NetUtils.humanReadableBytes(1024L * 1024 + 
1));
+    Assert.assertEquals("1.001 MB", NetUtils.humanReadableBytes(1024L * 1024 + 
1024));
+    Assert.assertEquals("1023.999 MB", NetUtils.humanReadableBytes(1024L * 
1024 * 1024 - 1024));
+    Assert.assertEquals("1024.000 MB", NetUtils.humanReadableBytes(1024L * 
1024 * 1024 - 1));
+
+    Assert.assertEquals("1.000 GB", NetUtils.humanReadableBytes(1024L * 1024 * 
1024));
+    Assert.assertEquals("1.000 GB", NetUtils.humanReadableBytes(1024L * 1024 * 
1024 + 1));
+    Assert.assertEquals("1.000 GB", NetUtils.humanReadableBytes(1024L * 1024 * 
1024 + 1024));
+    Assert.assertEquals("1023.999 GB", NetUtils.humanReadableBytes(1024L * 
1024 * 1024 * 1024 - 1024 * 1024));
+    Assert.assertEquals("1024.000 GB", NetUtils.humanReadableBytes(1024L * 
1024 * 1024 * 1024 - 1024));
+    Assert.assertEquals("1.000 TB", NetUtils.humanReadableBytes(1024L * 1024 * 
1024 * 1024));
+    Assert.assertEquals("1.001 TB", NetUtils.humanReadableBytes(1024L * 1024 * 
1024 * 1024 + 1024 * 1024 * 1024));
+    Assert.assertEquals("1023.999 TB",
+        NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 - 1024L 
* 1024 * 1024));
+
+    Assert.assertEquals("1.000 PB", NetUtils.humanReadableBytes(1024L * 1024 * 
1024 * 1024 * 1024));
+    Assert.assertEquals("1.001 PB",
+        NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 + 1024L 
* 1024 * 1024 * 1024));
+    Assert.assertEquals("1023.999 PB",
+        NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 * 1024 - 
1024L * 1024 * 1024 * 1024));
+
+    Assert.assertEquals("1.000 EB", NetUtils.humanReadableBytes(1024L * 1024 * 
1024 * 1024 * 1024 * 1024));
+    Assert.assertEquals("1.001 EB",
+        NetUtils.humanReadableBytes(1024L * 1024 * 1024 * 1024 * 1024 * 1024 + 
1024L * 1024 * 1024 * 1024 * 1024));
+    Assert.assertEquals("8.000 EB", 
NetUtils.humanReadableBytes(Long.MAX_VALUE));
+  }
+
   @Test
   public void testGetHostName() {
     Assert.assertNotEquals(null, NetUtils.getHostName());
diff --git 
a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrap.java
 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrap.java
index 7f13bf17c..318097313 100644
--- 
a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrap.java
+++ 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/MetricsBootstrap.java
@@ -33,6 +33,7 @@
 import com.netflix.spectator.api.Meter;
 
 public class MetricsBootstrap {
+
   private CompositeRegistry globalRegistry;
 
   private EventBus eventBus;
@@ -73,12 +74,13 @@ protected void loadMetricsInitializers() {
 
   protected void startPoll() {
     executorService.scheduleAtFixedRate(this::pollMeters,
-        0,
+        config.getMsPollInterval(),
         config.getMsPollInterval(),
         TimeUnit.MILLISECONDS);
   }
 
   protected void pollMeters() {
+    eventBus.post(new PollEvent(config.getMsPollInterval()));
     List<Meter> meters = Lists.newArrayList(globalRegistry.iterator());
     // must collect measurements
     // otherwise if there is no any period publisher, normal publisher maybe 
get NaN values 
@@ -86,6 +88,7 @@ protected void pollMeters() {
     for (Meter meter : meters) {
       meter.measure().forEach(measurements::add);
     }
+
     PolledEvent event = new PolledEvent(meters, measurements);
 
     eventBus.post(event);
diff --git 
a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PollEvent.java
 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PollEvent.java
new file mode 100644
index 000000000..80a2055b5
--- /dev/null
+++ 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/PollEvent.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.servicecomb.foundation.metrics;
+
+/**
+ * give not standard meters to calc measurement , eg : cpu usage, net 
throughput, and so on
+ */
+public class PollEvent {
+  private final long msPollInterval;
+
+  public PollEvent(long msPollInterval) {
+    this.msPollInterval = msPollInterval;
+  }
+
+  public long getMsPollInterval() {
+    return msPollInterval;
+  }
+}
diff --git 
a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/DefaultTagFinder.java
 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/DefaultTagFinder.java
index 74601f3b9..dc731a846 100644
--- 
a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/DefaultTagFinder.java
+++ 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/DefaultTagFinder.java
@@ -21,10 +21,22 @@
 public class DefaultTagFinder implements TagFinder {
   private String tagKey;
 
+  private boolean skipOnNull;
+
   public DefaultTagFinder(String tagKey) {
     this.tagKey = tagKey;
   }
 
+  public DefaultTagFinder(String tagKey, boolean skipOnNull) {
+    this.tagKey = tagKey;
+    this.skipOnNull = skipOnNull;
+  }
+
+  @Override
+  public boolean skipOnNull() {
+    return skipOnNull;
+  }
+
   @Override
   public String getTagKey() {
     return tagKey;
diff --git 
a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java
 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java
index 1a07720aa..a342f34fc 100644
--- 
a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java
+++ 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java
@@ -55,6 +55,9 @@ public void from(Iterable<Measurement> measurements, 
MeasurementGroupConfig grou
       for (TagFinder tagFinder : tagFinders) {
         Tag tag = tagFinder.find(id.tags());
         if (tag == null) {
+          if (tagFinder.skipOnNull()) {
+            return;
+          }
           throw new IllegalStateException(
               String.format("tag key \"%s\" not exist in %s",
                   tagFinder.getTagKey(),
diff --git 
a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TagFinder.java
 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TagFinder.java
index 40c26bb6d..0762afb8d 100644
--- 
a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TagFinder.java
+++ 
b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TagFinder.java
@@ -33,6 +33,10 @@ static TagFinder build(Object obj) {
             (obj == null ? "null" : obj.getClass().getName()));
   }
 
+  default boolean skipOnNull() {
+    return false;
+  }
+
   String getTagKey();
 
   // read target tag from tags
diff --git 
a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/TestMetricsBootstrap.java
 
b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/TestMetricsBootstrap.java
index 50cb30c72..c22315a07 100644
--- 
a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/TestMetricsBootstrap.java
+++ 
b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/TestMetricsBootstrap.java
@@ -85,7 +85,13 @@ public void pollMeters(@Mocked Meter meter, @Mocked 
Measurement measurement,
     bootstrap.start(globalRegistry, eventBus);
 
     PolledEvent result = new PolledEvent(null, null);
+    List<PollEvent> events = new ArrayList<>();
     eventBus.register(new Object() {
+      @Subscribe
+      public void onPollEvent(PollEvent pollEvent) {
+        events.add(pollEvent);
+      }
+
       @Subscribe
       public void onEvent(PolledEvent event) {
         result.setMeters(event.getMeters());
@@ -95,7 +101,7 @@ public void onEvent(PolledEvent event) {
 
     bootstrap.pollMeters();
     bootstrap.shutdown();
-
+    Assert.assertEquals(1, events.size());
     Assert.assertEquals(meters, result.getMeters());
     Assert.assertThat(result.getMeasurements(), 
Matchers.contains(measurement));
   }
diff --git 
a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java
 
b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java
index e568c67e1..219369603 100644
--- 
a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java
+++ 
b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java
@@ -73,6 +73,16 @@ public void from() {
     Assert.assertEquals(0d, tree.findChild("id_notCare").summary(), 0);
   }
 
+  @Test
+  public void from_withSkipOnNull() {
+    try {
+      MeasurementGroupConfig config = new MeasurementGroupConfig("id", new 
DefaultTagFinder("notExist", true));
+      tree.from(registry.iterator(), config);
+    } catch (Exception e) {
+      Assert.fail("should not throw exception");
+    }
+  }
+
   @Test
   public void from_failed() {
     expectedException.expect(IllegalStateException.class);
diff --git 
a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestTagFinder.java
 
b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestTagFinder.java
index 1f74e1944..1f5551b04 100644
--- 
a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestTagFinder.java
+++ 
b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestTagFinder.java
@@ -39,6 +39,8 @@ public void buildFromString() {
   public void buildFromTagFinder() {
     TagFinder finder = new DefaultTagFinder("key");
     Assert.assertSame(finder, TagFinder.build(finder));
+    DefaultTagFinder tagFinder = new DefaultTagFinder("key", true);
+    Assert.assertSame(tagFinder, TagFinder.build(tagFinder));
   }
 
   @Test
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/OsMetersInitializer.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/OsMetersInitializer.java
new file mode 100644
index 000000000..f94cf1888
--- /dev/null
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/OsMetersInitializer.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.servicecomb.metrics.core;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig;
+import org.apache.servicecomb.foundation.metrics.MetricsInitializer;
+import org.apache.servicecomb.metrics.core.meter.os.OsMeter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.eventbus.EventBus;
+import com.netflix.spectator.api.CompositeRegistry;
+import com.netflix.spectator.api.Registry;
+
+public class OsMetersInitializer implements MetricsInitializer {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(OsMetersInitializer.class);
+
+  private OsMeter osMeter;
+
+  @Override
+  public void init(CompositeRegistry globalRegistry, EventBus eventBus, 
MetricsBootstrapConfig config) {
+    if (!SystemUtils.IS_OS_LINUX) {
+      LOGGER.info("only support linux os to collect cpu and net info");
+      return;
+    }
+    DefaultRegistryInitializer defaultRegistryInitializer = SPIServiceUtils
+        .getTargetService(MetricsInitializer.class, 
DefaultRegistryInitializer.class);
+    Registry registry = defaultRegistryInitializer.getRegistry();
+    osMeter = new OsMeter(registry, eventBus);
+    registry.register(osMeter);
+  }
+
+  public OsMeter getOsMeter() {
+    return osMeter;
+  }
+}
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java
new file mode 100644
index 000000000..d6e916e65
--- /dev/null
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.servicecomb.metrics.core.meter.os;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.netflix.spectator.api.Id;
+import com.netflix.spectator.api.Measurement;
+
+public class CpuMeter {
+  private static final Logger LOGGER = LoggerFactory.getLogger(CpuMeter.class);
+
+  private double rate;
+
+  private long lastTotalTime;
+
+  private long lastIdleTime;
+
+  private int cpuNum;
+
+  private Id id;
+
+  public CpuMeter(Id id) {
+    this.id = id;
+    this.cpuNum = Runtime.getRuntime().availableProcessors();
+    refreshCpu();
+    rate = 0.0;
+  }
+
+  public void calcMeasurements(List<Measurement> measurements, long timestap) {
+    refreshCpu();
+    measurements.add(new Measurement(id, timestap, rate));
+  }
+
+  /*
+   * unit : 1 jiffies = 10ms = 0.01 s
+   * more details :
+   * http://man7.org/linux/man-pages/man5/proc.5.html
+   * cpu  2445171 599297 353967 24490633 11242   0    10780    2993            
 0      0
+   * cpu  user    nice   system idle     iowait  irq  softirq  stealstolen     
 guest  guest_nice
+   * 0    1       2      3      4        5        6   7        8
+   * cpuTotal = user + nice + system + idle + iowait + irq + softirq + 
stealstolen
+   */
+  protected void refreshCpu() {
+    try {
+      File file = new File("/proc/stat");
+      //just use first line
+      String cpuStr = FileUtils.readLines(file, StandardCharsets.UTF_8).get(0);
+      String[] cpuInfo = cpuStr.trim().split("\\s+");
+      long idle = Long.parseLong(cpuInfo[4]);
+      long total = 0L;
+      for (int i = 1; i <= 8; i++) {
+        total += Long.parseLong(cpuInfo[i]);
+      }
+      //just check, make sure it's safe
+      if (total != lastTotalTime) {
+        rate = 1.0 - (double) (idle - lastIdleTime) / (total - lastTotalTime);
+        rate *= cpuNum;
+      }
+      lastTotalTime = total;
+      lastIdleTime = idle;
+    } catch (IOException e) {
+      LOGGER.error("Failed to read current cpu info.", e);
+    }
+  }
+
+  public double getRate() {
+    return rate;
+  }
+
+  public long getLastTotalTime() {
+    return lastTotalTime;
+  }
+
+  public long getLastIdleTime() {
+    return lastIdleTime;
+  }
+
+  public int getCpuNum() {
+    return cpuNum;
+  }
+
+  public Id getId() {
+    return id;
+  }
+}
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/NetMeter.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/NetMeter.java
new file mode 100644
index 000000000..1c1d59da9
--- /dev/null
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/NetMeter.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.servicecomb.metrics.core.meter.os;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.servicecomb.foundation.metrics.PollEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.netflix.spectator.api.BasicTag;
+import com.netflix.spectator.api.Id;
+import com.netflix.spectator.api.Measurement;
+import com.netflix.spectator.api.Tag;
+
+public class NetMeter {
+  private static final Logger LOGGER = LoggerFactory.getLogger(NetMeter.class);
+
+  public static final String STATISTIC = "statistic";
+
+  public static final String INTERFACE = "interface";
+
+  public static final Tag TAG_RECEIVE = new BasicTag(STATISTIC, "receive");
+
+  public static final Tag TAG_SEND = new BasicTag(STATISTIC, "send");
+
+  private final Id id;
+
+  private Map<String, InterfaceInfo> interfaceInfoMap = new 
ConcurrentHashMap<>();
+
+  public static class InterfaceInfo {
+
+    private final String name;
+
+    private Id sendId;
+
+    private Id receiveId;
+
+    //receive bytes
+    private long lastRxBytes;
+
+    //transmit bytes
+    private long lastTxBytes;
+
+    // bytes per second
+    private double sendRate;
+
+    private double receiveRate;
+
+    InterfaceInfo(Id id, String name) {
+      this.name = name;
+      id = id.withTag(INTERFACE, name);
+      this.sendId = id.withTag(TAG_SEND);
+      this.receiveId = id.withTag(TAG_RECEIVE);
+    }
+
+    public void update(String interfaceData, long interval) {
+      String[] netInfo = interfaceData.trim().split("\\s+");
+      long rxBytes = Long.parseLong(netInfo[0]);
+      long txBytes = Long.parseLong(netInfo[8]);
+      sendRate = (double) (txBytes - lastTxBytes) * 1000 / interval;
+      receiveRate = (double) (rxBytes - lastRxBytes) * 1000 / interval;
+      lastRxBytes = rxBytes;
+      lastTxBytes = txBytes;
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public long getLastRxBytes() {
+      return lastRxBytes;
+    }
+
+    public long getLastTxBytes() {
+      return lastTxBytes;
+    }
+
+    public double getSendRate() {
+      return sendRate;
+    }
+
+    public double getReceiveRate() {
+      return receiveRate;
+    }
+  }
+
+  public NetMeter(Id id) {
+    this.id = id;
+    refreshNet(1);
+    for (InterfaceInfo interfaceInfo : interfaceInfoMap.values()) {
+      interfaceInfo.sendRate = 0;
+      interfaceInfo.receiveRate = 0;
+    }
+  }
+
+  public void calcMeasurements(List<Measurement> measurements, long timestap, 
PollEvent pollEvent) {
+    refreshNet(pollEvent.getMsPollInterval());
+
+    for (InterfaceInfo interfaceInfo : interfaceInfoMap.values()) {
+      measurements.add(new Measurement(interfaceInfo.sendId, timestap, 
interfaceInfo.sendRate));
+      measurements.add(new Measurement(interfaceInfo.receiveId, timestap, 
interfaceInfo.receiveRate));
+    }
+  }
+
+  /*
+   * Inter-|   Receive                                                         
   |  Transmit
+   *  face |bytes      packets     errs drop fifo  frame      compressed 
multicast|bytes       packets     errs   drop  fifo colls carrier compressed
+   *  eth0: 2615248100 32148518    0    0    0     0          0          0     
    87333034794 21420267    0      0     0     0    0    0
+   *        0          1           2    3    4     5          6          7     
     8
+   */
+  protected void refreshNet(long interval) {
+    try {
+      File file = new File("/proc/net/dev");
+      List<String> netInfo = FileUtils.readLines(file, StandardCharsets.UTF_8);
+      //the first two lines is useless
+
+      Set<String> nameSet = new HashSet<>();
+      for (int i = 2; i < netInfo.size(); i++) {
+        String interfaceData = netInfo.get(i);
+        String[] strings = interfaceData.split(":");
+        if (strings.length != 2) {
+          LOGGER.warn(" there is something wrong with {} ", interfaceData);
+          continue;
+        }
+
+        String name = strings[0].trim();
+        nameSet.add(name);
+
+        InterfaceInfo interfaceInfo = interfaceInfoMap.computeIfAbsent(name, 
key -> new InterfaceInfo(id, key));
+        interfaceInfo.update(strings[1], interval);
+      }
+
+      // clear deleted interfaces
+      for (String interfaceName : interfaceInfoMap.keySet()) {
+        if (!nameSet.contains(interfaceName)) {
+          this.interfaceInfoMap.remove(interfaceName);
+        }
+      }
+    } catch (IOException e) {
+      LOGGER.error("Failed to read net info/", e);
+    }
+  }
+
+  public Map<String, InterfaceInfo> getInterfaceInfoMap() {
+    return interfaceInfoMap;
+  }
+}
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/OsMeter.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/OsMeter.java
new file mode 100644
index 000000000..961dbe047
--- /dev/null
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/OsMeter.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.servicecomb.metrics.core.meter.os;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.servicecomb.foundation.metrics.PollEvent;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import com.netflix.spectator.api.Id;
+import com.netflix.spectator.api.Measurement;
+import com.netflix.spectator.api.Meter;
+import com.netflix.spectator.api.Registry;
+
+/**
+ * name=os type=cpu value=10.0
+ * name=os type=net interface=eth0 statistic=send value=100
+ * name=os type=net interface=eth0 statistic=receive value=100
+ */
+public class OsMeter implements Meter {
+  public static final String OS_NAME = "os";
+
+  public static final String OS_TYPE = "type";
+
+  public static final String OS_TYPE_CPU = "cpu";
+
+  public static final String OS_TYPE_NET = "net";
+
+  private List<Measurement> measurements = new ArrayList<>();
+
+  private Id id;
+
+  private Registry registry;
+
+  private CpuMeter cpuMeter;
+
+  private NetMeter netMeter;
+
+  public OsMeter(Registry registry, EventBus eventBus) {
+    this.registry = registry;
+    this.id = registry.createId(OS_NAME);
+
+    cpuMeter = new CpuMeter(id.withTag(OS_TYPE, OS_TYPE_CPU));
+    netMeter = new NetMeter(id.withTag(OS_TYPE, OS_TYPE_NET));
+
+    eventBus.register(this);
+  }
+
+  @Subscribe
+  public void calcMeasurements(PollEvent pollEvent) {
+    final long now = registry.clock().wallTime();
+
+    final List<Measurement> tmpCpuMeasurements = new ArrayList<>();
+    cpuMeter.calcMeasurements(tmpCpuMeasurements, now);
+    netMeter.calcMeasurements(tmpCpuMeasurements, now, pollEvent);
+
+    measurements = tmpCpuMeasurements;
+  }
+
+  @Override
+  public Id id() {
+    return id;
+  }
+
+  @Override
+  public Iterable<Measurement> measure() {
+    return measurements;
+  }
+
+  @Override
+  public boolean hasExpired() {
+    return false;
+  }
+
+  public CpuMeter getCpuMeter() {
+    return cpuMeter;
+  }
+
+  public NetMeter getNetMeter() {
+    return netMeter;
+  }
+}
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java
index e9575fc65..6052f7eb9 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java
@@ -16,15 +16,22 @@
  */
 package org.apache.servicecomb.metrics.core.publish;
 
+import static 
org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine;
+
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.apache.servicecomb.foundation.common.net.NetUtils;
 import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig;
 import org.apache.servicecomb.foundation.metrics.MetricsInitializer;
 import org.apache.servicecomb.foundation.metrics.PolledEvent;
+import 
org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode;
+import 
org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree;
 import org.apache.servicecomb.foundation.vertx.VertxUtils;
 import 
org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst;
+import org.apache.servicecomb.metrics.core.meter.os.NetMeter;
+import org.apache.servicecomb.metrics.core.meter.os.OsMeter;
 import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel;
 import 
org.apache.servicecomb.metrics.core.publish.model.ThreadPoolPublishModel;
 import 
org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerf;
@@ -93,6 +100,7 @@ public void onPolledEvent(PolledEvent event) {
   }
 
   protected void printLog(List<Meter> meters) {
+
     StringBuilder sb = new StringBuilder();
     sb.append("\n");
 
@@ -102,7 +110,7 @@ protected void printLog(List<Meter> meters) {
     DefaultPublishModel model = factory.createDefaultPublishModel();
 
     printThreadPoolMetrics(model, sb);
-
+    printOsLog(factory.getTree(), sb);
     printConsumerLog(model, sb);
     printProducerLog(model, sb);
     printEdgeLog(model, sb);
@@ -110,6 +118,52 @@ protected void printLog(List<Meter> meters) {
     LOGGER.info(sb.toString());
   }
 
+  protected void printOsLog(MeasurementTree tree, StringBuilder sb) {
+    MeasurementNode osNode = tree.findChild(OsMeter.OS_NAME);
+    if (osNode == null || osNode.getMeasurements().isEmpty()) {
+      return;
+    }
+
+    appendLine(sb, "os:");
+    printCpuLog(sb, osNode);
+    printNetLog(sb, osNode);
+  }
+
+  private void printNetLog(StringBuilder sb, MeasurementNode osNode) {
+    MeasurementNode netNode = osNode.findChild(OsMeter.OS_TYPE_NET);
+    if (netNode == null || netNode.getMeasurements().isEmpty()) {
+      return;
+    }
+
+    appendLine(sb, "  net:");
+    appendLine(sb, "    send         receive      interface");
+
+    StringBuilder tmpSb = new StringBuilder();
+    for (MeasurementNode interfaceNode : netNode.getChildren().values()) {
+      double sendRate = 
interfaceNode.findChild(NetMeter.TAG_SEND.value()).summary();
+      double receiveRate = 
interfaceNode.findChild(NetMeter.TAG_RECEIVE.value()).summary();
+      if (sendRate == 0 && receiveRate == 0) {
+        continue;
+      }
+
+      appendLine(tmpSb, "    %-12s %-12s %s",
+          NetUtils.humanReadableBytes((long) sendRate),
+          NetUtils.humanReadableBytes((long) receiveRate),
+          interfaceNode.getName());
+    }
+    if (tmpSb.length() != 0) {
+      appendLine(sb, tmpSb.toString());
+    }
+  }
+
+  private void printCpuLog(StringBuilder sb, MeasurementNode osNode) {
+    MeasurementNode cpuNode = osNode.findChild(OsMeter.OS_TYPE_CPU);
+    if (cpuNode != null && !cpuNode.getMeasurements().isEmpty()) {
+      appendLine(sb, "  cpu: %.2f%%", cpuNode.summary() * 100);
+    }
+  }
+
+
   protected void printThreadPoolMetrics(DefaultPublishModel model, 
StringBuilder sb) {
     if (model.getThreadPools().isEmpty()) {
       return;
diff --git 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java
 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java
index 58ef4ef83..d12d0eb79 100644
--- 
a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java
+++ 
b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java
@@ -18,10 +18,13 @@
 
 import java.util.List;
 
+import 
org.apache.servicecomb.foundation.metrics.publish.spectator.DefaultTagFinder;
 import 
org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementGroupConfig;
 import 
org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode;
 import 
org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree;
 import 
org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst;
+import org.apache.servicecomb.metrics.core.meter.os.NetMeter;
+import org.apache.servicecomb.metrics.core.meter.os.OsMeter;
 import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel;
 import 
org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroups;
 import org.apache.servicecomb.swagger.invocation.InvocationType;
@@ -44,6 +47,10 @@ protected MeasurementTree createMeasurementTree(List<Meter> 
meters) {
     return tree;
   }
 
+  public MeasurementTree getTree() {
+    return tree;
+  }
+
   protected MeasurementGroupConfig createMeasurementGroupConfig() {
     MeasurementGroupConfig groupConfig = new MeasurementGroupConfig();
     groupConfig.addGroup(MeterInvocationConst.INVOCATION_NAME,
@@ -53,6 +60,11 @@ protected MeasurementGroupConfig 
createMeasurementGroupConfig() {
         MeterInvocationConst.TAG_STATUS,
         MeterInvocationConst.TAG_STAGE,
         MeterInvocationConst.TAG_STATISTIC);
+    //os config
+    groupConfig.addGroup(OsMeter.OS_NAME,
+        OsMeter.OS_TYPE,
+        new DefaultTagFinder(NetMeter.INTERFACE, true),
+        NetMeter.STATISTIC);
 
     return groupConfig;
   }
diff --git 
a/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
 
b/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
index c4ed8e76e..3fed5383d 100644
--- 
a/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
+++ 
b/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
@@ -19,4 +19,5 @@ org.apache.servicecomb.metrics.core.DefaultRegistryInitializer
 org.apache.servicecomb.metrics.core.InvocationMetersInitializer
 org.apache.servicecomb.metrics.core.ThreadPoolMetersInitializer
 org.apache.servicecomb.metrics.core.publish.DefaultLogPublisher
+org.apache.servicecomb.metrics.core.OsMetersInitializer
 org.apache.servicecomb.metrics.core.publish.MetricsRestPublisher
\ No newline at end of file
diff --git 
a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java
 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java
new file mode 100644
index 000000000..db266af9b
--- /dev/null
+++ 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.servicecomb.metrics.core;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.servicecomb.foundation.common.utils.ReflectUtils;
+import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.foundation.metrics.MetricsInitializer;
+import org.apache.servicecomb.metrics.core.meter.os.CpuMeter;
+import org.apache.servicecomb.metrics.core.meter.os.NetMeter;
+import org.apache.servicecomb.metrics.core.meter.os.NetMeter.InterfaceInfo;
+import org.apache.servicecomb.metrics.core.meter.os.OsMeter;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.eventbus.EventBus;
+import com.netflix.spectator.api.DefaultRegistry;
+import com.netflix.spectator.api.ManualClock;
+import com.netflix.spectator.api.Registry;
+
+import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
+
+public class TestOsMeterInitializer {
+  private Registry registry = new DefaultRegistry(new ManualClock());
+
+  @Mocked
+  private DefaultRegistryInitializer defaultRegistryInitializer;
+
+  @Mocked
+  private EventBus eventBus;
+
+  private boolean isLinux;
+
+  @Before
+  public void beforeTest() {
+    isLinux = SystemUtils.IS_OS_LINUX;
+  }
+
+  @Test
+  public void init(@Mocked Runtime runtime) {
+    ReflectUtils.setField(SystemUtils.class, null, "IS_OS_LINUX", true);
+    new Expectations(SPIServiceUtils.class) {
+      {
+        SPIServiceUtils.getTargetService(MetricsInitializer.class, 
DefaultRegistryInitializer.class);
+        result = defaultRegistryInitializer;
+        defaultRegistryInitializer.getRegistry();
+        result = registry;
+      }
+    };
+    List<String> list = new ArrayList<>();
+    list.add("cpu  1 1 1 1 1 1 1 1 0 0");
+    list.add("useless");
+    list.add("eth0: 0 0    0    0    0     0          0          0         0 0 
   0      0     0     0    0    0");
+    new MockUp<FileUtils>() {
+      @Mock
+      public List<String> readLines(File file, Charset encoding) {
+        return list;
+      }
+    };
+    new MockUp<Runtime>() {
+      @Mock
+      public Runtime getRuntime() {
+        return runtime;
+      }
+    };
+    new Expectations() {
+      {
+        runtime.availableProcessors();
+        result = 2;
+      }
+    };
+    OsMetersInitializer osMetersInitializer = new OsMetersInitializer();
+    osMetersInitializer.init(null, eventBus, null);
+    OsMeter osMeter = osMetersInitializer.getOsMeter();
+    Assert.assertNotNull(osMeter);
+    Assert.assertNotNull(osMeter.getCpuMeter());
+    Assert.assertNotNull(osMeter.getNetMeter());
+    CpuMeter cpuMeter = osMeter.getCpuMeter();
+    NetMeter netMeter = osMeter.getNetMeter();
+    Assert.assertEquals(2, cpuMeter.getCpuNum());
+    Assert.assertEquals(1L, cpuMeter.getLastIdleTime());
+    Assert.assertEquals(8L, cpuMeter.getLastTotalTime());
+    Map<String, InterfaceInfo> interfaceInfoMap = 
netMeter.getInterfaceInfoMap();
+    Assert.assertEquals(1, interfaceInfoMap.size());
+    InterfaceInfo eth0 = interfaceInfoMap.get("eth0");
+    Assert.assertEquals(0L, eth0.getLastRxBytes());
+    Assert.assertEquals(0L, eth0.getLastTxBytes());
+    Assert.assertEquals(0.0, eth0.getSendRate(), 0.0);
+    Assert.assertEquals(0.0, eth0.getReceiveRate(), 0.0);
+  }
+
+  @Test
+  public void initFail() {
+    OsMetersInitializer osMetersInitializer = new OsMetersInitializer();
+    ReflectUtils.setField(SystemUtils.class, null, "IS_OS_LINUX", false);
+    osMetersInitializer.init(null, eventBus, null);
+    Assert.assertNull(osMetersInitializer.getOsMeter());
+  }
+
+  @After
+  public void afterTest() {
+    ReflectUtils.setField(SystemUtils.class, null, "IS_OS_LINUX", isLinux);
+  }
+}
diff --git 
a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestCpuMeter.java
 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestCpuMeter.java
new file mode 100644
index 000000000..1399cb65f
--- /dev/null
+++ 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestCpuMeter.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.servicecomb.metrics.core.meter.os;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.netflix.spectator.api.Id;
+import com.netflix.spectator.api.Measurement;
+
+import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
+
+public class TestCpuMeter {
+
+  @Test
+  public void testRefreshCpuSuccess(@Mocked Id id, @Mocked Runtime runtime) {
+    List<String> list = new ArrayList<>();
+    list.add("cpu  1 1 1 1 1 1 1 1 0 0");
+    new MockUp<FileUtils>() {
+      @Mock
+      public List<String> readLines(File file, Charset encoding) {
+        return list;
+      }
+    };
+    new Expectations() {
+      {
+        runtime.availableProcessors();
+        result = 2;
+      }
+    };
+    new MockUp<Runtime>() {
+      @Mock
+      public Runtime getRuntime() {
+        return runtime;
+      }
+    };
+    CpuMeter cpuMeter = new CpuMeter(id);
+    Assert.assertEquals(0.0, cpuMeter.getRate(), 0.0);
+    Assert.assertEquals(8, cpuMeter.getLastTotalTime());
+    Assert.assertEquals(1, cpuMeter.getLastIdleTime());
+    Assert.assertEquals(2, cpuMeter.getCpuNum());
+    list.add(0, "cpu  2 2 2 2 2 2 2 2 0 0");
+    cpuMeter.refreshCpu();
+    Assert.assertEquals(1.75, cpuMeter.getRate(), 0.0);
+    Assert.assertEquals(16, cpuMeter.getLastTotalTime());
+    Assert.assertEquals(2, cpuMeter.getLastIdleTime());
+    Assert.assertEquals(2, cpuMeter.getCpuNum());
+  }
+
+  @Test
+  public void testRefreshError(@Mocked Id id, @Mocked Runtime runtime) {
+    List<String> list = new ArrayList<>();
+    list.add("cpu  1 1 1 1 1 1 1 1 0 0");
+    new MockUp<FileUtils>() {
+      @Mock
+      public List<String> readLines(File file, Charset encoding) {
+        return list;
+      }
+    };
+    new Expectations() {
+      {
+        runtime.availableProcessors();
+        result = 2;
+      }
+    };
+    new MockUp<Runtime>() {
+      @Mock
+      public Runtime getRuntime() {
+        return runtime;
+      }
+    };
+    CpuMeter cpuMeter = new CpuMeter(id);
+    Assert.assertEquals(0.0, cpuMeter.getRate(), 0.0);
+    Assert.assertEquals(8, cpuMeter.getLastTotalTime());
+    Assert.assertEquals(1, cpuMeter.getLastIdleTime());
+    Assert.assertEquals(2, cpuMeter.getCpuNum());
+    list.add(0, "cpu  1 1 1 1 1 1 1 1 0 0");
+    cpuMeter.refreshCpu();
+    Assert.assertEquals(0.0, cpuMeter.getRate(), 0.0);
+    Assert.assertEquals(8, cpuMeter.getLastTotalTime());
+    Assert.assertEquals(1, cpuMeter.getLastIdleTime());
+  }
+
+  @Test
+  public void testCalcMeasurements(@Mocked Id id, @Mocked Runtime runtime) {
+    List<Measurement> measurements = new ArrayList<>();
+    List<String> list = new ArrayList<>();
+    list.add("cpu  1 1 1 1 1 1 1 1 0 0");
+    new MockUp<FileUtils>() {
+      @Mock
+      public List<String> readLines(File file, Charset encoding) {
+        return list;
+      }
+    };
+    new Expectations() {
+      {
+        runtime.availableProcessors();
+        result = 2;
+      }
+    };
+    new MockUp<Runtime>() {
+      @Mock
+      public Runtime getRuntime() {
+        return runtime;
+      }
+    };
+    CpuMeter cpuMeter = new CpuMeter(id);
+    list.add(0, "cpu  2 2 2 2 2 2 2 2 0 0");
+    cpuMeter.calcMeasurements(measurements, 0);
+    Assert.assertEquals(1, measurements.size());
+    Measurement measurement = measurements.get(0);
+    Assert.assertEquals(0, measurement.timestamp());
+    Assert.assertEquals(1.75, measurement.value(), 0.0);
+  }
+}
diff --git 
a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestNetMeter.java
 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestNetMeter.java
new file mode 100644
index 000000000..3995083cd
--- /dev/null
+++ 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestNetMeter.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.servicecomb.metrics.core.meter.os;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.servicecomb.foundation.metrics.PollEvent;
+import org.apache.servicecomb.metrics.core.meter.os.NetMeter.InterfaceInfo;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.netflix.spectator.api.Id;
+import com.netflix.spectator.api.Measurement;
+
+import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
+
+public class TestNetMeter {
+  @Test
+  public void testNetRefreshUnchanged(@Mocked Id id) {
+    List<String> list = new ArrayList<>();
+    list.add("useless");
+    list.add("useless");
+    list.add("eth0: 0 0    0    0    0     0          0          0         0 0 
   0      0     0     0    0    0");
+    new MockUp<FileUtils>() {
+      @Mock
+      public List<String> readLines(File file, Charset encoding) {
+        return list;
+      }
+    };
+    NetMeter netMeter = new NetMeter(id);
+    list.remove(2);
+    list.add("eth0: 1 1    0    0    0     0          0          1         1 1 
   1      0     0     0    0    0");
+    netMeter.refreshNet(1000);
+    Map<String, InterfaceInfo> meterInterfaceInfoMap = 
netMeter.getInterfaceInfoMap();
+    Assert.assertTrue(meterInterfaceInfoMap.containsKey("eth0"));
+    InterfaceInfo eth0 = meterInterfaceInfoMap.get("eth0");
+    Assert.assertEquals("eth0", eth0.getName());
+    Assert.assertEquals(1L, eth0.getLastRxBytes());
+    Assert.assertEquals(1L, eth0.getLastTxBytes());
+    Assert.assertEquals(1, eth0.getReceiveRate(), 0.0);
+    Assert.assertEquals(1, eth0.getSendRate(), 0.0);
+  }
+
+
+  @Test
+  public void testNetRefreshAdd(@Mocked Id id) {
+    List<String> list = new ArrayList<>();
+    list.add("useless");
+    list.add("useless");
+    list.add("eth0: 0 0    0    0    0     0          0          0         0 0 
   0      0     0     0    0    0");
+    new MockUp<FileUtils>() {
+      @Mock
+      public List<String> readLines(File file, Charset encoding) {
+        return list;
+      }
+    };
+    NetMeter netMeter = new NetMeter(id);
+    Map<String, InterfaceInfo> netMap = netMeter.getInterfaceInfoMap();
+    Assert.assertEquals(1, netMap.size());
+    list.remove(2);
+    list.add("eth0: 1 1    0    0    0     0          0          1         1 1 
   1      0     0     0    0    0");
+    list.add("lo: 0 0    0    0    0     0          0          0         0 0   
 0      0     0     0    0    0");
+    netMeter.refreshNet(1000);
+    Assert.assertEquals(2, netMap.size());
+    InterfaceInfo eth0 = netMap.get("eth0");
+    Assert.assertEquals("eth0", eth0.getName());
+    Assert.assertEquals(1L, eth0.getLastRxBytes());
+    Assert.assertEquals(1L, eth0.getLastTxBytes());
+    Assert.assertEquals(1, eth0.getReceiveRate(), 0.0);
+    Assert.assertEquals(1, eth0.getSendRate(), 0.0);
+    InterfaceInfo lo = netMap.get("lo");
+    Assert.assertEquals("lo", lo.getName());
+    Assert.assertEquals(0L, lo.getLastRxBytes());
+    Assert.assertEquals(0L, lo.getLastTxBytes());
+    Assert.assertEquals(0, lo.getReceiveRate(), 0.0);
+    Assert.assertEquals(0, lo.getSendRate(), 0.0);
+  }
+
+
+  @Test
+  public void testNetRefreshRemove(@Mocked Id id) {
+    List<String> list = new ArrayList<>();
+    list.add("useless");
+    list.add("useless");
+    list.add("eth0: 0 0    0    0    0     0          0          0         0 0 
   0      0     0     0    0    0");
+    list.add("lo: 0 0    0    0    0     0          0          0         0 0   
 0      0     0     0    0    0");
+    new MockUp<FileUtils>() {
+      @Mock
+      public List<String> readLines(File file, Charset encoding) {
+        return list;
+      }
+    };
+    NetMeter netMeter = new NetMeter(id);
+    Map<String, InterfaceInfo> netMap = netMeter.getInterfaceInfoMap();
+    Assert.assertEquals(2, netMap.size());
+    InterfaceInfo lo = netMap.get("lo");
+    InterfaceInfo eth0 = netMap.get("eth0");
+    Assert.assertEquals("lo", lo.getName());
+    Assert.assertEquals(0L, lo.getLastRxBytes());
+    Assert.assertEquals(0L, lo.getLastTxBytes());
+    Assert.assertEquals(0, lo.getReceiveRate(), 0.0);
+    Assert.assertEquals(0, lo.getSendRate(), 0.0);
+    Assert.assertEquals("eth0", eth0.getName());
+    Assert.assertEquals(0L, eth0.getLastTxBytes());
+    Assert.assertEquals(0L, eth0.getLastRxBytes());
+    Assert.assertEquals(0, eth0.getReceiveRate(), 0.0);
+    Assert.assertEquals(0, eth0.getSendRate(), 0.0);
+    list.remove(2);
+    list.remove(2);
+    list.add("eth0: 1 1    0    0    0     0          0          1         1 1 
   1      0     0     0    0    0");
+    netMeter.refreshNet(1000);
+    Assert.assertNull(netMap.get("lo"));
+    Assert.assertEquals(1, netMap.size());
+    Assert.assertEquals("eth0", eth0.getName());
+    Assert.assertEquals(1L, eth0.getLastRxBytes());
+    Assert.assertEquals(1L, eth0.getLastTxBytes());
+    Assert.assertEquals(1, eth0.getReceiveRate(), 0.0);
+    Assert.assertEquals(1, eth0.getSendRate(), 0.0);
+  }
+
+
+  @Test
+  public void testCalcMeasurements(@Mocked Id id, @Mocked PollEvent pollEvent) 
{
+
+    List<String> list = new ArrayList<>();
+    list.add("useless");
+    list.add("useless");
+    list.add("eth0: 0 0    0    0    0     0          0          0         0 0 
   0      0     0     0    0    0");
+    new Expectations() {
+      {
+        pollEvent.getMsPollInterval();
+        result = 1000;
+      }
+    };
+    new MockUp<FileUtils>() {
+      @Mock
+      public List<String> readLines(File file, Charset encoding) {
+        return list;
+      }
+    };
+    NetMeter netMeter = new NetMeter(id);
+    list.remove(2);
+    list.add("eth0: 1 1    0    0    0     0          0          1         1 1 
   1      0     0     0    0    0");
+    List<Measurement> measurements = new ArrayList<>();
+    netMeter.calcMeasurements(measurements, 0L, pollEvent);
+    Assert.assertEquals(2, measurements.size());
+    Measurement send = measurements.get(0);
+    Measurement recv = measurements.get(1);
+    Assert.assertEquals(1.0, send.value(), 0.0);
+    Assert.assertEquals(1.0, recv.value(), 0.0);
+  }
+}
diff --git 
a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java
 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java
new file mode 100644
index 000000000..aa3c3ba6b
--- /dev/null
+++ 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.servicecomb.metrics.core.meter.os;
+
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.servicecomb.foundation.metrics.PollEvent;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+import com.google.common.eventbus.EventBus;
+import com.netflix.spectator.api.DefaultRegistry;
+import com.netflix.spectator.api.ManualClock;
+import com.netflix.spectator.api.Measurement;
+import com.netflix.spectator.api.Registry;
+
+import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
+
+public class TestOsMeter {
+  EventBus eventBus = new EventBus();
+
+  Registry registry = new DefaultRegistry(new ManualClock());
+
+  @Test
+  public void testCalcMeasurement(@Mocked PollEvent pollEvent, @Mocked Runtime 
runtime) {
+    List<String> list = new ArrayList<>();
+    list.add("cpu  1 1 1 1 1 1 1 1 0 0");
+    list.add("useless");
+    list.add("eth0: 0 0    0    0    0     0          0          0         0 0 
   0      0     0     0    0    0");
+    new MockUp<FileUtils>() {
+      @Mock
+      public List<String> readLines(File file, Charset encoding) {
+        return list;
+      }
+    };
+    new MockUp<Runtime>() {
+      @Mock
+      public Runtime getRuntime() {
+        return runtime;
+      }
+    };
+    new Expectations() {
+      {
+        runtime.availableProcessors();
+        result = 2;
+        pollEvent.getMsPollInterval();
+        result = 1000;
+      }
+    };
+    OsMeter osMeter = new OsMeter(registry, eventBus);
+    list.clear();
+    list.add("cpu  2 2 2 2 2 2 2 2 0 0");
+    list.add("useless");
+    list.add("eth0: 1 1    0    0    0     0          0          1         1 1 
   1      0     0     0    0    0");
+    eventBus.post(pollEvent);
+    ArrayList<Measurement> measurements = 
Lists.newArrayList(osMeter.measure());
+    Assert.assertEquals(3, measurements.size());
+    Assert.assertEquals(1.75, measurements.get(0).value(), 0.0);
+    Assert.assertEquals(1.0, measurements.get(1).value(), 0.0);
+    Assert.assertEquals(1.0, measurements.get(2).value(), 0.0);
+  }
+}
diff --git 
a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java
 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java
index 2accd3473..2ad68a62a 100644
--- 
a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java
+++ 
b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java
@@ -17,6 +17,7 @@
 package org.apache.servicecomb.metrics.core.publish;
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -27,10 +28,13 @@
 import org.apache.servicecomb.core.Const;
 import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig;
 import org.apache.servicecomb.foundation.metrics.PolledEvent;
+import 
org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode;
+import 
org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree;
 import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
 import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector;
 import org.apache.servicecomb.foundation.vertx.VertxUtils;
 import 
org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst;
+import org.apache.servicecomb.metrics.core.meter.os.OsMeter;
 import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel;
 import 
org.apache.servicecomb.metrics.core.publish.model.ThreadPoolPublishModel;
 import 
org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerf;
@@ -44,6 +48,7 @@
 
 import com.google.common.eventbus.EventBus;
 import com.netflix.spectator.api.CompositeRegistry;
+import com.netflix.spectator.api.Measurement;
 
 import io.vertx.core.impl.VertxImplEx;
 import mockit.Expectations;
@@ -127,7 +132,7 @@ public void onPolledEvent_failed() {
   }
 
   @Test
-  public void onPolledEvent(@Mocked VertxImplEx vertxImplEx) {
+  public void onPolledEvent(@Mocked VertxImplEx vertxImplEx, @Mocked 
MeasurementTree tree) {
     new Expectations(VertxUtils.class) {
       {
         VertxUtils.getVertxMap();
@@ -172,12 +177,44 @@ public void onPolledEvent(@Mocked VertxImplEx 
vertxImplEx) {
     model.getProducer().setOperationPerfGroups(operationPerfGroups);
 
     model.getThreadPools().put("test", new ThreadPoolPublishModel());
+    Measurement measurement = new Measurement(null, 0L, 1.0);
+
+    MeasurementNode measurementNodeSend = new MeasurementNode("send", new 
HashMap<>());
+    MeasurementNode measurementNodeCpu = new MeasurementNode("cpu", new 
HashMap<>());
+    MeasurementNode measurementNodeRecv = new MeasurementNode("receive", new 
HashMap<>());
+    MeasurementNode measurementNodeEth0 = new MeasurementNode("eth0", new 
HashMap<>());
+    MeasurementNode measurementNodeNet = new MeasurementNode("net", new 
HashMap<>());
+    MeasurementNode measurementNodeOs = new MeasurementNode("os", new 
HashMap<>());
+
+    measurementNodeSend.getMeasurements().add(measurement);
+    measurementNodeRecv.getMeasurements().add(measurement);
+    measurementNodeEth0.getChildren().put("send", measurementNodeSend);
+    measurementNodeEth0.getChildren().put("receive", measurementNodeRecv);
+    measurementNodeNet.getChildren().put("eth0", measurementNodeEth0);
+    measurementNodeOs.getChildren().put("cpu", measurementNodeCpu);
+    measurementNodeOs.getChildren().put("net", measurementNodeNet);
+
+    measurementNodeOs.getMeasurements().add(measurement);
+    measurementNodeNet.getMeasurements().add(measurement);
+    measurementNodeCpu.getMeasurements().add(measurement);
+    measurementNodeEth0.getMeasurements().add(measurement);
+    new Expectations() {
+      {
+        tree.findChild(OsMeter.OS_NAME);
+        result = measurementNodeOs;
+      }
+    };
 
     new MockUp<PublishModelFactory>() {
       @Mock
       DefaultPublishModel createDefaultPublishModel() {
         return model;
       }
+
+      @Mock
+      MeasurementTree getTree() {
+        return tree;
+      }
     };
 
     publisher.onPolledEvent(new PolledEvent(Collections.emptyList(), 
Collections.emptyList()));
@@ -185,7 +222,6 @@ DefaultPublishModel createDefaultPublishModel() {
     List<LoggingEvent> events = collector.getEvents().stream().filter(e -> {
       return DefaultLogPublisher.class.getName().equals(e.getLoggerName());
     }).collect(Collectors.toList());
-
     LoggingEvent event = events.get(0);
     Assert.assertEquals("\n" +
             "vertx:\n" +
@@ -194,6 +230,12 @@ DefaultPublishModel createDefaultPublishModel() {
             "threadPool:\n" +
             "  corePoolSize maxThreads poolSize currentThreadsBusy queueSize 
taskCount completedTaskCount name\n" +
             "  0            0          0        0                  0         
0.0       0.0                test\n" +
+            "os:\n"
+            + "  cpu: 100.00%\n"
+            + "  net:\n"
+            + "    send         receive      interface\n"
+            + "    1 B          1 B          eth0\n" +
+            "\n" +
             "consumer:\n" +
             "  simple:\n"
             + "    status          tps           latency                       
             operation\n"


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


> [SCB-1017] add os cpu net info  in the metrics with linux os
> ------------------------------------------------------------
>
>                 Key: SCB-1017
>                 URL: https://issues.apache.org/jira/browse/SCB-1017
>             Project: Apache ServiceComb
>          Issue Type: Improvement
>            Reporter: 何一乐
>            Priority: Major
>




--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to