1+ /*
2+ * Copyright 2025 Google LLC
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+ package com .example .bigquery ;
18+
19+ // [START bigquery_enable_otel_tracing_with_parent_span]
20+ import com .google .cloud .bigquery .BigQuery ;
21+ import com .google .cloud .bigquery .BigQueryOptions ;
22+ import com .google .cloud .bigquery .Dataset ;
23+ import com .google .cloud .bigquery .DatasetId ;
24+ import com .google .cloud .bigquery .DatasetInfo ;
25+ import io .opentelemetry .api .OpenTelemetry ;
26+ import io .opentelemetry .api .common .AttributeKey ;
27+ import io .opentelemetry .api .trace .Span ;
28+ import io .opentelemetry .api .trace .Tracer ;
29+ import io .opentelemetry .context .Scope ;
30+ import java .util .HashMap ;
31+ import java .util .Map ;
32+ import java .util .Collection ;
33+ import io .opentelemetry .sdk .OpenTelemetrySdk ;
34+ import io .opentelemetry .sdk .common .CompletableResultCode ;
35+ import io .opentelemetry .sdk .trace .SdkTracerProvider ;
36+ import io .opentelemetry .sdk .trace .data .SpanData ;
37+ import io .opentelemetry .sdk .trace .export .SimpleSpanProcessor ;
38+ import io .opentelemetry .sdk .trace .samplers .Sampler ;
39+
40+ public class EnableOpenTelemetryTracingWithParentSpan {
41+
42+ // Data structures for captured Span data
43+ private static final Map <String , Map <AttributeKey <?>, Object >> OTEL_ATTRIBUTES =
44+ new HashMap <String , Map <AttributeKey <?>, Object >>();
45+ private static final Map <String , String > OTEL_PARENT_SPAN_IDS = new HashMap <>();
46+ private static final Map <String , String > OTEL_SPAN_IDS_TO_NAMES = new HashMap <>();
47+
48+ // Create a SpanExporter to determine how to handle captured Span data.
49+ // See more at https://opentelemetry.io/docs/languages/java/sdk/#spanexporter
50+ private static class SampleSpanExporter implements io .opentelemetry .sdk .trace .export .SpanExporter {
51+ @ Override
52+ public CompletableResultCode export (Collection <SpanData > collection ) {
53+ // Export data. This data can be sent out of process via netowork calls, though
54+ // for this example a local map is used.
55+ if (collection .isEmpty ()) {
56+ // No span data was collected.
57+ return CompletableResultCode .ofFailure ();
58+ }
59+ // TODO(developer): Replace export output before running the sample.
60+ for (SpanData data : collection ) {
61+ OTEL_ATTRIBUTES .put (data .getName (), data .getAttributes ().asMap ());
62+ OTEL_PARENT_SPAN_IDS .put (data .getName (), data .getParentSpanId ());
63+ OTEL_SPAN_IDS_TO_NAMES .put (data .getSpanId (), data .getName ());
64+ }
65+ return CompletableResultCode .ofSuccess ();
66+ }
67+
68+ // TODO(developer): Replace these functions to suit your needs.
69+ @ Override
70+ public CompletableResultCode flush () {
71+ // Export any data that has been queued up but not yet exported.
72+ return CompletableResultCode .ofSuccess ();
73+ }
74+
75+ @ Override
76+ public CompletableResultCode shutdown () {
77+ // Shut down the exporter and clean up any resources.
78+ return CompletableResultCode .ofSuccess ();
79+ }
80+ }
81+
82+ public static void main (String [] args ) {
83+ enableOpenTelemetryWithParentSpan ("Sample Tracer" );
84+ }
85+
86+ public static void enableOpenTelemetryWithParentSpan (String tracerName ) {
87+ // Create TracerProvider using the custom SpanExporter.
88+ SdkTracerProvider tracerProvider =
89+ SdkTracerProvider .builder ()
90+ .addSpanProcessor (SimpleSpanProcessor .create (new SampleSpanExporter ()))
91+ .setSampler (Sampler .alwaysOn ())
92+ .build ();
93+
94+ // Create global OpenTelemetry instance using the TracerProvider.
95+ OpenTelemetry otel = OpenTelemetrySdk .builder ()
96+ .setTracerProvider (tracerProvider )
97+ .buildAndRegisterGlobal ();
98+
99+ // Create Tracer instance from the global OpenTelemetry object. Tracers are used to create
100+ // Spans. There can be multiple Tracers in a global OpenTelemetry instance.
101+ // TODO(developer): Replace Tracer name
102+ Tracer tracer = otel .getTracer (tracerName );
103+
104+ // Create BigQuery client to trace. EnableOpenTelemetryTracing and OpenTelemetryTracer must
105+ // be set to enable tracing.
106+ BigQueryOptions otelOptions =
107+ BigQueryOptions .newBuilder ()
108+ .setEnableOpenTelemetryTracing (true )
109+ .setOpenTelemetryTracer (tracer )
110+ .build ();
111+ BigQuery bigquery = otelOptions .getService ();
112+
113+ // Create the root parent Span. setNoParent() ensures that it is a parent Span.
114+ // TODO(developer): Replace Span and attribute names.
115+ Span parentSpan =
116+ tracer
117+ .spanBuilder ("Sample Parent Span" )
118+ .setNoParent ()
119+ .setAttribute ("sample-parent-attribute" , "sample-parent-value" )
120+ .startSpan ();
121+
122+ // Wrap nested functions in try-catch-finally block to pass on the Span Context.
123+ try (Scope parentScope = parentSpan .makeCurrent ()) {
124+ createDataset (bigquery , tracer , "sample-dataset-id" );
125+ } finally {
126+ // finally block ensures that Spans are cleaned up properly.
127+ parentSpan .end ();
128+
129+ if (OTEL_ATTRIBUTES .get ("Sample Parent Span" ).get (AttributeKey .stringKey ("sample-parent-attribute" )) == "sample-parent-value" ) {
130+ System .out .println ("Parent Span was captured!" );
131+ } else {
132+ System .out .println ("Parent Span was not captured!" );
133+ }
134+ if (OTEL_ATTRIBUTES .get ("Sample Child Span" ).get (AttributeKey .stringKey ("sample-child-attribute" )) == "sample-child-value" ) {
135+ System .out .println ("Child Span was captured!" );
136+ } else {
137+ System .out .println ("Child Span was not captured!" );
138+ }
139+ if (OTEL_ATTRIBUTES .get ("Sample Child Span" ).get (AttributeKey .stringKey ("sample-child-attribute" )) == "sample-child-value" ) {
140+ System .out .println ("Child Span was captured!" );
141+ } else {
142+ System .out .println ("Child Span was not captured!" );
143+ }
144+ String childSpanParentId = OTEL_PARENT_SPAN_IDS .get ("Sample Child Span" );
145+ String parentSpanId = OTEL_SPAN_IDS_TO_NAMES .get (childSpanParentId );
146+ if (parentSpanId == "Sample Parent Span" ) {
147+ System .out .println ("Sample Child Span is the child of Sample Parent Span!" );
148+ }
149+ }
150+ }
151+
152+ public static void createDataset (BigQuery bigquery , Tracer tracer , String datasetId ) {
153+ // Parent Span Context is passed on here.
154+ Span childSpan =
155+ tracer
156+ .spanBuilder ("Sample Child Span" )
157+ .setNoParent ()
158+ .setAttribute ("sample-child-attribute" , "sample-child-value" )
159+ .startSpan ();
160+
161+ DatasetInfo info =
162+ DatasetInfo .newBuilder (datasetId )
163+ .build ();
164+
165+ Dataset dataset = bigquery .create (info );
166+ }
167+ }
168+ // [END bigquery_enable_otel_tracing_with_parent_span]
0 commit comments