From 68e9e5a01dfa70cfee42e98daba7bc1134566a44 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lievremont Date: Mon, 25 Aug 2014 17:57:47 +0200 Subject: [PATCH] SONAR-5484 Add detailed search information per node --- .../sonar/server/search/ClusterHealth.java | 42 ++++++++++++++++++ .../org/sonar/server/search/NodeHealth.java | 44 ++++++++++++++++--- .../org/sonar/server/search/SearchClient.java | 31 ++----------- .../org/sonar/server/search/SearchHealth.java | 19 +++++++- .../server/search/SearchHealthMediumTest.java | 8 +++- .../main/webapp/WEB-INF/app/models/server.rb | 30 +++++++++---- .../WEB-INF/app/views/system/index.html.erb | 25 +++++++++-- 7 files changed, 151 insertions(+), 48 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/search/ClusterHealth.java 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 index 00000000000..45b260ad192 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/search/ClusterHealth.java @@ -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; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/NodeHealth.java b/server/sonar-server/src/main/java/org/sonar/server/search/NodeHealth.java index 3f77c3cbb1d..1d59e9b65a7 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/search/NodeHealth.java +++ b/server/sonar-server/src/main/java/org/sonar/server/search/NodeHealth.java @@ -19,12 +19,14 @@ */ 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()); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/SearchClient.java b/server/sonar-server/src/main/java/org/sonar/server/search/SearchClient.java index 0c919160eda..eef7012c67f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/search/SearchClient.java +++ b/server/sonar-server/src/main/java/org/sonar/server/search/SearchClient.java @@ -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; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/SearchHealth.java b/server/sonar-server/src/main/java/org/sonar/server/search/SearchHealth.java index e4d077a121c..cfc274c1780 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/search/SearchHealth.java +++ b/server/sonar-server/src/main/java/org/sonar/server/search/SearchHealth.java @@ -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 getIndexHealth() { @@ -60,4 +65,14 @@ public class SearchHealth { return builder.build(); } + public Map getNodesHealth() { + NodesStatsRequestBuilder nodesStatsRequest = searchClient.admin().cluster().prepareNodesStats().all(); + NodesStatsResponse nodesStats = searchClient.execute(nodesStatsRequest); + + Map health = Maps.newHashMap(); + for (Entry nodeEntry: nodesStats.getNodesMap().entrySet()) { + health.put(nodeEntry.getKey(), new NodeHealth(nodeEntry.getValue())); + } + return ImmutableMap.copyOf(health); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/search/SearchHealthMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/search/SearchHealthMediumTest.java index ec865abb3dc..4236b4fc851 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/search/SearchHealthMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/search/SearchHealthMediumTest.java @@ -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); diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/models/server.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/models/server.rb index e33a68466ea..d1116ecf15c 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/models/server.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/models/server.rb @@ -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| diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/system/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/system/index.html.erb index 5449aed0585..2916e4bcc7d 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/system/index.html.erb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/system/index.html.erb @@ -60,21 +60,38 @@
- +
- + - <% @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 %>

Search Info

Search Info - Cluster


+<% @server.nodes_info.each do |node_info| -%> + + + + + + + + <% node_info.drop(1).each do |data| %> + <%= render :partial => 'row', :locals => {:title => data[0], :value => data[1], :name => 'node' } %> + <% end %> + +

Search Info - <%= node_info[0][1] -%>

+ +
+<% end -%> + -- 2.39.5