Skip to content
This repository was archived by the owner on Dec 23, 2023. It is now read-only.

Commit 8716b0c

Browse files
author
Bogdan Drutu
authored
Add option to add attributes to all exported spans to Stackdriver. (#1692)
* Add option to add attributes to all exported spans to Stackdriver. * Fix checker framework errors.
1 parent 327cafb commit 8716b0c

File tree

5 files changed

+149
-31
lines changed

5 files changed

+149
-31
lines changed

exporters/trace/stackdriver/src/main/java/io/opencensus/exporter/trace/stackdriver/StackdriverTraceConfiguration.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import com.google.auth.Credentials;
2020
import com.google.auto.value.AutoValue;
2121
import com.google.cloud.trace.v2.stub.TraceServiceStub;
22+
import io.opencensus.trace.AttributeValue;
23+
import java.util.Map;
2224
import javax.annotation.Nullable;
2325
import javax.annotation.concurrent.Immutable;
2426

@@ -60,6 +62,15 @@ public abstract class StackdriverTraceConfiguration {
6062
@Nullable
6163
public abstract TraceServiceStub getTraceServiceStub();
6264

65+
/**
66+
* Returns a map of attributes that is added to all the exported spans.
67+
*
68+
* @return the map of attributes that is added to all the exported spans.
69+
* @since 0.19
70+
*/
71+
@Nullable
72+
public abstract Map<String, AttributeValue> getFixedAttributes();
73+
6374
/**
6475
* Returns a new {@link Builder}.
6576
*
@@ -107,6 +118,15 @@ public abstract static class Builder {
107118
*/
108119
public abstract Builder setTraceServiceStub(TraceServiceStub traceServiceStub);
109120

121+
/**
122+
* Sets the map of attributes that is added to all the exported spans.
123+
*
124+
* @param fixedAttributes the map of attributes that is added to all the exported spans.
125+
* @return this.
126+
* @since 0.16
127+
*/
128+
public abstract Builder setFixedAttributes(Map<String, AttributeValue> fixedAttributes);
129+
110130
/**
111131
* Builds a {@link StackdriverTraceConfiguration}.
112132
*

exporters/trace/stackdriver/src/main/java/io/opencensus/exporter/trace/stackdriver/StackdriverTraceExporter.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,13 @@ public static void createAndRegister(StackdriverTraceConfiguration configuration
8787
if (stub == null) {
8888
handler =
8989
StackdriverV2ExporterHandler.createWithCredentials(
90+
projectId,
9091
credentials != null ? credentials : GoogleCredentials.getApplicationDefault(),
91-
projectId);
92+
configuration.getFixedAttributes());
9293
} else {
93-
handler = new StackdriverV2ExporterHandler(projectId, TraceServiceClient.create(stub));
94+
handler =
95+
StackdriverV2ExporterHandler.createWithStub(
96+
projectId, TraceServiceClient.create(stub), configuration.getFixedAttributes());
9497
}
9598

9699
registerInternal(handler);

exporters/trace/stackdriver/src/main/java/io/opencensus/exporter/trace/stackdriver/StackdriverV2ExporterHandler.java

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ final class StackdriverV2ExporterHandler extends SpanExporter.Handler {
9999
.put("http.status_code", "/http/status_code")
100100
.build();
101101

102-
@Deprecated @javax.annotation.Nullable
102+
@javax.annotation.Nullable
103+
@SuppressWarnings("deprecation")
103104
private static final MonitoredResource RESOURCE = MonitoredResourceUtils.getDefaultResource();
104105

105106
// Only initialize once.
@@ -110,28 +111,24 @@ final class StackdriverV2ExporterHandler extends SpanExporter.Handler {
110111
new Function<String, /*@Nullable*/ AttributeValue>() {
111112
@Override
112113
public AttributeValue apply(String stringValue) {
113-
AttributeValue.Builder attributeValueBuilder = AttributeValue.newBuilder();
114-
attributeValueBuilder.setStringValue(toTruncatableStringProto(stringValue));
115-
return attributeValueBuilder.build();
114+
return AttributeValue.newBuilder()
115+
.setStringValue(toTruncatableStringProto(stringValue))
116+
.build();
116117
}
117118
};
118119
private static final Function<Boolean, /*@Nullable*/ AttributeValue>
119120
booleanAttributeValueFunction =
120121
new Function<Boolean, /*@Nullable*/ AttributeValue>() {
121122
@Override
122123
public AttributeValue apply(Boolean booleanValue) {
123-
AttributeValue.Builder attributeValueBuilder = AttributeValue.newBuilder();
124-
attributeValueBuilder.setBoolValue(booleanValue);
125-
return attributeValueBuilder.build();
124+
return AttributeValue.newBuilder().setBoolValue(booleanValue).build();
126125
}
127126
};
128127
private static final Function<Long, /*@Nullable*/ AttributeValue> longAttributeValueFunction =
129128
new Function<Long, /*@Nullable*/ AttributeValue>() {
130129
@Override
131130
public AttributeValue apply(Long longValue) {
132-
AttributeValue.Builder attributeValueBuilder = AttributeValue.newBuilder();
133-
attributeValueBuilder.setIntValue(longValue);
134-
return attributeValueBuilder.build();
131+
return AttributeValue.newBuilder().setIntValue(longValue).build();
135132
}
136133
};
137134
private static final Function<Double, /*@Nullable*/ AttributeValue> doubleAttributeValueFunction =
@@ -149,30 +146,58 @@ public AttributeValue apply(Double doubleValue) {
149146
private static final EndSpanOptions END_SPAN_OPTIONS =
150147
EndSpanOptions.builder().setSampleToLocalSpanStore(true).build();
151148

149+
private final Map<String, AttributeValue> fixedAttributes;
152150
private final String projectId;
153151
private final TraceServiceClient traceServiceClient;
154152
private final ProjectName projectName;
155153

156-
@VisibleForTesting
157-
StackdriverV2ExporterHandler(String projectId, TraceServiceClient traceServiceClient) {
154+
private StackdriverV2ExporterHandler(
155+
String projectId,
156+
TraceServiceClient traceServiceClient,
157+
@javax.annotation.Nullable Map<String, io.opencensus.trace.AttributeValue> fixedAttributes) {
158158
this.projectId = checkNotNull(projectId, "projectId");
159159
this.traceServiceClient = traceServiceClient;
160+
if (fixedAttributes == null) {
161+
this.fixedAttributes = Collections.emptyMap();
162+
} else {
163+
this.fixedAttributes = new HashMap<>();
164+
for (Map.Entry<String, io.opencensus.trace.AttributeValue> label :
165+
fixedAttributes.entrySet()) {
166+
AttributeValue value = toAttributeValueProto(label.getValue());
167+
if (value != null) {
168+
this.fixedAttributes.put(label.getKey(), value);
169+
}
170+
}
171+
}
160172
projectName = ProjectName.of(this.projectId);
161173
}
162174

175+
static StackdriverV2ExporterHandler createWithStub(
176+
String projectId,
177+
TraceServiceClient traceServiceClient,
178+
@javax.annotation.Nullable Map<String, io.opencensus.trace.AttributeValue> fixedAttributes) {
179+
return new StackdriverV2ExporterHandler(projectId, traceServiceClient, fixedAttributes);
180+
}
181+
163182
static StackdriverV2ExporterHandler createWithCredentials(
164-
Credentials credentials, String projectId) throws IOException {
165-
checkNotNull(credentials, "credentials");
183+
String projectId,
184+
Credentials credentials,
185+
@javax.annotation.Nullable Map<String, io.opencensus.trace.AttributeValue> fixedAttributes)
186+
throws IOException {
166187
TraceServiceSettings traceServiceSettings =
167188
TraceServiceSettings.newBuilder()
168-
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
189+
.setCredentialsProvider(
190+
FixedCredentialsProvider.create(checkNotNull(credentials, "credentials")))
169191
.build();
170192
return new StackdriverV2ExporterHandler(
171-
projectId, TraceServiceClient.create(traceServiceSettings));
193+
projectId, TraceServiceClient.create(traceServiceSettings), fixedAttributes);
172194
}
173195

174196
@VisibleForTesting
175-
Span generateSpan(SpanData spanData, Map<String, AttributeValue> resourceLabels) {
197+
Span generateSpan(
198+
SpanData spanData,
199+
Map<String, AttributeValue> resourceLabels,
200+
Map<String, AttributeValue> fixedAttributes) {
176201
SpanContext context = spanData.getContext();
177202
final String spanIdHex = context.getSpanId().toLowerBase16();
178203
SpanName spanName =
@@ -188,7 +213,8 @@ Span generateSpan(SpanData spanData, Map<String, AttributeValue> resourceLabels)
188213
.setDisplayName(
189214
toTruncatableStringProto(toDisplayName(spanData.getName(), spanData.getKind())))
190215
.setStartTime(toTimestampProto(spanData.getStartTimestamp()))
191-
.setAttributes(toAttributesProto(spanData.getAttributes(), resourceLabels))
216+
.setAttributes(
217+
toAttributesProto(spanData.getAttributes(), resourceLabels, fixedAttributes))
192218
.setTimeEvents(
193219
toTimeEventsProto(spanData.getAnnotations(), spanData.getMessageEvents()));
194220
io.opencensus.trace.Status status = spanData.getStatus();
@@ -269,14 +295,18 @@ private static TimeEvent.MessageEvent.Type toMessageEventTypeProto(
269295
// These are the attributes of the Span, where usually we may add more attributes like the agent.
270296
private static Attributes toAttributesProto(
271297
io.opencensus.trace.export.SpanData.Attributes attributes,
272-
Map<String, AttributeValue> resourceLabels) {
298+
Map<String, AttributeValue> resourceLabels,
299+
Map<String, AttributeValue> fixedAttributes) {
273300
Attributes.Builder attributesBuilder =
274301
toAttributesBuilderProto(
275302
attributes.getAttributeMap(), attributes.getDroppedAttributesCount());
276303
attributesBuilder.putAttributeMap(AGENT_LABEL_KEY, AGENT_LABEL_VALUE);
277304
for (Entry<String, AttributeValue> entry : resourceLabels.entrySet()) {
278305
attributesBuilder.putAttributeMap(entry.getKey(), entry.getValue());
279306
}
307+
for (Entry<String, AttributeValue> entry : fixedAttributes.entrySet()) {
308+
attributesBuilder.putAttributeMap(entry.getKey(), entry.getValue());
309+
}
280310
return attributesBuilder.build();
281311
}
282312

@@ -493,7 +523,7 @@ public void export(Collection<SpanData> spanDataList) {
493523
try {
494524
List<Span> spans = new ArrayList<>(spanDataList.size());
495525
for (SpanData spanData : spanDataList) {
496-
spans.add(generateSpan(spanData, RESOURCE_LABELS));
526+
spans.add(generateSpan(spanData, RESOURCE_LABELS, fixedAttributes));
497527
}
498528
// Sync call because it is already called for a batch of data, and on a separate thread.
499529
// TODO(bdrutu): Consider to make this async in the future.

exporters/trace/stackdriver/src/test/java/io/opencensus/exporter/trace/stackdriver/StackdriverV2ExporterHandlerExportTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import com.google.cloud.trace.v2.TraceServiceClient;
2222
import com.google.cloud.trace.v2.stub.TraceServiceStub;
23+
import io.opencensus.trace.AttributeValue;
2324
import io.opencensus.trace.export.SpanData;
2425
import java.util.Collection;
2526
import java.util.Collections;
@@ -49,7 +50,9 @@ public void setUp() {
4950
// TODO(@Hailong): TraceServiceClient.create(TraceServiceStub) is a beta API and might change
5051
// in the future.
5152
traceServiceClient = TraceServiceClient.create(traceServiceStub);
52-
handler = new StackdriverV2ExporterHandler(PROJECT_ID, traceServiceClient);
53+
handler =
54+
StackdriverV2ExporterHandler.createWithStub(
55+
PROJECT_ID, traceServiceClient, Collections.<String, AttributeValue>emptyMap());
5356
}
5457

5558
@Test

exporters/trace/stackdriver/src/test/java/io/opencensus/exporter/trace/stackdriver/StackdriverV2ExporterHandlerProtoTest.java

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,11 @@ public final class StackdriverV2ExporterHandlerProtoTest {
180180

181181
@Before
182182
public void setUp() throws IOException {
183-
handler = StackdriverV2ExporterHandler.createWithCredentials(FAKE_CREDENTIALS, PROJECT_ID);
183+
handler =
184+
StackdriverV2ExporterHandler.createWithCredentials(
185+
PROJECT_ID,
186+
FAKE_CREDENTIALS,
187+
Collections.<String, io.opencensus.trace.AttributeValue>emptyMap());
184188
}
185189

186190
@Test
@@ -283,7 +287,9 @@ public void generateSpan() {
283287
.setNanos(endTimestamp.getNanos())
284288
.build();
285289

286-
Span span = handler.generateSpan(spanData, EMPTY_RESOURCE_LABELS);
290+
Span span =
291+
handler.generateSpan(
292+
spanData, EMPTY_RESOURCE_LABELS, Collections.<String, AttributeValue>emptyMap());
287293
assertThat(span.getName()).isEqualTo(SD_SPAN_NAME);
288294
assertThat(span.getSpanId()).isEqualTo(SPAN_ID);
289295
assertThat(span.getParentSpanId()).isEqualTo(PARENT_SPAN_ID);
@@ -353,7 +359,9 @@ public void generateSpan_WithResourceLabels() {
353359
CHILD_SPAN_COUNT,
354360
status,
355361
endTimestamp);
356-
Span span = handler.generateSpan(spanData, AWS_RESOURCE_LABELS);
362+
Span span =
363+
handler.generateSpan(
364+
spanData, AWS_RESOURCE_LABELS, Collections.<String, AttributeValue>emptyMap());
357365
Map<String, AttributeValue> attributeMap = span.getAttributes().getAttributeMapMap();
358366
assertThat(attributeMap.entrySet()).containsAllIn(AWS_RESOURCE_LABELS.entrySet());
359367
}
@@ -390,7 +398,9 @@ public void mapHttpAttributes() {
390398
status,
391399
endTimestamp);
392400

393-
Span span = handler.generateSpan(spanData, EMPTY_RESOURCE_LABELS);
401+
Span span =
402+
handler.generateSpan(
403+
spanData, EMPTY_RESOURCE_LABELS, Collections.<String, AttributeValue>emptyMap());
394404
Map<String, AttributeValue> attributes = span.getAttributes().getAttributeMapMap();
395405

396406
assertThat(attributes).containsEntry("/http/host", toStringAttributeValueProto("host"));
@@ -420,7 +430,12 @@ public void generateSpanName_ForServer() {
420430
CHILD_SPAN_COUNT,
421431
status,
422432
endTimestamp);
423-
assertThat(handler.generateSpan(spanData, EMPTY_RESOURCE_LABELS).getDisplayName().getValue())
433+
assertThat(
434+
handler
435+
.generateSpan(
436+
spanData, EMPTY_RESOURCE_LABELS, Collections.<String, AttributeValue>emptyMap())
437+
.getDisplayName()
438+
.getValue())
424439
.isEqualTo("Recv." + SPAN_NAME);
425440
}
426441

@@ -441,7 +456,12 @@ public void generateSpanName_ForServerWithRecv() {
441456
CHILD_SPAN_COUNT,
442457
status,
443458
endTimestamp);
444-
assertThat(handler.generateSpan(spanData, EMPTY_RESOURCE_LABELS).getDisplayName().getValue())
459+
assertThat(
460+
handler
461+
.generateSpan(
462+
spanData, EMPTY_RESOURCE_LABELS, Collections.<String, AttributeValue>emptyMap())
463+
.getDisplayName()
464+
.getValue())
445465
.isEqualTo("Recv." + SPAN_NAME);
446466
}
447467

@@ -462,7 +482,12 @@ public void generateSpanName_ForClient() {
462482
CHILD_SPAN_COUNT,
463483
status,
464484
endTimestamp);
465-
assertThat(handler.generateSpan(spanData, EMPTY_RESOURCE_LABELS).getDisplayName().getValue())
485+
assertThat(
486+
handler
487+
.generateSpan(
488+
spanData, EMPTY_RESOURCE_LABELS, Collections.<String, AttributeValue>emptyMap())
489+
.getDisplayName()
490+
.getValue())
466491
.isEqualTo("Sent." + SPAN_NAME);
467492
}
468493

@@ -483,7 +508,44 @@ public void generateSpanName_ForClientWithSent() {
483508
CHILD_SPAN_COUNT,
484509
status,
485510
endTimestamp);
486-
assertThat(handler.generateSpan(spanData, EMPTY_RESOURCE_LABELS).getDisplayName().getValue())
511+
assertThat(
512+
handler
513+
.generateSpan(
514+
spanData, EMPTY_RESOURCE_LABELS, Collections.<String, AttributeValue>emptyMap())
515+
.getDisplayName()
516+
.getValue())
487517
.isEqualTo("Sent." + SPAN_NAME);
488518
}
519+
520+
@Test
521+
public void addFixedAttributes() {
522+
final ImmutableMap<String, AttributeValue> fixedAttributes =
523+
ImmutableMap.of(
524+
createResourceLabelKey(AWS_EC2_INSTANCE, "string_attr"),
525+
toStringAttributeValueProto("my-project"),
526+
createResourceLabelKey(AWS_EC2_INSTANCE, "long_attr"),
527+
AttributeValue.newBuilder().setIntValue(1234).build(),
528+
createResourceLabelKey(AWS_EC2_INSTANCE, "bool_attr"),
529+
AttributeValue.newBuilder().setBoolValue(true).build());
530+
531+
SpanData spanData =
532+
SpanData.create(
533+
spanContext,
534+
parentSpanId,
535+
/* hasRemoteParent= */ true,
536+
"Sent." + SPAN_NAME,
537+
Kind.CLIENT,
538+
startTimestamp,
539+
attributes,
540+
annotations,
541+
messageEvents,
542+
links,
543+
CHILD_SPAN_COUNT,
544+
status,
545+
endTimestamp);
546+
547+
Span span = handler.generateSpan(spanData, EMPTY_RESOURCE_LABELS, fixedAttributes);
548+
Map<String, AttributeValue> attributeMap = span.getAttributes().getAttributeMapMap();
549+
assertThat(attributeMap.entrySet()).containsAllIn(fixedAttributes.entrySet());
550+
}
489551
}

0 commit comments

Comments
 (0)