[HLRC] Added support for CCR Stats API (#36213)

This change also adds documentation for the CCR Stats API.

Relates to #33824
This commit is contained in:
Martijn van Groningen 2018-12-05 13:14:51 +01:00 committed by GitHub
parent 11935cd480
commit 786697a4b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1146 additions and 9 deletions

View File

@ -20,6 +20,8 @@
package org.elasticsearch.client;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.ccr.CcrStatsRequest;
import org.elasticsearch.client.ccr.CcrStatsResponse;
import org.elasticsearch.client.ccr.DeleteAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.GetAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.GetAutoFollowPatternResponse;
@ -360,4 +362,48 @@ public final class CcrClient {
);
}
/**
* Gets all CCR stats.
*
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-stats.html">
* the docs</a> for more.
*
* @param request the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public CcrStatsResponse getCcrStats(CcrStatsRequest request,
RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(
request,
CcrRequestConverters::getCcrStats,
options,
CcrStatsResponse::fromXContent,
Collections.emptySet()
);
}
/**
* Gets all CCR stats.
*
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-get-stats.html">
* the docs</a> for more.
*
* @param request the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
*/
public void getCcrStatsAsync(CcrStatsRequest request,
RequestOptions options,
ActionListener<CcrStatsResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(
request,
CcrRequestConverters::getCcrStats,
options,
CcrStatsResponse::fromXContent,
listener,
Collections.emptySet()
);
}
}

View File

@ -23,6 +23,7 @@ import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.elasticsearch.client.ccr.CcrStatsRequest;
import org.elasticsearch.client.ccr.DeleteAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.GetAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.PauseFollowRequest;
@ -100,4 +101,11 @@ final class CcrRequestConverters {
return new Request(HttpGet.METHOD_NAME, endpoint);
}
static Request getCcrStats(CcrStatsRequest ccrStatsRequest) {
String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_ccr", "stats")
.build();
return new Request(HttpGet.METHOD_NAME, endpoint);
}
}

View File

@ -0,0 +1,105 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.client.ccr;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.stream.Collectors;
public final class AutoFollowStats {
static final ParseField NUMBER_OF_SUCCESSFUL_INDICES_AUTO_FOLLOWED = new ParseField("number_of_successful_follow_indices");
static final ParseField NUMBER_OF_FAILED_INDICES_AUTO_FOLLOWED = new ParseField("number_of_failed_follow_indices");
static final ParseField NUMBER_OF_FAILED_REMOTE_CLUSTER_STATE_REQUESTS =
new ParseField("number_of_failed_remote_cluster_state_requests");
static final ParseField RECENT_AUTO_FOLLOW_ERRORS = new ParseField("recent_auto_follow_errors");
static final ParseField LEADER_INDEX = new ParseField("leader_index");
static final ParseField AUTO_FOLLOW_EXCEPTION = new ParseField("auto_follow_exception");
@SuppressWarnings("unchecked")
static final ConstructingObjectParser<AutoFollowStats, Void> STATS_PARSER = new ConstructingObjectParser<>("auto_follow_stats",
args -> new AutoFollowStats(
(Long) args[0],
(Long) args[1],
(Long) args[2],
new TreeMap<>(
((List<Map.Entry<String, ElasticsearchException>>) args[3])
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))
));
private static final ConstructingObjectParser<Map.Entry<String, ElasticsearchException>, Void> AUTO_FOLLOW_EXCEPTIONS_PARSER =
new ConstructingObjectParser<>(
"auto_follow_stats_errors",
args -> new AbstractMap.SimpleEntry<>((String) args[0], (ElasticsearchException) args[1]));
static {
AUTO_FOLLOW_EXCEPTIONS_PARSER.declareString(ConstructingObjectParser.constructorArg(), LEADER_INDEX);
AUTO_FOLLOW_EXCEPTIONS_PARSER.declareObject(
ConstructingObjectParser.constructorArg(),
(p, c) -> ElasticsearchException.fromXContent(p),
AUTO_FOLLOW_EXCEPTION);
STATS_PARSER.declareLong(ConstructingObjectParser.constructorArg(), NUMBER_OF_FAILED_INDICES_AUTO_FOLLOWED);
STATS_PARSER.declareLong(ConstructingObjectParser.constructorArg(), NUMBER_OF_FAILED_REMOTE_CLUSTER_STATE_REQUESTS);
STATS_PARSER.declareLong(ConstructingObjectParser.constructorArg(), NUMBER_OF_SUCCESSFUL_INDICES_AUTO_FOLLOWED);
STATS_PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), AUTO_FOLLOW_EXCEPTIONS_PARSER,
RECENT_AUTO_FOLLOW_ERRORS);
}
private final long numberOfFailedFollowIndices;
private final long numberOfFailedRemoteClusterStateRequests;
private final long numberOfSuccessfulFollowIndices;
private final NavigableMap<String, ElasticsearchException> recentAutoFollowErrors;
AutoFollowStats(long numberOfFailedFollowIndices,
long numberOfFailedRemoteClusterStateRequests,
long numberOfSuccessfulFollowIndices,
NavigableMap<String, ElasticsearchException> recentAutoFollowErrors) {
this.numberOfFailedFollowIndices = numberOfFailedFollowIndices;
this.numberOfFailedRemoteClusterStateRequests = numberOfFailedRemoteClusterStateRequests;
this.numberOfSuccessfulFollowIndices = numberOfSuccessfulFollowIndices;
this.recentAutoFollowErrors = recentAutoFollowErrors;
}
public long getNumberOfFailedFollowIndices() {
return numberOfFailedFollowIndices;
}
public long getNumberOfFailedRemoteClusterStateRequests() {
return numberOfFailedRemoteClusterStateRequests;
}
public long getNumberOfSuccessfulFollowIndices() {
return numberOfSuccessfulFollowIndices;
}
public NavigableMap<String, ElasticsearchException> getRecentAutoFollowErrors() {
return recentAutoFollowErrors;
}
}

View File

@ -0,0 +1,25 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.client.ccr;
import org.elasticsearch.client.Validatable;
public final class CcrStatsRequest implements Validatable {
}

View File

