[CCR] Added auto_follow_exception.timestamp field to auto follow stats (#36947)

Currently auto follow stats users are unable to see whether an auto follow
error was recent or old. The new timestamp field will help user distinguish
between old and new errors.
This commit is contained in:
Martijn van Groningen 2018-12-24 07:53:51 +01:00 committed by GitHub
parent 4fb62fcba6
commit 44fe265d82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 110 additions and 65 deletions

View File

@ -21,6 +21,7 @@ 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;
@ -38,6 +39,7 @@ public final class AutoFollowStats {
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 TIMESTAMP = new ParseField("timestamp");
static final ParseField AUTO_FOLLOW_EXCEPTION = new ParseField("auto_follow_exception");
static final ParseField AUTO_FOLLOWED_CLUSTERS = new ParseField("auto_followed_clusters");
static final ParseField CLUSTER_NAME = new ParseField("cluster_name");
@ -51,7 +53,7 @@ public final class AutoFollowStats {
(Long) args[1],
(Long) args[2],
new TreeMap<>(
((List<Map.Entry<String, ElasticsearchException>>) args[3])
((List<Map.Entry<String, Tuple<Long, ElasticsearchException>>>) args[3])
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
new TreeMap<>(
@ -60,10 +62,10 @@ public final class AutoFollowStats {
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))
));
private static final ConstructingObjectParser<Map.Entry<String, ElasticsearchException>, Void> AUTO_FOLLOW_EXCEPTIONS_PARSER =
static final ConstructingObjectParser<Map.Entry<String, Tuple<Long, ElasticsearchException>>, Void> AUTO_FOLLOW_EXCEPTIONS_PARSER =
new ConstructingObjectParser<>(
"auto_follow_stats_errors",
args -> new AbstractMap.SimpleEntry<>((String) args[0], (ElasticsearchException) args[1]));
args -> new AbstractMap.SimpleEntry<>((String) args[0], Tuple.tuple((Long) args[1], (ElasticsearchException) args[2])));
private static final ConstructingObjectParser<Map.Entry<String, AutoFollowedCluster>, Void> AUTO_FOLLOWED_CLUSTERS_PARSER =
new ConstructingObjectParser<>(
@ -72,6 +74,7 @@ public final class AutoFollowStats {
static {
AUTO_FOLLOW_EXCEPTIONS_PARSER.declareString(ConstructingObjectParser.constructorArg(), LEADER_INDEX);
AUTO_FOLLOW_EXCEPTIONS_PARSER.declareLong(ConstructingObjectParser.constructorArg(), TIMESTAMP);
AUTO_FOLLOW_EXCEPTIONS_PARSER.declareObject(
ConstructingObjectParser.constructorArg(),
(p, c) -> ElasticsearchException.fromXContent(p),
@ -93,13 +96,13 @@ public final class AutoFollowStats {
private final long numberOfFailedFollowIndices;
private final long numberOfFailedRemoteClusterStateRequests;
private final long numberOfSuccessfulFollowIndices;
private final NavigableMap<String, ElasticsearchException> recentAutoFollowErrors;
private final NavigableMap<String, Tuple<Long, ElasticsearchException>> recentAutoFollowErrors;
private final NavigableMap<String, AutoFollowedCluster> autoFollowedClusters;
AutoFollowStats(long numberOfFailedFollowIndices,
long numberOfFailedRemoteClusterStateRequests,
long numberOfSuccessfulFollowIndices,
NavigableMap<String, ElasticsearchException> recentAutoFollowErrors,
NavigableMap<String, Tuple<Long, ElasticsearchException>> recentAutoFollowErrors,
NavigableMap<String, AutoFollowedCluster> autoFollowedClusters) {
this.numberOfFailedFollowIndices = numberOfFailedFollowIndices;
this.numberOfFailedRemoteClusterStateRequests = numberOfFailedRemoteClusterStateRequests;
@ -120,7 +123,7 @@ public final class AutoFollowStats {
return numberOfSuccessfulFollowIndices;
}
public NavigableMap<String, ElasticsearchException> getRecentAutoFollowErrors() {
public NavigableMap<String, Tuple<Long, ElasticsearchException>> getRecentAutoFollowErrors() {
return recentAutoFollowErrors;
}

View File

@ -74,15 +74,18 @@ public class CcrStatsResponseTests extends ESTestCase {
equalTo(expectedAutoFollowStats.getRecentAutoFollowErrors().size()));
assertThat(newAutoFollowStats.getRecentAutoFollowErrors().keySet(),
equalTo(expectedAutoFollowStats.getRecentAutoFollowErrors().keySet()));
for (final Map.Entry<String, ElasticsearchException> entry : newAutoFollowStats.getRecentAutoFollowErrors().entrySet()) {
for (final Map.Entry<String, Tuple<Long, 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());
final Tuple<Long, ElasticsearchException> expected =
expectedAutoFollowStats.getRecentAutoFollowErrors().get(entry.getKey());
assertThat(entry.getValue().v2().getMessage(), containsString(expected.v2().getMessage()));
assertThat(entry.getValue().v1(), equalTo(expected.v1()));
assertNotNull(entry.getValue().v2().getCause());
assertThat(
entry.getValue().getCause(),
entry.getValue().v2().getCause(),
anyOf(instanceOf(ElasticsearchException.class), instanceOf(IllegalStateException.class)));
assertThat(entry.getValue().getCause().getMessage(), containsString(expected.getCause().getMessage()));
assertThat(entry.getValue().v2().getCause().getMessage(), containsString(expected.v2().getCause().getMessage()));
}
}
{
@ -172,14 +175,16 @@ public class CcrStatsResponseTests extends ESTestCase {
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()) {
for (Map.Entry<String, Tuple<Long, ElasticsearchException>> entry :
autoFollowStats.getRecentAutoFollowErrors().entrySet()) {
builder.startObject();
{
builder.field(AutoFollowStats.LEADER_INDEX.getPreferredName(), entry.getKey());
builder.field(AutoFollowStats.TIMESTAMP.getPreferredName(), entry.getValue().v1());
builder.field(AutoFollowStats.AUTO_FOLLOW_EXCEPTION.getPreferredName());
builder.startObject();
{
ElasticsearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, entry.getValue());
ElasticsearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, entry.getValue().v2());
}
builder.endObject();
}
@ -325,9 +330,10 @@ public class CcrStatsResponseTests extends ESTestCase {
private static AutoFollowStats randomAutoFollowStats() {
final int count = randomIntBetween(0, 16);
final NavigableMap<String, ElasticsearchException> readExceptions = new TreeMap<>();
final NavigableMap<String, Tuple<Long, ElasticsearchException>> readExceptions = new TreeMap<>();
for (int i = 0; i < count; i++) {
readExceptions.put("" + i, new ElasticsearchException(new IllegalStateException("index [" + i + "]")));
readExceptions.put("" + i, Tuple.tuple(randomNonNegativeLong(),
new ElasticsearchException(new IllegalStateException("index [" + i + "]"))));
}
final NavigableMap<String, AutoFollowedCluster> autoFollowClusters = new TreeMap<>();
for (int i = 0; i < count; i++) {

View File

@ -162,7 +162,8 @@ public class Ccr extends Plugin implements ActionPlugin, PersistentTaskPlugin, E
ccrLicenseChecker,
restoreSourceService,
new CcrRepositoryManager(settings, clusterService, client),
new AutoFollowCoordinator(settings, client, clusterService, ccrLicenseChecker, threadPool::relativeTimeInMillis)
new AutoFollowCoordinator(settings, client, clusterService, ccrLicenseChecker,
threadPool::relativeTimeInMillis, threadPool::absoluteTimeInMillis)
);
}

View File

@ -74,6 +74,7 @@ public class AutoFollowCoordinator implements ClusterStateListener {
private final ClusterService clusterService;
private final CcrLicenseChecker ccrLicenseChecker;
private final LongSupplier relativeMillisTimeProvider;
private final LongSupplier absoluteMillisTimeProvider;
private volatile TimeValue waitForMetadataTimeOut;
private volatile Map<String, AutoFollower> autoFollowers = Collections.emptyMap();
@ -82,23 +83,25 @@ public class AutoFollowCoordinator implements ClusterStateListener {
private long numberOfSuccessfulIndicesAutoFollowed = 0;
private long numberOfFailedIndicesAutoFollowed = 0;
private long numberOfFailedRemoteClusterStateRequests = 0;
private final LinkedHashMap<String, ElasticsearchException> recentAutoFollowErrors;
private final LinkedHashMap<String, Tuple<Long, ElasticsearchException>> recentAutoFollowErrors;
public AutoFollowCoordinator(
Settings settings,
Client client,
ClusterService clusterService,
CcrLicenseChecker ccrLicenseChecker,
LongSupplier relativeMillisTimeProvider) {
LongSupplier relativeMillisTimeProvider,
LongSupplier absoluteMillisTimeProvider) {
this.client = client;
this.clusterService = clusterService;
this.ccrLicenseChecker = Objects.requireNonNull(ccrLicenseChecker, "ccrLicenseChecker");
this.relativeMillisTimeProvider = relativeMillisTimeProvider;
this.absoluteMillisTimeProvider = absoluteMillisTimeProvider;
clusterService.addListener(this);
this.recentAutoFollowErrors = new LinkedHashMap<String, ElasticsearchException>() {
this.recentAutoFollowErrors = new LinkedHashMap<String, Tuple<Long, ElasticsearchException>>() {
@Override
protected boolean removeEldestEntry(final Map.Entry<String, ElasticsearchException> eldest) {
protected boolean removeEldestEntry(final Map.Entry<String, Tuple<Long, ElasticsearchException>> eldest) {
return size() > MAX_AUTO_FOLLOW_ERRORS;
}
};
@ -138,10 +141,11 @@ public class AutoFollowCoordinator implements ClusterStateListener {
}
synchronized void updateStats(List<AutoFollowResult> results) {
long newStatsReceivedTimeStamp = absoluteMillisTimeProvider.getAsLong();
for (AutoFollowResult result : results) {
if (result.clusterStateFetchException != null) {
recentAutoFollowErrors.put(result.autoFollowPatternName,
new ElasticsearchException(result.clusterStateFetchException));
Tuple.tuple(newStatsReceivedTimeStamp, new ElasticsearchException(result.clusterStateFetchException)));
numberOfFailedRemoteClusterStateRequests++;
LOGGER.warn(new ParameterizedMessage("failure occurred while fetching cluster state for auto follow pattern [{}]",
result.autoFollowPatternName), result.clusterStateFetchException);
@ -150,7 +154,7 @@ public class AutoFollowCoordinator implements ClusterStateListener {
if (entry.getValue() != null) {
numberOfFailedIndicesAutoFollowed++;
recentAutoFollowErrors.put(result.autoFollowPatternName + ":" + entry.getKey().getName(),
ExceptionsHelper.convertToElastic(entry.getValue()));
Tuple.tuple(newStatsReceivedTimeStamp, ExceptionsHelper.convertToElastic(entry.getValue())));
LOGGER.warn(new ParameterizedMessage("failure occurred while auto following index [{}] for auto follow " +
"pattern [{}]", entry.getKey(), result.autoFollowPatternName), entry.getValue());
} else {

View File

@ -281,12 +281,12 @@ public class AutoFollowIT extends CcrIntegTestCase {
assertThat(autoFollowStats.getNumberOfFailedRemoteClusterStateRequests(), equalTo(0L));
assertThat(autoFollowStats.getRecentAutoFollowErrors().size(), equalTo(2));
ElasticsearchException autoFollowError1 = autoFollowStats.getRecentAutoFollowErrors().get("my-pattern1:logs-201801");
ElasticsearchException autoFollowError1 = autoFollowStats.getRecentAutoFollowErrors().get("my-pattern1:logs-201801").v2();
assertThat(autoFollowError1, notNullValue());
assertThat(autoFollowError1.getRootCause().getMessage(), equalTo("index to follow [logs-201801] for pattern [my-pattern1] " +
"matches with other patterns [my-pattern2]"));
ElasticsearchException autoFollowError2 = autoFollowStats.getRecentAutoFollowErrors().get("my-pattern2:logs-201801");
ElasticsearchException autoFollowError2 = autoFollowStats.getRecentAutoFollowErrors().get("my-pattern2:logs-201801").v2();
assertThat(autoFollowError2, notNullValue());
assertThat(autoFollowError2.getRootCause().getMessage(), equalTo("index to follow [logs-201801] for pattern [my-pattern2] " +
"matches with other patterns [my-pattern1]"));
@ -311,7 +311,7 @@ public class AutoFollowIT extends CcrIntegTestCase {
assertThat(autoFollowStats.getNumberOfSuccessfulFollowIndices(), equalTo(0L));
assertThat(autoFollowStats.getNumberOfFailedFollowIndices(), equalTo(1L));
assertThat(autoFollowStats.getRecentAutoFollowErrors().size(), equalTo(1));
ElasticsearchException failure = autoFollowStats.getRecentAutoFollowErrors().firstEntry().getValue();
ElasticsearchException failure = autoFollowStats.getRecentAutoFollowErrors().firstEntry().getValue().v2();
assertThat(failure.getMessage(), equalTo("index [logs-20200101] cannot be followed, " +
"because soft deletes are not enabled"));
IndicesExistsRequest request = new IndicesExistsRequest("copy-logs-20200101");

View File

@ -539,7 +539,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
null,
mockClusterService(),
new CcrLicenseChecker(() -> true, () -> false),
() -> 1L);
() -> 1L, () -> 1L);
autoFollowCoordinator.updateStats(Collections.singletonList(
new AutoFollowCoordinator.AutoFollowResult("_alias1"))
@ -558,7 +558,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
assertThat(autoFollowStats.getNumberOfFailedRemoteClusterStateRequests(), equalTo(1L));
assertThat(autoFollowStats.getNumberOfSuccessfulFollowIndices(), equalTo(0L));
assertThat(autoFollowStats.getRecentAutoFollowErrors().size(), equalTo(1));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1").getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1").v2().getCause().getMessage(), equalTo("error"));
autoFollowCoordinator.updateStats(Arrays.asList(
new AutoFollowCoordinator.AutoFollowResult("_alias1",
@ -571,9 +571,9 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
assertThat(autoFollowStats.getNumberOfFailedRemoteClusterStateRequests(), equalTo(1L));
assertThat(autoFollowStats.getNumberOfSuccessfulFollowIndices(), equalTo(0L));
assertThat(autoFollowStats.getRecentAutoFollowErrors().size(), equalTo(3));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1").getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1:index1").getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias2:index2").getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1").v2().getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1:index1").v2().getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias2:index2").v2().getCause().getMessage(), equalTo("error"));
autoFollowCoordinator.updateStats(Arrays.asList(
new AutoFollowCoordinator.AutoFollowResult("_alias1",
@ -586,9 +586,9 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
assertThat(autoFollowStats.getNumberOfFailedRemoteClusterStateRequests(), equalTo(1L));
assertThat(autoFollowStats.getNumberOfSuccessfulFollowIndices(), equalTo(2L));
assertThat(autoFollowStats.getRecentAutoFollowErrors().size(), equalTo(3));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1").getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1:index1").getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias2:index2").getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1").v2().getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias1:index1").v2().getCause().getMessage(), equalTo("error"));
assertThat(autoFollowStats.getRecentAutoFollowErrors().get("_alias2:index2").v2().getCause().getMessage(), equalTo("error"));
}
public void testUpdateAutoFollowers() {
@ -604,7 +604,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
null,
clusterService,
new CcrLicenseChecker(() -> true, () -> false),
() -> 1L);
() -> 1L, () -> 1L);
// Add 3 patterns:
Map<String, AutoFollowPattern> patterns = new HashMap<>();
patterns.put("pattern1", new AutoFollowPattern("remote1", Collections.singletonList("logs-*"), null, null, null,
@ -659,7 +659,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
null,
mockClusterService(),
new CcrLicenseChecker(() -> true, () -> false),
() -> 1L);
() -> 1L, () -> 1L);
ClusterState clusterState = ClusterState.builder(new ClusterName("remote"))
.metaData(MetaData.builder().putCustom(AutoFollowMetadata.TYPE,
new AutoFollowMetadata(Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap())))
@ -674,7 +674,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
null,
mockClusterService(),
new CcrLicenseChecker(() -> true, () -> false),
() -> 1L);
() -> 1L, () -> 1L);
ClusterState clusterState = ClusterState.builder(new ClusterName("remote")).build();
autoFollowCoordinator.updateAutoFollowers(clusterState);
assertThat(autoFollowCoordinator.getStats().getAutoFollowedClusters().size(), equalTo(0));

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.ccr.action;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractSerializingTestCase;
@ -40,11 +41,12 @@ public class AutoFollowStatsTests extends AbstractSerializingTestCase<AutoFollow
);
}
static NavigableMap<String, ElasticsearchException> randomReadExceptions() {
static NavigableMap<String, Tuple<Long, ElasticsearchException>> randomReadExceptions() {
final int count = randomIntBetween(0, 16);
final NavigableMap<String, ElasticsearchException> readExceptions = new TreeMap<>();
final NavigableMap<String, Tuple<Long, ElasticsearchException>> readExceptions = new TreeMap<>();
for (int i = 0; i < count; i++) {
readExceptions.put("" + i, new ElasticsearchException(new IllegalStateException("index [" + i + "]")));
readExceptions.put("" + i, Tuple.tuple(randomNonNegativeLong(),
new ElasticsearchException(new IllegalStateException("index [" + i + "]"))));
}
return readExceptions;
}
@ -74,15 +76,16 @@ public class AutoFollowStatsTests extends AbstractSerializingTestCase<AutoFollow
assertThat(newInstance.getRecentAutoFollowErrors().size(), equalTo(expectedInstance.getRecentAutoFollowErrors().size()));
assertThat(newInstance.getRecentAutoFollowErrors().keySet(), equalTo(expectedInstance.getRecentAutoFollowErrors().keySet()));
for (final Map.Entry<String, ElasticsearchException> entry : newInstance.getRecentAutoFollowErrors().entrySet()) {
for (final Map.Entry<String, Tuple<Long, ElasticsearchException>> entry : newInstance.getRecentAutoFollowErrors().entrySet()) {
// x-content loses the exception
final ElasticsearchException expected = expectedInstance.getRecentAutoFollowErrors().get(entry.getKey());
assertThat(entry.getValue().getMessage(), containsString(expected.getMessage()));
assertNotNull(entry.getValue().getCause());
final Tuple<Long, ElasticsearchException> expected = expectedInstance.getRecentAutoFollowErrors().get(entry.getKey());
assertThat(entry.getValue().v1(), equalTo(expected.v1()));
assertThat(entry.getValue().v2().getMessage(), containsString(expected.v2().getMessage()));
assertNotNull(entry.getValue().v2().getCause());
assertThat(
entry.getValue().getCause(),
entry.getValue().v2().getCause(),
anyOf(instanceOf(ElasticsearchException.class), instanceOf(IllegalStateException.class)));
assertThat(entry.getValue().getCause().getMessage(), containsString(expected.getCause().getMessage()));
assertThat(entry.getValue().v2().getCause().getMessage(), containsString(expected.v2().getCause().getMessage()));
}
assertThat(newInstance.getAutoFollowedClusters(), equalTo(expectedInstance.getAutoFollowedClusters()));

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.monitoring.collector.ccr;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
@ -72,10 +73,10 @@ public class AutoFollowStatsMonitoringDocTests extends BaseMonitoringDocTestCase
final long nodeTimestamp = System.currentTimeMillis();
final MonitoringDoc.Node node = new MonitoringDoc.Node("_uuid", "_host", "_addr", "_ip", "_name", nodeTimestamp);
final NavigableMap<String, ElasticsearchException> recentAutoFollowExceptions =
final NavigableMap<String, Tuple<Long, ElasticsearchException>> recentAutoFollowExceptions =
new TreeMap<>(Collections.singletonMap(
randomAlphaOfLength(4),
new ElasticsearchException("cannot follow index")));
Tuple.tuple(1L, new ElasticsearchException("cannot follow index"))));
final NavigableMap<String, AutoFollowedCluster> trackingClusters =
new TreeMap<>(Collections.singletonMap(
@ -112,6 +113,7 @@ public class AutoFollowStatsMonitoringDocTests extends BaseMonitoringDocTestCase
+ "\"recent_auto_follow_errors\":["
+ "{"
+ "\"leader_index\":\"" + recentAutoFollowExceptions.keySet().iterator().next() + "\","
+ "\"timestamp\":1,"
+ "\"auto_follow_exception\":{"
+ "\"type\":\"exception\","
+ "\"reason\":\"cannot follow index\""
@ -132,8 +134,8 @@ public class AutoFollowStatsMonitoringDocTests extends BaseMonitoringDocTestCase
}
public void testShardFollowNodeTaskStatusFieldsMapped() throws IOException {
final NavigableMap<String, ElasticsearchException> fetchExceptions =
new TreeMap<>(Collections.singletonMap("leader_index", new ElasticsearchException("cannot follow index")));
final NavigableMap<String, Tuple<Long, ElasticsearchException>> fetchExceptions =
new TreeMap<>(Collections.singletonMap("leader_index", Tuple.tuple(1L, new ElasticsearchException("cannot follow index"))));
final NavigableMap<String, AutoFollowedCluster> trackingClusters =
new TreeMap<>(Collections.singletonMap(
randomAlphaOfLength(4),
@ -169,6 +171,7 @@ public class AutoFollowStatsMonitoringDocTests extends BaseMonitoringDocTestCase
assertThat(fieldType, equalTo("nested"));
assertThat(((Map<?, ?>) fieldMapping.get("properties")).size(), equalTo(innerFieldValue.size()));
assertThat(XContentMapValues.extractValue("properties.leader_index.type", fieldMapping), equalTo("keyword"));
assertThat(XContentMapValues.extractValue("properties.timestamp.type", fieldMapping), equalTo("long"));
assertThat(XContentMapValues.extractValue("properties.auto_follow_exception.type", fieldMapping), equalTo("object"));
innerFieldValue = (Map<?, ?>) innerFieldValue.get("auto_follow_exception");

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.core.ccr;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
@ -35,6 +36,7 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
private static final ParseField RECENT_AUTO_FOLLOW_ERRORS = new ParseField("recent_auto_follow_errors");
private static final ParseField LEADER_INDEX = new ParseField("leader_index");
private static final ParseField AUTO_FOLLOW_EXCEPTION = new ParseField("auto_follow_exception");
private static final ParseField TIMESTAMP = new ParseField("timestamp");
private static final ParseField AUTO_FOLLOWED_CLUSTERS = new ParseField("auto_followed_clusters");
private static final ParseField CLUSTER_NAME = new ParseField("cluster_name");
private static final ParseField TIME_SINCE_LAST_CHECK_MILLIS = new ParseField("time_since_last_check_millis");
@ -47,7 +49,7 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
(Long) args[1],
(Long) args[2],
new TreeMap<>(
((List<Map.Entry<String, ElasticsearchException>>) args[3])
((List<Map.Entry<String, Tuple<Long, ElasticsearchException>>>) args[3])
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
new TreeMap<>(
@ -55,10 +57,11 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))));
private static final ConstructingObjectParser<Map.Entry<String, ElasticsearchException>, Void> AUTO_FOLLOW_EXCEPTIONS_PARSER =
private static final ConstructingObjectParser<Map.Entry<String,
Tuple<Long, ElasticsearchException>>, Void> AUTO_FOLLOW_EXCEPTIONS_PARSER =
new ConstructingObjectParser<>(
"auto_follow_stats_errors",
args -> new AbstractMap.SimpleEntry<>((String) args[0], (ElasticsearchException) args[1]));
args -> new AbstractMap.SimpleEntry<>((String) args[0], new Tuple<>((Long) args[1], (ElasticsearchException) args[2])));
private static final ConstructingObjectParser<Map.Entry<String, AutoFollowedCluster>, Void> AUTO_FOLLOWED_CLUSTERS_PARSER =
new ConstructingObjectParser<>(
@ -67,6 +70,7 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
static {
AUTO_FOLLOW_EXCEPTIONS_PARSER.declareString(ConstructingObjectParser.constructorArg(), LEADER_INDEX);
AUTO_FOLLOW_EXCEPTIONS_PARSER.declareLong(ConstructingObjectParser.constructorArg(), TIMESTAMP);
AUTO_FOLLOW_EXCEPTIONS_PARSER.declareObject(
ConstructingObjectParser.constructorArg(),
(p, c) -> ElasticsearchException.fromXContent(p),
@ -91,14 +95,14 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
private final long numberOfFailedFollowIndices;
private final long numberOfFailedRemoteClusterStateRequests;
private final long numberOfSuccessfulFollowIndices;
private final NavigableMap<String, ElasticsearchException> recentAutoFollowErrors;
private final NavigableMap<String, Tuple<Long, ElasticsearchException>> recentAutoFollowErrors;
private final NavigableMap<String, AutoFollowedCluster> autoFollowedClusters;
public AutoFollowStats(
long numberOfFailedFollowIndices,
long numberOfFailedRemoteClusterStateRequests,
long numberOfSuccessfulFollowIndices,
NavigableMap<String, ElasticsearchException> recentAutoFollowErrors,
NavigableMap<String, Tuple<Long, ElasticsearchException>> recentAutoFollowErrors,
NavigableMap<String, AutoFollowedCluster> autoFollowedClusters
) {
this.numberOfFailedFollowIndices = numberOfFailedFollowIndices;
@ -112,7 +116,13 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
numberOfFailedFollowIndices = in.readVLong();
numberOfFailedRemoteClusterStateRequests = in.readVLong();
numberOfSuccessfulFollowIndices = in.readVLong();
recentAutoFollowErrors = new TreeMap<>(in.readMap(StreamInput::readString, StreamInput::readException));
if (in.getVersion().onOrAfter(Version.V_6_7_0)) {
recentAutoFollowErrors = new TreeMap<>(in.readMap(StreamInput::readString,
in1 -> new Tuple<>(in1.readZLong(), in1.readException())));
} else {
recentAutoFollowErrors = new TreeMap<>(in.readMap(StreamInput::readString,
in1 -> new Tuple<>(-1L, in1.readException())));
}
if (in.getVersion().onOrAfter(Version.V_6_6_0)) {
autoFollowedClusters = new TreeMap<>(in.readMap(StreamInput::readString, AutoFollowedCluster::new));
} else {
@ -125,7 +135,14 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
out.writeVLong(numberOfFailedFollowIndices);
out.writeVLong(numberOfFailedRemoteClusterStateRequests);
out.writeVLong(numberOfSuccessfulFollowIndices);
out.writeMap(recentAutoFollowErrors, StreamOutput::writeString, StreamOutput::writeException);
if (out.getVersion().onOrAfter(Version.V_6_7_0)) {
out.writeMap(recentAutoFollowErrors, StreamOutput::writeString, (out1, value) -> {
out1.writeZLong(value.v1());
out1.writeException(value.v2());
});
} else {
out.writeMap(recentAutoFollowErrors, StreamOutput::writeString, (out1, value) -> out1.writeException(value.v2()));
}
if (out.getVersion().onOrAfter(Version.V_6_6_0)) {
out.writeMap(autoFollowedClusters, StreamOutput::writeString, (out1, value) -> value.writeTo(out1));
}
@ -143,7 +160,7 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
return numberOfSuccessfulFollowIndices;
}
public NavigableMap<String, ElasticsearchException> getRecentAutoFollowErrors() {
public NavigableMap<String, Tuple<Long, ElasticsearchException>> getRecentAutoFollowErrors() {
return recentAutoFollowErrors;
}
@ -167,14 +184,15 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
builder.field(NUMBER_OF_SUCCESSFUL_INDICES_AUTO_FOLLOWED.getPreferredName(), numberOfSuccessfulFollowIndices);
builder.startArray(RECENT_AUTO_FOLLOW_ERRORS.getPreferredName());
{
for (final Map.Entry<String, ElasticsearchException> entry : recentAutoFollowErrors.entrySet()) {
for (final Map.Entry<String, Tuple<Long, ElasticsearchException>> entry : recentAutoFollowErrors.entrySet()) {
builder.startObject();
{
builder.field(LEADER_INDEX.getPreferredName(), entry.getKey());
builder.field(TIMESTAMP.getPreferredName(), entry.getValue().v1());
builder.field(AUTO_FOLLOW_EXCEPTION.getPreferredName());
builder.startObject();
{
ElasticsearchException.generateThrowableXContent(builder, params, entry.getValue());
ElasticsearchException.generateThrowableXContent(builder, params, entry.getValue().v2());
}
builder.endObject();
}
@ -233,7 +251,11 @@ public class AutoFollowStats implements Writeable, ToXContentObject {
}
private static List<String> getFetchExceptionMessages(final AutoFollowStats status) {
return status.getRecentAutoFollowErrors().values().stream().map(ElasticsearchException::getMessage).collect(Collectors.toList());
return status.getRecentAutoFollowErrors().values()
.stream()
.map(Tuple::v2)
.map(ElasticsearchException::getMessage)
.collect(Collectors.toList());
}
@Override

View File

@ -1048,6 +1048,9 @@
"leader_index": {
"type": "keyword"
},
"timestamp": {
"type": "long"
},
"auto_follow_exception": {
"type": "object",
"properties": {