From 22824e47bc894e7d06e27a6fa7b221488516cb35 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Thu, 17 Mar 2022 04:52:51 -0400 Subject: [PATCH] TSDB: Add dimensions and timestamp to parse errors (#84962) This adds a list of dimensions and `@timestamp` to the parse errors we make in tsdb if the `_tsid` or `@timestamp` are built. --- .../index/mapper/DocumentParserContext.java | 2 +- .../index/mapper/IdFieldMapper.java | 2 +- .../index/mapper/ProvidedIdFieldMapper.java | 4 +- .../mapper/TsidExtractingIdFieldMapper.java | 30 ++- .../index/mapper/DocumentParserTests.java | 18 +- .../mapper/ProvidedIdFieldMapperTests.java | 12 +- .../TsidExtractingIdFieldMapperTests.java | 177 +++++++++++------- 7 files changed, 171 insertions(+), 74 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DocumentParserContext.java b/server/src/main/java/org/elasticsearch/index/mapper/DocumentParserContext.java index b4d50ff7ee8a6..90d0aa5abc8fb 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DocumentParserContext.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DocumentParserContext.java @@ -220,7 +220,7 @@ public final void seqID(SeqNoFieldMapper.SequenceIDFields seqID) { */ public final String documentDescription() { IdFieldMapper idMapper = (IdFieldMapper) getMetadataMapper(IdFieldMapper.NAME); - return idMapper.documentDescription(sourceToParse); + return idMapper.documentDescription(this); } /** diff --git a/server/src/main/java/org/elasticsearch/index/mapper/IdFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/IdFieldMapper.java index 6a44994bd764a..fb85fcd0465c8 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/IdFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/IdFieldMapper.java @@ -35,7 +35,7 @@ protected final String contentType() { * Description on the document being parsed used in error messages. Not * called unless there is an error. */ - public abstract String documentDescription(SourceToParse source); + public abstract String documentDescription(DocumentParserContext context); /** * Create a {@link Field} to store the provided {@code _id} that "stores" diff --git a/server/src/main/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapper.java index 86be5f90b8841..0ccf52a046dc3 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapper.java @@ -271,7 +271,7 @@ public void preParse(DocumentParserContext context) { } @Override - public String documentDescription(SourceToParse source) { - return "document with id '" + source.id() + "'"; + public String documentDescription(DocumentParserContext context) { + return "document with id '" + context.sourceToParse().id() + "'"; } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/TsidExtractingIdFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/TsidExtractingIdFieldMapper.java index 79fbf0553e2b7..32a4d5d228726 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/TsidExtractingIdFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/TsidExtractingIdFieldMapper.java @@ -37,6 +37,11 @@ */ public class TsidExtractingIdFieldMapper extends IdFieldMapper { private static final FieldType FIELD_TYPE = new FieldType(); + /** + * Maximum length of the {@code _tsid} in the {@link #documentDescription}. + */ + static final int DESCRIPTION_TSID_LIMIT = 1000; + static { FIELD_TYPE.setTokenized(false); FIELD_TYPE.setIndexOptions(IndexOptions.DOCS); @@ -156,13 +161,28 @@ public void createField(DocumentParserContext context, BytesRef tsid) { } @Override - public String documentDescription(SourceToParse source) { + public String documentDescription(DocumentParserContext context) { /* * We don't yet have an _id because it'd be generated by the document - * parsing process. And the _id isn't all that useful anyway - what - * folks really want to to see is the dimensions and timestamp. And - * those too aren't available until after we've parsed the document. + * parsing process. But we *might* have something more useful - the + * time series dimensions and the timestamp! If we have those, then + * include them in the description. If not, all we know is + * "a time series document". */ - return "a time series document"; + StringBuilder description = new StringBuilder("a time series document"); + IndexableField tsidField = context.doc().getField(TimeSeriesIdFieldMapper.NAME); + if (tsidField != null) { + String tsid = TimeSeriesIdFieldMapper.decodeTsid(tsidField.binaryValue()).toString(); + if (tsid.length() > DESCRIPTION_TSID_LIMIT) { + tsid = tsid.substring(0, DESCRIPTION_TSID_LIMIT) + "...}"; + } + description.append(" with dimensions ").append(tsid); + } + IndexableField timestampField = context.doc().getField(DataStreamTimestampFieldMapper.DEFAULT_PATH); + if (timestampField != null) { + String timestamp = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.formatMillis(timestampField.numericValue().longValue()); + description.append(" at [").append(timestamp).append(']'); + } + return description.toString(); } } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java index 2cc7f9ee1ed6c..727682bcd5d0f 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java @@ -2049,7 +2049,23 @@ public void testDocumentDescriptionInTsdb() throws IOException { MapperException.class, () -> mapper.parse(source(null, b -> b.field("foo", true), null)) ); - assertThat(exception.getMessage(), containsString("failed to parse field [foo] of type [long] in a time series document")); + assertThat( + exception.getMessage(), + equalTo("failed to parse field [foo] of type [long] in a time series document. Preview of field's value: 'true'") + ); + } + { + MapperException exception = expectThrows( + MapperException.class, + () -> mapper.parse(source(null, b -> b.field("@timestamp", "2021-04-28T00:01:00Z").field("foo", true), null)) + ); + assertThat( + exception.getMessage(), + equalTo( + "failed to parse field [foo] of type [long] in a time series document at " + + "[2021-04-28T00:01:00.000Z]. Preview of field's value: 'true'" + ) + ); } } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapperTests.java index 53f2f9501f9ed..c177f23373d85 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/ProvidedIdFieldMapperTests.java @@ -12,6 +12,8 @@ import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.IndexSearcher; +import org.elasticsearch.Version; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.indices.IndicesService; import org.elasticsearch.search.lookup.SearchLookup; @@ -89,7 +91,15 @@ public void testFetchIdFieldValue() throws IOException { public void testDescription() throws IOException { String id = randomAlphaOfLength(4); assertThat( - ProvidedIdFieldMapper.NO_FIELD_DATA.documentDescription(source(id, b -> {}, randomAlphaOfLength(2))), + ProvidedIdFieldMapper.NO_FIELD_DATA.documentDescription( + new TestDocumentParserContext( + MappingLookup.EMPTY, + MapperTestCase.createIndexSettings(Version.CURRENT, Settings.EMPTY), + null, + null, + source(id, b -> {}, randomAlphaOfLength(2)) + ) + ), equalTo("document with id '" + id + "'") ); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/TsidExtractingIdFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/TsidExtractingIdFieldMapperTests.java index 6961589bdd086..91f36c7005605 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/TsidExtractingIdFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/TsidExtractingIdFieldMapperTests.java @@ -9,6 +9,8 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import org.apache.lucene.document.LongPoint; +import org.apache.lucene.index.IndexableField; import org.elasticsearch.Version; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.routing.IndexRouting; @@ -25,6 +27,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.stream.Stream; import static org.hamcrest.Matchers.equalTo; @@ -32,12 +35,14 @@ public class TsidExtractingIdFieldMapperTests extends MetadataMapperTestCase { private static class TestCase { private final String name; private final String expectedId; + private final String expectedTsid; private final CheckedConsumer source; private final List> equivalentSources = new ArrayList<>(); - TestCase(String name, String expectedId, CheckedConsumer source) { + TestCase(String name, String expectedId, String expectedTsid, CheckedConsumer source) { this.name = name; this.expectedId = expectedId; + this.expectedTsid = expectedTsid; this.source = source; } @@ -50,6 +55,10 @@ public TestCase and(CheckedConsumer equivalentSour public String toString() { return name; } + + public CheckedConsumer randomSource() { + return randomFrom(Stream.concat(Stream.of(source), equivalentSources.stream()).toList()); + } } @ParametersFactory @@ -63,29 +72,29 @@ public static Iterable params() { */ // Dates - items.add(new TestCase("2022-01-01T01:00:00Z", "XsFI2ezm5OViFixWgIomE34BAAA", b -> { + items.add(new TestCase("2022-01-01T01:00:00Z", "XsFI2ezm5OViFixWgIomE34BAAA", "{r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); })); - items.add(new TestCase("2022-01-01T01:00:01Z", "XsFI2ezm5OViFixWaI4mE34BAAA", b -> { + items.add(new TestCase("2022-01-01T01:00:01Z", "XsFI2ezm5OViFixWaI4mE34BAAA", "{r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:01Z"); b.field("r1", "cat"); })); - items.add(new TestCase("1970-01-01T00:00:00Z", "XsFI2ezm5OViFixWAAAAAAAAAAA", b -> { + items.add(new TestCase("1970-01-01T00:00:00Z", "XsFI2ezm5OViFixWAAAAAAAAAAA", "{r1=cat}", b -> { b.field("@timestamp", "1970-01-01T00:00:00Z"); b.field("r1", "cat"); })); - items.add(new TestCase("-9998-01-01T00:00:00Z", "XsFI2ezm5OViFixWABhgBIKo_v8", b -> { + items.add(new TestCase("-9998-01-01T00:00:00Z", "XsFI2ezm5OViFixWABhgBIKo_v8", "{r1=cat}", b -> { b.field("@timestamp", "-9998-01-01T00:00:00Z"); b.field("r1", "cat"); })); - items.add(new TestCase("9998-01-01T00:00:00Z", "XsFI2ezm5OViFixWAIS9ImnmAAA", b -> { + items.add(new TestCase("9998-01-01T00:00:00Z", "XsFI2ezm5OViFixWAIS9ImnmAAA", "{r1=cat}", b -> { b.field("@timestamp", "9998-01-01T00:00:00Z"); b.field("r1", "cat"); })); // routing keywords - items.add(new TestCase("r1", "XsFI2ezm5OViFixWgIomE34BAAA", b -> { + items.add(new TestCase("r1", "XsFI2ezm5OViFixWgIomE34BAAA", "{r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); }).and(b -> { @@ -113,11 +122,11 @@ public static Iterable params() { b.field("r1", "cat"); b.field("ip1", (String) null); })); - items.add(new TestCase("r2", "1y-UzdYi98F0UVRigIomE34BAAA", b -> { + items.add(new TestCase("r2", "1y-UzdYi98F0UVRigIomE34BAAA", "{r2=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r2", "cat"); })); - items.add(new TestCase("o.r3", "zh4dcftpIU55Ond-gIomE34BAAA", b -> { + items.add(new TestCase("o.r3", "zh4dcftpIU55Ond-gIomE34BAAA", "{o.r3=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.startObject("o").field("r3", "cat").endObject(); }).and(b -> { @@ -126,32 +135,32 @@ public static Iterable params() { })); // non-routing keyword - items.add(new TestCase("k1=dog", "XsFI2dL8sZeQhBgxgIomE34BAAA", b -> { + items.add(new TestCase("k1=dog", "XsFI2dL8sZeQhBgxgIomE34BAAA", "{k1=dog, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("k1", "dog"); })); - items.add(new TestCase("k1=pumpkin", "XsFI2VlD6_SkSo4MgIomE34BAAA", b -> { + items.add(new TestCase("k1=pumpkin", "XsFI2VlD6_SkSo4MgIomE34BAAA", "{k1=pumpkin, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("k1", "pumpkin"); })); - items.add(new TestCase("k1=empty string", "XsFI2aBA6UgrxLRqgIomE34BAAA", b -> { + items.add(new TestCase("k1=empty string", "XsFI2aBA6UgrxLRqgIomE34BAAA", "{k1=, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("k1", ""); })); - items.add(new TestCase("k2", "XsFI2W2e5Ycw0o5_gIomE34BAAA", b -> { + items.add(new TestCase("k2", "XsFI2W2e5Ycw0o5_gIomE34BAAA", "{k2=dog, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("k2", "dog"); })); - items.add(new TestCase("o.k3", "XsFI2ZAfOI6DMQhFgIomE34BAAA", b -> { + items.add(new TestCase("o.k3", "XsFI2ZAfOI6DMQhFgIomE34BAAA", "{o.k3=dog, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.startObject("o").field("k3", "dog").endObject(); })); - items.add(new TestCase("o.r3", "zh4dcbFtT1qHtjl8gIomE34BAAA", b -> { + items.add(new TestCase("o.r3", "zh4dcbFtT1qHtjl8gIomE34BAAA", "{o.k3=dog, o.r3=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.startObject("o"); { @@ -174,22 +183,22 @@ public static Iterable params() { })); // long - items.add(new TestCase("L1=1", "XsFI2eGMFOYjW7LLgIomE34BAAA", b -> { + items.add(new TestCase("L1=1", "XsFI2eGMFOYjW7LLgIomE34BAAA", "{L1=1, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("L1", 1); })); - items.add(new TestCase("L1=min", "XsFI2f9V0yuDfkRWgIomE34BAAA", b -> { + items.add(new TestCase("L1=min", "XsFI2f9V0yuDfkRWgIomE34BAAA", "{L1=" + Long.MIN_VALUE + ", r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("L1", Long.MIN_VALUE); })); - items.add(new TestCase("L2=1234", "XsFI2S8PYEBSm6QYgIomE34BAAA", b -> { + items.add(new TestCase("L2=1234", "XsFI2S8PYEBSm6QYgIomE34BAAA", "{L2=1234, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("L2", 1234); })); - items.add(new TestCase("o.L3=max", "zh4dcaI-57LdG7-cgIomE34BAAA", b -> { + items.add(new TestCase("o.L3=max", "zh4dcaI-57LdG7-cgIomE34BAAA", "{o.L3=" + Long.MAX_VALUE + ", o.r3=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.startObject("o"); { @@ -212,22 +221,22 @@ public static Iterable params() { })); // int - items.add(new TestCase("i1=1", "XsFI2R3LiMZSeUGKgIomE34BAAA", b -> { + items.add(new TestCase("i1=1", "XsFI2R3LiMZSeUGKgIomE34BAAA", "{i1=1, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("i1", 1); })); - items.add(new TestCase("i1=min", "XsFI2fC7DMEVFaU9gIomE34BAAA", b -> { + items.add(new TestCase("i1=min", "XsFI2fC7DMEVFaU9gIomE34BAAA", "{i1=" + Integer.MIN_VALUE + ", r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("i1", Integer.MIN_VALUE); })); - items.add(new TestCase("i2=1234", "XsFI2ZVte8HK90RJgIomE34BAAA", b -> { + items.add(new TestCase("i2=1234", "XsFI2ZVte8HK90RJgIomE34BAAA", "{i2=1324, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("i2", 1324); })); - items.add(new TestCase("o.i3=max", "zh4dcQy_QJRCqIx7gIomE34BAAA", b -> { + items.add(new TestCase("o.i3=max", "zh4dcQy_QJRCqIx7gIomE34BAAA", "{o.i3=" + Integer.MAX_VALUE + ", o.r3=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.startObject("o"); { @@ -250,22 +259,22 @@ public static Iterable params() { })); // short - items.add(new TestCase("s1=1", "XsFI2axCr11Q93m7gIomE34BAAA", b -> { + items.add(new TestCase("s1=1", "XsFI2axCr11Q93m7gIomE34BAAA", "{r1=cat, s1=1}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("s1", 1); })); - items.add(new TestCase("s1=min", "XsFI2Rbs9Ua9BH1wgIomE34BAAA", b -> { + items.add(new TestCase("s1=min", "XsFI2Rbs9Ua9BH1wgIomE34BAAA", "{r1=cat, s1=" + Short.MIN_VALUE + "}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("s1", Short.MIN_VALUE); })); - items.add(new TestCase("s2=1234", "XsFI2SBKaLBqXMBYgIomE34BAAA", b -> { + items.add(new TestCase("s2=1234", "XsFI2SBKaLBqXMBYgIomE34BAAA", "{r1=cat, s2=1234}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("s2", 1234); })); - items.add(new TestCase("o.s3=max", "zh4dcYIFo98LQWs4gIomE34BAAA", b -> { + items.add(new TestCase("o.s3=max", "zh4dcYIFo98LQWs4gIomE34BAAA", "{o.r3=cat, o.s3=" + Short.MAX_VALUE + "}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.startObject("o"); { @@ -288,22 +297,22 @@ public static Iterable params() { })); // byte - items.add(new TestCase("b1=1", "XsFI2dDrcWaf3zDPgIomE34BAAA", b -> { + items.add(new TestCase("b1=1", "XsFI2dDrcWaf3zDPgIomE34BAAA", "{b1=1, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("b1", 1); })); - items.add(new TestCase("b1=min", "XsFI2cTzLrNqHtxngIomE34BAAA", b -> { + items.add(new TestCase("b1=min", "XsFI2cTzLrNqHtxngIomE34BAAA", "{b1=" + Byte.MIN_VALUE + ", r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("b1", Byte.MIN_VALUE); })); - items.add(new TestCase("b2=12", "XsFI2Sb77VB9AswjgIomE34BAAA", b -> { + items.add(new TestCase("b2=12", "XsFI2Sb77VB9AswjgIomE34BAAA", "{b2=12, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("b2", 12); })); - items.add(new TestCase("o.s3=max", "zh4dcfFauKzj6lgxgIomE34BAAA", b -> { + items.add(new TestCase("o.s3=max", "zh4dcfFauKzj6lgxgIomE34BAAA", "{o.b3=" + Byte.MAX_VALUE + ", o.r3=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.startObject("o"); { @@ -326,7 +335,7 @@ public static Iterable params() { })); // ip - items.add(new TestCase("ip1=192.168.0.1", "XsFI2dJ1cyrrjNa2gIomE34BAAA", b -> { + items.add(new TestCase("ip1=192.168.0.1", "XsFI2dJ1cyrrjNa2gIomE34BAAA", "{ip1=192.168.0.1, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("ip1", "192.168.0.1"); @@ -335,7 +344,7 @@ public static Iterable params() { b.field("r1", "cat"); b.field("ip1", "::ffff:c0a8:1"); })); - items.add(new TestCase("ip1=12.12.45.254", "XsFI2ZUAcRxOwhHKgIomE34BAAA", b -> { + items.add(new TestCase("ip1=12.12.45.254", "XsFI2ZUAcRxOwhHKgIomE34BAAA", "{ip1=12.12.45.254, r1=cat}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); b.field("ip1", "12.12.45.254"); @@ -344,31 +353,53 @@ public static Iterable params() { b.field("r1", "cat"); b.field("ip1", "::ffff:c0c:2dfe"); })); - items.add(new TestCase("ip2=FE80:CD00:0000:0CDE:1257:0000:211E:729C", "XsFI2XTGWAekP_oGgIomE34BAAA", b -> { + items.add( + new TestCase( + "ip2=FE80:CD00:0000:0CDE:1257:0000:211E:729C", + "XsFI2XTGWAekP_oGgIomE34BAAA", + "{ip2=fe80:cd00:0:cde:1257:0:211e:729c, r1=cat}", + b -> { + b.field("@timestamp", "2022-01-01T01:00:00Z"); + b.field("r1", "cat"); + b.field("ip2", "FE80:CD00:0000:0CDE:1257:0000:211E:729C"); + } + ) + ); + items.add( + new TestCase( + "o.ip3=2001:db8:85a3:8d3:1319:8a2e:370:7348", + "zh4dcU_FSGP9GuHjgIomE34BAAA", + "{o.ip3=2001:db8:85a3:8d3:1319:8a2e:370:7348, o.r3=cat}", + b -> { + b.field("@timestamp", "2022-01-01T01:00:00Z"); + b.startObject("o"); + { + b.field("r3", "cat"); + b.field("ip3", "2001:db8:85a3:8d3:1319:8a2e:370:7348"); + } + b.endObject(); + } + ).and(b -> { + b.field("@timestamp", "2022-01-01T01:00:00Z"); + b.field("o.r3", "cat"); + b.startObject("o").field("ip3", "2001:db8:85a3:8d3:1319:8a2e:370:7348").endObject(); + }).and(b -> { + b.field("@timestamp", "2022-01-01T01:00:00Z"); + b.startObject("o").field("r3", "cat").endObject(); + b.field("o.ip3", "2001:db8:85a3:8d3:1319:8a2e:370:7348"); + }).and(b -> { + b.field("@timestamp", "2022-01-01T01:00:00Z"); + b.field("o.r3", "cat"); + b.field("o.ip3", "2001:db8:85a3:8d3:1319:8a2e:370:7348"); + }) + ); + + String huge = "foo ".repeat(200); + items.add(new TestCase("huge", "XsFI2ajoxid9Tfl3gIomE34BAAA", "{k1=" + huge + ", k2=" + huge.substring(0, 191) + "...}", b -> { b.field("@timestamp", "2022-01-01T01:00:00Z"); b.field("r1", "cat"); - b.field("ip2", "FE80:CD00:0000:0CDE:1257:0000:211E:729C"); - })); - items.add(new TestCase("o.ip3=2001:db8:85a3:8d3:1319:8a2e:370:7348", "zh4dcU_FSGP9GuHjgIomE34BAAA", b -> { - b.field("@timestamp", "2022-01-01T01:00:00Z"); - b.startObject("o"); - { - b.field("r3", "cat"); - b.field("ip3", "2001:db8:85a3:8d3:1319:8a2e:370:7348"); - } - b.endObject(); - }).and(b -> { - b.field("@timestamp", "2022-01-01T01:00:00Z"); - b.field("o.r3", "cat"); - b.startObject("o").field("ip3", "2001:db8:85a3:8d3:1319:8a2e:370:7348").endObject(); - }).and(b -> { - b.field("@timestamp", "2022-01-01T01:00:00Z"); - b.startObject("o").field("r3", "cat").endObject(); - b.field("o.ip3", "2001:db8:85a3:8d3:1319:8a2e:370:7348"); - }).and(b -> { - b.field("@timestamp", "2022-01-01T01:00:00Z"); - b.field("o.r3", "cat"); - b.field("o.ip3", "2001:db8:85a3:8d3:1319:8a2e:370:7348"); + b.field("k1", huge); + b.field("k2", huge); })); return items.stream().map(td -> new Object[] { td }).toList(); @@ -490,15 +521,35 @@ protected String fieldName() { protected void registerParameters(ParameterChecker checker) throws IOException {} public void testDescription() throws IOException { + assertThat(TsidExtractingIdFieldMapper.INSTANCE.documentDescription(documentParserContext()), equalTo("a time series document")); + IndexableField timestamp = new LongPoint("@timestamp", 231431434); assertThat( - TsidExtractingIdFieldMapper.INSTANCE.documentDescription(source(null, testCase.source, null)), - equalTo("a time series document") + TsidExtractingIdFieldMapper.INSTANCE.documentDescription(documentParserContext(timestamp)), + equalTo("a time series document at [1970-01-03T16:17:11.434Z]") ); - for (CheckedConsumer equivalent : testCase.equivalentSources) { - assertThat( - TsidExtractingIdFieldMapper.INSTANCE.documentDescription(source(null, equivalent, null)), - equalTo("a time series document") - ); + ParsedDocument d = parse(null, mapperService(), testCase.randomSource()); + IndexableField tsid = d.rootDoc().getField(TimeSeriesIdFieldMapper.NAME); + assertThat( + TsidExtractingIdFieldMapper.INSTANCE.documentDescription(documentParserContext(tsid)), + equalTo("a time series document with dimensions " + testCase.expectedTsid) + ); + assertThat( + TsidExtractingIdFieldMapper.INSTANCE.documentDescription(documentParserContext(tsid, timestamp)), + equalTo("a time series document with dimensions " + testCase.expectedTsid + " at [1970-01-03T16:17:11.434Z]") + ); + } + + private TestDocumentParserContext documentParserContext(IndexableField... fields) throws IOException { + TestDocumentParserContext ctx = new TestDocumentParserContext( + mapperService().mappingLookup(), + MapperTestCase.createIndexSettings(Version.CURRENT, Settings.EMPTY), + null, + null, + source(null, testCase.randomSource(), null) + ); + for (IndexableField f : fields) { + ctx.doc().add(f); } + return ctx; } }