]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5484 Add detailed search information per node
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Mon, 25 Aug 2014 15:57:47 +0000 (17:57 +0200)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Tue, 26 Aug 2014 12:55:04 +0000 (14:55 +0200)
server/sonar-server/src/main/java/org/sonar/server/search/ClusterHealth.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/search/NodeHealth.java
server/sonar-server/src/main/java/org/sonar/server/search/SearchClient.java
server/sonar-server/src/main/java/org/sonar/server/search/SearchHealth.java
server/sonar-server/src/test/java/org/sonar/server/search/SearchHealthMediumTest.java
server/sonar-web/src/main/webapp/WEB-INF/app/models/server.rb
server/sonar-web/src/main/webapp/WEB-INF/app/views/system/index.html.erb

diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/ClusterHealth.java b/server/sonar-server/src/main/java/org/sonar/server/search/ClusterHealth.java
new file mode 100644 (file)
index 0000000..45b260a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.search;
+
+public class ClusterHealth {
+
+  private boolean clusterAvailable;
+  private int numberOfNodes;
+
+  void setClusterAvailable(boolean clusterAvailable) {
+    this.clusterAvailable = clusterAvailable;
+  }
+
+  public boolean isClusterAvailable() {
+    return clusterAvailable;
+  }
+
+  void setNumberOfNodes(int total) {
+    this.numberOfNodes = total;
+  }
+
+  public int getNumberOfNodes() {
+    return numberOfNodes;
+  }
+}
index 3f77c3cbb1d88e3e40acc088602e3b7245b9511e..1d59e9b65a70eef24160f097cea9cb32e6df4148 100644 (file)
  */
 package org.sonar.server.search;
 
