-
Notifications
You must be signed in to change notification settings - Fork 24.3k
/
ClusterStatsMonitoringDoc.java
225 lines (196 loc) · 8.16 KB
/
ClusterStatsMonitoringDoc.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.monitoring.collector.cluster;
import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.license.License;
import org.elasticsearch.xpack.core.XPackFeatureSet;
import org.elasticsearch.xpack.core.monitoring.MonitoredSystem;
import org.elasticsearch.xpack.core.monitoring.exporter.MonitoringDoc;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
/**
* Monitoring document collected by {@link ClusterStatsCollector}.
* <p>
* It contains all information about the current cluster, mostly for enabling/disabling features on Kibana side according to the license
* and also for the "phone home" feature.
* <p>
* In the future, the usage stats (and possibly the license) may be collected <em>less</em> frequently and therefore
* split into a separate monitoring document, but keeping them here simplifies the code.
*/
public class ClusterStatsMonitoringDoc extends MonitoringDoc {
private static final ToXContent.MapParams CLUSTER_STATS_PARAMS =
new ToXContent.MapParams(
Collections.singletonMap("metric",
ClusterState.Metric.VERSION + "," +
ClusterState.Metric.MASTER_NODE + "," +
ClusterState.Metric.NODES));
public static final String TYPE = "cluster_stats";
protected static final String SETTING_DISPLAY_NAME = "cluster.metadata.display_name";
private final String clusterName;
private final String version;
private final License license;
private final boolean apmIndicesExist;
private final List<XPackFeatureSet.Usage> usages;
private final ClusterStatsResponse clusterStats;
private final ClusterState clusterState;
private final ClusterHealthStatus status;
private final boolean clusterNeedsTLSEnabled;
ClusterStatsMonitoringDoc(final String cluster,
final long timestamp,
final long intervalMillis,
final MonitoringDoc.Node node,
final String clusterName,
final String version,
final ClusterHealthStatus status,
@Nullable final License license,
final boolean apmIndicesExist,
@Nullable final List<XPackFeatureSet.Usage> usages,
@Nullable final ClusterStatsResponse clusterStats,
@Nullable final ClusterState clusterState,
final boolean clusterNeedsTLSEnabled) {
super(cluster, timestamp, intervalMillis, node, MonitoredSystem.ES, TYPE, null);
this.clusterName = Objects.requireNonNull(clusterName);
this.version = Objects.requireNonNull(version);
this.status = Objects.requireNonNull(status);
this.license = license;
this.apmIndicesExist = apmIndicesExist;
this.usages = usages;
this.clusterStats = clusterStats;
this.clusterState = clusterState;
this.clusterNeedsTLSEnabled = clusterNeedsTLSEnabled;
}
String getClusterName() {
return clusterName;
}
String getVersion() {
return version;
}
License getLicense() {
return license;
}
boolean getAPMIndicesExist() {
return apmIndicesExist;
}
List<XPackFeatureSet.Usage> getUsages() {
return usages;
}
ClusterStatsResponse getClusterStats() {
return clusterStats;
}
ClusterState getClusterState() {
return clusterState;
}
ClusterHealthStatus getStatus() {
return status;
}
boolean getClusterNeedsTLSEnabled() {
return clusterNeedsTLSEnabled;
}
String getClusterDisplayName() {
MetaData metaData = this.clusterState.getMetaData();
if (metaData == null) {
return null;
}
return metaData.settings().get(SETTING_DISPLAY_NAME);
}
@Override
protected void innerToXContent(XContentBuilder builder, Params params) throws IOException {
builder.field("cluster_name", clusterName);
builder.field("version", version);
if (license != null) {
builder.startObject("license");
{
Map<String, String> extraParams = new MapBuilder<String, String>()
.put(License.REST_VIEW_MODE, "true")
.map();
params = new ToXContent.DelegatingMapParams(extraParams, params);
license.toInnerXContent(builder, params);
if (clusterNeedsTLSEnabled) {
builder.field("cluster_needs_tls", true);
}
}
builder.endObject();
}
if (clusterStats != null) {
builder.startObject("cluster_stats");
{
clusterStats.toXContent(builder, params);
}
builder.endObject();
}
if (clusterState != null) {
builder.startObject("cluster_state");
{
builder.field("nodes_hash", nodesHash(clusterState.nodes()));
builder.field("status", status.name().toLowerCase(Locale.ROOT));
clusterState.toXContent(builder, CLUSTER_STATS_PARAMS);
}
builder.endObject();
}
String displayName = getClusterDisplayName();
if (displayName != null) {
builder.startObject("cluster_settings");
{
builder.startObject("cluster");
{
builder.startObject("metadata");
{
builder.field("display_name", displayName);
}
builder.endObject();
}
builder.endObject();
}
builder.endObject();
}
builder.startObject("stack_stats");
{
// in the future, it may be useful to pass in an object that represents APM (and others), but for now this
// is good enough
builder.startObject("apm");
{
builder.field("found", apmIndicesExist);
}
builder.endObject();
if (usages != null) {
builder.startObject("xpack");
for (final XPackFeatureSet.Usage usage : usages) {
builder.field(usage.name(), usage);
}
builder.endObject();
}
}
builder.endObject();
}
/**
* Create a simple hash value that can be used to determine if the nodes listing has changed since the last report.
*
* @param nodes All nodes in the cluster state.
* @return A hash code value whose value can be used to determine if the node listing has changed (including node restarts).
*/
public static int nodesHash(final DiscoveryNodes nodes) {
final StringBuilder temp = new StringBuilder();
// adds the Ephemeral ID (as opposed to the Persistent UUID) to catch node restarts, which is critical for 1 node clusters
for (final DiscoveryNode node : nodes) {
temp.append(node.getEphemeralId());
}
return temp.toString().hashCode();
}
}