-
Notifications
You must be signed in to change notification settings - Fork 1k
/
IndexerOverviewResource.java
177 lines (159 loc) · 8.36 KB
/
IndexerOverviewResource.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
/**
* This file is part of Graylog.
*
* Graylog is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Graylog 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Graylog. If not, see <http://www.gnu.org/licenses/>.
*/
package org.graylog2.rest.resources.system.indexer;
import com.codahale.metrics.annotation.Timed;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.ImmutableMap;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.graylog2.indexer.IndexSet;
import org.graylog2.indexer.IndexSetRegistry;
import org.graylog2.indexer.cluster.Cluster;
import org.graylog2.indexer.indices.Indices;
import org.graylog2.indexer.indices.TooManyAliasesException;
import org.graylog2.rest.models.system.deflector.responses.DeflectorSummary;
import org.graylog2.rest.models.system.indexer.responses.IndexRangeSummary;
import org.graylog2.rest.models.system.indexer.responses.IndexSizeSummary;
import org.graylog2.rest.models.system.indexer.responses.IndexSummary;
import org.graylog2.rest.models.system.indexer.responses.IndexerClusterOverview;
import org.graylog2.rest.models.system.indexer.responses.IndexerOverview;
import org.graylog2.rest.resources.count.CountResource;
import org.graylog2.rest.resources.system.DeflectorResource;
import org.graylog2.rest.resources.system.IndexRangesResource;
import org.graylog2.shared.rest.resources.RestResource;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.ServiceUnavailableException;
import javax.ws.rs.core.MediaType;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@RequiresAuthentication
@Api(value = "Indexer/Overview", description = "Indexing overview")
@Path("/system/indexer/overview")
public class IndexerOverviewResource extends RestResource {
private final DeflectorResource deflectorResource;
private final IndexerClusterResource indexerClusterResource;
private final IndexRangesResource indexRangesResource;
private final CountResource countResource;
private final IndexSetRegistry indexSetRegistry;
private final Indices indices;
private final Cluster cluster;
@Inject
public IndexerOverviewResource(DeflectorResource deflectorResource,
IndexerClusterResource indexerClusterResource,
IndexRangesResource indexRangesResource,
CountResource countResource,
IndexSetRegistry indexSetRegistry,
Indices indices,
Cluster cluster) {
this.deflectorResource = deflectorResource;
this.indexerClusterResource = indexerClusterResource;
this.indexRangesResource = indexRangesResource;
this.countResource = countResource;
this.indexSetRegistry = indexSetRegistry;
this.indices = indices;
this.cluster = cluster;
}
@GET
@Timed
@ApiOperation(value = "Get overview of current indexing state, including deflector config, cluster state, index ranges & message counts.")
@Produces(MediaType.APPLICATION_JSON)
@Deprecated
public IndexerOverview index() throws TooManyAliasesException {
if (!cluster.isConnected()) {
throw new ServiceUnavailableException("Elasticsearch cluster is not available, check your configuration and logs for more information.");
}
try {
return getIndexerOverview(indexSetRegistry.getDefault());
} catch (IllegalStateException e) {
throw new NotFoundException("Default index set not found");
}
}
@GET
@Timed
@Path("/{indexSetId}")
@ApiOperation(value = "Get overview of current indexing state for the given index set, including deflector config, cluster state, index ranges & message counts.")
@Produces(MediaType.APPLICATION_JSON)
public IndexerOverview index(@ApiParam(name = "indexSetId") @PathParam("indexSetId") String indexSetId) throws TooManyAliasesException {
if (!cluster.isConnected()) {
throw new ServiceUnavailableException("Elasticsearch cluster is not available, check your configuration and logs for more information.");
}
final IndexSet indexSet = getIndexSet(indexSetRegistry, indexSetId);
return getIndexerOverview(indexSet);
}
private IndexerOverview getIndexerOverview(IndexSet indexSet) throws TooManyAliasesException {
final String indexSetId = indexSet.getConfig().id();
final DeflectorSummary deflectorSummary = deflectorResource.deflector(indexSetId);
final List<IndexRangeSummary> indexRanges = indexRangesResource.list().ranges();
final JsonNode indexStats = indices.getIndexStats(indexSet);
final List<String> indexNames = new ArrayList<>();
indexStats.fieldNames().forEachRemaining(indexNames::add);
final Map<String, Boolean> areReopened = indices.areReopened(indexNames);
final Map<String, IndexSummary> indicesSummaries = buildIndexSummaries(deflectorSummary, indexSet, indexRanges, indexStats, areReopened);
return IndexerOverview.create(deflectorSummary,
IndexerClusterOverview.create(indexerClusterResource.clusterHealth(), indexerClusterResource.clusterName().name()),
countResource.total(indexSetId), indicesSummaries);
}
private Map<String, IndexSummary> buildIndexSummaries(DeflectorSummary deflectorSummary, IndexSet indexSet, List<IndexRangeSummary> indexRanges, JsonNode indexStats, Map<String, Boolean> areReopened) {
final Iterator<Map.Entry<String, JsonNode>> fields = indexStats.fields();
final ImmutableMap.Builder<String, IndexSummary> indexSummaries = ImmutableMap.builder();
while (fields.hasNext()) {
final Map.Entry<String, JsonNode> entry = fields.next();
indexSummaries.put(entry.getKey(), buildIndexSummary(entry, indexRanges, deflectorSummary, areReopened));
}
indices.getClosedIndices(indexSet).forEach(indexName -> indexSummaries.put(indexName, IndexSummary.create(
null,
indexRanges.stream().filter((indexRangeSummary) -> indexRangeSummary.indexName().equals(indexName)).findFirst().orElse(null),
indexName.equals(deflectorSummary.currentTarget()),
true,
false
)));
return indexSummaries.build();
}
private IndexSummary buildIndexSummary(Map.Entry<String, JsonNode> indexStats,
List<IndexRangeSummary> indexRanges,
DeflectorSummary deflectorSummary,
Map<String, Boolean> areReopened) {
final String index = indexStats.getKey();
final JsonNode primaries = indexStats.getValue().path("primaries");
final JsonNode docs = primaries.path("docs");
final long count = docs.path("count").asLong();
final long deleted = docs.path("deleted").asLong();
final JsonNode store = primaries.path("store");
final long sizeInBytes = store.path("size_in_bytes").asLong();
final Optional<IndexRangeSummary> range = indexRanges.stream()
.filter(indexRangeSummary -> indexRangeSummary.indexName().equals(index))
.findFirst();
final boolean isDeflector = index.equals(deflectorSummary.currentTarget());
final boolean isReopened = areReopened.get(index);
return IndexSummary.create(
IndexSizeSummary.create(count, deleted, sizeInBytes),
range.orElse(null),
isDeflector,
false,
isReopened);
}
}