diff --git a/api/all/src/main/java/io/opentelemetry/api/logs/LogRecordBuilder.java b/api/all/src/main/java/io/opentelemetry/api/logs/LogRecordBuilder.java index 21feb4d87ce..31c5fc07cb9 100644 --- a/api/all/src/main/java/io/opentelemetry/api/logs/LogRecordBuilder.java +++ b/api/all/src/main/java/io/opentelemetry/api/logs/LogRecordBuilder.java @@ -196,6 +196,21 @@ default LogRecordBuilder setAttribute(String key, int value) { return setAttribute(key, (long) value); } + /** + * Sets a {@link Value} attribute on the {@code LogRecord}. If the {@code LogRecord} previously + * contained a mapping for the key, the old value is replaced by the specified value. + * + *

Note: It is strongly recommended to use {@link #setAttribute(AttributeKey, Object)}, and + * pre-allocate your keys, if possible. + * + * @param key the key for this attribute. + * @param value the value for this attribute. + * @return this. + */ + default LogRecordBuilder setAttribute(String key, Value value) { + return setAttribute(AttributeKey.valueKey(key), value); + } + /** * Sets the event name, which identifies the class / type of the Event. * diff --git a/api/all/src/main/java/io/opentelemetry/api/trace/Span.java b/api/all/src/main/java/io/opentelemetry/api/trace/Span.java index 708bb1de077..39447b35be9 100644 --- a/api/all/src/main/java/io/opentelemetry/api/trace/Span.java +++ b/api/all/src/main/java/io/opentelemetry/api/trace/Span.java @@ -10,6 +10,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.internal.ApiUsageLogger; import io.opentelemetry.context.Context; import io.opentelemetry.context.ImplicitContextKeyed; @@ -148,6 +149,21 @@ default Span setAttribute(String key, boolean value) { return setAttribute(AttributeKey.booleanKey(key), value); } + /** + * Sets a {@link Value} attribute on the {@code Span}. If the {@code Span} previously contained a + * mapping for the key, the old value is replaced by the specified value. + * + *

Note: It is strongly recommended to use {@link #setAttribute(AttributeKey, Object)}, and + * pre-allocate your keys, if possible. + * + * @param key the key for this attribute. + * @param value the value for this attribute. + * @return this. + */ + default Span setAttribute(String key, Value value) { + return setAttribute(AttributeKey.valueKey(key), value); + } + /** * Sets an attribute to the {@code Span}. If the {@code Span} previously contained a mapping for * the key, the old value is replaced by the specified value. diff --git a/api/all/src/test/java/io/opentelemetry/api/trace/PropagatedSpanTest.java b/api/all/src/test/java/io/opentelemetry/api/trace/PropagatedSpanTest.java index 7c3807775c7..ea33c957b42 100644 --- a/api/all/src/test/java/io/opentelemetry/api/trace/PropagatedSpanTest.java +++ b/api/all/src/test/java/io/opentelemetry/api/trace/PropagatedSpanTest.java @@ -15,6 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import java.time.Instant; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; @@ -40,16 +41,17 @@ void doNotCrash() { span.setAttribute(booleanKey("MyBooleanAttributeKey"), true); span.setAttribute(longKey("MyLongAttributeKey"), 123L); span.setAttribute(longKey("MyLongAttributeKey"), 123); - span.setAttribute("NullString", null); + span.setAttribute("NullString", (String) null); span.setAttribute("EmptyString", ""); span.setAttribute("long", 1); span.setAttribute("double", 1.0); span.setAttribute("boolean", true); + span.setAttribute("value", Value.of("val")); span.setAttribute(stringArrayKey("NullArrayString"), null); span.setAttribute(booleanArrayKey("NullArrayBoolean"), null); span.setAttribute(longArrayKey("NullArrayLong"), null); span.setAttribute(doubleArrayKey("NullArrayDouble"), null); - span.setAttribute((String) null, null); + span.setAttribute((String) null, (String) null); span.setAllAttributes(null); span.setAllAttributes(Attributes.empty()); span.setAllAttributes( diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt index b9f67186813..07f0f56142c 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt @@ -3,6 +3,9 @@ Comparing source compatibility of opentelemetry-api-1.61.0-SNAPSHOT.jar against === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 +++ NEW METHOD: PUBLIC(+) boolean isEnabled(io.opentelemetry.api.logs.Severity, io.opentelemetry.context.Context) +++ NEW METHOD: PUBLIC(+) boolean isEnabled(io.opentelemetry.api.logs.Severity) +*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.logs.LogRecordBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.logs.LogRecordBuilder setAttribute(java.lang.String, io.opentelemetry.api.common.Value) *** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.metrics.DoubleCounter (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 +++ NEW METHOD: PUBLIC(+) boolean isEnabled() @@ -27,6 +30,9 @@ Comparing source compatibility of opentelemetry-api-1.61.0-SNAPSHOT.jar against *** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.metrics.LongUpDownCounter (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 +++ NEW METHOD: PUBLIC(+) boolean isEnabled() +*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.trace.Span (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.trace.Span setAttribute(java.lang.String, io.opentelemetry.api.common.Value) *** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.trace.Tracer (not serializable) === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 +++ NEW METHOD: PUBLIC(+) boolean isEnabled() diff --git a/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/DelegatingSpan.java b/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/DelegatingSpan.java index ad1f624795a..254fca4830b 100644 --- a/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/DelegatingSpan.java +++ b/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/DelegatingSpan.java @@ -8,6 +8,7 @@ import com.google.errorprone.annotations.MustBeClosed; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.StatusCode; @@ -77,6 +78,11 @@ default Span setAttribute(String key, boolean value) { return getDelegate().setAttribute(key, value); } + @Override + default Span setAttribute(String key, Value value) { + return getDelegate().setAttribute(key, value); + } + @Override default Span setAttribute(AttributeKey key, int value) { return getDelegate().setAttribute(key, value); diff --git a/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/OpenTelemetryNoRecordEventsSpanImpl.java b/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/OpenTelemetryNoRecordEventsSpanImpl.java index a1e48f5eb40..8ec2fc6296e 100644 --- a/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/OpenTelemetryNoRecordEventsSpanImpl.java +++ b/opencensus-shim/src/main/java/io/opentelemetry/opencensusshim/OpenTelemetryNoRecordEventsSpanImpl.java @@ -33,6 +33,7 @@ import io.opencensus.trace.Status; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.trace.StatusCode; import java.util.EnumSet; import java.util.Map; @@ -129,6 +130,11 @@ public io.opentelemetry.api.trace.Span setAttribute(String key, boolean value) { return this; } + @Override + public io.opentelemetry.api.trace.Span setAttribute(String key, Value value) { + return this; + } + @Override public io.opentelemetry.api.trace.Span setAttribute(AttributeKey key, @Nullable T value) { return this; diff --git a/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/DelegatingSpanTest.java b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/DelegatingSpanTest.java index 2843ed89061..55bb1a58d82 100644 --- a/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/DelegatingSpanTest.java +++ b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/DelegatingSpanTest.java @@ -10,6 +10,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.StatusCode; @@ -95,6 +96,7 @@ static Stream delegateMethodsProvider() { Arguments.of("setAttribute", new Class[] {String.class, long.class}, times(1)), Arguments.of("setAttribute", new Class[] {String.class, double.class}, times(1)), Arguments.of("setAttribute", new Class[] {String.class, boolean.class}, times(1)), + Arguments.of("setAttribute", new Class[] {String.class, Value.class}, times(1)), Arguments.of( "recordException", new Class[] {Throwable.class, Attributes.class}, times(1)), Arguments.of("recordException", new Class[] {Throwable.class}, times(1)), diff --git a/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/OpenTelemetryNoRecordEventsSpanImplTest.java b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/OpenTelemetryNoRecordEventsSpanImplTest.java index 8f6d67e5e36..9a14ad5fc15 100644 --- a/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/OpenTelemetryNoRecordEventsSpanImplTest.java +++ b/opencensus-shim/src/test/java/io/opentelemetry/opencensusshim/OpenTelemetryNoRecordEventsSpanImplTest.java @@ -38,6 +38,7 @@ import io.opencensus.trace.Tracestate; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import java.util.HashMap; import java.util.Map; import java.util.Random; @@ -93,6 +94,7 @@ public void doNotCrash() { noRecordEventsSpan.setAttribute("OTelAttributeKeyLong", 123); noRecordEventsSpan.setAttribute("OTelAttributeKeyDouble", 123.45); noRecordEventsSpan.setAttribute("OTelAttributeKeyBoolean", true); + noRecordEventsSpan.setAttribute("OTelAttributeKeyValue", Value.empty()); noRecordEventsSpan.addEvent("OTel event 1"); noRecordEventsSpan.addEvent("OTel event 2", 29922310, TimeUnit.HOURS); noRecordEventsSpan.addEvent( diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java index 54f2d15199f..a89426c5363 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java @@ -9,6 +9,7 @@ import static io.opentelemetry.api.common.AttributeKey.doubleKey; import static io.opentelemetry.api.common.AttributeKey.longKey; import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static io.opentelemetry.api.common.AttributeKey.valueKey; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; import static org.mockito.ArgumentMatchers.eq; @@ -160,6 +161,7 @@ void testConvenienceAttributeMethods() { .setAttribute("dk", 12.123) .setAttribute("bk", true) .setAttribute("ik", 13) + .setAttribute("vk", Value.of(new byte[] {1, 2, 3})) .emit(); assertThat(emittedLog.get().toLogRecordData()) .hasAttributesSatisfyingExactly( @@ -167,7 +169,8 @@ void testConvenienceAttributeMethods() { equalTo(longKey("lk"), 12L), equalTo(doubleKey("dk"), 12.123), equalTo(booleanKey("bk"), true), - equalTo(longKey("ik"), 13L)); + equalTo(longKey("ik"), 13L), + equalTo(valueKey("vk"), Value.of(new byte[] {1, 2, 3}))); } @Test diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanBuilderTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanBuilderTest.java index 55eb81d0b20..c4615675b05 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanBuilderTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanBuilderTest.java @@ -391,7 +391,7 @@ void setAttribute_nullAttributeValue_afterEnd() { SdkSpan span = (SdkSpan) spanBuilder.startSpan(); assertThat(span.toSpanData().getAttributes().size()).isEqualTo(10); span.end(); - span.setAttribute("emptyString", null); + span.setAttribute("emptyString", (String) null); span.setAttribute(stringKey("emptyStringAttributeValue"), null); span.setAttribute(longKey("longAttribute"), null); span.setAttribute(booleanKey("boolAttribute"), null); diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java index 12e35475a8f..207bcaebf07 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java @@ -548,7 +548,7 @@ void setAttribute() { SdkSpan span = createTestRootSpan(); try { span.setAttribute("StringKey", "StringVal"); - span.setAttribute("NullStringKey", null); + span.setAttribute("NullStringKey", (String) null); span.setAttribute("EmptyStringKey", ""); span.setAttribute(stringKey("NullStringAttributeValue"), null); span.setAttribute(stringKey("EmptyStringAttributeValue"), ""); @@ -557,6 +557,7 @@ void setAttribute() { span.setAttribute(longKey("LongKey3"), 6L); span.setAttribute("DoubleKey", 10.0); span.setAttribute("BooleanKey", false); + span.setAttribute("BytesValueKey", Value.of(new byte[] {1, 2, 3})); span.setAttribute( stringArrayKey("ArrayStringKey"), Arrays.asList("StringVal", null, "", "StringVal2")); span.setAttribute(longArrayKey("ArrayLongKey"), Arrays.asList(1L, 2L, 3L, 4L, 5L)); @@ -579,7 +580,7 @@ void setAttribute() { span.end(); } SpanData spanData = span.toSpanData(); - assertThat(spanData.getAttributes().size()).isEqualTo(17); + assertThat(spanData.getAttributes().size()).isEqualTo(18); assertThat(spanData.getAttributes().get(stringKey("StringKey"))).isNotNull(); assertThat(spanData.getAttributes().get(stringKey("EmptyStringKey"))).isNotNull(); assertThat(spanData.getAttributes().get(stringKey("EmptyStringAttributeValue"))).isNotNull(); @@ -588,6 +589,8 @@ void setAttribute() { assertThat(spanData.getAttributes().get(longKey("LongKey3"))).isEqualTo(6L); assertThat(spanData.getAttributes().get(doubleKey("DoubleKey"))).isNotNull(); assertThat(spanData.getAttributes().get(booleanKey("BooleanKey"))).isNotNull(); + assertThat(spanData.getAttributes().get(valueKey("BytesValueKey"))) + .isEqualTo(Value.of(new byte[] {1, 2, 3})); assertThat(spanData.getAttributes().get(stringArrayKey("ArrayStringKey"))).isNotNull(); assertThat(spanData.getAttributes().get(longArrayKey("ArrayLongKey"))).isNotNull(); assertThat(spanData.getAttributes().get(doubleArrayKey("ArrayDoubleKey"))).isNotNull(); @@ -630,7 +633,7 @@ void setAttribute_nullKeys() { span.setAttribute(null, Collections.emptyList()); span.setAttribute(null, Collections.emptyList()); span.setAttribute(null, Collections.emptyList()); - span.setAttribute(null, Value.empty()); + span.setAttribute((AttributeKey>) null, Value.empty()); assertThat(span.toSpanData().getAttributes().size()).isZero(); } @@ -658,7 +661,7 @@ void setAttribute_emptyArrayAttributeValue() { @Test void setAttribute_nullStringValue() { SdkSpan span = createTestRootSpan(); - span.setAttribute("nullString", null); + span.setAttribute("nullString", (String) null); span.setAttribute("emptyString", ""); span.setAttribute(stringKey("nullStringAttributeValue"), null); span.setAttribute(stringKey("emptyStringAttributeValue"), "");