diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrClient.java
index 25eb260eec4df..243eee12195d8 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrClient.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrClient.java
@@ -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 void getAutoFollowPatternAsync(GetAutoFollowPatternRequest request,
);
}
+ /**
+ * Gets all CCR stats.
+ *
+ * See
+ * the docs 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
+ * the docs 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 listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(
+ request,
+ CcrRequestConverters::getCcrStats,
+ options,
+ CcrStatsResponse::fromXContent,
+ listener,
+ Collections.emptySet()
+ );
+ }
+
}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrRequestConverters.java
index 5bcb0c04d3b86..8644651c59110 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrRequestConverters.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrRequestConverters.java
@@ -23,6 +23,7 @@
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 @@ static Request getAutoFollowPattern(GetAutoFollowPatternRequest getAutoFollowPat
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);
+ }
+
}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/AutoFollowStats.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/AutoFollowStats.java
new file mode 100644
index 0000000000000..09b57e68ff522
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/AutoFollowStats.java
@@ -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 STATS_PARSER = new ConstructingObjectParser<>("auto_follow_stats",
+ args -> new AutoFollowStats(
+ (Long) args[0],
+ (Long) args[1],
+ (Long) args[2],
+ new TreeMap<>(
+ ((List>) args[3])
+ .stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))
+ ));
+
+ private static final ConstructingObjectParser, 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 recentAutoFollowErrors;
+
+ AutoFollowStats(long numberOfFailedFollowIndices,
+ long numberOfFailedRemoteClusterStateRequests,
+ long numberOfSuccessfulFollowIndices,
+ NavigableMap 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 getRecentAutoFollowErrors() {
+ return recentAutoFollowErrors;
+ }
+
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/CcrStatsRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/CcrStatsRequest.java
new file mode 100644
index 0000000000000..97f48535fef99
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/CcrStatsRequest.java
@@ -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 {
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/CcrStatsResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/CcrStatsResponse.java
new file mode 100644
index 0000000000000..889a96683bfb3
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/CcrStatsResponse.java
@@ -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 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;
+ }
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/IndicesFollowStats.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/IndicesFollowStats.java
new file mode 100644
index 0000000000000..02e2fc4f4ed18
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/IndicesFollowStats.java
@@ -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>, Void> ENTRY_PARSER =
+ new ConstructingObjectParser<>(
+ "entry",
+ args -> {
+ String index = (String) args[0];
+ @SuppressWarnings("unchecked")
+ List shardFollowStats = (List) 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 PARSER = new ConstructingObjectParser<>("indices",
+ args -> {
+ @SuppressWarnings("unchecked")
+ List>> entries = (List>>) args[0];
+ Map> 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> shardFollowStats;
+
+ IndicesFollowStats(NavigableMap> shardFollowStats) {
+ this.shardFollowStats = Collections.unmodifiableNavigableMap(shardFollowStats);
+ }
+
+ public List getShardFollowStats(String index) {
+ return shardFollowStats.get(index);
+ }
+
+ public Map> 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 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>>) args[26])
+ .stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
+ (ElasticsearchException) args[27]));
+
+ static final ConstructingObjectParser>, 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> 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> 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> getReadExceptions() {
+ return readExceptions;
+ }
+
+ public ElasticsearchException getFatalException() {
+ return fatalException;
+ }
+ }
+
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java
index 391ee1fcd18b4..2c63835af8c52 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java
@@ -29,9 +29,12 @@
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.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 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 void testIndexFollowing() throws Exception {
assertThat(leaderSearchResponse.getHits().getTotalHits(), equalTo(1L));
assertBusy(() -> {
+ CcrStatsRequest ccrStatsRequest = new CcrStatsRequest();
+ CcrStatsResponse ccrStatsResponse = execute(ccrStatsRequest, ccrClient::getCcrStats, ccrClient::getCcrStatsAsync);
+ List 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 void testIndexFollowing() throws Exception {
assertThat(resumeFollowResponse.isAcknowledged(), is(true));
assertBusy(() -> {
+ CcrStatsRequest ccrStatsRequest = new CcrStatsRequest();
+ CcrStatsResponse ccrStatsResponse = execute(ccrStatsRequest, ccrClient::getCcrStats, ccrClient::getCcrStatsAsync);
+ List 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 void testAutoFollowing() throws Exception {
assertThat(response.isAcknowledged(), is(true));
assertBusy(() -> {
- assertThat(indexExists("copy-logs-20200101"), is(true));
- // TODO: replace with HLRC follow stats when available:
- Map 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();
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ccr/CcrStatsResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ccr/CcrStatsResponseTests.java
new file mode 100644
index 0000000000000..66e80130baf4a
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ccr/CcrStatsResponseTests.java
@@ -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 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> indexEntry : newIndicesFollowStats.getShardFollowStats().entrySet()) {
+ List newStats = indexEntry.getValue();
+ List 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> entry :
+ actualShardFollowStats.getReadExceptions().entrySet()) {
+ final Tuple 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 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> 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> 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 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> shardFollowStats = new TreeMap<>();
+ for (int i = 0; i < numIndices; i++) {
+ String index = randomAlphaOfLength(4);
+ int numShards = randomIntBetween(0, 5);
+ List stats = new ArrayList<>(numShards);
+ shardFollowStats.put(index, stats);
+ for (int j = 0; j < numShards; j++) {
+ final int count = randomIntBetween(0, 16);
+ final NavigableMap> 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);
+ }
+
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java
index fea6ad0fbd720..42bd600a224f8 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java
@@ -33,10 +33,14 @@
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 void onFailure(Exception e) {
}
}
+ 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 listener =
+ new ActionListener() {
+ @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 toMap(Response response) throws IOException {
return XContentHelper.convertToMap(JsonXContent.jsonXContent, EntityUtils.toString(response.getEntity()), false);
}
diff --git a/docs/java-rest/high-level/ccr/get_stats.asciidoc b/docs/java-rest/high-level/ccr/get_stats.asciidoc
new file mode 100644
index 0000000000000..28c9e107a09f2
--- /dev/null
+++ b/docs/java-rest/high-level/ccr/get_stats.asciidoc
@@ -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[]
+
+
diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc
index 661ce78fe80a5..a8d5e580f840c 100644
--- a/docs/java-rest/high-level/supported-apis.asciidoc
+++ b/docs/java-rest/high-level/supported-apis.asciidoc
@@ -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