diff --git a/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/TrackingSpanDecorator.groovy b/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/TrackingSpanDecorator.groovy index 70f1a2a6731..7db4f70a272 100644 --- a/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/TrackingSpanDecorator.groovy +++ b/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/TrackingSpanDecorator.groovy @@ -114,6 +114,11 @@ class TrackingSpanDecorator implements AgentSpan { return delegate.setTag(key, value) } + @Override + AgentSpan setTag(TagMap.EntryReader entry) { + return delegate.setTag(entry) + } + @Override void setRequestBlockingAction(Flow.Action.RequestBlockingAction rba) { delegate.setRequestBlockingAction(rba) @@ -184,6 +189,11 @@ class TrackingSpanDecorator implements AgentSpan { return delegate.setMetric(key, value) } + @Override + AgentSpan setMetric(TagMap.EntryReader entry) { + return delegate.setMetric(entry) + } + @Override boolean isError() { return delegate.isError() diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java index 1b321f4536a..e8a6ce87edb 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java @@ -392,7 +392,7 @@ private boolean isExceptionReplayEnabled() { public final DDSpan setTag(final String tag, final String value) { if (value == null || value.isEmpty()) { // Remove the tag - context.setTag(tag, null); + context.removeTag(tag); } else { context.setTag(tag, value); } @@ -405,6 +405,12 @@ public final DDSpan setTag(final String tag, final boolean value) { return this; } + @Override + public final DDSpan setTag(TagMap.EntryReader entry) { + context.setTag(entry); + return this; + } + @Override public void setRequestBlockingAction(Flow.Action.RequestBlockingAction rba) { this.requestBlockingAction = rba; @@ -474,6 +480,12 @@ public DDSpan setMetric(final CharSequence metric, final double value) { return this; } + @Override + public DDSpan setMetric(TagMap.EntryReader entry) { + context.setMetric(entry); + return this; + } + @Override public DDSpan setFlag(CharSequence name, boolean value) { context.setMetric(name, value ? 1 : 0); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java index 96d6292c6ae..4a0eb4378b5 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java @@ -751,6 +751,22 @@ public void setMetric(final CharSequence key, final Number value) { } } + public void setMetric(final TagMap.EntryReader entry) { + if (entry == null) { + return; + } + + synchronized (unsafeTags) { + unsafeTags.set(entry); + } + } + + public void removeTag(String tag) { + synchronized (unsafeTags) { + unsafeTags.remove(tag); + } + } + /** * Sets a tag to the span. Tags are not propagated to the children. * @@ -790,6 +806,22 @@ public void setTag(final String tag, final String value) { } } + public void setTag(TagMap.EntryReader entry) { + if (entry == null) { + return; + } + + // pre-check to avoid boxing + boolean intercepted = + precheckIntercept(entry.tag()) + && tagInterceptor.interceptTag(this, entry.tag(), entry.objectValue()); + if (!intercepted) { + synchronized (unsafeTags) { + unsafeTags.set(entry); + } + } + } + /* * Uses to determine if there's an opportunity to avoid primitve boxing. * If the underlying map doesn't support efficient primitives, then boxing is used. diff --git a/dd-trace-core/src/test/java/datadog/trace/core/SpanTest.java b/dd-trace-core/src/test/java/datadog/trace/core/SpanTest.java new file mode 100644 index 00000000000..cfe345aa6b4 --- /dev/null +++ b/dd-trace-core/src/test/java/datadog/trace/core/SpanTest.java @@ -0,0 +1,52 @@ +package datadog.trace.core; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import datadog.trace.api.TagMap; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class SpanTest { + static final CoreTracer TRACER = CoreTracer.builder().build(); + + @Test + @DisplayName("setTag: TagMap.Entry") + public void setTagEntry() { + AgentSpan span = TRACER.startSpan("foo", "foo"); + span.setTag(TagMap.Entry.create("message", "hello")); + + assertEquals("hello", span.getTag("message")); + } + + @Test + @DisplayName("setTag: null") + public void setTagEntryNull() { + AgentSpan span = TRACER.startSpan("foo", "foo"); + int initialSize = span.getTags().size(); + + span.setTag(null); + + assertEquals(initialSize, span.getTags().size()); + } + + @Test + @DisplayName("setMetric: TagMap.Entry") + public void setMetricEntry() { + AgentSpan span = TRACER.startSpan("foo", "foo"); + span.setMetric(TagMap.Entry.create("metric", 20L)); + + assertEquals(Long.valueOf(20L), span.getTag("metric")); + } + + @Test + @DisplayName("setMetric: null") + public void setMetricEntryNull() { + AgentSpan span = TRACER.startSpan("foo", "foo"); + int initialSize = span.getTags().size(); + + span.setMetric(null); + + assertEquals(initialSize, span.getTags().size()); + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/TagMap.java b/internal-api/src/main/java/datadog/trace/api/TagMap.java index dbbc19e5bba..95f676245ef 100644 --- a/internal-api/src/main/java/datadog/trace/api/TagMap.java +++ b/internal-api/src/main/java/datadog/trace/api/TagMap.java @@ -369,6 +369,43 @@ final class Entry extends EntryChange implements Map.Entry, Entr */ static final byte ANY = 0; + /** If value is non-null, returns a new TagMap.Entry If value is null, returns null */ + public static final Entry create(String tag, Object value) { + // NOTE: From the static typing, it is possible that value is a primitive box, so need to call + // Any variant + + return (value == null) ? null : TagMap.Entry.newAnyEntry(tag, value); + } + + /** If value is non-null, returns a new TagMap.Entry If value is null or empty, returns null */ + public static final Entry create(String tag, CharSequence value) { + // NOTE: From the static typing, we know that value is not a primitive box + + return (value == null || value.length() == 0) + ? null + : TagMap.Entry.newObjectEntry(tag, value); + } + + public static final Entry create(String tag, boolean value) { + return TagMap.Entry.newBooleanEntry(tag, value); + } + + public static final Entry create(String tag, int value) { + return TagMap.Entry.newIntEntry(tag, value); + } + + public static final Entry create(String tag, long value) { + return TagMap.Entry.newLongEntry(tag, value); + } + + public static final Entry create(String tag, float value) { + return TagMap.Entry.newFloatEntry(tag, value); + } + + public static final Entry create(String tag, double value) { + return TagMap.Entry.newDoubleEntry(tag, value); + } + static Entry newAnyEntry(Map.Entry entry) { return newAnyEntry(entry.getKey(), entry.getValue()); } diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java index 5deb8520d3a..59999d67881 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java @@ -77,6 +77,9 @@ default boolean isValid() { AgentSpan setTag(String key, Object value); + /** entry may be null - in which case the tags remained unchanged */ + AgentSpan setTag(TagMap.EntryReader entry); + AgentSpan setAllTags(Map map); @Override @@ -91,6 +94,9 @@ default boolean isValid() { @Override AgentSpan setMetric(CharSequence key, double value); + /** metricEntry may be null - in which case the tags remained unchanged */ + AgentSpan setMetric(TagMap.EntryReader metricEntry); + @Override AgentSpan setSpanType(final CharSequence type); diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/ImmutableSpan.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/ImmutableSpan.java index a7dcab6cebf..1f857a6e7df 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/ImmutableSpan.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/ImmutableSpan.java @@ -1,5 +1,6 @@ package datadog.trace.bootstrap.instrumentation.api; +import datadog.trace.api.TagMap; import datadog.trace.api.gateway.Flow.Action.RequestBlockingAction; import datadog.trace.api.interceptor.MutableSpan; import java.util.Map; @@ -41,6 +42,11 @@ public AgentSpan setTag(String key, String value) { return this; } + @Override + public AgentSpan setTag(TagMap.EntryReader entry) { + return this; + } + @Override public AgentSpan setTag(String key, CharSequence value) { return this; @@ -76,6 +82,11 @@ public AgentSpan setMetric(CharSequence key, double value) { return this; } + @Override + public AgentSpan setMetric(TagMap.EntryReader entry) { + return this; + } + @Override public AgentSpan setSpanType(CharSequence type) { return this; diff --git a/internal-api/src/test/java/datadog/trace/api/TagMapEntryTest.java b/internal-api/src/test/java/datadog/trace/api/TagMapEntryTest.java index 13da8723b60..9eef1cb40c9 100644 --- a/internal-api/src/test/java/datadog/trace/api/TagMapEntryTest.java +++ b/internal-api/src/test/java/datadog/trace/api/TagMapEntryTest.java @@ -3,12 +3,15 @@ import static org.junit.Assert.assertSame; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import datadog.trace.api.TagMap.Entry; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -17,6 +20,7 @@ import java.util.concurrent.ThreadFactory; import java.util.function.Function; import java.util.function.Supplier; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -48,6 +52,57 @@ public void isNumericPrimitive() { assertTrue(TagMap.Entry._isNumericPrimitive(TagMap.Entry.DOUBLE)); } + @Test + @DisplayName("TagMap.Entry.create: Object") + public void createObject() { + Map map = new HashMap<>(); + + test( + () -> TagMap.Entry.create("foo", map), + TagMap.Entry.ANY, + (entry) -> + multiCheck( + checkKey("foo", entry), + checkValue(map, entry), + checkTrue(entry::isObject), + checkFalse(entry::isNumber), + checkType(TagMap.Entry.OBJECT, entry))); + } + + @Test + @DisplayName("TagMap.Entry.create: null Object") + public void createEntryNullObject() { + assertNull(TagMap.Entry.create("foo", null)); + } + + @Test + @DisplayName("TagMap.Entry.create: CharSequence") + public void createCharSequence() { + test( + () -> TagMap.Entry.create("foo", "bar"), + TagMap.Entry.OBJECT, + (entry) -> + multiCheck( + checkKey("foo", entry), + checkValue("bar", entry), + checkEquals("bar", entry::stringValue), + checkFalse(entry::isNumber), + checkTrue(entry::isObject), + checkType(TagMap.Entry.OBJECT, entry))); + } + + @Test + @DisplayName("TagMap.Entry.create: null CharSequence") + public void createNullCharSequence() { + assertNull(TagMap.Entry.create("foo", (String) null)); + } + + @Test + @DisplayName("TagMap.Entry.create: empty CharSequence") + public void createEmptyCharSequence() { + assertNull(TagMap.Entry.create("foo", "")); + } + @Test public void objectEntry() { test( @@ -58,12 +113,14 @@ public void objectEntry() { checkKey("foo", entry), checkValue("bar", entry), checkEquals("bar", entry::stringValue), + checkFalse(entry::isNumber), checkTrue(entry::isObject), - checkFalse(entry::isNumber))); + checkType(TagMap.Entry.OBJECT, entry))); } @Test - public void anyEntry_object() { + @DisplayName("anyEntry: Object") + public void anyEntryObject() { test( () -> TagMap.Entry.newAnyEntry("foo", "bar"), TagMap.Entry.ANY, @@ -73,13 +130,30 @@ public void anyEntry_object() { checkValue("bar", entry), checkTrue(entry::isObject), checkFalse(entry::isNumber), + checkType(TagMap.EntryReader.OBJECT, entry))); + } + + @ParameterizedTest + @DisplayName("TagMap.Entry.create: boolean") + @ValueSource(booleans = {false, true}) + public void createBoolean(boolean value) { + test( + () -> TagMap.Entry.create("foo", value), + TagMap.Entry.BOOLEAN, + (entry) -> + multiCheck( checkKey("foo", entry), - checkValue("bar", entry))); + checkValue(value, entry), + checkFalse(entry::isNumericPrimitive), + checkFalse(entry::isNumber), + checkFalse(entry::isObject), + checkType(TagMap.Entry.BOOLEAN, entry))); } @ParameterizedTest + @DisplayName("newBooleanEntry: boolean") @ValueSource(booleans = {false, true}) - public void booleanEntry(boolean value) { + public void newBooleanEntry(boolean value) { test( () -> TagMap.Entry.newBooleanEntry("foo", value), TagMap.Entry.BOOLEAN, @@ -94,8 +168,9 @@ public void booleanEntry(boolean value) { } @ParameterizedTest + @DisplayName("newBooleanEntry: Boolean") @ValueSource(booleans = {false, true}) - public void booleanEntry_boxed(boolean value) { + public void newBooleanEntryBoxed(boolean value) { test( () -> TagMap.Entry.newBooleanEntry("foo", Boolean.valueOf(value)), TagMap.Entry.BOOLEAN, @@ -110,8 +185,9 @@ public void booleanEntry_boxed(boolean value) { } @ParameterizedTest + @DisplayName("newAnyEntry: Boolean") @ValueSource(booleans = {false, true}) - public void anyEntry_boolean(boolean value) { + public void newAnyEntryBoolean(boolean value) { test( () -> TagMap.Entry.newAnyEntry("foo", Boolean.valueOf(value)), TagMap.Entry.ANY, @@ -127,8 +203,25 @@ public void anyEntry_boolean(boolean value) { } @ParameterizedTest + @DisplayName("TagMap.Entry.create: int") @ValueSource(ints = {Integer.MIN_VALUE, -256, -128, -1, 0, 1, 128, 256, Integer.MAX_VALUE}) - public void intEntry(int value) { + public void createInt(int value) { + test( + () -> TagMap.Entry.create("foo", value), + TagMap.Entry.INT, + (entry) -> + multiCheck( + checkKey("foo", entry), + checkValue(value, entry), + checkIsNumericPrimitive(entry), + checkInstanceOf(Number.class, entry), + checkType(TagMap.Entry.INT, entry))); + } + + @ParameterizedTest + @DisplayName("newIntEntry: int") + @ValueSource(ints = {Integer.MIN_VALUE, -256, -128, -1, 0, 1, 128, 256, Integer.MAX_VALUE}) + public void newIntEntry(int value) { test( () -> TagMap.Entry.newIntEntry("foo", value), TagMap.Entry.INT, @@ -142,8 +235,9 @@ public void intEntry(int value) { } @ParameterizedTest + @DisplayName("newIntEntry: Integer") @ValueSource(ints = {Integer.MIN_VALUE, -256, -128, -1, 0, 1, 128, 256, Integer.MAX_VALUE}) - public void intEntry_boxed(int value) { + public void newIntEntryBoxed(int value) { test( () -> TagMap.Entry.newIntEntry("foo", Integer.valueOf(value)), TagMap.Entry.INT, @@ -157,8 +251,9 @@ public void intEntry_boxed(int value) { } @ParameterizedTest + @DisplayName("newIntEntry: Short") @ValueSource(shorts = {Short.MIN_VALUE, -256, -128, -1, 0, 1, 128, 256, Short.MAX_VALUE}) - public void intEntry_boxedShort(short value) { + public void intEntryBoxedShort(short value) { test( () -> TagMap.Entry.newIntEntry("foo", Short.valueOf(value)), TagMap.Entry.INT, @@ -172,8 +267,9 @@ public void intEntry_boxedShort(short value) { } @ParameterizedTest + @DisplayName("newIntEntry: Byte") @ValueSource(bytes = {Byte.MIN_VALUE, -32, -1, 0, 1, 32, Byte.MAX_VALUE}) - public void intEntry_boxedByte(byte value) { + public void intEntryBoxedByte(byte value) { test( () -> TagMap.Entry.newIntEntry("foo", Byte.valueOf(value)), TagMap.Entry.INT, @@ -187,8 +283,9 @@ public void intEntry_boxedByte(byte value) { } @ParameterizedTest + @DisplayName("newAnyEntry: Integer") @ValueSource(ints = {Integer.MIN_VALUE, -256, -128, -1, 0, 1, 128, 256, Integer.MAX_VALUE}) - public void anyEntry_int(int value) { + public void newAnyEntryInteger(int value) { test( () -> TagMap.Entry.newAnyEntry("foo", Integer.valueOf(value)), TagMap.Entry.ANY, @@ -203,6 +300,7 @@ public void anyEntry_int(int value) { } @ParameterizedTest + @DisplayName("TagMap.Entry.create: long") @ValueSource( longs = { Long.MIN_VALUE, @@ -219,7 +317,37 @@ public void anyEntry_int(int value) { Integer.MAX_VALUE, Long.MAX_VALUE }) - public void longEntry(long value) { + public void createLong(long value) { + test( + () -> TagMap.Entry.create("foo", value), + TagMap.Entry.LONG, + (entry) -> + multiCheck( + checkKey("foo", entry), + checkValue(value, entry), + checkTrue(entry::isNumericPrimitive), + checkType(TagMap.Entry.LONG, entry))); + } + + @ParameterizedTest + @DisplayName("newLongEntry: long") + @ValueSource( + longs = { + Long.MIN_VALUE, + Integer.MIN_VALUE, + -1_048_576L, + -256L, + -128L, + -1L, + 0L, + 1L, + 128L, + 256L, + 1_048_576L, + Integer.MAX_VALUE, + Long.MAX_VALUE + }) + public void newLongEntry(long value) { test( () -> TagMap.Entry.newLongEntry("foo", value), TagMap.Entry.LONG, @@ -232,6 +360,7 @@ public void longEntry(long value) { } @ParameterizedTest + @DisplayName("newLongEntry: Long") @ValueSource( longs = { Long.MIN_VALUE, @@ -248,7 +377,7 @@ public void longEntry(long value) { Integer.MAX_VALUE, Long.MAX_VALUE }) - public void longEntry_boxed(long value) { + public void newLongEntryBoxed(long value) { test( () -> TagMap.Entry.newLongEntry("foo", Long.valueOf(value)), TagMap.Entry.LONG, @@ -261,6 +390,7 @@ public void longEntry_boxed(long value) { } @ParameterizedTest + @DisplayName("newAnyEntry: Long") @ValueSource( longs = { Long.MIN_VALUE, @@ -277,7 +407,7 @@ public void longEntry_boxed(long value) { Integer.MAX_VALUE, Long.MAX_VALUE }) - public void anyEntry_long(long value) { + public void newAnyEntryLong(long value) { test( () -> TagMap.Entry.newAnyEntry("foo", Long.valueOf(value)), TagMap.Entry.ANY, @@ -291,8 +421,24 @@ public void anyEntry_long(long value) { } @ParameterizedTest + @DisplayName("TagMap.Entry.create: float") + @ValueSource(floats = {Float.MIN_VALUE, -1F, 0F, 1F, 2.171828F, 3.1415F, Float.MAX_VALUE}) + public void createFloat(float value) { + test( + () -> TagMap.Entry.create("foo", value), + TagMap.Entry.FLOAT, + (entry) -> + multiCheck( + checkKey("foo", entry), + checkValue(value, entry), + checkTrue(entry::isNumericPrimitive), + checkType(TagMap.Entry.FLOAT, entry))); + } + + @ParameterizedTest + @DisplayName("newFloatEntry: float") @ValueSource(floats = {Float.MIN_VALUE, -1F, 0F, 1F, 2.171828F, 3.1415F, Float.MAX_VALUE}) - public void floatEntry(float value) { + public void newFloatEntry(float value) { test( () -> TagMap.Entry.newFloatEntry("foo", value), TagMap.Entry.FLOAT, @@ -305,8 +451,9 @@ public void floatEntry(float value) { } @ParameterizedTest + @DisplayName("newFloatEntry: Float") @ValueSource(floats = {Float.MIN_VALUE, -1F, 0F, 1F, 2.171828F, 3.1415F, Float.MAX_VALUE}) - public void floatEntry_boxed(float value) { + public void newFloatEntryBoxed(float value) { test( () -> TagMap.Entry.newFloatEntry("foo", Float.valueOf(value)), TagMap.Entry.FLOAT, @@ -319,8 +466,9 @@ public void floatEntry_boxed(float value) { } @ParameterizedTest + @DisplayName("newAnyEntry: Float") @ValueSource(floats = {Float.MIN_VALUE, -1F, 0F, 1F, 2.171828F, 3.1415F, Float.MAX_VALUE}) - public void anyEntry_float(float value) { + public void newAnyEntryFloat(float value) { test( () -> TagMap.Entry.newAnyEntry("foo", Float.valueOf(value)), TagMap.Entry.ANY, @@ -333,6 +481,23 @@ public void anyEntry_float(float value) { } @ParameterizedTest + @DisplayName("TagMap.Entry.create: double") + @ValueSource( + doubles = {Double.MIN_VALUE, Float.MIN_VALUE, -1D, 0D, 1D, Math.E, Math.PI, Double.MAX_VALUE}) + public void createDouble(double value) { + test( + () -> TagMap.Entry.create("foo", value), + TagMap.Entry.DOUBLE, + (entry) -> + multiCheck( + checkKey("foo", entry), + checkValue(value, entry), + checkIsNumericPrimitive(entry), + checkType(TagMap.Entry.DOUBLE, entry))); + } + + @ParameterizedTest + @DisplayName("newDoubleEntry: double") @ValueSource( doubles = {Double.MIN_VALUE, Float.MIN_VALUE, -1D, 0D, 1D, Math.E, Math.PI, Double.MAX_VALUE}) public void doubleEntry(double value) { @@ -348,9 +513,10 @@ public void doubleEntry(double value) { } @ParameterizedTest + @DisplayName("newDoubleEntry: Double") @ValueSource( doubles = {Double.MIN_VALUE, Float.MIN_VALUE, -1D, 0D, 1D, Math.E, Math.PI, Double.MAX_VALUE}) - public void doubleEntry_boxed(double value) { + public void newDoubleEntryBoxed(double value) { test( () -> TagMap.Entry.newDoubleEntry("foo", Double.valueOf(value)), TagMap.Entry.DOUBLE, @@ -363,6 +529,7 @@ public void doubleEntry_boxed(double value) { } @ParameterizedTest + @DisplayName("newAnyEntry: Double") @ValueSource( doubles = {Double.MIN_VALUE, Float.MIN_VALUE, -1D, 0D, 1D, Math.E, Math.PI, Double.MAX_VALUE}) public void anyEntry_double(double value) { @@ -422,7 +589,7 @@ static final void test( static final void testSingleThreaded( Supplier entrySupplier, byte rawType, Function checkSupplier) { Entry entry = entrySupplier.get(); - assertEquals(rawType, entry.rawType); + assertEquals(rawType, entry.rawType, "rawType"); Check checks = checkSupplier.apply(entry); checks.check(); @@ -431,7 +598,7 @@ static final void testSingleThreaded( static final void testMultiThreaded( Supplier entrySupplier, byte rawType, Function checkSupplier) { Entry sharedEntry = entrySupplier.get(); - assertEquals(rawType, sharedEntry.rawType); + assertEquals(rawType, sharedEntry.rawType, "rawType"); Check checks = checkSupplier.apply(sharedEntry); @@ -716,8 +883,8 @@ static final Check checkInstanceOf(Class klass, TagMap.Entry entry) { static final Check checkType(byte entryType, TagMap.Entry entry) { // TODO: TVC checks return multiCheck( - checkTrue(() -> entry.is(entryType), "type is " + entryType), - checkEquals(entryType, entry::type)); + checkTrue(() -> entry.is(entryType), "Entry::is(type) type=" + entryType), + checkEquals(entryType, entry::type, "Entry::type check")); } static final Check multiCheck(Check... checks) {