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 index b442336ca4d..bb286b6e5d5 100644 --- 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 @@ -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>) args[3]) + ((List>>) 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, Void> AUTO_FOLLOW_EXCEPTIONS_PARSER = + static final ConstructingObjectParser>, 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, 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 recentAutoFollowErrors; + private final NavigableMap> recentAutoFollowErrors; private final NavigableMap autoFollowedClusters; AutoFollowStats(long numberOfFailedFollowIndices, long numberOfFailedRemoteClusterStateRequests, long numberOfSuccessfulFollowIndices, - NavigableMap recentAutoFollowErrors, + NavigableMap> recentAutoFollowErrors, NavigableMap autoFollowedClusters) { this.numberOfFailedFollowIndices = numberOfFailedFollowIndices; this.numberOfFailedRemoteClusterStateRequests = numberOfFailedRemoteClusterStateRequests; @@ -120,7 +123,7 @@ public final class AutoFollowStats { return numberOfSuccessfulFollowIndices; } - public NavigableMap getRecentAutoFollowErrors() { + public NavigableMap> getRecentAutoFollowErrors() { return recentAutoFollowErrors; } 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 index 8d53b5cde08..b818b7ae421 100644 --- 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 @@ -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 entry : newAutoFollowStats.getRecentAutoFollowErrors().entrySet()) { + 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()); + final Tuple 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 entry : autoFollowStats.getRecentAutoFollowErrors().entrySet()) { + for (Map.Entry> 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 readExceptions = new TreeMap<>(); + final NavigableMap> 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 autoFollowClusters = new TreeMap<>(); for (int i = 0; i < count; i++) { diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java index 8d677866e32..b3d2d050482 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/Ccr.java @@ -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) ); } diff --git a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinator.java b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinator.java index 8d91c39fe93..89c1144cbd6 100644 --- a/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinator.java +++ b/x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinator.java @@ -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 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 recentAutoFollowErrors; + private final LinkedHashMap> recentAutoFollowErrors; public AutoFollowCoordinator( - Settings settings, - Client client, - ClusterService clusterService, - CcrLicenseChecker ccrLicenseChecker, - LongSupplier relativeMillisTimeProvider) { + Settings settings, + Client client, + ClusterService clusterService, + CcrLicenseChecker ccrLicenseChecker, + 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() { + this.recentAutoFollowErrors = new LinkedHashMap>() { @Override - protected boolean removeEldestEntry(final Map.Entry eldest) { + protected boolean removeEldestEntry(final Map.Entry> eldest) { return size() > MAX_AUTO_FOLLOW_ERRORS; } }; @@ -138,10 +141,11 @@ public class AutoFollowCoordinator implements ClusterStateListener { } synchronized void updateStats(List 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 { diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/AutoFollowIT.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/AutoFollowIT.java index 6c85b2cb489..1db42dba44e 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/AutoFollowIT.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/AutoFollowIT.java @@ -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"); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinatorTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinatorTests.java index 3acdde52a44..1eb4a7dcced 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinatorTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinatorTests.java @@ -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 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)); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowStatsTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowStatsTests.java index 61b92b485c1..8023213aeae 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowStatsTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/action/AutoFollowStatsTests.java @@ -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 randomReadExceptions() { + static NavigableMap> randomReadExceptions() { final int count = randomIntBetween(0, 16); - final NavigableMap readExceptions = new TreeMap<>(); + final NavigableMap> 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 entry : newInstance.getRecentAutoFollowErrors().entrySet()) { + for (final Map.Entry> 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 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())); diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/monitoring/collector/ccr/AutoFollowStatsMonitoringDocTests.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/monitoring/collector/ccr/AutoFollowStatsMonitoringDocTests.java index cebb7cfd775..a764086f889 100644 --- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/monitoring/collector/ccr/AutoFollowStatsMonitoringDocTests.java +++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/monitoring/collector/ccr/AutoFollowStatsMonitoringDocTests.java @@ -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 recentAutoFollowExceptions = + final NavigableMap> recentAutoFollowExceptions = new TreeMap<>(Collections.singletonMap( randomAlphaOfLength(4), - new ElasticsearchException("cannot follow index"))); + Tuple.tuple(1L, new ElasticsearchException("cannot follow index")))); final NavigableMap 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 fetchExceptions = - new TreeMap<>(Collections.singletonMap("leader_index", new ElasticsearchException("cannot follow index"))); + final NavigableMap> fetchExceptions = + new TreeMap<>(Collections.singletonMap("leader_index", Tuple.tuple(1L, new ElasticsearchException("cannot follow index")))); final NavigableMap 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"); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/AutoFollowStats.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/AutoFollowStats.java index 032cedbdcdf..e709959b279 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/AutoFollowStats.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ccr/AutoFollowStats.java @@ -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>) args[3]) + ((List>>) 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, Void> AUTO_FOLLOW_EXCEPTIONS_PARSER = + 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])); + args -> new AbstractMap.SimpleEntry<>((String) args[0], new Tuple<>((Long) args[1], (ElasticsearchException) args[2]))); private static final ConstructingObjectParser, 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 recentAutoFollowErrors; + private final NavigableMap> recentAutoFollowErrors; private final NavigableMap autoFollowedClusters; public AutoFollowStats( long numberOfFailedFollowIndices, long numberOfFailedRemoteClusterStateRequests, long numberOfSuccessfulFollowIndices, - NavigableMap recentAutoFollowErrors, + NavigableMap> recentAutoFollowErrors, NavigableMap 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 getRecentAutoFollowErrors() { + public NavigableMap> 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 entry : recentAutoFollowErrors.entrySet()) { + for (final Map.Entry> 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 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 diff --git a/x-pack/plugin/core/src/main/resources/monitoring-es.json b/x-pack/plugin/core/src/main/resources/monitoring-es.json index c34fed37516..872d3df43a8 100644 --- a/x-pack/plugin/core/src/main/resources/monitoring-es.json +++ b/x-pack/plugin/core/src/main/resources/monitoring-es.json @@ -1048,6 +1048,9 @@ "leader_index": { "type": "keyword" }, + "timestamp": { + "type": "long" + }, "auto_follow_exception": { "type": "object", "properties": {