Skip to content

Commit fd822b4

Browse files
authored
Expose index age in ILM explain output (#44457)
* Expose index age in ILM explain output This adds the index's age to the ILM explain output, for example: ``` { "indices" : { "ilm-000001" : { "index" : "ilm-000001", "managed" : true, "policy" : "full-lifecycle", "lifecycle_date" : "2019-07-16T19:48:22.294Z", "lifecycle_date_millis" : 1563306502294, "age" : "1.34m", "phase" : "hot", "phase_time" : "2019-07-16T19:48:22.487Z", ... etc ... } } } ``` This age can be used to tell when ILM will transition the index to the next phase, based on that phase's `min_age`. Resolves #38988 * Expose age in getters and in HLRC
1 parent bbe97b0 commit fd822b4

File tree

12 files changed

+108
-32
lines changed

12 files changed

+108
-32
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/indexlifecycle/IndexLifecycleExplainResponse.java

+11
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.elasticsearch.common.Strings;
2424
import org.elasticsearch.common.bytes.BytesArray;
2525
import org.elasticsearch.common.bytes.BytesReference;
26+
import org.elasticsearch.common.unit.TimeValue;
2627
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
2728
import org.elasticsearch.common.xcontent.ToXContentObject;
2829
import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -52,6 +53,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject {
5253
private static final ParseField STEP_TIME_FIELD = new ParseField("step_time");
5354
private static final ParseField STEP_INFO_FIELD = new ParseField("step_info");
5455
private static final ParseField PHASE_EXECUTION_INFO = new ParseField("phase_execution");
56+
private static final ParseField AGE_FIELD = new ParseField("age");
5557

5658
public static final ConstructingObjectParser<IndexLifecycleExplainResponse, Void> PARSER = new ConstructingObjectParser<>(
5759
"index_lifecycle_explain_response", true,
@@ -205,6 +207,14 @@ public PhaseExecutionInfo getPhaseExecutionInfo() {
205207
return phaseExecutionInfo;
206208
}
207209

210+
public TimeValue getAge() {
211+
if (lifecycleDate == null) {
212+
return TimeValue.MINUS_ONE;
213+
} else {
214+
return TimeValue.timeValueMillis(System.currentTimeMillis() - lifecycleDate);
215+
}
216+
}
217+
208218
@Override
209219
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
210220
builder.startObject();
@@ -214,6 +224,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
214224
builder.field(POLICY_NAME_FIELD.getPreferredName(), policyName);
215225
if (lifecycleDate != null) {
216226
builder.timeField(LIFECYCLE_DATE_MILLIS_FIELD.getPreferredName(), LIFECYCLE_DATE_FIELD.getPreferredName(), lifecycleDate);
227+
builder.field(AGE_FIELD.getPreferredName(), getAge().toHumanReadableString(2));
217228
}
218229
if (phase != null) {
219230
builder.field(PHASE_FIELD.getPreferredName(), phase);

client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/ExplainLifecycleResponseTests.java

+5
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ protected boolean supportsUnknownFields() {
5252
return false;
5353
}
5454

55+
@Override
56+
protected boolean assertToXContentEquivalence() {
57+
return false;
58+
}
59+
5560
@Override
5661
protected NamedXContentRegistry xContentRegistry() {
5762
List<NamedXContentRegistry.Entry> entries = new ArrayList<>(ClusterModule.getNamedXWriteables());

client/rest-high-level/src/test/java/org/elasticsearch/client/indexlifecycle/IndexLifecycleExplainResponseTests.java

+5
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ protected boolean supportsUnknownFields() {
103103
return true;
104104
}
105105

106+
@Override
107+
protected boolean assertToXContentEquivalence() {
108+
return false;
109+
}
110+
106111
@Override
107112
protected Predicate<String> getRandomFieldsExcludeFilter() {
108113
return (field) ->

docs/reference/ilm/apis/explain.asciidoc

+11-6
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,13 @@ that the index is managed and in the `new` phase:
9898
"managed": true, <1>
9999
"policy": "my_policy", <2>
100100
"lifecycle_date_millis": 1538475653281, <3>
101+
"age": "15s", <4>
101102
"phase": "new",
102-
"phase_time_millis": 1538475653317, <4>
103+
"phase_time_millis": 1538475653317, <5>
103104
"action": "complete",
104-
"action_time_millis": 1538475653317, <5>
105+
"action_time_millis": 1538475653317, <6>
105106
"step": "complete",
106-
"step_time_millis": 1538475653317 <6>
107+
"step_time_millis": 1538475653317 <7>
107108
}
108109
}
109110
}
@@ -114,9 +115,10 @@ that the index is managed and in the `new` phase:
114115
ILM the other fields will not be shown
115116
<2> The name of the policy which ILM is using for this index
116117
<3> The timestamp used for the `min_age`
117-
<4> When the index entered the current phase
118-
<5> When the index entered the current action
119-
<6> When the index entered the current step
118+
<4> The age of the index (used for calculating when to enter the next phase)
119+
<5> When the index entered the current phase
120+
<6> When the index entered the current action
121+
<7> When the index entered the current step
120122

121123
Once the policy is running on the index, the response includes a
122124
`phase_execution` object that shows the definition of the current phase.
@@ -133,6 +135,7 @@ phase completes.
133135
"policy": "my_lifecycle3",
134136
"lifecycle_date_millis": 1538475653281,
135137
"lifecycle_date": "2018-10-15T13:45:21.981Z",
138+
"age": "25.14s",
136139
"phase": "hot",
137140
"phase_time_millis": 1538475653317,
138141
"phase_time": "2018-10-15T13:45:22.577Z",
@@ -181,6 +184,7 @@ information for the step that's being performed on the index.
181184
"policy": "my_lifecycle3",
182185
"lifecycle_date_millis": 1538475653281,
183186
"lifecycle_date": "2018-10-15T13:45:21.981Z",
187+
"age": "4.12m",
184188
"phase": "warm",
185189
"phase_time_millis": 1538475653317,
186190
"phase_time": "2018-10-15T13:45:22.577Z",
@@ -241,6 +245,7 @@ the step that failed and the step info provides information about the error.
241245
"policy": "my_lifecycle3",
242246
"lifecycle_date_millis": 1538475653281,
243247
"lifecycle_date": "2018-10-15T13:45:21.981Z",
248+
"age": "50.1d",
244249
"phase": "hot",
245250
"phase_time_millis": 1538475653317,
246251
"phase_time": "2018-10-15T13:45:22.577Z",

docs/reference/ilm/error-handling.asciidoc

+16-14
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,21 @@ Which returns the following information:
7676
"managed" : true, <1>
7777
"policy" : "shrink-the-index", <2>
7878
"lifecycle_date_millis" : 1541717265865,
79-
"phase" : "warm", <3>
79+
"age": "5.1d", <3>
80+
"phase" : "warm", <4>
8081
"phase_time_millis" : 1541717272601,
81-
"action" : "shrink", <4>
82+
"action" : "shrink", <5>
8283
"action_time_millis" : 1541717272601,
83-
"step" : "ERROR", <5>
84+
"step" : "ERROR", <6>
8485
"step_time_millis" : 1541717272688,
85-
"failed_step" : "shrink", <6>
86+
"failed_step" : "shrink", <7>
8687
"step_info" : {
87-
"type" : "illegal_argument_exception", <7>
88-
"reason" : "the number of target shards [4] must be less that the number of source shards [2]" <8>
88+
"type" : "illegal_argument_exception", <8>
89+
"reason" : "the number of target shards [4] must be less that the number of source shards [2]" <9>
8990
},
9091
"phase_execution" : {
9192
"policy" : "shrink-the-index",
92-
"phase_definition" : { <9>
93+
"phase_definition" : { <10>
9394
"min_age" : "5d",
9495
"actions" : {
9596
"shrink" : {
@@ -108,13 +109,14 @@ Which returns the following information:
108109
// TESTRESPONSE[skip:no way to know if we will get this response immediately]
109110
<1> this index is managed by ILM
110111
<2> the policy in question, in this case, "shrink-the-index"
111-
<3> what phase the index is currently in
112-
<4> what action the index is currently on
113-
<5> what step the index is currently on, in this case, because there is an error, the index is in the "ERROR" step
114-
<6> the name of the step that failed to execute, in this case "shrink"
115-
<7> the error class that occurred during this step
116-
<8> the error message that occurred during the execution failure
117-
<9> the definition of the phase (in this case, the "warm" phase) that the index is currently on
112+
<3> the current age for the index
113+
<4> what phase the index is currently in
114+
<5> what action the index is currently on
115+
<6> what step the index is currently on, in this case, because there is an error, the index is in the "ERROR" step
116+
<7> the name of the step that failed to execute, in this case "shrink"
117+
<8> the error class that occurred during this step
118+
<9> the error message that occurred during the execution failure
119+
<10> the definition of the phase (in this case, the "warm" phase) that the index is currently on
118120

119121
The index here has been moved to the error step because the shrink definition in
120122
the policy is using an incorrect number of shards. So rectifying that in the

docs/reference/ilm/getting-started-ilm.asciidoc

+12-10
Original file line numberDiff line numberDiff line change
@@ -173,15 +173,16 @@ managed indices.
173173
"managed": true, <1>
174174
"policy": "datastream_policy", <2>
175175
"lifecycle_date_millis": 1538475653281,
176-
"phase": "hot", <3>
176+
"age": "30s", <3>
177+
"phase": "hot", <4>
177178
"phase_time_millis": 1538475653317,
178-
"action": "rollover", <4>
179+
"action": "rollover", <5>
179180
"action_time_millis": 1538475653317,
180-
"step": "attempt-rollover", <5>
181+
"step": "attempt-rollover", <6>
181182
"step_time_millis": 1538475653317,
182183
"phase_execution": {
183184
"policy": "datastream_policy",
184-
"phase_definition": { <6>
185+
"phase_definition": { <7>
185186
"min_age": "0ms",
186187
"actions": {
187188
"rollover": {
@@ -190,7 +191,7 @@ managed indices.
190191
}
191192
}
192193
},
193-
"version": 1, <7>
194+
"version": 1, <8>
194195
"modified_date_in_millis": 1539609701576
195196
}
196197
}
@@ -201,12 +202,13 @@ managed indices.
201202
// TESTRESPONSE[skip:no way to know if we will get this response immediately]
202203
<1> this index is managed by ILM
203204
<2> the policy in question, in this case, "datastream_policy"
204-
<3> what phase the index is currently in
205-
<4> what action the index is currently on
206-
<5> what step the index is currently on
207-
<6> the definition of the phase
205+
<3> the current age of the index
206+
<4> what phase the index is currently in
207+
<5> what action the index is currently on
208+
<6> what step the index is currently on
209+
<7> the definition of the phase
208210
(in this case, the "hot" phase) that the index is currently on
209-
<7> the version of the policy being used to execute the current phase
211+
<8> the version of the policy being used to execute the current phase
210212

211213
You can read about the full details of this response in the
212214
<<ilm-explain-lifecycle, explain API docs>>. For now, let's focus on how

docs/reference/ilm/update-lifecycle-policy.asciidoc

+4
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ GET my_index/_ilm/explain
198198
"managed": true,
199199
"policy": "my_executing_policy",
200200
"lifecycle_date_millis": 1538475653281,
201+
"age": "30s",
201202
"phase": "hot",
202203
"phase_time_millis": 1538475653317,
203204
"action": "rollover",
@@ -275,6 +276,7 @@ GET my_index/_ilm/explain
275276
"managed": true,
276277
"policy": "my_executing_policy",
277278
"lifecycle_date_millis": 1538475653281,
279+
"age": "30s",
278280
"phase": "hot",
279281
"phase_time_millis": 1538475653317,
280282
"action": "rollover",
@@ -354,6 +356,7 @@ GET my_index/_ilm/explain
354356
"managed": true,
355357
"policy": "my_executing_policy",
356358
"lifecycle_date_millis": 1538475653281,
359+
"age": "30s",
357360
"phase": "hot",
358361
"phase_time_millis": 1538475653317,
359362
"action": "rollover",
@@ -408,6 +411,7 @@ GET my_index/_ilm/explain
408411
"managed": true,
409412
"policy": "my_executing_policy",
410413
"lifecycle_date_millis": 1538475653281,
414+
"age": "30s",
411415
"phase": "warm",
412416
"phase_time_millis": 1538475653317,
413417
"action": "forcemerge",

test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public final void testFromXContent() throws IOException {
4343
.shuffleFieldsExceptions(getShuffleFieldsExceptions())
4444
.randomFieldsExcludeFilter(getRandomFieldsExcludeFilter())
4545
.assertEqualsConsumer(this::assertEqualInstances)
46-
.assertToXContentEquivalence(true)
46+
.assertToXContentEquivalence(assertToXContentEquivalence())
4747
.test();
4848
}
4949

@@ -83,6 +83,16 @@ protected String[] getShuffleFieldsExceptions() {
8383
return Strings.EMPTY_ARRAY;
8484
}
8585

86+
/**
87+
* Whether or not to assert equivalence of the {@link org.elasticsearch.common.xcontent.XContent} of the test instance and the instance
88+
* parsed from the {@link org.elasticsearch.common.xcontent.XContent} of the test instance.
89+
*
90+
* @return true if equivalence should be asserted, otherwise false
91+
*/
92+
protected boolean assertToXContentEquivalence() {
93+
return true;
94+
}
95+
8696
/**
8797
* Params that have to be provided when calling calling {@link ToXContent#toXContent(XContentBuilder, ToXContent.Params)}
8898
*/

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleExplainResponse.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.elasticsearch.common.io.stream.StreamInput;
1414
import org.elasticsearch.common.io.stream.StreamOutput;
1515
import org.elasticsearch.common.io.stream.Writeable;
16+
import org.elasticsearch.common.unit.TimeValue;
1617
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
1718
import org.elasticsearch.common.xcontent.ToXContentObject;
1819
import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -42,6 +43,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
4243
private static final ParseField STEP_TIME_FIELD = new ParseField("step_time");
4344
private static final ParseField STEP_INFO_FIELD = new ParseField("step_info");
4445
private static final ParseField PHASE_EXECUTION_INFO = new ParseField("phase_execution");
46+
private static final ParseField AGE_FIELD = new ParseField("age");
4547

4648
public static final ConstructingObjectParser<IndexLifecycleExplainResponse, Void> PARSER = new ConstructingObjectParser<>(
4749
"index_lifecycle_explain_response",
@@ -58,7 +60,9 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
5860
(Long) (a[9]),
5961
(Long) (a[10]),
6062
(BytesReference) a[11],
61-
(PhaseExecutionInfo) a[12]));
63+
(PhaseExecutionInfo) a[12]
64+
// a[13] == "age"
65+
));
6266
static {
6367
PARSER.declareString(ConstructingObjectParser.constructorArg(), INDEX_FIELD);
6468
PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), MANAGED_BY_ILM_FIELD);
@@ -78,6 +82,7 @@ public class IndexLifecycleExplainResponse implements ToXContentObject, Writeabl
7882
}, STEP_INFO_FIELD);
7983
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(), (p, c) -> PhaseExecutionInfo.parse(p, ""),
8084
PHASE_EXECUTION_INFO);
85+
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), AGE_FIELD);
8186
}
8287