@ -0,0 +1,62 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.client.ccr;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
public final class CcrStatsResponse {
static final ParseField AUTO_FOLLOW_STATS_FIELD = new ParseField("auto_follow_stats");
static final ParseField FOLLOW_STATS_FIELD = new ParseField("follow_stats");
private static final ConstructingObjectParser<CcrStatsResponse, Void> PARSER = new ConstructingObjectParser<>("indices",
args -> {
AutoFollowStats autoFollowStats = (AutoFollowStats) args[0];
IndicesFollowStats indicesFollowStats = (IndicesFollowStats) args[1];
return new CcrStatsResponse(autoFollowStats, indicesFollowStats);
});
static {
PARSER.declareObject(ConstructingObjectParser.constructorArg(), AutoFollowStats.STATS_PARSER, AUTO_FOLLOW_STATS_FIELD);
PARSER.declareObject(ConstructingObjectParser.constructorArg(), IndicesFollowStats.PARSER, FOLLOW_STATS_FIELD);
}
public static CcrStatsResponse fromXContent(XContentParser parser) {
return PARSER.apply(parser, null);
}
private final AutoFollowStats autoFollowStats;
private final IndicesFollowStats indicesFollowStats;
public CcrStatsResponse(AutoFollowStats autoFollowStats, IndicesFollowStats indicesFollowStats) {
this.autoFollowStats = autoFollowStats;
this.indicesFollowStats = indicesFollowStats;
}
public AutoFollowStats getAutoFollowStats() {
return autoFollowStats;
}
public IndicesFollowStats getIndicesFollowStats() {
return indicesFollowStats;
}
}

View File

