3232
3333import com .google .api .core .BetaApi ;
3434import com .google .api .core .InternalApi ;
35+ import io .opentelemetry .api .trace .Span ;
36+ import io .opentelemetry .api .trace .SpanBuilder ;
37+ import io .opentelemetry .api .trace .SpanKind ;
38+ import io .opentelemetry .api .trace .Tracer ;
3539import java .util .HashMap ;
3640import java .util .Map ;
3741
38- /**
39- * An implementation of {@link ApiTracer} that uses a {@link TraceManager} to record traces. This
40- * implementation is agnostic to the specific {@link TraceManager} in order to allow extensions that
41- * interact with other backends.
42- */
42+ /** An implementation of {@link ApiTracer} that uses OpenTelemetry to record traces. */
4343@ BetaApi
4444@ InternalApi
4545public class SpanTracer implements ApiTracer {
4646 public static final String LANGUAGE_ATTRIBUTE = "gcp.client.language" ;
4747
4848 public static final String DEFAULT_LANGUAGE = "Java" ;
4949
50- private final TraceManager traceManager ;
50+ private final Tracer tracer ;
5151 private final Map <String , Object > attemptAttributes ;
5252 private final String attemptSpanName ;
5353 private final ApiTracerContext apiTracerContext ;
54- private TraceManager . Span attemptHandle ;
54+ private Span attemptSpan ;
5555
5656 /**
5757 * Creates a new instance of {@code SpanTracer}.
5858 *
59- * @param traceManager the {@link TraceManager} to use for recording spans
59+ * @param tracer the {@link Tracer} to use for recording spans
60+ * @param apiTracerContext the {@link ApiTracerContext} to use for recording spans
61+ */
62+ public SpanTracer (Tracer tracer , ApiTracerContext apiTracerContext ) {
63+ this .tracer = tracer ;
64+ this .apiTracerContext = apiTracerContext ;
65+ this .attemptSpanName = resolveAttemptSpanName (apiTracerContext );
66+ this .attemptAttributes = new HashMap <>();
67+ buildAttributes ();
68+ }
69+
70+ /**
71+ * Creates a new instance of {@code SpanTracer} with an explicitly provided span name.
72+ *
73+ * @param tracer the {@link Tracer} to use for recording spans
74+ * @param apiTracerContext the {@link ApiTracerContext} to use for recording spans
6075 * @param attemptSpanName the name of the individual attempt spans
6176 */
62- public SpanTracer (
63- TraceManager traceManager , ApiTracerContext apiTracerContext , String attemptSpanName ) {
64- this .traceManager = traceManager ;
77+ @ InternalApi
78+ SpanTracer ( Tracer tracer , ApiTracerContext apiTracerContext , String attemptSpanName ) {
79+ this .tracer = tracer ;
6580 this .attemptSpanName = attemptSpanName ;
6681 this .apiTracerContext = apiTracerContext ;
6782 this .attemptAttributes = new HashMap <>();
6883 buildAttributes ();
6984 }
7085
86+ private static String resolveAttemptSpanName (ApiTracerContext apiTracerContext ) {
87+ if (apiTracerContext .transport () == ApiTracerContext .Transport .GRPC ) {
88+ // gRPC Uses the full method name as span name.
89+ return apiTracerContext .fullMethodName ();
90+ } else if (apiTracerContext .httpMethod () == null
91+ || apiTracerContext .httpPathTemplate () == null ) {
92+ // HTTP method name without necessary components defaults to the full method name
93+ return apiTracerContext .fullMethodName ();
94+ } else {
95+ // We construct the span name with HTTP method and path template.
96+ return String .format (
97+ "%s %s" , apiTracerContext .httpMethod (), apiTracerContext .httpPathTemplate ());
98+ }
99+ }
100+
71101 private void buildAttributes () {
72102 this .attemptAttributes .put (LANGUAGE_ATTRIBUTE , DEFAULT_LANGUAGE );
73103 this .attemptAttributes .putAll (this .apiTracerContext .getAttemptAttributes ());
74104 }
75105
76106 @ Override
77107 public void attemptStarted (Object request , int attemptNumber ) {
78- Map <String , Object > attemptAttributes = new HashMap <>(this .attemptAttributes );
79- // Start the specific attempt span with the operation span as parent
80- this .attemptHandle = traceManager .createSpan (attemptSpanName , attemptAttributes );
108+ SpanBuilder spanBuilder = tracer .spanBuilder (attemptSpanName );
109+
110+ // Attempt spans are of the CLIENT kind
111+ spanBuilder .setSpanKind (SpanKind .CLIENT );
112+
113+ spanBuilder .setAllAttributes (ObservabilityUtils .toOtelAttributes (this .attemptAttributes ));
114+
115+ this .attemptSpan = spanBuilder .startSpan ();
81116 }
82117
83118 @ Override
@@ -86,9 +121,9 @@ public void attemptSucceeded() {
86121 }
87122
88123 private void endAttempt () {
89- if (attemptHandle != null ) {
90- attemptHandle .end ();
91- attemptHandle = null ;
124+ if (attemptSpan != null ) {
125+ attemptSpan .end ();
126+ attemptSpan = null ;
92127 }
93128 }
94129}
0 commit comments