Add the OpenTelemetry schema URL to the Resource. (#3319)

* Add the OpenTelemetry schema URL to the Resource.

* A few cleanups from PR review.
This commit is contained in:
John Watson 2021-06-18 08:52:56 -07:00 committed by GitHub
parent 5f03e70628
commit df1f47d929
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 207 additions and 49 deletions

View File

@ -4,3 +4,11 @@ Comparing source compatibility of against
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.InstrumentationLibraryInfo create(java.lang.String, java.lang.String, java.lang.String)
+++* NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.String getSchemaUrl()
+++ NEW ANNOTATION: javax.annotation.Nullable
**** MODIFIED CLASS: PUBLIC ABSTRACT io.opentelemetry.sdk.resources.Resource (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.resources.Resource create(io.opentelemetry.api.common.Attributes, java.lang.String)
+++* NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.String getSchemaUrl()
+++ NEW ANNOTATION: javax.annotation.Nullable
*** MODIFIED CLASS: PUBLIC io.opentelemetry.sdk.resources.ResourceBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.resources.ResourceBuilder setSchemaUrl(java.lang.String)

View File

@ -61,14 +61,24 @@ public final class MetricAdapter {
instrumentationLibraryMetrics.add(buildInstrumentationLibraryMetrics(entryLibrary));
}
resourceMetrics.add(
ResourceMetrics.newBuilder()
.setResource(ResourceAdapter.toProtoResource(entryResource.getKey()))
.addAllInstrumentationLibraryMetrics(instrumentationLibraryMetrics)
.build());
buildResourceMetrics(entryResource.getKey(), instrumentationLibraryMetrics));
}
return resourceMetrics;
}
private static ResourceMetrics buildResourceMetrics(
Resource resource, List<InstrumentationLibraryMetrics> instrumentationLibraryMetrics) {
ResourceMetrics.Builder resourceMetricsBuilder =
ResourceMetrics.newBuilder()
.setResource(ResourceAdapter.toProtoResource(resource))
.addAllInstrumentationLibraryMetrics(instrumentationLibraryMetrics);
String schemaUrl = resource.getSchemaUrl();
if (schemaUrl != null) {
resourceMetricsBuilder.setSchemaUrl(schemaUrl);
}
return resourceMetricsBuilder.build();
}
private static InstrumentationLibraryMetrics buildInstrumentationLibraryMetrics(
Map.Entry<InstrumentationLibraryInfo, List<Metric>> entryLibrary) {
InstrumentationLibraryMetrics.Builder metricsBuilder =

View File

@ -74,6 +74,9 @@ public final class SpanAdapter {
(resource, librarySpans) -> {
ResourceSpans.Builder resourceSpansBuilder =
ResourceSpans.newBuilder().setResource(ResourceAdapter.toProtoResource(resource));
if (resource.getSchemaUrl() != null) {
resourceSpansBuilder.setSchemaUrl(resource.getSchemaUrl());
}
librarySpans.forEach(
(library, spans) -> {
resourceSpansBuilder.addInstrumentationLibrarySpans(

View File

@ -558,7 +558,8 @@ class MetricAdapterTest {
@Test
void toProtoResourceMetrics() {
Resource resource = Resource.create(Attributes.of(stringKey("ka"), "va"));
Resource resource =
Resource.create(Attributes.of(stringKey("ka"), "va"), "http://resource.url");
io.opentelemetry.proto.resource.v1.Resource resourceProto =
io.opentelemetry.proto.resource.v1.Resource.newBuilder()
.addAllAttributes(
@ -647,6 +648,7 @@ class MetricAdapterTest {
.containsExactlyInAnyOrder(
ResourceMetrics.newBuilder()
.setResource(resourceProto)
.setSchemaUrl("http://resource.url")
.addAllInstrumentationLibraryMetrics(
singletonList(
InstrumentationLibraryMetrics.newBuilder()

View File

@ -36,6 +36,7 @@ import io.opentelemetry.proto.trace.v1.ResourceSpans;
import io.opentelemetry.proto.trace.v1.Span;
import io.opentelemetry.proto.trace.v1.Status;
import io.opentelemetry.sdk.common.InstrumentationLibraryInfo;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.testing.trace.TestSpanData;
import io.opentelemetry.sdk.trace.data.EventData;
import io.opentelemetry.sdk.trace.data.LinkData;
@ -73,10 +74,13 @@ class SpanAdapterTest {
.setStatus(StatusData.unset())
.setInstrumentationLibraryInfo(
InstrumentationLibraryInfo.create("testLib", "1.0", "http://url"))
.setResource(
Resource.builder().put("one", 1).setSchemaUrl("http://url").build())
.build()));
assertThat(resourceSpans).hasSize(1);
ResourceSpans onlyResourceSpans = resourceSpans.get(0);
assertThat(onlyResourceSpans.getSchemaUrl()).isEqualTo("http://url");
assertThat(onlyResourceSpans.getInstrumentationLibrarySpansCount()).isEqualTo(1);
InstrumentationLibrarySpans instrumentationLibrarySpans =
onlyResourceSpans.getInstrumentationLibrarySpans(0);

View File

@ -31,7 +31,7 @@ public final class EnvironmentResource {
}
static Resource create(ConfigProperties config) {
return Resource.create(getAttributes(config));
return Resource.create(getAttributes(config), ResourceAttributes.SCHEMA_URL);
}
// visible for testing

View File

@ -18,7 +18,7 @@ class EnvironmentResourceTest {
@Test
void get() {
assertThat(EnvironmentResource.get()).isNotNull();
assertThat(EnvironmentResource.get().getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
}
@Test

View File

@ -8,12 +8,15 @@ package io.opentelemetry.sdk.autoconfigure;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.junit.jupiter.api.Test;
class ResourceTest {
@Test
void noResourceProviders() {
assertThat(OpenTelemetrySdkAutoConfiguration.getResource()).isEqualTo(Resource.getDefault());
assertThat(OpenTelemetrySdkAutoConfiguration.getResource())
.isEqualTo(
Resource.getDefault().toBuilder().setSchemaUrl(ResourceAttributes.SCHEMA_URL).build());
}
}

View File

@ -58,7 +58,7 @@ public final class BeanstalkResource {
if (!parser.isExpectedStartObjectToken()) {
logger.log(Level.WARNING, "Invalid Beanstalk config: ", configPath);
return Resource.create(attrBuilders.build());
return Resource.create(attrBuilders.build(), ResourceAttributes.SCHEMA_URL);
}
while (parser.nextToken() != JsonToken.END_OBJECT) {
@ -85,7 +85,7 @@ public final class BeanstalkResource {
attrBuilders.put(ResourceAttributes.CLOUD_PROVIDER, AwsResourceConstants.cloudProvider());
return Resource.create(attrBuilders.build());
return Resource.create(attrBuilders.build(), ResourceAttributes.SCHEMA_URL);
}
private BeanstalkResource() {}

View File

@ -119,7 +119,7 @@ public final class Ec2Resource {
attrBuilders.put(ResourceAttributes.HOST_NAME, hostname);
return Resource.create(attrBuilders.build());
return Resource.create(attrBuilders.build(), ResourceAttributes.SCHEMA_URL);
}
private static String fetchToken(URL tokenUrl) {

View File

@ -59,7 +59,7 @@ public final class EcsResource {
attrBuilders.put(ResourceAttributes.CONTAINER_ID, containerId);
}
return Resource.create(attrBuilders.build());
return Resource.create(attrBuilders.build(), ResourceAttributes.SCHEMA_URL);
}
private static boolean isOnEcs(Map<String, String> sysEnv) {

View File

@ -73,7 +73,7 @@ public final class EksResource {
attrBuilders.put(ResourceAttributes.CONTAINER_ID, containerId);
}
return Resource.create(attrBuilders.build());
return Resource.create(attrBuilders.build(), ResourceAttributes.SCHEMA_URL);
}
private static boolean isEks(

View File

@ -53,7 +53,7 @@ public final class LambdaResource {
builder.put(ResourceAttributes.FAAS_VERSION, functionVersion);
}
return Resource.create(builder.build());
return Resource.create(builder.build(), ResourceAttributes.SCHEMA_URL);
}
private static boolean isLambda(String... envVariables) {

View File

@ -11,6 +11,7 @@ import com.google.common.base.Charsets;
import com.google.common.io.Files;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import java.io.File;
import java.io.IOException;
@ -27,7 +28,8 @@ class BeanstalkResourceTest {
"{\"noise\": \"noise\", \"deployment_id\":4,\""
+ "version_label\":\"2\",\"environment_name\":\"HttpSubscriber-env\"}";
Files.write(content.getBytes(Charsets.UTF_8), file);
Attributes attributes = BeanstalkResource.buildResource(file.getPath()).getAttributes();
Resource resource = BeanstalkResource.buildResource(file.getPath());
Attributes attributes = resource.getAttributes();
assertThat(attributes)
.isEqualTo(
Attributes.of(
@ -35,6 +37,7 @@ class BeanstalkResourceTest {
ResourceAttributes.SERVICE_INSTANCE_ID, "4",
ResourceAttributes.SERVICE_VERSION, "2",
ResourceAttributes.SERVICE_NAMESPACE, "HttpSubscriber-env"));
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
}
@Test

View File

@ -15,6 +15,7 @@ import com.linecorp.armeria.testing.junit5.server.mock.MockWebServerExtension;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import java.util.ServiceLoader;
import org.junit.jupiter.api.Test;
@ -50,8 +51,9 @@ class Ec2ResourceTest {
server.enqueue(HttpResponse.of(MediaType.JSON_UTF_8, IDENTITY_DOCUMENT));
server.enqueue(HttpResponse.of("ec2-1-2-3-4"));
Attributes attributes =
Ec2Resource.buildResource("localhost:" + server.httpPort()).getAttributes();
Resource resource = Ec2Resource.buildResource("localhost:" + server.httpPort());
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
AttributesBuilder expectedAttrBuilders = Attributes.builder();
expectedAttrBuilders.put(ResourceAttributes.CLOUD_PROVIDER, "aws");
@ -83,8 +85,9 @@ class Ec2ResourceTest {
server.enqueue(HttpResponse.of(MediaType.JSON_UTF_8, IDENTITY_DOCUMENT));
server.enqueue(HttpResponse.of("ec2-1-2-3-4"));
Attributes attributes =
Ec2Resource.buildResource("localhost:" + server.httpPort()).getAttributes();
Resource resource = Ec2Resource.buildResource("localhost:" + server.httpPort());
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
AttributesBuilder expectedAttrBuilders =
Attributes.builder()

View File

@ -10,6 +10,7 @@ import static org.mockito.Mockito.when;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import java.net.InetAddress;
import java.net.UnknownHostException;
@ -33,7 +34,10 @@ class EcsResourceTest {
when(mockDockerHelper.getContainerId()).thenReturn("0123456789A");
Map<String, String> mockSysEnv = new HashMap<>();
mockSysEnv.put(ECS_METADATA_KEY_V3, "ecs_metadata_v3_uri");
Attributes attributes = EcsResource.buildResource(mockSysEnv, mockDockerHelper).getAttributes();
Resource resource = EcsResource.buildResource(mockSysEnv, mockDockerHelper);
Attributes attributes = resource.getAttributes();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(attributes)
.isEqualTo(
Attributes.of(

View File

@ -60,6 +60,7 @@ public class EksResourceTest {
mockK8sKeystoreFile.getPath());
Attributes attributes = eksResource.getAttributes();
assertThat(eksResource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(attributes)
.isEqualTo(
Attributes.of(

View File

@ -11,6 +11,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import java.util.HashMap;
import java.util.Map;
@ -26,9 +27,11 @@ class LambdaResourceTest {
@Test
void shouldAddNonEmptyAttributes() {
Attributes attributes =
LambdaResource.buildResource(singletonMap("AWS_LAMBDA_FUNCTION_NAME", "my-function"))
.getAttributes();
Resource resource =
LambdaResource.buildResource(singletonMap("AWS_LAMBDA_FUNCTION_NAME", "my-function"));
Attributes attributes = resource.getAttributes();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(attributes)
.isEqualTo(
Attributes.of(
@ -45,8 +48,10 @@ class LambdaResourceTest {
envVars.put("AWS_LAMBDA_FUNCTION_NAME", "my-function");
envVars.put("AWS_LAMBDA_FUNCTION_VERSION", "1.2.3");
Attributes attributes = LambdaResource.buildResource(envVars).getAttributes();
Resource resource = LambdaResource.buildResource(envVars);
Attributes attributes = resource.getAttributes();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(attributes)
.isEqualTo(
Attributes.of(

View File

@ -40,7 +40,7 @@ public final class HostResource {
attributes.put(ResourceAttributes.HOST_ARCH, hostArch);
}
return Resource.create(attributes.build());
return Resource.create(attributes.build(), ResourceAttributes.SCHEMA_URL);
}
private HostResource() {}

View File

@ -55,7 +55,7 @@ public final class OsResource {
String osDescription = version != null ? os + ' ' + version : os;
attributes.put(ResourceAttributes.OS_DESCRIPTION, osDescription);
return Resource.create(attributes.build());
return Resource.create(attributes.build(), ResourceAttributes.SCHEMA_URL);
}
@Nullable

View File

@ -78,7 +78,7 @@ public final class ProcessResource {
attributes.put(ResourceAttributes.PROCESS_COMMAND_LINE, commandLine.toString());
}
return Resource.create(attributes.build());
return Resource.create(attributes.build(), ResourceAttributes.SCHEMA_URL);
}
private ProcessResource() {}

View File

@ -11,6 +11,7 @@ import static io.opentelemetry.semconv.resource.attributes.ResourceAttributes.PR
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
/** Factory of a {@link Resource} which provides information about the Java runtime. */
public final class ProcessRuntimeResource {
@ -41,7 +42,8 @@ public final class ProcessRuntimeResource {
PROCESS_RUNTIME_VERSION,
version,
PROCESS_RUNTIME_DESCRIPTION,
description));
description),
ResourceAttributes.SCHEMA_URL);
} catch (SecurityException ignored) {
return Resource.empty();
}

View File

@ -8,6 +8,7 @@ package io.opentelemetry.sdk.extension.resources;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@ -18,9 +19,11 @@ class HostResourceTest {
@Test
void shouldCreateRuntimeAttributes() {
// when
Attributes attributes = HostResource.buildResource().getAttributes();
Resource resource = HostResource.buildResource();
Attributes attributes = resource.getAttributes();
// then
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(attributes.get(ResourceAttributes.HOST_NAME)).isNotBlank();
assertThat(attributes.get(ResourceAttributes.HOST_ARCH)).isNotBlank();
}

View File

@ -21,7 +21,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "Linux 4.11")
void linux() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.LINUX);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -30,7 +32,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "MacOS X 11")
void macos() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.DARWIN);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -39,7 +43,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "Windows 10")
void windows() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.WINDOWS);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -48,7 +54,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "FreeBSD 10")
void freebsd() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.FREEBSD);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -57,7 +65,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "NetBSD 10")
void netbsd() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.NETBSD);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -66,7 +76,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "OpenBSD 10")
void openbsd() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.OPENBSD);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -75,7 +87,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "DragonFlyBSD 10")
void dragonflybsd() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.DRAGONFLYBSD);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -84,7 +98,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "HP-UX 10")
void hpux() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.HPUX);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -93,7 +109,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "AIX 10")
void aix() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.AIX);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -102,7 +120,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "Solaris 10")
void solaris() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.SOLARIS);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -111,7 +131,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "Z/OS 10")
void zos() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE))
.isEqualTo(ResourceAttributes.OsTypeValues.Z_OS);
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
@ -120,7 +142,9 @@ class OsResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "RagOS 10")
void unknown() {
Attributes attributes = OsResource.buildResource().getAttributes();
Resource resource = OsResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.OS_TYPE)).isNull();
assertThat(attributes.get(ResourceAttributes.OS_DESCRIPTION)).isNotEmpty();
}

View File

@ -8,6 +8,7 @@ package io.opentelemetry.sdk.extension.resources;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@ -20,7 +21,9 @@ class ProcessResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "Linux 4.12")
void notWindows() {
Attributes attributes = ProcessResource.buildResource().getAttributes();
Resource resource = ProcessResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.PROCESS_PID)).isGreaterThan(1);
assertThat(attributes.get(ResourceAttributes.PROCESS_EXECUTABLE_PATH))
@ -33,7 +36,9 @@ class ProcessResourceTest {
@Test
@SetSystemProperty(key = "os.name", value = "Windows 10")
void windows() {
Attributes attributes = ProcessResource.buildResource().getAttributes();
Resource resource = ProcessResource.buildResource();
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(ResourceAttributes.PROCESS_PID)).isGreaterThan(1);
assertThat(attributes.get(ResourceAttributes.PROCESS_EXECUTABLE_PATH))

View File

@ -19,9 +19,11 @@ class ProcessRuntimeResourceTest {
@Test
void shouldCreateRuntimeAttributes() {
// when
Attributes attributes = ProcessRuntimeResource.buildResource().getAttributes();
Resource resource = ProcessRuntimeResource.buildResource();
Attributes attributes = resource.getAttributes();
// then
assertThat(resource.getSchemaUrl()).isEqualTo(ResourceAttributes.SCHEMA_URL);
assertThat(attributes.get(ResourceAttributes.PROCESS_RUNTIME_NAME)).isNotBlank();
assertThat(attributes.get(ResourceAttributes.PROCESS_RUNTIME_VERSION)).isNotBlank();
assertThat(attributes.get(ResourceAttributes.PROCESS_RUNTIME_DESCRIPTION)).isNotBlank();

View File

@ -19,6 +19,7 @@ import io.opentelemetry.api.internal.StringUtils;
import io.opentelemetry.api.internal.Utils;
import java.util.Objects;
import java.util.Properties;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@ -29,6 +30,7 @@ import javax.annotation.concurrent.Immutable;
@Immutable
@AutoValue
public abstract class Resource {
private static final Logger logger = Logger.getLogger(Resource.class.getName());
private static final int MAX_LENGTH = 255;
private static final String ERROR_MESSAGE_INVALID_CHARS =
@ -90,8 +92,22 @@ public abstract class Resource {
* ASCII string or exceed {@link #MAX_LENGTH} characters.
*/
public static Resource create(Attributes attributes) {
return create(attributes, null);
}
/**
* Returns a {@link Resource}.
*
* @param attributes a map of {@link Attributes} that describe the resource.
* @param schemaUrl The URL of the OpenTelemetry schema used to create this Resource.
* @return a {@code Resource}.
* @throws NullPointerException if {@code attributes} is null.
* @throws IllegalArgumentException if attribute key or attribute value is not a valid printable
* ASCII string or exceed {@link #MAX_LENGTH} characters.
*/
public static Resource create(Attributes attributes, @Nullable String schemaUrl) {
checkAttributes(Objects.requireNonNull(attributes, "attributes"));
return new AutoValue_Resource(attributes);
return new AutoValue_Resource(schemaUrl, attributes);
}
@Nullable
@ -107,7 +123,13 @@ public abstract class Resource {
return properties.getProperty("sdk.version");
}
Resource() {}
/**
* Returns the URL of the OpenTelemetry schema used by this resource. May be null.
*
* @return An OpenTelemetry schema URL.
*/
@Nullable
public abstract String getSchemaUrl();
/**
* Returns a map of attributes that describe the resource.
@ -135,7 +157,25 @@ public abstract class Resource {
AttributesBuilder attrBuilder = Attributes.builder();
attrBuilder.putAll(this.getAttributes());
attrBuilder.putAll(other.getAttributes());
return new AutoValue_Resource(attrBuilder.build());
if (other.getSchemaUrl() == null) {
return create(attrBuilder.build(), getSchemaUrl());
}
if (getSchemaUrl() == null) {
return create(attrBuilder.build(), other.getSchemaUrl());
}
if (!other.getSchemaUrl().equals(getSchemaUrl())) {
logger.info(
"Attempting to merge Resources with different schemaUrls. "
+ "The resulting Resource will have no schemaUrl assigned. Schema 1: "
+ getSchemaUrl()
+ " Schema 2: "
+ other.getSchemaUrl());
// currently, behavior is undefined if schema URLs don't match. In the future, we may
// apply schema transformations if possible.
return create(attrBuilder.build(), null);
}
return create(attrBuilder.build(), getSchemaUrl());
}
private static void checkAttributes(Attributes attributes) {
@ -187,4 +227,6 @@ public abstract class Resource {
public ResourceBuilder toBuilder() {
return builder().putAll(this);
}
Resource() {}
}

View File

@ -8,6 +8,7 @@ package io.opentelemetry.sdk.resources;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;
import javax.annotation.Nullable;
/**
* A builder of {@link Resource} that allows to add key-value pairs and copy attributes from other
@ -18,6 +19,7 @@ import io.opentelemetry.api.common.AttributesBuilder;
public class ResourceBuilder {
private final AttributesBuilder attributesBuilder = Attributes.builder();
@Nullable private String schemaUrl;
/**
* Puts a String attribute into this.
@ -171,8 +173,19 @@ public class ResourceBuilder {
return this;
}
/**
* Assign an OpenTelemetry schema URL to the resulting Resource.
*
* @param schemaUrl The URL of the OpenTelemetry schema being used to create this Resource.
* @return this
*/
public ResourceBuilder setSchemaUrl(String schemaUrl) {
this.schemaUrl = schemaUrl;
return this;
}
/** Create the {@link Resource} from this. */
public Resource build() {
return Resource.create(attributesBuilder.build());
return Resource.create(attributesBuilder.build(), schemaUrl);
}
}

View File

@ -145,6 +145,9 @@ class ResourceTest {
new EqualsTester()
.addEqualityGroup(Resource.create(attribute1), Resource.create(attribute1), resource1)
.addEqualityGroup(Resource.create(attribute2), resource2)
.addEqualityGroup(
Resource.create(attribute1, "http://schema"),
Resource.create(attribute1, "http://schema"))
.testEquals();
}
@ -157,6 +160,23 @@ class ResourceTest {
assertThat(resource.getAttributes()).isEqualTo(expectedAttributes);
}
@Test
void testMergeResources_schema() {
Resource noSchemaOne = Resource.builder().put("a", 1).build();
Resource noSchemaTwo = Resource.builder().put("b", 2).build();
Resource schemaOne = Resource.builder().setSchemaUrl("http://schema.1").put("c", 3).build();
Resource schemaTwo = Resource.builder().setSchemaUrl("http://schema.2").put("d", 4).build();
Resource schemaTwoAgain =
Resource.builder().setSchemaUrl("http://schema.2").put("e", 5).build();
assertThat(noSchemaOne.merge(noSchemaTwo).getSchemaUrl()).isNull();
assertThat(schemaOne.merge(noSchemaOne).getSchemaUrl()).isEqualTo(schemaOne.getSchemaUrl());
assertThat(noSchemaOne.merge(schemaOne).getSchemaUrl()).isEqualTo(schemaOne.getSchemaUrl());
assertThat(schemaTwo.merge(schemaTwoAgain).getSchemaUrl()).isEqualTo(schemaTwo.getSchemaUrl());
assertThat(schemaOne.merge(schemaTwo).getSchemaUrl()).isNull();
assertThat(schemaTwo.merge(schemaOne).getSchemaUrl()).isNull();
}
@Test
void testMergeResources_Resource1() {
Attributes expectedAttributes = Attributes.of(stringKey("a"), "1", stringKey("b"), "2");

View File

@ -953,7 +953,8 @@ class SdkSpanBuilderTest {
+ "spanId=0000000000000000, "
+ "traceFlags=00, "
+ "traceState=ArrayBasedTraceState\\{entries=\\[]}, remote=false, valid=false}, "
+ "resource=Resource\\{attributes=\\{service.name=\"unknown_service:java\", "
+ "resource=Resource\\{schemaUrl=null, "
+ "attributes=\\{service.name=\"unknown_service:java\", "
+ "telemetry.sdk.language=\"java\", telemetry.sdk.name=\"opentelemetry\", "
+ "telemetry.sdk.version=\"\\d+.\\d+.\\d+(-SNAPSHOT)?\"}}, "
+ "instrumentationLibraryInfo=InstrumentationLibraryInfo\\{"