Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resource.Builder for convenient work with Resource class #3065

Merged
merged 7 commits into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
Expand Down Expand Up @@ -67,10 +66,9 @@ private static OpenTelemetry initOpenTelemetry() {
SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(jaegerExporter))
.setResource(
Resource.getDefault()
.merge(
Resource.create(
Attributes.of(ResourceAttributes.SERVICE_NAME, SERVICE_NAME))))
Resource.getDefault().toBuilder()
.put(ResourceAttributes.SERVICE_NAME, SERVICE_NAME)
.build())
.build())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.resources.Resource;
Expand Down Expand Up @@ -71,10 +70,9 @@ private static OpenTelemetry initOpenTelemetry() {
SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(jaegerExporter))
.setResource(
Resource.getDefault()
.merge(
Resource.create(
Attributes.of(ResourceAttributes.SERVICE_NAME, SERVICE_NAME))))
Resource.getDefault().toBuilder()
.put(ResourceAttributes.SERVICE_NAME, SERVICE_NAME)
.build())
.build())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.exporter.jaeger.JaegerGrpcSpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
Expand Down Expand Up @@ -117,11 +116,9 @@ private static OpenTelemetry initOpenTelemetry(String ip, int port) {
SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(jaegerExporter))
.setResource(
Resource.getDefault()
.merge(
Resource.create(
Attributes.of(
ResourceAttributes.SERVICE_NAME, "integration test"))))
Resource.getDefault().toBuilder()
.put(ResourceAttributes.SERVICE_NAME, "integration test")
.build())
.build())
.buildAndRegisterGlobal();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,17 @@ private static boolean isValid(String name) {
private static boolean isValidAndNotEmpty(AttributeKey<?> name) {
return !name.getKey().isEmpty() && isValid(name.getKey());
}

/** Returns a new {@link ResourceBuilder} instance for creating arbitrary {@link Resource}. */
public static ResourceBuilder builder() {
jkwatson marked this conversation as resolved.
Show resolved Hide resolved
return new ResourceBuilder();
}

/**
* Returns a new {@link ResourceBuilder} instance populated with the data of this {@link
* Resource}.
*/
public ResourceBuilder toBuilder() {
return builder().putAll(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.resources;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.common.AttributesBuilder;

/**
* A builder of {@link Resource} that allows to add key-value pairs and copy attributes from other
* {@link Attributes} or {@link Resource}.
*/
public class ResourceBuilder {
jkwatson marked this conversation as resolved.
Show resolved Hide resolved

private final AttributesBuilder attributesBuilder = Attributes.builder();

/**
* Puts a String attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(AttributeKey, Object)}, and pre-allocate
* your keys, if possible.
*
* @return this Builder
*/
public ResourceBuilder put(String key, String value) {
if (key != null && value != null) {
attributesBuilder.put(key, value);
}
return this;
}

/**
* Puts a long attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(AttributeKey, Object)}, and pre-allocate
* your keys, if possible.
*
* @return this Builder
*/
public ResourceBuilder put(String key, long value) {
if (key != null) {
attributesBuilder.put(key, value);
}
return this;
}

/**
* Puts a double attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(AttributeKey, Object)}, and pre-allocate
* your keys, if possible.
*
* @return this Builder
*/
public ResourceBuilder put(String key, double value) {
if (key != null) {
attributesBuilder.put(key, value);
}
return this;
}

/**
* Puts a boolean attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(AttributeKey, Object)}, and pre-allocate
* your keys, if possible.
*
* @return this Builder
*/
public ResourceBuilder put(String key, boolean value) {
if (key != null) {
attributesBuilder.put(key, value);
}
return this;
}

/**
* Puts a String array attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(AttributeKey, Object)}, and pre-allocate
* your keys, if possible.
*
* @return this Builder
*/
public ResourceBuilder put(String key, String... values) {
if (key != null && values != null) {
attributesBuilder.put(key, values);
}
return this;
}

/**
* Puts a Long array attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(AttributeKey, Object)}, and pre-allocate
* your keys, if possible.
*
* @return this Builder
*/
public ResourceBuilder put(String key, long... values) {
if (key != null && values != null) {
attributesBuilder.put(key, values);
}
return this;
}

/**
* Puts a Double array attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(AttributeKey, Object)}, and pre-allocate
* your keys, if possible.
*
* @return this Builder
*/
public ResourceBuilder put(String key, double... values) {
if (key != null && values != null) {
attributesBuilder.put(key, values);
}
return this;
}

/**
* Puts a Boolean array attribute into this.
*
* <p>Note: It is strongly recommended to use {@link #put(AttributeKey, Object)}, and pre-allocate
* your keys, if possible.
*
* @return this Builder
*/
public ResourceBuilder put(String key, boolean... values) {
if (key != null && values != null) {
attributesBuilder.put(key, values);
}
return this;
}

/** Puts a {@link AttributeKey} with associated value into this. */
public <T> ResourceBuilder put(AttributeKey<T> key, T value) {
if (key != null && key.getKey() != null && key.getKey().length() > 0 && value != null) {
attributesBuilder.put(key, value);
}
return this;
}

/** Puts a {@link AttributeKey} with associated value into this. */
public ResourceBuilder put(AttributeKey<Long> key, int value) {
if (key != null && key.getKey() != null) {
attributesBuilder.put(key, value);
}
return this;
}

/** Puts all {@link Attributes} into this. */
public ResourceBuilder putAll(Attributes attributes) {
if (attributes != null) {
attributesBuilder.putAll(attributes);
}
return this;
}

/** Puts all attributes from {@link Resource} into this. */
public ResourceBuilder putAll(Resource resource) {
if (resource != null) {
attributesBuilder.putAll(resource.getAttributes());
}
return this;
}

/** Create the {@link Resource} from this. */
public Resource build() {
return Resource.create(attributesBuilder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,76 @@ void testDefaultResources() {
assertThat(attributes.get(ResourceAttributes.TELEMETRY_SDK_LANGUAGE)).isEqualTo("java");
assertThat(attributes.get(ResourceAttributes.TELEMETRY_SDK_VERSION)).isNotNull();
}

@Test
void shouldBuilderNotFailWithNullResource() {
// given
ResourceBuilder builder = Resource.getDefault().toBuilder();

// when
builder.putAll((Resource) null);

// then no exception is thrown
// and
assertThat(builder.build().getAttributes().get(ResourceAttributes.SERVICE_NAME))
.isEqualTo("unknown_service:java");
}

@Test
void shouldBuilderCopyResource() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to add test coverage of all the new methods

// given
ResourceBuilder builder = Resource.getDefault().toBuilder();

// when
builder.put("dog says what?", "woof");

// then
Resource resource = builder.build();
assertThat(resource).isNotSameAs(Resource.getDefault());
assertThat(resource.getAttributes().get(stringKey("dog says what?"))).isEqualTo("woof");
}

@Test
void shouldBuilderHelperMethodsBuildResource() {
// given
ResourceBuilder builder = Resource.getDefault().toBuilder();
Attributes sourceAttributes = Attributes.of(stringKey("hello"), "world");
Resource source = Resource.create(sourceAttributes);
Attributes sourceAttributes2 = Attributes.of(stringKey("OpenTelemetry"), "Java");

// when
Resource resource =
builder
.put("long", 42L)
.put("double", Math.E)
.put("boolean", true)
.put("string", "abc")
.put("long array", 1L, 2L, 3L)
.put("double array", Math.E, Math.PI)
.put("boolean array", true, false)
.put("string array", "first", "second")
.put(longKey("long key"), 4242L)
.put(longKey("int in disguise"), 21)
.putAll(source)
.putAll(sourceAttributes2)
.build();

// then
Attributes attributes = resource.getAttributes();
assertThat(attributes.get(longKey("long"))).isEqualTo(42L);
assertThat(attributes.get(doubleKey("double"))).isEqualTo(Math.E);
assertThat(attributes.get(booleanKey("boolean"))).isEqualTo(true);
assertThat(attributes.get(stringKey("string"))).isEqualTo("abc");
assertThat(attributes.get(longArrayKey("long array"))).isEqualTo(Arrays.asList(1L, 2L, 3L));
assertThat(attributes.get(doubleArrayKey("double array")))
.isEqualTo(Arrays.asList(Math.E, Math.PI));
assertThat(attributes.get(booleanArrayKey("boolean array")))
.isEqualTo(Arrays.asList(true, false));
assertThat(attributes.get(stringArrayKey("string array")))
.isEqualTo(Arrays.asList("first", "second"));
assertThat(attributes.get(longKey("long key"))).isEqualTo(4242L);
assertThat(attributes.get(longKey("int in disguise"))).isEqualTo(21);
assertThat(attributes.get(stringKey("hello"))).isEqualTo("world");
assertThat(attributes.get(stringKey("OpenTelemetry"))).isEqualTo("Java");
}
}