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