Skip to content

Commit ac99dd7

Browse files
committed
Make the TraceExporter thread-safe
1 parent 1f0b695 commit ac99dd7

File tree

2 files changed

+63
-17
lines changed

2 files changed

+63
-17
lines changed

exporters/trace/src/main/java/com/google/cloud/opentelemetry/trace/InternalTraceExporter.java

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 Google
2+
* Copyright 2022 Google
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
1515
*/
1616
package com.google.cloud.opentelemetry.trace;
1717

18+
import static com.google.api.client.util.Preconditions.checkNotNull;
19+
1820
import com.google.api.gax.core.FixedCredentialsProvider;
1921
import com.google.api.gax.core.NoCredentialsProvider;
2022
import com.google.api.gax.grpc.GrpcTransportChannel;
@@ -33,14 +35,12 @@
3335
import io.opentelemetry.sdk.common.CompletableResultCode;
3436
import io.opentelemetry.sdk.trace.data.SpanData;
3537
import io.opentelemetry.sdk.trace.export.SpanExporter;
36-
3738
import java.io.IOException;
3839
import java.util.ArrayList;
3940
import java.util.Collection;
4041
import java.util.List;
4142
import java.util.Map;
42-
43-
import static com.google.api.client.util.Preconditions.checkNotNull;
43+
import javax.annotation.Nonnull;
4444

4545
class InternalTraceExporter implements SpanExporter {
4646

@@ -53,6 +53,15 @@ class InternalTraceExporter implements SpanExporter {
5353
Map.of("User-Agent", "opentelemetry-operations-java/" + TraceVersions.EXPORTER_VERSION);
5454
private static final HeaderProvider HEADER_PROVIDER = () -> HEADERS;
5555

56+
private static InternalTraceExporter createWithClient(
57+
String projectId,
58+
CloudTraceClient cloudTraceClient,
59+
ImmutableMap<String, String> attributeMappings,
60+
Map<String, AttributeValue> fixedAttributes) {
61+
return new InternalTraceExporter(
62+
projectId, cloudTraceClient, attributeMappings, fixedAttributes);
63+
}
64+
5665
static SpanExporter createWithConfiguration(TraceConfiguration configuration) throws IOException {
5766
String projectId = configuration.getProjectId();
5867
TraceServiceStub stub = configuration.getTraceServiceStub();
@@ -99,13 +108,34 @@ static SpanExporter createWithConfiguration(TraceConfiguration configuration) th
99108
configuration.getFixedAttributes());
100109
}
101110

102-
private static InternalTraceExporter createWithClient(
103-
String projectId,
104-
CloudTraceClient cloudTraceClient,
105-
ImmutableMap<String, String> attributeMappings,
106-
Map<String, AttributeValue> fixedAttributes) {
107-
return new InternalTraceExporter(
108-
projectId, cloudTraceClient, attributeMappings, fixedAttributes);
111+
/**
112+
* A noop implementation of {@link TraceExporter}. Should be used when {@link TraceExporter}
113+
* cannot be initialized due to some error/exception.
114+
*
115+
* @return noop implementation of {@link TraceExporter} as a {@link SpanExporter}.
116+
*/
117+
static SpanExporter noop() {
118+
return new SpanExporter() {
119+
@Override
120+
public CompletableResultCode export(@Nonnull Collection<SpanData> spans) {
121+
return CompletableResultCode.ofSuccess();
122+
}
123+
124+
@Override
125+
public CompletableResultCode flush() {
126+
return CompletableResultCode.ofSuccess();
127+
}
128+
129+
@Override
130+
public CompletableResultCode shutdown() {
131+
return CompletableResultCode.ofSuccess();
132+
}
133+
134+
@Override
135+
public String toString() {
136+
return "NoopTraceExporter{}";
137+
}
138+
};
109139
}
110140

111141
InternalTraceExporter(

exporters/trace/src/main/java/com/google/cloud/opentelemetry/trace/TraceExporter.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,29 @@
1717

1818
import com.google.cloud.ServiceOptions;
1919
import io.opentelemetry.sdk.common.CompletableResultCode;
20+
import io.opentelemetry.sdk.internal.ThrottlingLogger;
2021
import io.opentelemetry.sdk.trace.data.SpanData;
2122
import io.opentelemetry.sdk.trace.export.SpanExporter;
2223
import java.io.IOException;
2324
import java.util.Collection;
25+
import java.util.Objects;
2426
import java.util.concurrent.atomic.AtomicReference;
27+
import java.util.logging.Level;
28+
import java.util.logging.Logger;
2529
import javax.annotation.Nonnull;
2630

2731
public class TraceExporter implements SpanExporter {
2832

33+
private static final Logger logger = Logger.getLogger(TraceExporter.class.getName());
34+
2935
private final TraceConfiguration.Builder customTraceConfigurationBuilder;
3036
private final AtomicReference<SpanExporter> internalTraceExporter;
37+
private final ThrottlingLogger throttlingLogger;
3138

3239
private TraceExporter(TraceConfiguration.Builder configurationBuilder) {
3340
this.customTraceConfigurationBuilder = configurationBuilder;
3441
this.internalTraceExporter = new AtomicReference<>(null);
42+
this.throttlingLogger = new ThrottlingLogger(logger);
3543
}
3644

3745
private static SpanExporter generateStubTraceExporter(TraceConfiguration.Builder configBuilder) {
@@ -93,13 +101,21 @@ public CompletableResultCode flush() {
93101

94102
@Override
95103
public CompletableResultCode export(@Nonnull Collection<SpanData> spanDataList) {
96-
try {
97-
internalTraceExporter.compareAndSet(null, createActualTraceExporter());
98-
return internalTraceExporter.get().export(spanDataList);
99-
} catch (IOException e) {
100-
e.printStackTrace();
101-
return CompletableResultCode.ofFailure();
104+
if (Objects.isNull(internalTraceExporter.get())) {
105+
synchronized (this) {
106+
try {
107+
internalTraceExporter.compareAndSet(null, createActualTraceExporter());
108+
} catch (IOException e) {
109+
// unable to create actual trace exporter
110+
throttlingLogger.log(
111+
Level.WARNING,
112+
String.format("Unable to initialize trace exporter. Error %s", e.getMessage()));
113+
throttlingLogger.log(Level.INFO, "Setting TraceExporter to noop.");
114+
internalTraceExporter.set(InternalTraceExporter.noop());
115+
}
116+
}
102117
}
118+
return internalTraceExporter.get().export(spanDataList);
103119
}
104120

105121
@Override

0 commit comments

Comments
 (0)