+import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
+
 import java.util.Calendar;
 import java.util.Date;
 
 public class NodeHealth {
 
-  private boolean clusterAvailable;
+  private boolean master;
   private long jvmHeapMax;
   private long jvmHeapUsed;
   private long fsAvailable;
@@ -34,12 +36,12 @@ public class NodeHealth {
   private long openFiles;
   private long jvmUptimeMillis;
 
-  void setClusterAvailable(boolean clusterAvailable) {
-    this.clusterAvailable = clusterAvailable;
+  public boolean isMaster() {
+    return master;
   }
 
-  public boolean isClusterAvailable() {
-    return clusterAvailable;
+  void setMaster(boolean master) {
+    this.master = master;
   }
 
   void setJvmHeapMax(long bytes) {
@@ -115,4 +117,36 @@ public class NodeHealth {
     calendar.setTimeInMillis(calendar.getTimeInMillis() - getJvmUptimeMillis());
     return calendar.getTime();
   }
+
+  NodeHealth(NodeStats nodesStats) {
+    // Master/slave
+    setMaster(nodesStats.getNode().isMasterNode());
+
+    // JVM Heap Usage
+    setJvmHeapMax(nodesStats.getJvm().getMem().getHeapMax().bytes());
+    setJvmHeapUsed(nodesStats.getJvm().getMem().getHeapUsed().bytes());
+
+    // OS Memory Usage ?
+    // nodesStats.getOs().getMem().freePercent();
+
+    // Disk Usage
+    setFsTotal(nodesStats.getFs().getTotal().getTotal().bytes());
+    setFsAvailable(nodesStats.getFs().getTotal().getAvailable().bytes());
+
+    // Ping ?
+
+    // Threads
+    setJvmThreads(nodesStats.getJvm().getThreads().count());
+
+    // CPU
+    if(nodesStats.getProcess().getCpu() != null) {
+      setProcessCpuPercent(nodesStats.getProcess().cpu().getPercent());
+    }
+
+    // Open Files
+    setOpenFiles(nodesStats.getProcess().getOpenFileDescriptors());
+
+    // Uptime
+    setJvmUptimeMillis(nodesStats.getJvm().getUptime().getMillis());
+  }
 }
index 0c919160eda0ba7c566838c413e946aa15f77450..eef7012c67f9ab68e08439e9bef95d5243b96ab0 100644 (file)
@@ -75,38 +75,15 @@ public class SearchClient extends TransportClient {
     this.profiling = new Profiling(settings);
   }
 
-  public NodeHealth getNodeHealth() {
-    NodeHealth health = new NodeHealth();
+  public ClusterHealth getClusterHealth() {
+    ClusterHealth health = new ClusterHealth();
     ClusterStatsResponse clusterStatsResponse = this.admin().cluster().prepareClusterStats().get();
 
     // Cluster health
     health.setClusterAvailable(clusterStatsResponse.getStatus() != ClusterHealthStatus.RED);
 
-    ClusterStatsNodes nodesStats = clusterStatsResponse.getNodesStats();
-
-    // JVM Heap Usage
-    health.setJvmHeapMax(nodesStats.getJvm().getHeapMax().bytes());
-    health.setJvmHeapUsed(nodesStats.getJvm().getHeapUsed().bytes());
-
-    // OS Memory Usage ?
-
-    // Disk Usage
-    health.setFsTotal(nodesStats.getFs().getTotal().bytes());
-    health.setFsAvailable(nodesStats.getFs().getAvailable().bytes());
-
-    // Ping ?
-
-    // Threads
-    health.setJvmThreads(nodesStats.getJvm().getThreads());
-
-    // CPU
-    health.setProcessCpuPercent(nodesStats.getProcess().getCpuPercent());
-
-    // Open Files
-    health.setOpenFiles(nodesStats.getProcess().getAvgOpenFileDescriptors());
-
-    // Uptime
-    health.setJvmUptimeMillis(nodesStats.getJvm().getMaxUpTime().getMillis());
+    // Number of nodes
+    health.setNumberOfNodes(clusterStatsResponse.getNodesStats().getCounts().getTotal());
 
     return health;
   }
index e4d077a121cc8ccedad0eeb7f1103fe2a0059e56..cfc274c1780d6b81953c6106923654999f64b560 100644 (file)
@@ -21,10 +21,15 @@ package org.sonar.server.search;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Maps;
+import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
+import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsRequestBuilder;
+import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
 import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequestBuilder;
 import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
 
 import java.util.Map;
+import java.util.Map.Entry;
 
 public class SearchHealth {
 
@@ -36,8 +41,8 @@ public class SearchHealth {
     this.indexClient = indexClient;
   }
 
-  public NodeHealth getNodeHealth() {
-    return searchClient.getNodeHealth();
+  public ClusterHealth getClusterHealth() {
+    return searchClient.getClusterHealth();
   }
 
   public Map<String, IndexHealth> getIndexHealth() {
@@ -60,4 +65,14 @@ public class SearchHealth {
     return builder.build();
   }
 
+  public Map<String, NodeHealth > getNodesHealth() {
+    NodesStatsRequestBuilder nodesStatsRequest = searchClient.admin().cluster().prepareNodesStats().all();
+    NodesStatsResponse nodesStats = searchClient.execute(nodesStatsRequest);
+
+    Map<String, NodeHealth> health = Maps.newHashMap();
+    for (Entry<String, NodeStats> nodeEntry: nodesStats.getNodesMap().entrySet()) {
+      health.put(nodeEntry.getKey(), new NodeHealth(nodeEntry.getValue()));
+    }
+    return ImmutableMap.copyOf(health);
+  }
 }
index ec865abb3dcf673b8d32e9e2c52471dd296d35b1..4236b4fc85134a28a8171749c4f50e7ab9a73ea0 100644 (file)
@@ -38,8 +38,12 @@ public class SearchHealthMediumTest {
     SearchHealth health = tester.get(SearchHealth.class);
     Date now = new Date();
 
-    NodeHealth nodeHealth = health.getNodeHealth();
-    assertThat(nodeHealth.isClusterAvailable()).isTrue();
+    ClusterHealth clusterHealth = health.getClusterHealth();
+    assertThat(clusterHealth.isClusterAvailable()).isTrue();
+    assertThat(clusterHealth.getNumberOfNodes()).isEqualTo(1);
+
+    NodeHealth nodeHealth = health.getNodesHealth().values().iterator().next();
+    assertThat(nodeHealth.isMaster()).isTrue();
     assertThat(nodeHealth.getJvmHeapUsedPercent()).contains("%");
     assertThat(nodeHealth.getFsUsedPercent()).contains("%");
     assertThat(nodeHealth.getJvmThreads()).isGreaterThanOrEqualTo(0L);
index e33a68466eaeae4838b250ee30ed4bdf4f719996..d1116ecf15c9d8dc53418bca9adf96ccc6187f55 100644 (file)
@@ -76,17 +76,12 @@ class Server
     sonar_info
   end
 
-  def search_info
+  def cluster_info
     search_info=[]
     search_health = Java::OrgSonarServerPlatform::Platform.component(Java::OrgSonarServerSearch::SearchHealth.java_class)
-    node_health = search_health.getNodeHealth()
+    node_health = search_health.getClusterHealth()
     add_property(search_info, 'Cluster State') { node_health.isClusterAvailable() ? 'Available' : 'Unavailable' }
-    add_property(search_info, 'JVM Heap Usage') { node_health.getJvmHeapUsedPercent() }
-    add_property(search_info, 'JVM Threads') { node_health.getJvmThreads() }
-    add_property(search_info, 'JVM Uptime') { Internal.i18n.ageFromNow(node_health.getJvmUpSince()) }
-    add_property(search_info, 'Disk Usage') { node_health.getFsUsedPercent() }
-    add_property(search_info, 'Open Files') { node_health.getOpenFiles() }
-    add_property(search_info, 'CPU Load Average') { node_health.getProcessCpuPercent() }
+    add_property(search_info, 'Number of Nodes') { node_health.getNumberOfNodes() }
 
     search_health.getIndexHealth().each do |name, index_health|
       add_property(search_info, "#{name} - Document Count") { index_health.getDocumentCount() }
@@ -97,6 +92,25 @@ class Server
     search_info
   end
 
+  def nodes_info
+    nodes_info=[]
+    search_health = Java::OrgSonarServerPlatform::Platform.component(Java::OrgSonarServerSearch::SearchHealth.java_class)
+    search_health.getNodesHealth().each do |name, node_health|
+      node_info=[]
+      add_property(node_info, 'Node Name') { name }
+      add_property(node_info, 'Node Type') { node_health.isMaster() ? 'Master' : 'Slave' }
+      add_property(node_info, 'JVM Heap Usage') { node_health.getJvmHeapUsedPercent() }
+      add_property(node_info, 'JVM Threads') { node_health.getJvmThreads() }
+      add_property(node_info, 'JVM Uptime') { Internal.i18n.ageFromNow(node_health.getJvmUpSince()) }
+      add_property(node_info, 'Disk Usage') { node_health.getFsUsedPercent() }
+      add_property(node_info, 'Open Files') { node_health.getOpenFiles() }
+      add_property(node_info, 'CPU Load Average') { node_health.getProcessCpuPercent() }
+      nodes_info.push(node_info)
+    end
+
+    nodes_info
+  end
+
   def sonar_plugins
     sonar_plugins=[]
     Java::OrgSonarServerUi::JRubyFacade.getInstance().getPluginsMetadata().to_a.select { |plugin| !plugin.isCore() }.sort.each do |plugin|
index 5449aed0585a36d3a1afda565737704ef92d6aaf..2916e4bcc7df2ff875aaaf56a62ce30f4adb6265 100644 (file)
 
 <br/>
 
-<table class="data width100" id="search_info">
+<table class="data width100" id="cluster_info">
 <thead>
   <tr>
-    <th colspan="2"><h2>Search Info</h2></th>
+    <th colspan="2"><h2>Search Info - Cluster</h2></th>
   </tr>
 </thead>
 <tbody>
-  <% @server.search_info.each do |data| %>
-    <%= render :partial => 'row', :locals => {:title => data[0], :value => data[1], :name => 'search' } %>
+  <% @server.cluster_info.each do |data| %>
+    <%= render :partial => 'row', :locals => {:title => data[0], :value => data[1], :name => 'cluster' } %>
   <% end %>
 <tbody>
 </table>
 
 <br/>
 
+<% @server.nodes_info.each do |node_info| -%>
+<table class="data width100" id="cluster_info<%= node_info[0][1] -%>">
+<thead>
+  <tr>
+    <th colspan="2"><h2>Search Info - <%= node_info[0][1] -%></h2></th>
+  </tr>
+</thead>
+<tbody>
+  <% node_info.drop(1).each do |data| %>
+    <%= render :partial => 'row', :locals => {:title => data[0], :value => data[1], :name => 'node' } %>
+  <% end %>
+<tbody>
+</table>
+
+<br/>
+<% end -%>
+
 <table class="data width100" id="memory">
 <thead>
   <tr>