opencensus-stackdriver 0.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+ require "yard"
4
+
5
+ require "rubocop/rake_task"
6
+ RuboCop::RakeTask.new
7
+
8
+ Rake::TestTask.new :test do |t|
9
+ t.libs << "test"
10
+ t.libs << "lib"
11
+ t.test_files = FileList["test/**/*_test.rb"]
12
+ t.warning = false
13
+ end
14
+
15
+ YARD::Rake::YardocTask.new do |t|
16
+ t.files = ['lib/**/*.rb'] # optional
17
+ t.options = ['--output-dir', 'docs/api'] # optional
18
+ t.stats_options = ['--list-undoc'] # optional
19
+ end
20
+
21
+ task :default => [:test, :rubocop, :yard]
@@ -0,0 +1,15 @@
1
+ # Copyright 2018 OpenCensus Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "opencensus/stackdriver"
@@ -0,0 +1,25 @@
1
+ # Copyright 2018 OpenCensus Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "opencensus"
16
+
17
+ module OpenCensus
18
+ ## Information about the Stackdriver exporter plugin
19
+ module Stackdriver
20
+ end
21
+ end
22
+
23
+ require "opencensus/stackdriver/version"
24
+ require "opencensus/trace/exporters/stackdriver"
25
+ require "opencensus/trace/exporters/stackdriver/converter"
@@ -0,0 +1,20 @@
1
+ # Copyright 2018 OpenCensus Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module OpenCensus
16
+ module Stackdriver
17
+ ## Current OpenCensus Stackdriver plugin version
18
+ VERSION = "0.1.0.pre1".freeze
19
+ end
20
+ end
@@ -0,0 +1,259 @@
1
+ # Copyright 2018 OpenCensus Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ gem "google-cloud-trace"
16
+ gem "concurrent-ruby"
17
+
18
+ require "concurrent"
19
+ require "google/cloud/trace"
20
+ require "google/cloud/trace/v2"
21
+
22
+ module OpenCensus
23
+ module Trace
24
+ module Exporters
25
+ ##
26
+ # The Stackdriver exporter for OpenCensus Trace exports captured spans
27
+ # to a Google Stackdriver project. It calls the Stackdriver Trace API in
28
+ # a background thread pool.
29
+ #
30
+ class Stackdriver
31
+ ##
32
+ # Create a Stackdriver exporter.
33
+ #
34
+ # @param [String] project_id The project identifier for the Stackdriver
35
+ # Trace service you are connecting to. If you are running on Google
36
+ # Cloud hosting (e.g. Compute Engine, Kubernetes Engine, or App
37
+ # Engine), this parameter is optional and will default to the
38
+ # hosting project. Otherwise, it is required.
39
+ # @param [String, Hash, Google::Auth::Credentials] credentials The
40
+ # Stackdriver API credentials, which can be a path to a keyfile as
41
+ # a String, the contents of a keyfile as a Hash, or a
42
+ # Google::Auth::Credentials object. If you are running on Google
43
+ # Cloud hosting (e.g. Compute Engine, Kubernetes Engine, or App
44
+ # Engine), this parameter is optional and will default to the
45
+ # credentials provided by the hosting project. Otherwise, it is
46
+ # required.
47
+ # @param [String, Array<String>] scope The OAuth 2.0 scopes controlling
48
+ # the set of resources and operations the API client can access.
49
+ # Optional. Most applications can leave this set to the default.
50
+ # @param [Integer] timeout The default timeout for API requests, in
51
+ # seconds. Optional.
52
+ # @param [Hash] client_config An optional set of additional
53
+ # configuration values for the API connection.
54
+ # @param [Integer] max_queue The maximum number of API requests that
55
+ # can be queued for background operation. If the queue exceeds this
56
+ # value, additional requests will be run in the calling thread
57
+ # rather than in the background. Set to 0 to allow the queue to
58
+ # grow indefinitely. Default is 1000.
59
+ # @param [Integer] max_threads The maximum number of threads that can
60
+ # be spun up to handle API requests. Default is 1. If set to 0,
61
+ # backgrounding will be disabled and all requests will run in the
62
+ # calling thread.
63
+ # @param [Integer] auto_terminate_time The time in seconds allotted to
64
+ # complete any pending background requests when Ruby is exiting.
65
+ #
66
+ def initialize \
67
+ project_id: nil,
68
+ credentials: nil,
69
+ scope: nil,
70
+ timeout: nil,
71
+ client_config: nil,
72
+ max_queue: 1000,
73
+ max_threads: 1,
74
+ auto_terminate_time: 10,
75
+ mock_client: nil
76
+ @project_id = final_project_id project_id
77
+
78
+ @executor = create_executor max_threads, max_queue
79
+ if auto_terminate_time
80
+ terminate_at_exit! @executor, auto_terminate_time
81
+ end
82
+
83
+ if mock_client
84
+ @client_promise =
85
+ Concurrent::Promise.fulfill mock_client, executor: @executor
86
+ else
87
+ credentials = final_credentials credentials, scope
88
+ scope ||= Google::Cloud.configure.trace.scope
89
+ timeout ||= Google::Cloud.configure.trace.timeout
90
+ client_config ||= Google::Cloud.configure.trace.client_config
91
+ @client_promise = create_client_promise \
92
+ @executor, credentials, scope, client_config, timeout
93
+ end
94
+ end
95
+
96
+ ##
97
+ # The project ID
98
+ # @return [String]
99
+ #
100
+ attr_reader :project_id
101
+
102
+ ##
103
+ # Export spans to Stackdriver asynchronously.
104
+ #
105
+ # @param [Array<OpenCensus::Trace::Span>] spans The captured spans to
106
+ # export to Stackdriver
107
+ #
108
+ def export spans
109
+ raise "Exporter is no longer running" unless @executor.running?
110
+
111
+ @client_promise.execute
112
+ export_promise = @client_promise.then do |client|
113
+ export_as_batch(client, spans)
114
+ end
115
+ export_promise.on_error do |reason|
116
+ warn "Unable to export to Stackdriver because: #{reason}"
117
+ end
118
+
119
+ true
120
+ end
121
+
122
+ ##
123
+ # Returns true if this exporter is running and will accept further
124
+ # export requests. Returns false once the exporter begins shutting down.
125
+ #
126
+ # @return [boolean]
127
+ #
128
+ def running?
129
+ @executor.running?
130
+ end
131
+
132
+ ##
133
+ # Returns true if this exporter has finished shutting down and all
134
+ # pending spans have been sent.
135
+ #
136
+ # @return [boolean]
137
+ #
138
+ def shutdown?
139
+ @executor.shutdown?
140
+ end
141
+
142
+ ##
143
+ # Returns true if this exporter has begun shutting down and is no
144
+ # longer accepting export requests, but is still running queued
145
+ # requests in the background.
146
+ #
147
+ # @return [boolean]
148
+ #
149
+ def shuttingdown?
150
+ @executor.shuttingdown?
151
+ end
152
+
153
+ ##
154
+ # Begin shutting down the exporter gracefully. After this operation is
155
+ # performed, the exporter will no longer accept export requests, but
156
+ # will finish any pending requests in the background.
157
+ #
158
+ def shutdown
159
+ @executor.shutdown
160
+ self
161
+ end
162
+
163
+ ##
164
+ # Begin shutting down the exporter forcefully. After this operation is
165
+ # performed, the exporter will no longer accept export requests, and
166
+ # will finish any currently running export requests, but will cancel
167
+ # all requests that are still pending in the queue.
168
+ #
169
+ def kill
170
+ @executor.kill
171
+ self
172
+ end
173
+
174
+ ##
175
+ # Wait for the exporter to finish shutting down.
176
+ #
177
+ # @param [Integer, nil] timeout A timeout in seconds, or nil for no
178
+ # timeout.
179
+ # @return [boolean] true if the exporter is shut down, or false if the
180
+ # wait timed out.
181
+ #
182
+ def wait_for_termination timeout = nil
183
+ @executor.wait_for_termination timeout
184
+ end
185
+
186
+ private
187
+
188
+ # Create the executor
189
+ def create_executor max_threads, max_queue
190
+ if max_threads >= 1
191
+ Concurrent::ThreadPoolExecutor.new \
192
+ min_length: 1, max_length: max_threads,
193
+ max_queue: max_queue, fallback_policy: :caller_runs,
194
+ auto_terminate: false
195
+ else
196
+ Concurrent::ImmediateExecutor.new
197
+ end
198
+ end
199
+
200
+ # Create the client promise.
201
+ # We create the client lazily so grpc doesn't get initialized until
202
+ # we actually need it. This is important because if it is intialized
203
+ # too early, before a fork, it can go into a bad state.
204
+ def create_client_promise executor, credentials, scopes, client_config,
205
+ timeout
206
+ Concurrent::Promise.new executor: executor do
207
+ Google::Cloud::Trace::V2.new(
208
+ credentials: credentials,
209
+ scopes: scopes,
210
+ client_config: client_config,
211
+ timeout: timeout,
212
+ lib_name: "opencensus",
213
+ lib_version: OpenCensus::Stackdriver::VERSION
214
+ )
215
+ end
216
+ end
217
+
218
+ # Set up an at_exit hook that shuts the exporter down.
219
+ def terminate_at_exit! executor, timeout
220
+ at_exit do
221
+ executor.shutdown
222
+ unless executor.wait_for_termination timeout
223
+ executor.kill
224
+ executor.wait_for_termination timeout
225
+ end
226
+ end
227
+ end
228
+
229
+ # Fall back to default project ID
230
+ def final_project_id project_id
231
+ project_id ||
232
+ Google::Cloud.configure.trace.project_id ||
233
+ Google::Cloud.configure.project_id ||
234
+ Google::Cloud.env.project_id
235
+ end
236
+
237
+ # Fall back to default credentials, and wrap in a creds object
238
+ def final_credentials credentials, scope
239
+ credentials ||=
240
+ Google::Cloud.configure.trace.credentials ||
241
+ Google::Cloud.configure.credentials ||
242
+ Google::Cloud::Trace::Credentials.default(scope: scope)
243
+ unless credentials.is_a? Google::Auth::Credentials
244
+ credentials =
245
+ Google::Cloud::Trace::Credentials.new credentials, scope: scope
246
+ end
247
+ credentials
248
+ end
249
+
250
+ # Export a list of spans in a single batch write, in the current thread
251
+ def export_as_batch client, spans
252
+ converter = Converter.new project_id
253
+ span_protos = Array(spans).map { |span| converter.convert_span span }
254
+ client.batch_write_spans "projects/#{project_id}", span_protos
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,356 @@
1
+ # Copyright 2018 OpenCensus Authors
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "google/devtools/cloudtrace/v2/trace_pb"
16
+ require "google/protobuf/well_known_types"
17
+
18
+ module OpenCensus
19
+ module Trace
20
+ module Exporters
21
+ class Stackdriver
22
+ ##
23
+ # An object that converts OpenCensus span data objects to Stackdriver
24
+ # Trace V2 protos.
25
+ #
26
+ # You should use one converter instance to convert the spans for a
27
+ # single export request, because the converter will keep track of and
28
+ # omit duplicate stack traces. Use a new converter instance for the
29
+ # next request.
30
+ #
31
+ # @private
32
+ #
33
+ class Converter
34
+ ##
35
+ # @private
36
+ # Alias for the V2 Cloudtrace protos namespace
37
+ #
38
+ TraceProtos = Google::Devtools::Cloudtrace::V2
39
+
40
+ ##
41
+ # Create a converter
42
+ #
43
+ # @param [String] project_id Google project ID
44
+ #
45
+ def initialize project_id
46
+ @project_id = project_id
47
+ @stack_trace_hash_ids = {}
48
+ end
49
+
50
+ # rubocop:disable Metrics/AbcSize
51
+
52
+ ##
53
+ # Convert a span object.
54
+ #
55
+ # @param [OpenCensus::Trace::Span] obj OpenCensus span object
56
+ # @return [Google::Devtools::Cloudtrace::V2::Span] The generated
57
+ # proto
58
+ #
59
+ def convert_span obj
60
+ TraceProtos::Span.new \
61
+ name: make_resource_name(@project_id, obj.trace_id, obj.span_id),
62
+ span_id: obj.span_id,
63
+ parent_span_id: obj.parent_span_id || "",
64
+ display_name: convert_truncatable_string(obj.name),
65
+ start_time: convert_time(obj.start_time),
66
+ end_time: convert_time(obj.end_time),
67
+ attributes:
68
+ convert_attributes(obj.attributes,
69
+ obj.dropped_attributes_count),
70
+ stack_trace:
71
+ convert_stack_trace(obj.stack_trace, obj.dropped_frames_count,
72
+ obj.stack_trace_hash_id),
73
+ time_events:
74
+ convert_time_events(obj.time_events,
75
+ obj.dropped_annotations_count,
76
+ obj.dropped_message_events_count),
77
+ links: convert_links(obj.links, obj.dropped_links_count),
78
+ status: convert_optional_status(obj.status),
79
+ same_process_as_parent_span:
80
+ convert_optional_bool(obj.same_process_as_parent_span),
81
+ child_span_count: convert_optional_int32(obj.child_span_count)
82
+ end
83
+
84
+ # rubocop:enable Metrics/AbcSize
85
+
86
+ ##
87
+ # Make a span resource name.
88
+ #
89
+ # @param [String] project_id The project ID
90
+ # @param [String] trace_id The project ID
91
+ # @param [String] span_id The project ID
92
+ # @return [String] The resource na,e
93
+ #
94
+ def make_resource_name project_id, trace_id, span_id
95
+ "projects/#{project_id}/traces/#{trace_id}/spans/#{span_id}"
96
+ end
97
+
98
+ ##
99
+ # Create a truncatable string proto.
100
+ #
101
+ # @param [String] str The string
102
+ # @param [Integer] truncated_byte_count The number of bytes omitted.
103
+ # Defaults to 0.
104
+ # @return [Google::Devtools::Cloudtrace::V2::TruncatableString] The
105
+ # generated proto
106
+ #
107
+ def make_truncatable_string str, truncated_byte_count = 0
108
+ TraceProtos::TruncatableString.new \
109
+ value: str,
110
+ truncated_byte_count: truncated_byte_count
111
+ end
112
+
113
+ ##
114
+ # Convert a truncatable string object.
115
+ #
116
+ # @param [OpenCensus::Trace::TruncatableString] obj OpenCensus
117
+ # truncatable string object
118
+ # @return [Google::Devtools::Cloudtrace::V2::TruncatableString] The
119
+ # generated proto
120
+ #
121
+ def convert_truncatable_string obj
122
+ make_truncatable_string obj.value, obj.truncated_byte_count
123
+ end
124
+
125
+ ##
126
+ # Convert a time object.
127
+ #
128
+ # @param [Time] time Ruby Time object
129
+ # @return [Google::Protobuf::Timestamp] The generated proto
130
+ #
131
+ def convert_time time
132
+ proto = Google::Protobuf::Timestamp.new
133
+ proto.from_time(time)
134
+ proto
135
+ end
136
+
137
+ ##
138
+ # Convert a value that can be used for an attribute.
139
+ #
140
+ # @param [OpenCensus::Trace::TruncatableString, Integer, boolean]
141
+ # obj Object to convert
142
+ # @return [Google::Devtools::Cloudtrace::V2::AttributeValue] The
143
+ # generated proto
144
+ #
145
+ def convert_attribute_value obj
146
+ case obj
147
+ when OpenCensus::Trace::TruncatableString
148
+ TraceProtos::AttributeValue.new \
149
+ string_value: convert_truncatable_string(obj)
150
+ when Integer
151
+ TraceProtos::AttributeValue.new int_value: obj
152
+ when true, false
153
+ TraceProtos::AttributeValue.new bool_value: obj
154
+ end
155
+ end
156
+
157
+ ##
158
+ # Convert an attributes hash
159
+ #
160
+ # @param [Hash] attributes The map of attribute values to convert
161
+ # @param [Integer] dropped_attributes_count Number of dropped
162
+ # @return [Google::Devtools::Cloudtrace::V2::Attributes] The
163
+ # generated proto
164
+ #
165
+ def convert_attributes attributes, dropped_attributes_count
166
+ attribute_map = {}
167
+ attributes.each do |k, v|
168
+ attribute_map[k] = convert_attribute_value v
169
+ end
170
+ TraceProtos::Span::Attributes.new \
171
+ attribute_map: attribute_map,
172
+ dropped_attributes_count: dropped_attributes_count
173
+ end
174
+
175
+ ##
176
+ # Convert a single stack frame as a Thread::Backtrace::Location
177
+ #
178
+ # @param [Thread::Backtrace::Location] frame The backtrace element to
179
+ # convert
180
+ # @return [Google::Devtools::Cloudtrace::V2::StackTrace::StackFrame]
181
+ # The generated proto
182
+ #
183
+ def convert_stack_frame frame
184
+ TraceProtos::StackTrace::StackFrame.new \
185
+ function_name: make_truncatable_string(frame.label),
186
+ file_name: make_truncatable_string(frame.path),
187
+ line_number: frame.lineno
188
+ end
189
+
190
+ ##
191
+ # Convert a full backtrace.
192
+ #
193
+ # @param [Array<Thread::Backtrace::Location>] backtrace The backtrace
194
+ # element array to convert
195
+ # @param [Integer] dropped_frames_count Frames that were dropped
196
+ # @param [Integer] stack_trace_hash_id Hash of the data
197
+ # @return [Google::Devtools::Cloudtrace::V2::StackTrace] The
198
+ # generated proto
199
+ #
200
+ def convert_stack_trace backtrace, dropped_frames_count,
201
+ stack_trace_hash_id
202
+ if @stack_trace_hash_ids[stack_trace_hash_id]
203
+ return TraceProtos::StackTrace.new \
204
+ stack_trace_hash_id: stack_trace_hash_id
205
+ end
206
+ @stack_trace_hash_ids[stack_trace_hash_id] = true
207
+ frame_protos = backtrace.map { |frame| convert_stack_frame(frame) }
208
+ frames_proto = TraceProtos::StackTrace::StackFrames.new \
209
+ frame: frame_protos,
210
+ dropped_frames_count: dropped_frames_count
211
+ TraceProtos::StackTrace.new \
212
+ stack_frames: frames_proto,
213
+ stack_trace_hash_id: stack_trace_hash_id
214
+ end
215
+
216
+ ##
217
+ # Convert an annotation object
218
+ #
219
+ # @param [OpenCensus::Trace::Annotation] annotation The annotation
220
+ # object to convert
221
+ # @return
222
+ # [Google::Devtools::Cloudtrace::V2::Span::TimeEvent::Annotation]
223
+ # The generated proto
224
+ #
225
+ def convert_annotation annotation
226
+ annotation_proto = TraceProtos::Span::TimeEvent::Annotation.new \
227
+ description: convert_truncatable_string(annotation.description),
228
+ attributes:
229
+ convert_attributes(annotation.attributes,
230
+ annotation.dropped_attributes_count)
231
+ TraceProtos::Span::TimeEvent.new \
232
+ time: convert_time(annotation.time),
233
+ annotation: annotation_proto
234
+ end
235
+
236
+ ##
237
+ # Convert a message event object
238
+ #
239
+ # @param [OpenCensus::Trace::MessageEvent] message_event The message
240
+ # event object to convert
241
+ # @return
242
+ # [Google::Devtools::Cloudtrace::V2::Span::TimeEvent::MessageEvent]
243
+ # The generated proto
244
+ #
245
+ def convert_message_event message_event
246
+ message_event_proto =
247
+ TraceProtos::Span::TimeEvent::MessageEvent.new \
248
+ type: message_event.type,
249
+ id: message_event.id,
250
+ uncompressed_size_bytes: message_event.uncompressed_size,
251
+ compressed_size_bytes: message_event.compressed_size
252
+ Google::Devtools::Cloudtrace::V2::Span::TimeEvent.new \
253
+ time: convert_time(message_event.time),
254
+ message_event: message_event_proto
255
+ end
256
+
257
+ ##
258
+ # Convert a list of time event objects
259
+ #
260
+ # @param [Array<OpenCensus::Trace::TimeEvent>] time_events The time
261
+ # event objects to convert
262
+ # @param [Integer] dropped_annotations_count Number of dropped
263
+ # annotations
264
+ # @param [Integer] dropped_message_events_count Number of dropped
265
+ # message events
266
+ # @return [Google::Devtools::Cloudtrace::V2::Span::TimeEvents] The
267
+ # generated proto
268
+ #
269
+ def convert_time_events time_events, dropped_annotations_count,
270
+ dropped_message_events_count
271
+ time_event_protos = time_events.map do |time_event|
272
+ case time_event
273
+ when OpenCensus::Trace::Annotation
274
+ convert_annotation time_event
275
+ when OpenCensus::Trace::MessageEvent
276
+ convert_message_event time_event
277
+ else
278
+ nil
279
+ end
280
+ end.compact
281
+ TraceProtos::Span::TimeEvents.new \
282
+ time_event: time_event_protos,
283
+ dropped_annotations_count: dropped_annotations_count,
284
+ dropped_message_events_count: dropped_message_events_count
285
+ end
286
+
287
+ ##
288
+ # Convert a link object
289
+ #
290
+ # @param [OpenCensus::Trace::Link] link The link object to convert
291
+ # @return [Google::Devtools::Cloudtrace::V2::Span::Link] The
292
+ # generated proto
293
+ #
294
+ def convert_link link
295
+ TraceProtos::Span::Link.new \
296
+ trace_id: link.trace_id,
297
+ span_id: link.span_id,
298
+ type: link.type,
299
+ attributes:
300
+ convert_attributes(link.attributes,
301
+ link.dropped_attributes_count)
302
+ end
303
+
304
+ ##
305
+ # Convert a list of link objects
306
+ #
307
+ # @param [Array<OpenCensus::Trace::Link>] links The link objects to
308
+ # convert
309
+ # @param [Integer] dropped_links_count Number of dropped links
310
+ # @return [Google::Devtools::Cloudtrace::V2::Span::Links] The
311
+ # generated proto
312
+ #
313
+ def convert_links links, dropped_links_count
314
+ TraceProtos::Span::Links.new \
315
+ link: links.map { |link| convert_link link },
316
+ dropped_links_count: dropped_links_count
317
+ end
318
+
319
+ ##
320
+ # Convert a nullable status object
321
+ #
322
+ # @param [OpenCensus::Trace::Status, nil] status The status object to
323
+ # convert, or nil if absent
324
+ # @return [Google::Rpc::Status, nil] The generated proto, or nil
325
+ #
326
+ def convert_optional_status status
327
+ return nil if status.nil?
328
+ Google::Rpc::Status.new code: status.code, message: status.message
329
+ end
330
+
331
+ ##
332
+ # Convert a nullable boolean object
333
+ #
334
+ # @param [boolean, nil] value The value to convert, or nil if absent
335
+ # @return [Google::Protobuf::BoolValue, nil] Generated proto, or nil
336
+ #
337
+ def convert_optional_bool value
338
+ return nil if value.nil?
339
+ Google::Protobuf::BoolValue.new value: value
340
+ end
341
+
342
+ ##
343
+ # Convert a nullable int32 object
344
+ #
345
+ # @param [Integer, nil] value The value to convert, or nil if absent
346
+ # @return [Google::Protobuf::Int32Value, nil] Generated proto, or nil
347
+ #
348
+ def convert_optional_int32 value
349
+ return nil if value.nil?
350
+ Google::Protobuf::Int32Value.new value: value
351
+ end
352
+ end
353
+ end
354
+ end
355
+ end
356
+ end