@ -0,0 +1,403 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.client.ccr;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.stream.Collectors;
public final class IndicesFollowStats {
static final ParseField INDICES_FIELD = new ParseField("indices");
static final ParseField INDEX_FIELD = new ParseField("index");
static final ParseField SHARDS_FIELD = new ParseField("shards");
private static final ConstructingObjectParser<Tuple<String, List<ShardFollowStats>>, Void> ENTRY_PARSER =
new ConstructingObjectParser<>(
"entry",
args -> {
String index = (String) args[0];
@SuppressWarnings("unchecked")
List<ShardFollowStats> shardFollowStats = (List<ShardFollowStats>) args[1];
return new Tuple<>(index, shardFollowStats);
}
);
static {
ENTRY_PARSER.declareString(ConstructingObjectParser.constructorArg(), INDEX_FIELD);
ENTRY_PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), ShardFollowStats.PARSER, SHARDS_FIELD);
}
static final ConstructingObjectParser<IndicesFollowStats, Void> PARSER = new ConstructingObjectParser<>("indices",
args -> {
@SuppressWarnings("unchecked")
List<Tuple<String, List<ShardFollowStats>>> entries = (List<Tuple<String, List<ShardFollowStats>>>) args[0];
Map<String, List<ShardFollowStats>> shardFollowStats = entries.stream().collect(Collectors.toMap(Tuple::v1, Tuple::v2));
return new IndicesFollowStats(new TreeMap<>(shardFollowStats));
});
static {
PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), ENTRY_PARSER, INDICES_FIELD);
}
private final NavigableMap<String, List<ShardFollowStats>> shardFollowStats;
IndicesFollowStats(NavigableMap<String, List<ShardFollowStats>> shardFollowStats) {
this.shardFollowStats = Collections.unmodifiableNavigableMap(shardFollowStats);
}
public List<ShardFollowStats> getShardFollowStats(String index) {
return shardFollowStats.get(index);
}
public Map<String, List<ShardFollowStats>> getShardFollowStats() {
return shardFollowStats;
}
public static final class ShardFollowStats {
static final ParseField LEADER_CLUSTER = new ParseField("remote_cluster");
static final ParseField LEADER_INDEX = new ParseField("leader_index");
static final ParseField FOLLOWER_INDEX = new ParseField("follower_index");
static final ParseField SHARD_ID = new ParseField("shard_id");
static final ParseField LEADER_GLOBAL_CHECKPOINT_FIELD = new ParseField("leader_global_checkpoint");
static final ParseField LEADER_MAX_SEQ_NO_FIELD = new ParseField("leader_max_seq_no");
static final ParseField FOLLOWER_GLOBAL_CHECKPOINT_FIELD = new ParseField("follower_global_checkpoint");
static final ParseField FOLLOWER_MAX_SEQ_NO_FIELD = new ParseField("follower_max_seq_no");
static final ParseField LAST_REQUESTED_SEQ_NO_FIELD = new ParseField("last_requested_seq_no");
static final ParseField OUTSTANDING_READ_REQUESTS = new ParseField("outstanding_read_requests");
static final ParseField OUTSTANDING_WRITE_REQUESTS = new ParseField("outstanding_write_requests");
static final ParseField WRITE_BUFFER_OPERATION_COUNT_FIELD = new ParseField("write_buffer_operation_count");
static final ParseField WRITE_BUFFER_SIZE_IN_BYTES_FIELD = new ParseField("write_buffer_size_in_bytes");
static final ParseField FOLLOWER_MAPPING_VERSION_FIELD = new ParseField("follower_mapping_version");
static final ParseField FOLLOWER_SETTINGS_VERSION_FIELD = new ParseField("follower_settings_version");
static final ParseField TOTAL_READ_TIME_MILLIS_FIELD = new ParseField("total_read_time_millis");
static final ParseField TOTAL_READ_REMOTE_EXEC_TIME_MILLIS_FIELD = new ParseField("total_read_remote_exec_time_millis");
static final ParseField SUCCESSFUL_READ_REQUESTS_FIELD = new ParseField("successful_read_requests");
static final ParseField FAILED_READ_REQUESTS_FIELD = new ParseField("failed_read_requests");
static final ParseField OPERATIONS_READ_FIELD = new ParseField("operations_read");
static final ParseField BYTES_READ = new ParseField("bytes_read");
static final ParseField TOTAL_WRITE_TIME_MILLIS_FIELD = new ParseField("total_write_time_millis");
static final ParseField SUCCESSFUL_WRITE_REQUESTS_FIELD = new ParseField("successful_write_requests");
static final ParseField FAILED_WRITE_REQUEST_FIELD = new ParseField("failed_write_requests");
static final ParseField OPERATIONS_WRITTEN = new ParseField("operations_written");
static final ParseField READ_EXCEPTIONS = new ParseField("read_exceptions");
static final ParseField TIME_SINCE_LAST_READ_MILLIS_FIELD = new ParseField("time_since_last_read_millis");
static final ParseField FATAL_EXCEPTION = new ParseField("fatal_exception");
@SuppressWarnings("unchecked")
static final ConstructingObjectParser<ShardFollowStats, Void> PARSER =
new ConstructingObjectParser<>(
"shard-follow-stats",
args -> new ShardFollowStats(
(String) args[0],
(String) args[1],
(String) args[2],
(int) args[3],
(long) args[4],
(long) args[5],
(long) args[6],
(long) args[7],
(long) args[8],
(int) args[9],
(int) args[10],
(int) args[11],
(long) args[12],
(long) args[13],
(long) args[14],
(long) args[15],
(long) args[16],
(long) args[17],
(long) args[18],
(long) args[19],
(long) args[20],
(long) args[21],
(long) args[22],
(long) args[23],
(long) args[24],
(long) args[25],
new TreeMap<>(
((List<Map.Entry<Long, Tuple<Integer, ElasticsearchException>>>) args[26])
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
(ElasticsearchException) args[27]));
static final ConstructingObjectParser<Map.Entry<Long, Tuple<Integer, ElasticsearchException>>, Void> READ_EXCEPTIONS_ENTRY_PARSER =
new ConstructingObjectParser<>(
"shard-follow-stats-read-exceptions-entry",
args -> new AbstractMap.SimpleEntry<>((long) args[0], Tuple.tuple((Integer) args[1], (ElasticsearchException)args[2])));
static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), LEADER_CLUSTER);
PARSER.declareString(ConstructingObjectParser.constructorArg(), LEADER_INDEX);
PARSER.declareString(ConstructingObjectParser.constructorArg(), FOLLOWER_INDEX);
PARSER.declareInt(ConstructingObjectParser.constructorArg(), SHARD_ID);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), LEADER_GLOBAL_CHECKPOINT_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), LEADER_MAX_SEQ_NO_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), FOLLOWER_GLOBAL_CHECKPOINT_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), FOLLOWER_MAX_SEQ_NO_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), LAST_REQUESTED_SEQ_NO_FIELD);
PARSER.declareInt(ConstructingObjectParser.constructorArg(), OUTSTANDING_READ_REQUESTS);
PARSER.declareInt(ConstructingObjectParser.constructorArg(), OUTSTANDING_WRITE_REQUESTS);
PARSER.declareInt(ConstructingObjectParser.constructorArg(), WRITE_BUFFER_OPERATION_COUNT_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), WRITE_BUFFER_SIZE_IN_BYTES_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), FOLLOWER_MAPPING_VERSION_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), FOLLOWER_SETTINGS_VERSION_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), TOTAL_READ_TIME_MILLIS_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), TOTAL_READ_REMOTE_EXEC_TIME_MILLIS_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), SUCCESSFUL_READ_REQUESTS_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), FAILED_READ_REQUESTS_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), OPERATIONS_READ_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), BYTES_READ);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), TOTAL_WRITE_TIME_MILLIS_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), SUCCESSFUL_WRITE_REQUESTS_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), FAILED_WRITE_REQUEST_FIELD);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), OPERATIONS_WRITTEN);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), TIME_SINCE_LAST_READ_MILLIS_FIELD);
PARSER.declareObjectArray(ConstructingObjectParser.constructorArg(), READ_EXCEPTIONS_ENTRY_PARSER, READ_EXCEPTIONS);
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(),
(p, c) -> ElasticsearchException.fromXContent(p),
FATAL_EXCEPTION);
}
static final ParseField READ_EXCEPTIONS_ENTRY_FROM_SEQ_NO = new ParseField("from_seq_no");
static final ParseField READ_EXCEPTIONS_RETRIES = new ParseField("retries");
static final ParseField READ_EXCEPTIONS_ENTRY_EXCEPTION = new ParseField("exception");
static {
READ_EXCEPTIONS_ENTRY_PARSER.declareLong(ConstructingObjectParser.constructorArg(), READ_EXCEPTIONS_ENTRY_FROM_SEQ_NO);
READ_EXCEPTIONS_ENTRY_PARSER.declareInt(ConstructingObjectParser.constructorArg(), READ_EXCEPTIONS_RETRIES);
READ_EXCEPTIONS_ENTRY_PARSER.declareObject(
ConstructingObjectParser.constructorArg(),
(p, c) -> ElasticsearchException.fromXContent(p),
READ_EXCEPTIONS_ENTRY_EXCEPTION);
}
private final String remoteCluster;
private final String leaderIndex;
private final String followerIndex;
private final int shardId;
private final long leaderGlobalCheckpoint;
private final long leaderMaxSeqNo;
private final long followerGlobalCheckpoint;
private final long followerMaxSeqNo;
private final long lastRequestedSeqNo;
private final int outstandingReadRequests;
private final int outstandingWriteRequests;
private final int writeBufferOperationCount;
private final long writeBufferSizeInBytes;
private final long followerMappingVersion;
private final long followerSettingsVersion;
private final long totalReadTimeMillis;
private final long totalReadRemoteExecTimeMillis;
private final long successfulReadRequests;
private final long failedReadRequests;
private final long operationsReads;
private final long bytesRead;
private final long totalWriteTimeMillis;
private final long successfulWriteRequests;
private final long failedWriteRequests;
private final long operationWritten;
private final long timeSinceLastReadMillis;
private final NavigableMap<Long, Tuple<Integer, ElasticsearchException>> readExceptions;
private final ElasticsearchException fatalException;
ShardFollowStats(String remoteCluster,
String leaderIndex,
String followerIndex,
int shardId,
long leaderGlobalCheckpoint,
long leaderMaxSeqNo,
long followerGlobalCheckpoint,
long followerMaxSeqNo,
long lastRequestedSeqNo,
int outstandingReadRequests,
int outstandingWriteRequests,
int writeBufferOperationCount,
long writeBufferSizeInBytes,
long followerMappingVersion,
long followerSettingsVersion,
long totalReadTimeMillis,
long totalReadRemoteExecTimeMillis,
long successfulReadRequests,
long failedReadRequests,
long operationsReads,
long bytesRead,
long totalWriteTimeMillis,
long successfulWriteRequests,
long failedWriteRequests,
long operationWritten,
long timeSinceLastReadMillis,
NavigableMap<Long, Tuple<Integer, ElasticsearchException>> readExceptions,
ElasticsearchException fatalException) {
this.remoteCluster = remoteCluster;
this.leaderIndex = leaderIndex;
this.followerIndex = followerIndex;
this.shardId = shardId;
this.leaderGlobalCheckpoint = leaderGlobalCheckpoint;
this.leaderMaxSeqNo = leaderMaxSeqNo;
this.followerGlobalCheckpoint = followerGlobalCheckpoint;
this.followerMaxSeqNo = followerMaxSeqNo;
this.lastRequestedSeqNo = lastRequestedSeqNo;
this.outstandingReadRequests = outstandingReadRequests;
this.outstandingWriteRequests = outstandingWriteRequests;
this.writeBufferOperationCount = writeBufferOperationCount;
this.writeBufferSizeInBytes = writeBufferSizeInBytes;
this.followerMappingVersion = followerMappingVersion;
this.followerSettingsVersion = followerSettingsVersion;
this.totalReadTimeMillis = totalReadTimeMillis;
this.totalReadRemoteExecTimeMillis = totalReadRemoteExecTimeMillis;
this.successfulReadRequests = successfulReadRequests;
this.failedReadRequests = failedReadRequests;
this.operationsReads = operationsReads;
this.bytesRead = bytesRead;
this.totalWriteTimeMillis = totalWriteTimeMillis;
this.successfulWriteRequests = successfulWriteRequests;
this.failedWriteRequests = failedWriteRequests;
this.operationWritten = operationWritten;
this.timeSinceLastReadMillis = timeSinceLastReadMillis;
this.readExceptions = readExceptions;
this.fatalException = fatalException;
}
public String getRemoteCluster() {
return remoteCluster;
}
public String getLeaderIndex() {
return leaderIndex;
}
public String getFollowerIndex() {
return followerIndex;
}
public int getShardId() {
return shardId;
}
public long getLeaderGlobalCheckpoint() {
return leaderGlobalCheckpoint;
}
public long getLeaderMaxSeqNo() {
return leaderMaxSeqNo;
}
public long getFollowerGlobalCheckpoint() {
return followerGlobalCheckpoint;
}
public long getFollowerMaxSeqNo() {
return followerMaxSeqNo;
}
public long getLastRequestedSeqNo() {
return lastRequestedSeqNo;
}
public int getOutstandingReadRequests() {
return outstandingReadRequests;
}
public int getOutstandingWriteRequests() {
return outstandingWriteRequests;
}
public int getWriteBufferOperationCount() {
return writeBufferOperationCount;
}
public long getWriteBufferSizeInBytes() {
return writeBufferSizeInBytes;
}
public long getFollowerMappingVersion() {
return followerMappingVersion;
}
public long getFollowerSettingsVersion() {
return followerSettingsVersion;
}
public long getTotalReadTimeMillis() {
return totalReadTimeMillis;
}
public long getTotalReadRemoteExecTimeMillis() {
return totalReadRemoteExecTimeMillis;
}
public long getSuccessfulReadRequests() {
return successfulReadRequests;
}
public long getFailedReadRequests() {
return failedReadRequests;
}
public long getOperationsReads() {
return operationsReads;
}
public long getBytesRead() {
return bytesRead;
}
public long getTotalWriteTimeMillis() {
return totalWriteTimeMillis;
}
public long getSuccessfulWriteRequests() {
return successfulWriteRequests;
}
public long getFailedWriteRequests() {
return failedWriteRequests;
}
public long getOperationWritten() {
return operationWritten;
}
public long getTimeSinceLastReadMillis() {
return timeSinceLastReadMillis;
}
public NavigableMap<Long, Tuple<Integer, ElasticsearchException>> getReadExceptions() {
return readExceptions;
}
public ElasticsearchException getFatalException() {
return fatalException;
}
}
}