8388
private final String index;
@@ -243,6 +248,14 @@ public PhaseExecutionInfo getPhaseExecutionInfo() {
243248
return phaseExecutionInfo;
244249
}
245250

251+
public TimeValue getAge() {
252+
if (lifecycleDate == null) {
253+
return TimeValue.MINUS_ONE;
254+
} else {
255+
return TimeValue.timeValueMillis(System.currentTimeMillis() - lifecycleDate);
256+
}
257+
}
258+
246259
@Override
247260
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
248261
builder.startObject();
@@ -252,6 +265,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
252265
builder.field(POLICY_NAME_FIELD.getPreferredName(), policyName);
253266
if (lifecycleDate != null) {
254267
builder.timeField(LIFECYCLE_DATE_MILLIS_FIELD.getPreferredName(), LIFECYCLE_DATE_FIELD.getPreferredName(), lifecycleDate);
268+
builder.field(AGE_FIELD.getPreferredName(), getAge().toHumanReadableString(2));
255269
}
256270
if (phase != null) {
257271
builder.field(PHASE_FIELD.getPreferredName(), phase);

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/ExplainLifecycleResponseTests.java

+5
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ protected boolean supportsUnknownFields() {
5656
return false;
5757
}
5858

59+
@Override
60+
protected boolean assertToXContentEquivalence() {
61+
return false;
62+
}
63+
5964
protected NamedWriteableRegistry getNamedWriteableRegistry() {
6065
return new NamedWriteableRegistry(Arrays
6166
.asList(new NamedWriteableRegistry.Entry(LifecycleAction.class, MockAction.NAME, MockAction::new)));

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleExplainResponseTests.java

+5
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ protected IndexLifecycleExplainResponse doParseInstance(XContentParser parser) t
9393
return IndexLifecycleExplainResponse.PARSER.apply(parser, null);
9494
}
9595

96+
@Override
97+
protected boolean assertToXContentEquivalence() {
98+
return false;
99+
}
100+
96101
@Override
97102
protected IndexLifecycleExplainResponse mutateInstance(IndexLifecycleExplainResponse instance) throws IOException {
98103
String index = instance.getIndex();

0 commit comments

Comments
 (0)