diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV1.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV1.java index 4657b00ac3d..4cb41c597f4 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV1.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddagent/TraceMapperV1.java @@ -374,10 +374,14 @@ private void encodeSpanAttributes( (tagCount + baggage.size() + metaStruct.size() + + 2 + (writeHttpStatus ? 1 : 0) + (writeTopLevel ? 1 : 0)) * 3); + writeAttribute(writable, DDTags.THREAD_ID, meta.getThreadId()); + writeAttribute(writable, DDTags.THREAD_NAME, meta.getThreadName()); + for (Map.Entry entry : baggage.entrySet()) { writeAttribute(writable, entry.getKey(), entry.getValue()); } @@ -470,16 +474,19 @@ private void encodeAttributes(Writable writable, int fieldId, Map att private void writeAttribute(Writable writable, String key, Object value) { writeStreamingString(writable, key); + if (value instanceof Number) { writable.writeInt(VALUE_TYPE_FLOAT); writable.writeDouble(((Number) value).doubleValue()); return; } + if (value instanceof Boolean) { writable.writeInt(VALUE_TYPE_BOOLEAN); writable.writeBoolean((Boolean) value); return; } + if (!(value instanceof String) && value != null) { log.debug("Not a string value for key: {}, value: {}", key, value); } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV1PayloadTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV1PayloadTest.groovy index 056d4a30a43..a1350a7538c 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV1PayloadTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/ddagent/TraceMapperV1PayloadTest.groovy @@ -701,6 +701,40 @@ class TraceMapperV1PayloadTest extends DDSpecification { assertEquals(4.25d, (attributes.get("tag.double") as Number).doubleValue(), 0.000001d) } + def "test thread metadata is encoded in v1 attributes"() { + setup: + def span = new TraceGenerator.PojoSpan( + "service-a", + "operation-a", + "resource-a", + DDTraceId.ONE, + 123L, + 0L, + 1000L, + 2000L, + 0, + [:], + [:], + "web", + false, + PrioritySampling.SAMPLER_KEEP, + 0, + null) + + TraceMapperV1 mapper = new TraceMapperV1() + byte[] encoded = serializeMappedPayload(mapper, [[span]]) + MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(encoded) + List stringTable = new ArrayList<>() + stringTable.add("") + + when: + Map attributes = readFirstSpanAttributes(unpacker, stringTable) + + then: + assertAttributeValueEquals(span.getTag(DDTags.THREAD_ID), attributes.get(DDTags.THREAD_ID), DDTags.THREAD_ID) + assertEquals(span.getTag(DDTags.THREAD_NAME).toString(), attributes.get(DDTags.THREAD_NAME)) + } + private static final class PayloadVerifier implements ByteBufferConsumer, WritableByteChannel { private final List> expectedTraces @@ -973,6 +1007,8 @@ class TraceMapperV1PayloadTest extends DDSpecification { for (Map.Entry entry : expectedSpan.getBaggage().entrySet()) { expectedAttributes.put(entry.getKey(), entry.getValue()) } + expectedAttributes.put(DDTags.THREAD_ID, expectedSpan.getTag(DDTags.THREAD_ID)) + expectedAttributes.put(DDTags.THREAD_NAME, expectedSpan.getTag(DDTags.THREAD_NAME)) for (Map.Entry entry : expectedSpan.getTags().entrySet()) { if (DDTags.SPAN_EVENTS == entry.getKey()) { continue