View File

@ -29,9 +29,12 @@ import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.client.ccr.CcrStatsRequest;
import org.elasticsearch.client.ccr.CcrStatsResponse;
import org.elasticsearch.client.ccr.DeleteAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.GetAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.GetAutoFollowPatternResponse;
import org.elasticsearch.client.ccr.IndicesFollowStats.ShardFollowStats;
import org.elasticsearch.client.ccr.PauseFollowRequest;
import org.elasticsearch.client.ccr.PutAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.PutFollowRequest;
@ -39,7 +42,6 @@ import org.elasticsearch.client.ccr.PutFollowResponse;
import org.elasticsearch.client.ccr.ResumeFollowRequest;
import org.elasticsearch.client.ccr.UnfollowRequest;
import org.elasticsearch.client.core.AcknowledgedResponse;
import org.elasticsearch.common.xcontent.ObjectPath;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
@ -47,6 +49,7 @@ import org.junit.Before;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.hamcrest.Matchers.equalTo;
@ -104,6 +107,15 @@ public class CCRIT extends ESRestHighLevelClientTestCase {
assertThat(leaderSearchResponse.getHits().getTotalHits(), equalTo(1L));
assertBusy(() -> {
CcrStatsRequest ccrStatsRequest = new CcrStatsRequest();
CcrStatsResponse ccrStatsResponse = execute(ccrStatsRequest, ccrClient::getCcrStats, ccrClient::getCcrStatsAsync);
List<ShardFollowStats> shardFollowStats = ccrStatsResponse.getIndicesFollowStats().getShardFollowStats("follower");
long followerGlobalCheckpoint = shardFollowStats.stream()
.mapToLong(ShardFollowStats::getFollowerGlobalCheckpoint)
.max()
.getAsLong();
assertThat(followerGlobalCheckpoint, equalTo(0L));
SearchRequest followerSearchRequest = new SearchRequest("follower");
SearchResponse followerSearchResponse = highLevelClient().search(followerSearchRequest, RequestOptions.DEFAULT);
assertThat(followerSearchResponse.getHits().getTotalHits(), equalTo(1L));
@ -120,6 +132,15 @@ public class CCRIT extends ESRestHighLevelClientTestCase {
assertThat(resumeFollowResponse.isAcknowledged(), is(true));
assertBusy(() -> {
CcrStatsRequest ccrStatsRequest = new CcrStatsRequest();
CcrStatsResponse ccrStatsResponse = execute(ccrStatsRequest, ccrClient::getCcrStats, ccrClient::getCcrStatsAsync);
List<ShardFollowStats> shardFollowStats = ccrStatsResponse.getIndicesFollowStats().getShardFollowStats("follower");
long followerGlobalCheckpoint = shardFollowStats.stream()
.mapToLong(ShardFollowStats::getFollowerGlobalCheckpoint)
.max()
.getAsLong();
assertThat(followerGlobalCheckpoint, equalTo(1L));
SearchRequest followerSearchRequest = new SearchRequest("follower");
SearchResponse followerSearchResponse = highLevelClient().search(followerSearchRequest, RequestOptions.DEFAULT);
assertThat(followerSearchResponse.getHits().getTotalHits(), equalTo(2L));
@ -156,15 +177,12 @@ public class CCRIT extends ESRestHighLevelClientTestCase {
assertThat(response.isAcknowledged(), is(true));
assertBusy(() -> {
assertThat(indexExists("copy-logs-20200101"), is(true));
// TODO: replace with HLRC follow stats when available:
Map<String, Object> rsp = toMap(client().performRequest(new Request("GET", "/copy-logs-20200101/_ccr/stats")));
String index = null;
try {
index = ObjectPath.eval("indices.0.index", rsp);
} catch (Exception e){ }
assertThat(index, equalTo("copy-logs-20200101"));
CcrStatsRequest ccrStatsRequest = new CcrStatsRequest();
CcrStatsResponse ccrStatsResponse = execute(ccrStatsRequest, ccrClient::getCcrStats, ccrClient::getCcrStatsAsync);
assertThat(ccrStatsResponse.getAutoFollowStats().getNumberOfSuccessfulFollowIndices(), equalTo(1L));
assertThat(ccrStatsResponse.getIndicesFollowStats().getShardFollowStats("copy-logs-20200101"), notNullValue());
});
assertThat(indexExists("copy-logs-20200101"), is(true));
GetAutoFollowPatternRequest getAutoFollowPatternRequest =
randomBoolean() ? new GetAutoFollowPatternRequest("pattern1") : new GetAutoFollowPatternRequest();

View File

@ -0,0 +1,376 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.elasticsearch.client.ccr;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.ccr.IndicesFollowStats.ShardFollowStats;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
public class CcrStatsResponseTests extends ESTestCase {
public void testFromXContent() throws IOException {
xContentTester(this::createParser,
CcrStatsResponseTests::createTestInstance,
CcrStatsResponseTests::toXContent,
CcrStatsResponse::fromXContent)
.supportsUnknownFields(false)
.assertEqualsConsumer(CcrStatsResponseTests::assertEqualInstances)
.assertToXContentEquivalence(false)
.test();
}
// Needed, because exceptions in IndicesFollowStats and AutoFollowStats cannot be compared
private static void assertEqualInstances(CcrStatsResponse expectedInstance, CcrStatsResponse newInstance) {
assertNotSame(expectedInstance, newInstance);
{
AutoFollowStats newAutoFollowStats = newInstance.getAutoFollowStats();
AutoFollowStats expectedAutoFollowStats = expectedInstance.getAutoFollowStats();
assertThat(newAutoFollowStats.getNumberOfSuccessfulFollowIndices(),
equalTo(expectedAutoFollowStats.getNumberOfSuccessfulFollowIndices()));
assertThat(newAutoFollowStats.getNumberOfFailedRemoteClusterStateRequests(),
equalTo(expectedAutoFollowStats.getNumberOfFailedRemoteClusterStateRequests()));
assertThat(newAutoFollowStats.getNumberOfFailedFollowIndices(),
equalTo(expectedAutoFollowStats.getNumberOfFailedFollowIndices()));
assertThat(newAutoFollowStats.getRecentAutoFollowErrors().size(),
equalTo(expectedAutoFollowStats.getRecentAutoFollowErrors().size()));
assertThat(newAutoFollowStats.getRecentAutoFollowErrors().keySet(),
equalTo(expectedAutoFollowStats.getRecentAutoFollowErrors().keySet()));
for (final Map.Entry<String, ElasticsearchException> entry : newAutoFollowStats.getRecentAutoFollowErrors().entrySet()) {
// x-content loses the exception
final ElasticsearchException expected = expectedAutoFollowStats.getRecentAutoFollowErrors().get(entry.getKey());
assertThat(entry.getValue().getMessage(), containsString(expected.getMessage()));
assertNotNull(entry.getValue().getCause());
assertThat(
entry.getValue().getCause(),
anyOf(instanceOf(ElasticsearchException.class), instanceOf(IllegalStateException.class)));
assertThat(entry.getValue().getCause().getMessage(), containsString(expected.getCause().getMessage()));
}
}
{
IndicesFollowStats newIndicesFollowStats = newInstance.getIndicesFollowStats();
IndicesFollowStats expectedIndicesFollowStats = expectedInstance.getIndicesFollowStats();
assertThat(newIndicesFollowStats.getShardFollowStats().size(),
equalTo(expectedIndicesFollowStats.getShardFollowStats().size()));
assertThat(newIndicesFollowStats.getShardFollowStats().keySet(),
equalTo(expectedIndicesFollowStats.getShardFollowStats().keySet()));
for (Map.Entry<String, List<ShardFollowStats>> indexEntry : newIndicesFollowStats.getShardFollowStats().entrySet()) {
List<ShardFollowStats> newStats = indexEntry.getValue();
List<ShardFollowStats> expectedStats = expectedIndicesFollowStats.getShardFollowStats(indexEntry.getKey());
assertThat(newStats.size(), equalTo(expectedStats.size()));
for (int i = 0; i < newStats.size(); i++) {
ShardFollowStats actualShardFollowStats = newStats.get(i);
ShardFollowStats expectedShardFollowStats = expectedStats.get(i);
assertThat(actualShardFollowStats.getRemoteCluster(), equalTo(expectedShardFollowStats.getRemoteCluster()));
assertThat(actualShardFollowStats.getLeaderIndex(), equalTo(expectedShardFollowStats.getLeaderIndex()));
assertThat(actualShardFollowStats.getFollowerIndex(), equalTo(expectedShardFollowStats.getFollowerIndex()));
assertThat(actualShardFollowStats.getShardId(), equalTo(expectedShardFollowStats.getShardId()));
assertThat(actualShardFollowStats.getLeaderGlobalCheckpoint(),
equalTo(expectedShardFollowStats.getLeaderGlobalCheckpoint()));
assertThat(actualShardFollowStats.getLeaderMaxSeqNo(), equalTo(expectedShardFollowStats.getLeaderMaxSeqNo()));
assertThat(actualShardFollowStats.getFollowerGlobalCheckpoint(),
equalTo(expectedShardFollowStats.getFollowerGlobalCheckpoint()));
assertThat(actualShardFollowStats.getLastRequestedSeqNo(), equalTo(expectedShardFollowStats.getLastRequestedSeqNo()));
assertThat(actualShardFollowStats.getOutstandingReadRequests(),
equalTo(expectedShardFollowStats.getOutstandingReadRequests()));
assertThat(actualShardFollowStats.getOutstandingWriteRequests(),
equalTo(expectedShardFollowStats.getOutstandingWriteRequests()));
assertThat(actualShardFollowStats.getWriteBufferOperationCount(),
equalTo(expectedShardFollowStats.getWriteBufferOperationCount()));
assertThat(actualShardFollowStats.getFollowerMappingVersion(),
equalTo(expectedShardFollowStats.getFollowerMappingVersion()));
assertThat(actualShardFollowStats.getFollowerSettingsVersion(),
equalTo(expectedShardFollowStats.getFollowerSettingsVersion()));
assertThat(actualShardFollowStats.getTotalReadTimeMillis(),
equalTo(expectedShardFollowStats.getTotalReadTimeMillis()));
assertThat(actualShardFollowStats.getSuccessfulReadRequests(),
equalTo(expectedShardFollowStats.getSuccessfulReadRequests()));
assertThat(actualShardFollowStats.getFailedReadRequests(), equalTo(expectedShardFollowStats.getFailedReadRequests()));
assertThat(actualShardFollowStats.getOperationsReads(), equalTo(expectedShardFollowStats.getOperationsReads()));
assertThat(actualShardFollowStats.getBytesRead(), equalTo(expectedShardFollowStats.getBytesRead()));
assertThat(actualShardFollowStats.getTotalWriteTimeMillis(),
equalTo(expectedShardFollowStats.getTotalWriteTimeMillis()));
assertThat(actualShardFollowStats.getSuccessfulWriteRequests(),
equalTo(expectedShardFollowStats.getSuccessfulWriteRequests()));
assertThat(actualShardFollowStats.getFailedWriteRequests(),
equalTo(expectedShardFollowStats.getFailedWriteRequests()));
assertThat(actualShardFollowStats.getOperationWritten(), equalTo(expectedShardFollowStats.getOperationWritten()));
assertThat(actualShardFollowStats.getReadExceptions().size(),
equalTo(expectedShardFollowStats.getReadExceptions().size()));
assertThat(actualShardFollowStats.getReadExceptions().keySet(),
equalTo(expectedShardFollowStats.getReadExceptions().keySet()));
for (final Map.Entry<Long, Tuple<Integer, ElasticsearchException>> entry :
actualShardFollowStats.getReadExceptions().entrySet()) {
final Tuple<Integer, ElasticsearchException> expectedTuple =
expectedShardFollowStats.getReadExceptions().get(entry.getKey());
assertThat(entry.getValue().v1(), equalTo(expectedTuple.v1()));
// x-content loses the exception
final ElasticsearchException expected = expectedTuple.v2();
assertThat(entry.getValue().v2().getMessage(), containsString(expected.getMessage()));
assertNotNull(entry.getValue().v2().getCause());
assertThat(
entry.getValue().v2().getCause(),
anyOf(instanceOf(ElasticsearchException.class), instanceOf(IllegalStateException.class)));
assertThat(entry.getValue().v2().getCause().getMessage(), containsString(expected.getCause().getMessage()));
}
assertThat(actualShardFollowStats.getTimeSinceLastReadMillis(),
equalTo(expectedShardFollowStats.getTimeSinceLastReadMillis()));
}
}
}
}
private static void toXContent(CcrStatsResponse response, XContentBuilder builder) throws IOException {
builder.startObject();
{
AutoFollowStats autoFollowStats = response.getAutoFollowStats();
builder.startObject(CcrStatsResponse.AUTO_FOLLOW_STATS_FIELD.getPreferredName());
{
builder.field(AutoFollowStats.NUMBER_OF_SUCCESSFUL_INDICES_AUTO_FOLLOWED.getPreferredName(),
autoFollowStats.getNumberOfSuccessfulFollowIndices());
builder.field(AutoFollowStats.NUMBER_OF_FAILED_REMOTE_CLUSTER_STATE_REQUESTS.getPreferredName(),
autoFollowStats.getNumberOfFailedRemoteClusterStateRequests());
builder.field(AutoFollowStats.NUMBER_OF_FAILED_INDICES_AUTO_FOLLOWED.getPreferredName(),
autoFollowStats.getNumberOfFailedFollowIndices());
builder.startArray(AutoFollowStats.RECENT_AUTO_FOLLOW_ERRORS.getPreferredName());
for (Map.Entry<String, ElasticsearchException> entry : autoFollowStats.getRecentAutoFollowErrors().entrySet()) {
builder.startObject();
{
builder.field(AutoFollowStats.LEADER_INDEX.getPreferredName(), entry.getKey());
builder.field(AutoFollowStats.AUTO_FOLLOW_EXCEPTION.getPreferredName());
builder.startObject();
{
ElasticsearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, entry.getValue());
}
builder.endObject();
}
builder.endObject();
}
builder.endArray();
}
builder.endObject();
IndicesFollowStats indicesFollowStats = response.getIndicesFollowStats();
builder.startObject(CcrStatsResponse.FOLLOW_STATS_FIELD.getPreferredName());
{
builder.startArray(IndicesFollowStats.INDICES_FIELD.getPreferredName());
for (Map.Entry<String, List<ShardFollowStats>> indexEntry :
indicesFollowStats.getShardFollowStats().entrySet()) {
builder.startObject();
{
builder.field(IndicesFollowStats.INDEX_FIELD.getPreferredName(), indexEntry.getKey());
builder.startArray(IndicesFollowStats.SHARDS_FIELD.getPreferredName());
{
for (ShardFollowStats stats : indexEntry.getValue()) {
builder.startObject();
{
builder.field(ShardFollowStats.LEADER_CLUSTER.getPreferredName(), stats.getRemoteCluster());
builder.field(ShardFollowStats.LEADER_INDEX.getPreferredName(), stats.getLeaderIndex());
builder.field(ShardFollowStats.FOLLOWER_INDEX.getPreferredName(), stats.getFollowerIndex());
builder.field(ShardFollowStats.SHARD_ID.getPreferredName(), stats.getShardId());
builder.field(ShardFollowStats.LEADER_GLOBAL_CHECKPOINT_FIELD.getPreferredName(),
stats.getLeaderGlobalCheckpoint());
builder.field(ShardFollowStats.LEADER_MAX_SEQ_NO_FIELD.getPreferredName(), stats.getLeaderMaxSeqNo());
builder.field(ShardFollowStats.FOLLOWER_GLOBAL_CHECKPOINT_FIELD.getPreferredName(),
stats.getFollowerGlobalCheckpoint());
builder.field(ShardFollowStats.FOLLOWER_MAX_SEQ_NO_FIELD.getPreferredName(),
stats.getFollowerMaxSeqNo());
builder.field(ShardFollowStats.LAST_REQUESTED_SEQ_NO_FIELD.getPreferredName(),
stats.getLastRequestedSeqNo());
builder.field(ShardFollowStats.OUTSTANDING_READ_REQUESTS.getPreferredName(),
stats.getOutstandingReadRequests());
builder.field(ShardFollowStats.OUTSTANDING_WRITE_REQUESTS.getPreferredName(),
stats.getOutstandingWriteRequests());
builder.field(ShardFollowStats.WRITE_BUFFER_OPERATION_COUNT_FIELD.getPreferredName(),
stats.getWriteBufferOperationCount());
builder.humanReadableField(
ShardFollowStats.WRITE_BUFFER_SIZE_IN_BYTES_FIELD.getPreferredName(),
"write_buffer_size",
new ByteSizeValue(stats.getWriteBufferSizeInBytes()));
builder.field(ShardFollowStats.FOLLOWER_MAPPING_VERSION_FIELD.getPreferredName(),
stats.getFollowerMappingVersion());
builder.field(ShardFollowStats.FOLLOWER_SETTINGS_VERSION_FIELD.getPreferredName(),
stats.getFollowerSettingsVersion());
builder.humanReadableField(
ShardFollowStats.TOTAL_READ_TIME_MILLIS_FIELD.getPreferredName(),
"total_read_time",
new TimeValue(stats.getTotalReadTimeMillis(), TimeUnit.MILLISECONDS));
builder.humanReadableField(
ShardFollowStats.TOTAL_READ_REMOTE_EXEC_TIME_MILLIS_FIELD.getPreferredName(),
"total_read_remote_exec_time",
new TimeValue(stats.getTotalReadRemoteExecTimeMillis(), TimeUnit.MILLISECONDS));
builder.field(ShardFollowStats.SUCCESSFUL_READ_REQUESTS_FIELD.getPreferredName(),
stats.getSuccessfulReadRequests());
builder.field(ShardFollowStats.FAILED_READ_REQUESTS_FIELD.getPreferredName(),
stats.getFailedReadRequests());
builder.field(ShardFollowStats.OPERATIONS_READ_FIELD.getPreferredName(), stats.getOperationsReads());
builder.humanReadableField(
ShardFollowStats.BYTES_READ.getPreferredName(),
"total_read",
new ByteSizeValue(stats.getBytesRead(), ByteSizeUnit.BYTES));
builder.humanReadableField(
ShardFollowStats.TOTAL_WRITE_TIME_MILLIS_FIELD.getPreferredName(),
"total_write_time",
new TimeValue(stats.getTotalWriteTimeMillis(), TimeUnit.MILLISECONDS));
builder.field(ShardFollowStats.SUCCESSFUL_WRITE_REQUESTS_FIELD.getPreferredName(),
stats.getSuccessfulWriteRequests());
builder.field(ShardFollowStats.FAILED_WRITE_REQUEST_FIELD.getPreferredName(),
stats.getFailedWriteRequests());
builder.field(ShardFollowStats.OPERATIONS_WRITTEN.getPreferredName(), stats.getOperationWritten());
builder.startArray(ShardFollowStats.READ_EXCEPTIONS.getPreferredName());
{
for (final Map.Entry<Long, Tuple<Integer, ElasticsearchException>> entry :
stats.getReadExceptions().entrySet()) {
builder.startObject();
{
builder.field(ShardFollowStats.READ_EXCEPTIONS_ENTRY_FROM_SEQ_NO.getPreferredName(),
entry.getKey());
builder.field(ShardFollowStats.READ_EXCEPTIONS_RETRIES.getPreferredName(),
entry.getValue().v1());
builder.field(ShardFollowStats.READ_EXCEPTIONS_ENTRY_EXCEPTION.getPreferredName());
builder.startObject();
{
ElasticsearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS,
entry.getValue().v2());
}
builder.endObject();
}
builder.endObject();
}
}
builder.endArray();
builder.humanReadableField(
ShardFollowStats.TIME_SINCE_LAST_READ_MILLIS_FIELD.getPreferredName(),
"time_since_last_read",
new TimeValue(stats.getTimeSinceLastReadMillis(), TimeUnit.MILLISECONDS));
if (stats.getFatalException() != null) {
builder.field(ShardFollowStats.FATAL_EXCEPTION.getPreferredName());
builder.startObject();
{
ElasticsearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS,
stats.getFatalException());
}
builder.endObject();
}
}
builder.endObject();
}
}
builder.endArray();
}
builder.endObject();
}
builder.endArray();
}
builder.endObject();
}
builder.endObject();
}
private static CcrStatsResponse createTestInstance() {
return new CcrStatsResponse(randomAutoFollowStats(), randomIndicesFollowStats());
}
private static AutoFollowStats randomAutoFollowStats() {
final int count = randomIntBetween(0, 16);
final NavigableMap<String, ElasticsearchException> readExceptions = new TreeMap<>();
for (int i = 0; i < count; i++) {
readExceptions.put("" + i, new ElasticsearchException(new IllegalStateException("index [" + i + "]")));
}
return new AutoFollowStats(
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
readExceptions
);
}
private static IndicesFollowStats randomIndicesFollowStats() {
int numIndices = randomIntBetween(0, 16);
NavigableMap<String, List<ShardFollowStats>> shardFollowStats = new TreeMap<>();
for (int i = 0; i < numIndices; i++) {
String index = randomAlphaOfLength(4);
int numShards = randomIntBetween(0, 5);
List<ShardFollowStats> stats = new ArrayList<>(numShards);
shardFollowStats.put(index, stats);
for (int j = 0; j < numShards; j++) {
final int count = randomIntBetween(0, 16);
final NavigableMap<Long, Tuple<Integer, ElasticsearchException>> readExceptions = new TreeMap<>();
for (long k = 0; k < count; k++) {
readExceptions.put(k, new Tuple<>(randomIntBetween(0, Integer.MAX_VALUE),
new ElasticsearchException(new IllegalStateException("index [" + k + "]"))));
}
stats.add(new ShardFollowStats(
randomAlphaOfLength(4),
randomAlphaOfLength(4),
randomAlphaOfLength(4),
randomInt(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomIntBetween(0, Integer.MAX_VALUE),
randomIntBetween(0, Integer.MAX_VALUE),
randomIntBetween(0, Integer.MAX_VALUE),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomNonNegativeLong(),
randomLong(),
readExceptions,
randomBoolean() ? new ElasticsearchException("fatal error") : null));
}
}
return new IndicesFollowStats(shardFollowStats);
}
}

View File

@ -33,10 +33,14 @@ import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.ccr.AutoFollowStats;
import org.elasticsearch.client.ccr.CcrStatsRequest;
import org.elasticsearch.client.ccr.CcrStatsResponse;
import org.elasticsearch.client.ccr.DeleteAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.GetAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.GetAutoFollowPatternResponse;
import org.elasticsearch.client.ccr.GetAutoFollowPatternResponse.Pattern;
import org.elasticsearch.client.ccr.IndicesFollowStats;
import org.elasticsearch.client.ccr.PauseFollowRequest;
import org.elasticsearch.client.ccr.PutAutoFollowPatternRequest;
import org.elasticsearch.client.ccr.PutFollowRequest;
@ -568,6 +572,57 @@ public class CCRDocumentationIT extends ESRestHighLevelClientTestCase {
}
}
public void testGetCCRStats() throws Exception {
RestHighLevelClient client = highLevelClient();
// tag::ccr-get-stats-request
CcrStatsRequest request =
new CcrStatsRequest(); // <1>
// end::ccr-get-stats-request
// tag::ccr-get-stats-execute
CcrStatsResponse response = client.ccr()
.getCcrStats(request, RequestOptions.DEFAULT);
// end::ccr-get-stats-execute
// tag::ccr-get-stats-response
IndicesFollowStats indicesFollowStats =
response.getIndicesFollowStats(); // <1>
AutoFollowStats autoFollowStats =
response.getAutoFollowStats(); // <2>
// end::ccr-get-stats-response
// tag::ccr-get-stats-execute-listener
ActionListener<CcrStatsResponse> listener =
new ActionListener<CcrStatsResponse>() {
@Override
public void onResponse(CcrStatsResponse response) { // <1>
IndicesFollowStats indicesFollowStats =
response.getIndicesFollowStats();
AutoFollowStats autoFollowStats =
response.getAutoFollowStats();
}
@Override
public void onFailure(Exception e) {
// <2>
}
};
// end::ccr-get-stats-execute-listener
// Replace the empty listener by a blocking listener in test
final CountDownLatch latch = new CountDownLatch(1);
listener = new LatchedActionListener<>(listener, latch);
// tag::ccr-get-stats-execute-async
client.ccr().getCcrStatsAsync(request,
RequestOptions.DEFAULT, listener); // <1>
// end::ccr-get-stats-execute-async
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
static Map<String, Object> toMap(Response response) throws IOException {
return XContentHelper.convertToMap(JsonXContent.jsonXContent, EntityUtils.toString(response.getEntity()), false);
}

View File

@ -0,0 +1,37 @@
--
:api: ccr-get-stats
:request: CcrStatsRequest
:response: CcrStatsResponse
--
[id="{upid}-{api}"]
=== Get CCR Stats API
[id="{upid}-{api}-request"]
==== Request
The Get CCR Stats API allows you to get statistics about index following and auto following.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-request]
--------------------------------------------------
<1> The request accepts no parameters.
[id="{upid}-{api}-response"]
==== Response
The returned +{response}+ always includes index follow statistics of all follow indices and
auto follow statistics.
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-response]
--------------------------------------------------
<1> The follow stats of active follower indices.
<2> The auto follow stats of the cluster that has been queried.
include::../execution.asciidoc[]

View File

@ -473,6 +473,7 @@ The Java High Level REST Client supports the following CCR APIs:
* <<{upid}-ccr-put-auto-follow-pattern>>
* <<{upid}-ccr-delete-auto-follow-pattern>>
* <<{upid}-ccr-get-auto-follow-pattern>>
* <<{upid}-ccr-get-stats>>
include::ccr/put_follow.asciidoc[]
include::ccr/pause_follow.asciidoc[]
@ -481,6 +482,7 @@ include::ccr/unfollow.asciidoc[]
include::ccr/put_auto_follow_pattern.asciidoc[]
include::ccr/delete_auto_follow_pattern.asciidoc[]
include::ccr/get_auto_follow_pattern.asciidoc[]
include::ccr/get_stats.asciidoc[]
== Index Lifecycle Management APIs