google-cloud-trace 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,199 @@
1
+ # Copyright 2014 Google Inc. All rights reserved.
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
+
16
+ module Google
17
+ module Cloud
18
+ module Trace
19
+ ##
20
+ # ResultSet represents the results of a `list_traces` request. It is
21
+ # an enumerable of the traces found, plus information about the request
22
+ # and a token to get the next page of results.
23
+ #
24
+ class ResultSet
25
+ include Enumerable
26
+
27
+ ##
28
+ # Create a new ResultSet given an enumerable of result Trace objects,
29
+ # a next page token (or nil if this is the last page), and all the
30
+ # query parameters.
31
+ #
32
+ # @private
33
+ #
34
+ def initialize service, project,
35
+ results, next_page_token,
36
+ start_time, end_time,
37
+ filter: nil,
38
+ order_by: nil,
39
+ view: nil,
40
+ page_size: nil,
41
+ page_token: nil
42
+ @service = service
43
+ @project = project
44
+ @results = results
45
+ @next_page_token = next_page_token
46
+ @view = view
47
+ @page_size = page_size
48
+ @start_time = start_time
49
+ @end_time = end_time
50
+ @filter = filter
51
+ @order_by = order_by
52
+ @page_token = page_token
53
+ end
54
+
55
+ ##
56
+ # An `each` method that supports the Enumerable module. Iterates over
57
+ # the results and yields each, as a {Google::Cloud::Trace::TraceRecord}
58
+ # object, to the given block. If no block is provided, returns an
59
+ # Enumerator.
60
+ #
61
+ def each &block
62
+ @results.each(&block)
63
+ end
64
+
65
+ ##
66
+ # Returns the number of traces in this page of results.
67
+ #
68
+ # @return [Integer]
69
+ #
70
+ def size
71
+ @results.size
72
+ end
73
+
74
+ ##
75
+ # The trace service client that obtained this result set
76
+ # @private
77
+ attr_reader :service
78
+
79
+ ##
80
+ # The project ID string.
81
+ #
82
+ # @return [String]
83
+ #
84
+ attr_reader :project
85
+
86
+ ##
87
+ # The token to pass to `list_traces` to get the next page, or nil if
88
+ # this is the last page.
89
+ #
90
+ # @return [String, nil]
91
+ #
92
+ attr_reader :next_page_token
93
+
94
+ ##
95
+ # The `view` query parameter.
96
+ #
97
+ # @return [Symbol, nil]
98
+ #
99
+ attr_reader :view
100
+
101
+ ##
102
+ # The `page_size` query parameter.
103
+ #
104
+ # @return [Integer, nil]
105
+ #
106
+ attr_reader :page_size
107
+
108
+ ##
109
+ # The `start_time` query parameter.
110
+ #
111
+ # @return [Time, nil]
112
+ #
113
+ attr_reader :start_time
114
+
115
+ ##
116
+ # The `end_time` query parameter.
117
+ #
118
+ # @return [Time, nil]
119
+ #
120
+ attr_reader :end_time
121
+
122
+ ##
123
+ # The `filter` query parameter.
124
+ #
125
+ # @return [String, nil]
126
+ #
127
+ attr_reader :filter
128
+
129
+ ##
130
+ # The `order_by` query parameter.
131
+ #
132
+ # @return [String, nil]
133
+ #
134
+ attr_reader :order_by
135
+
136
+ ##
137
+ # The page token used to obtain this page of results.
138
+ #
139
+ # @return [String, nil]
140
+ #
141
+ attr_reader :page_token
142
+
143
+ ##
144
+ # Returns true if at least one more page of results can be retrieved.
145
+ #
146
+ # @return [Boolean]
147
+ #
148
+ def results_pending?
149
+ !next_page_token.nil?
150
+ end
151
+
152
+ ##
153
+ # Queries the service for the next page of results and returns a new
154
+ # ResultSet for that page. Returns `nil` if there are no more results.
155
+ #
156
+ # @return [Google::Cloud::Trace::ResultSet]
157
+ #
158
+ def next_page
159
+ return nil unless results_pending?
160
+ service.list_traces \
161
+ project, start_time, end_time,
162
+ filter: filter,
163
+ order_by: order_by,
164
+ view: view,
165
+ page_size: page_size,
166
+ page_token: next_page_token
167
+ end
168
+
169
+ ##
170
+ # Create a new ResultSet given a Google::Gax::PagedEnumerable::Page,
171
+ # and all the query parameters.
172
+ #
173
+ # @private
174
+ #
175
+ def self.from_gax_page service, project_id,
176
+ page, start_time, end_time,
177
+ filter: nil,
178
+ order_by: nil,
179
+ view: nil,
180
+ page_size: nil,
181
+ page_token: nil
182
+ next_page_token = page.next_page_token
183
+ next_page_token = nil unless page.next_page_token?
184
+ results = page.map do |proto|
185
+ Google::Cloud::Trace::TraceRecord.from_grpc proto
186
+ end
187
+ new service, project_id,
188
+ results, next_page_token,
189
+ start_time, end_time,
190
+ filter: filter,
191
+ order_by: order_by,
192
+ view: view,
193
+ page_size: page_size,
194
+ page_token: page_token
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,166 @@
1
+ # Copyright 2014 Google Inc. All rights reserved.
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
+
16
+ require "google/cloud/errors"
17
+ require "google/cloud/trace/version"
18
+ require "google/cloud/trace/v1"
19
+ require "google/gax/errors"
20
+
21
+ module Google
22
+ module Cloud
23
+ module Trace
24
+ ##
25
+ # Represents the connection to Trace, and exposes the API calls.
26
+ #
27
+ # @private
28
+ #
29
+ class Service
30
+ ##
31
+ # @private
32
+ attr_accessor :project
33
+
34
+ ##
35
+ # @private
36
+ attr_accessor :credentials
37
+
38
+ ##
39
+ # @private
40
+ attr_accessor :host
41
+
42
+ ##
43
+ # @private
44
+ attr_accessor :timeout
45
+
46
+ ##
47
+ # @private
48
+ attr_accessor :client_config
49
+
50
+ ##
51
+ # Creates a new Service instance.
52
+ def initialize project, credentials, host: nil, timeout: nil,
53
+ client_config: nil
54
+ @project = project
55
+ @credentials = credentials
56
+ @host = host || V1::TraceServiceApi::SERVICE_ADDRESS
57
+ @timeout = timeout
58
+ @client_config = client_config || {}
59
+ end
60
+
61
+ def channel
62
+ require "grpc"
63
+ GRPC::Core::Channel.new host, nil, chan_creds
64
+ end
65
+
66
+ def chan_creds
67
+ return credentials if insecure?
68
+ require "grpc"
69
+ GRPC::Core::ChannelCredentials.new.compose \
70
+ GRPC::Core::CallCredentials.new credentials.client.updater_proc
71
+ end
72
+
73
+ def insecure?
74
+ credentials == :this_channel_is_insecure
75
+ end
76
+
77
+ def lowlevel_client
78
+ return mocked_lowlevel_client if mocked_lowlevel_client
79
+ @lowlevel_client ||= \
80
+ V1::TraceServiceApi.new(
81
+ service_path: host,
82
+ channel: channel,
83
+ timeout: timeout,
84
+ client_config: client_config,
85
+ app_name: "gcloud-ruby",
86
+ app_version: Google::Cloud::Trace::VERSION)
87
+ end
88
+ attr_accessor :mocked_lowlevel_client
89
+
90
+ ##
91
+ # Sends new traces to Stackdriver Trace or updates existing traces.
92
+ def patch_traces traces
93
+ traces = Array(traces)
94
+ traces_proto = Google::Devtools::Cloudtrace::V1::Traces.new
95
+ traces.each do |trace|
96
+ traces_proto.traces.push trace.to_grpc
97
+ end
98
+ execute do
99
+ lowlevel_client.patch_traces @project, traces_proto
100
+ end
101
+ traces
102
+ end
103
+
104
+ ##
105
+ # Returns a trace given its ID
106
+ def get_trace trace_id
107
+ trace_proto = execute do
108
+ lowlevel_client.get_trace @project, trace_id
109
+ end
110
+ Google::Cloud::Trace::TraceRecord.from_grpc trace_proto
111
+ end
112
+
113
+ ##
114
+ # Searches for traces matching the given criteria.
115
+ #
116
+ # rubocop:disable Metrics/MethodLength
117
+ def list_traces project_id, start_time, end_time,
118
+ filter: nil,
119
+ order_by: nil,
120
+ view: nil,
121
+ page_size: nil,
122
+ page_token: nil
123
+ if page_token
124
+ call_opts = Google::Gax::CallOptions.new page_token: page_token
125
+ else
126
+ call_opts = Google::Gax::CallOptions.new
127
+ end
128
+ start_proto = Google::Cloud::Trace::Utils.time_to_grpc start_time
129
+ end_proto = Google::Cloud::Trace::Utils.time_to_grpc end_time
130
+ paged_enum = execute do
131
+ lowlevel_client.list_traces project_id,
132
+ view: view,
133
+ page_size: page_size,
134
+ start_time: start_proto,
135
+ end_time: end_proto,
136
+ filter: filter,
137
+ order_by: order_by,
138
+ options: call_opts
139
+ end
140
+ Google::Cloud::Trace::ResultSet.from_gax_page \
141
+ self, project_id,
142
+ paged_enum.page, start_time, end_time,
143
+ filter: filter,
144
+ order_by: order_by,
145
+ view: view,
146
+ page_size: page_size,
147
+ page_token: page_token
148
+ end
149
+
150
+ # @private
151
+ def inspect
152
+ "#{self.class}(#{@project})"
153
+ end
154
+
155
+ protected
156
+
157
+ def execute
158
+ yield
159
+ rescue Google::Gax::GaxError => e
160
+ # GaxError wraps BadStatus, but exposes it as #cause
161
+ raise Google::Cloud::Error.from_error(e.cause)
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,450 @@
1
+ # Copyright 2014 Google Inc. All rights reserved.
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
+
16
+ require "set"
17
+ require "google/devtools/cloudtrace/v1/trace_pb"
18
+
19
+ module Google
20
+ module Cloud
21
+ module Trace
22
+ ##
23
+ # Span represents a span in a trace record. Spans are contained in
24
+ # a trace and arranged in a forest. That is, each span may be a root span
25
+ # or have a parent span, and may have zero or more children.
26
+ #
27
+ class Span
28
+ ##
29
+ # The Trace object containing this span.
30
+ #
31
+ # @return [Google::Cloud::Trace::TraceRecord]
32
+ #
33
+ attr_reader :trace
34
+
35
+ ##
36
+ # The TraceSpan object representing this span's parent, or `nil` if
37
+ # this span is a root span.
38
+ #
39
+ # @return [Google::Cloud::Trace::Span, nil]
40
+ #
41
+ attr_reader :parent
42
+
43
+ ##
44
+ # The numeric ID of this span.
45
+ #
46
+ # @return [Integer]
47
+ #
48
+ attr_reader :span_id
49
+
50
+ ##
51
+ # The ID of the parent span, as an integer that may be zero if this
52
+ # is a true root span.
53
+ #
54
+ # Note that it is possible for a span to be "orphaned", that is, to be
55
+ # a root span with a nonzero parent ID, indicating that parent has not
56
+ # (yet) been written. In that case, `parent` will return nil, but
57
+ # `parent_span_id` will have a value.
58
+ #
59
+ # @return [Integer]
60
+ #
61
+ attr_reader :parent_span_id
62
+
63
+ ##
64
+ # The kind of this span.
65
+ #
66
+ # @return [Google::Cloud::Trace::SpanKind]
67
+ #
68
+ attr_accessor :kind
69
+
70
+ ##
71
+ # The name of this span.
72
+ #
73
+ # @return [String]
74
+ #
75
+ attr_accessor :name
76
+
77
+ ##
78
+ # The starting timestamp of this span in UTC, or `nil` if the
79
+ # starting timestamp has not yet been populated.
80
+ #
81
+ # @return [Time, nil]
82
+ #
83
+ attr_accessor :start_time
84
+
85
+ ##
86
+ # The ending timestamp of this span in UTC, or `nil` if the
87
+ # ending timestamp has not yet been populated.
88
+ #
89
+ # @return [Time, nil]
90
+ #
91
+ attr_accessor :end_time
92
+
93
+ ##
94
+ # The properties of this span.
95
+ #
96
+ # @return [Hash{String => String}]
97
+ #
98
+ attr_reader :labels
99
+
100
+ ##
101
+ # Create an empty Span object.
102
+ #
103
+ # @private
104
+ #
105
+ def initialize trace, id, parent_span_id, parent, name, kind,
106
+ start_time, end_time, labels
107
+ @trace = trace
108
+ @span_id = id
109
+ @parent_span_id = parent_span_id
110
+ @parent = parent
111
+ @children = []
112
+ @name = name
113
+ @kind = kind
114
+ @start_time = start_time
115
+ @end_time = end_time
116
+ @labels = labels
117
+ end
118
+
119
+ ##
120
+ # Standard value equality check for this object.
121
+ #
122
+ # @param [Object] other
123
+ # @return [Boolean]
124
+ #
125
+ # rubocop:disable Metrics/AbcSize
126
+ def eql? other
127
+ other.is_a?(Google::Cloud::Trace::Span) &&
128
+ trace.trace_context == other.trace.trace_context &&
129
+ span_id == other.span_id &&
130
+ parent_span_id == other.parent_span_id &&
131
+ same_children?(other) &&
132
+ kind == other.kind &&
133
+ name == other.name &&
134
+ start_time == other.start_time &&
135
+ end_time == other.end_time &&
136
+ labels == other.labels
137
+ end
138
+ alias_method :==, :eql?
139
+
140
+ ##
141
+ # Create a new Span object from a TraceSpan protobuf and insert it
142
+ # into the given trace.
143
+ #
144
+ # @param [Google::Devtools::Cloudtrace::V1::TraceSpan] span_proto The
145
+ # span protobuf from the V1 gRPC Trace API.
146
+ # @param [Google::Cloud::Trace::TraceRecord] trace The trace object
147
+ # to contain the span.
148
+ # @return [Google::Cloud::Trace::Span] A corresponding Span object.
149
+ #
150
+ def self.from_grpc span_proto, trace
151
+ labels = {}
152
+ span_proto.labels.each { |k, v| labels[k] = v }
153
+ span_kind = SpanKind.get span_proto.kind
154
+ start_time =
155
+ Google::Cloud::Trace::Utils.grpc_to_time span_proto.start_time
156
+ end_time =
157
+ Google::Cloud::Trace::Utils.grpc_to_time span_proto.end_time
158
+ trace.create_span span_proto.name,
159
+ parent_span_id: span_proto.parent_span_id.to_i,
160
+ span_id: span_proto.span_id.to_i,
161
+ kind: span_kind,
162
+ start_time: start_time,
163
+ end_time: end_time,
164
+ labels: labels
165
+ end
166
+
167
+ ##
168
+ # Convert this Span object to an equivalent TraceSpan protobuf suitable
169
+ # for the V1 gRPC Trace API.
170
+ #
171
+ # @param [Integer] default_parent_id The parent span ID to use if the
172
+ # span has no parent in the trace tree. Optional; defaults to 0.
173
+ # @return [Google::Devtools::Cloudtrace::V1::TraceSpan] The generated
174
+ # protobuf.
175
+ #
176
+ def to_grpc default_parent_id = 0
177
+ start_proto = Google::Cloud::Trace::Utils.time_to_grpc start_time
178
+ end_proto = Google::Cloud::Trace::Utils.time_to_grpc end_time
179
+ Google::Devtools::Cloudtrace::V1::TraceSpan.new \
180
+ span_id: span_id.to_i,
181
+ kind: kind.to_sym,
182
+ name: name,
183
+ start_time: start_proto,
184
+ end_time: end_proto,
185
+ parent_span_id: parent_span_id || default_parent_id,
186
+ labels: labels
187
+ end
188
+
189
+ ##
190
+ # Returns true if this span exists. A span exists until it has been
191
+ # removed from its trace.
192
+ #
193
+ # @return [Boolean]
194
+ #
195
+ def exists?
196
+ !@trace.nil?
197
+ end
198
+
199
+ ##
200
+ # Returns the trace context in effect within this span.
201
+ #
202
+ # @return [Stackdriver::Core::TraceContext]
203
+ #
204
+ def trace_context
205
+ ensure_exists!
206
+ trace.trace_context.with span_id: span_id
207
+ end
208
+
209
+ ##
210
+ # Returns the trace ID for this span.
211
+ #
212
+ # @return [String] The trace ID string.
213
+ #
214
+ def trace_id
215
+ ensure_exists!
216
+ trace.trace_id
217
+ end
218
+
219
+ ##
220
+ # Returns a list of children of this span.
221
+ #
222
+ # @return [Array{TraceSpan}] The children.
223
+ #
224
+ def children
225
+ ensure_exists!
226
+ @children.dup
227
+ end
228
+
229
+ ##
230
+ # Creates a new child span under this span.
231
+ #
232
+ # @param [String] name The name of the span.
233
+ # @param [Integer] span_id The numeric ID of the span, or nil to
234
+ # generate a new random unique ID. Optional (defaults to nil).
235
+ # @param [SpanKind] kind The kind of span. Optional.
236
+ # @param [Time] start_time The starting timestamp, or nil if not yet
237
+ # specified. Optional (defaults to nil).
238
+ # @param [Time] end_time The ending timestamp, or nil if not yet
239
+ # specified. Optional (defaults to nil).
240
+ # @param [Hash{String=>String}] labels The span properties. Optional
241
+ # (defaults to empty).
242
+ # @return [TraceSpan] The created span.
243
+ #
244
+ # @example
245
+ # require "google/cloud/trace"
246
+ #
247
+ # trace = Google::Cloud::Trace.new trace_context
248
+ # span = trace.create_span "root_span"
249
+ # subspan = span.create_span "subspan"
250
+ #
251
+ def create_span name, span_id: nil, kind: SpanKind::UNSPECIFIED,
252
+ start_time: nil, end_time: nil,
253
+ labels: {}
254
+ ensure_exists!
255
+ span = trace.internal_create_span self, span_id, self.span_id, name,
256
+ kind, start_time, end_time, labels
257
+ @children << span
258
+ span
259
+ end
260
+
261
+ ##
262
+ # Creates a root span around the given block. Automatically populates
263
+ # the start and end timestamps. The span (with start time but not end
264
+ # time populated) is yielded to the block.
265
+ #
266
+ # @param [String] name The name of the span.
267
+ # @param [SpanKind] kind The kind of span. Optional.
268
+ # @param [Hash{String=>String}] labels The span properties. Optional
269
+ # (defaults to empty).
270
+ # @return [TraceSpan] The created span.
271
+ #
272
+ # @example
273
+ # require "google/cloud/trace"
274
+ #
275
+ # trace = Google::Cloud::Trace.new trace_context
276
+ # trace.in_span "root_span" do |span|
277
+ # # Do stuff...
278
+ # span.in_span "subspan" do |subspan|
279
+ # # Do subspan stuff...
280
+ # end
281
+ # # Do stuff...
282
+ # end
283
+ #
284
+ def in_span name, kind: SpanKind::UNSPECIFIED, labels: {}
285
+ span = create_span name, kind: kind, labels: labels
286
+ span.start!
287
+ yield span
288
+ ensure
289
+ span.finish!
290
+ end
291
+
292
+ ##
293
+ # Sets the starting timestamp for this span to the current time.
294
+ # Asserts that the timestamp has not yet been set, and throws a
295
+ # RuntimeError if that is not the case.
296
+ # Also ensures that all ancestor spans have already started, and
297
+ # starts them if not.
298
+ #
299
+ def start!
300
+ fail "Span already started" if start_time
301
+ ensure_started
302
+ end
303
+
304
+ ##
305
+ # Sets the ending timestamp for this span to the current time.
306
+ # Asserts that the timestamp has not yet been set, and throws a
307
+ # RuntimeError if that is not the case.
308
+ # Also ensures that all descendant spans have also finished, and
309
+ # finishes them if not.
310
+ #
311
+ def finish!
312
+ fail "Span not yet started" unless start_time
313
+ fail "Span already finished" if end_time
314
+ ensure_finished
315
+ end
316
+
317
+ ##
318
+ # Sets the starting timestamp for this span to the current time, if
319
+ # it has not yet been set. Also ensures that all ancestor spans have
320
+ # also been started.
321
+ # Does nothing if the starting timestamp for this span is already set.
322
+ #
323
+ def ensure_started
324
+ ensure_exists!
325
+ unless start_time
326
+ self.start_time = ::Time.now.utc
327
+ parent.ensure_started if parent
328
+ end
329
+ self
330
+ end
331
+
332
+ ##
333
+ # Sets the ending timestamp for this span to the current time, if
334
+ # it has not yet been set. Also ensures that all descendant spans have
335
+ # also been finished.
336
+ # Does nothing if the ending timestamp for this span is already set.
337
+ #
338
+ def ensure_finished
339
+ ensure_exists!
340
+ unless end_time
341
+ self.end_time = ::Time.now.utc
342
+ @children.each(&:ensure_finished)
343
+ end
344
+ self
345
+ end
346
+
347
+ ##
348
+ # Deletes this span, and all descendant spans. After this completes,
349
+ # {Span#exists?} will return `false`.
350
+ #
351
+ def delete
352
+ ensure_exists!
353
+ @children.each(&:delete)
354
+ parent.remove_child(self) if parent
355
+ trace.remove_span(self)
356
+ @trace = nil
357
+ @parent = nil
358
+ self
359
+ end
360
+
361
+ ##
362
+ # Moves this span under a new parent, which must be part of the same
363
+ # trace. The entire tree under this span moves with it.
364
+ #
365
+ # @param [Google::Cloud::Trace::Span] new_parent The new parent.
366
+ #
367
+ # @example
368
+ # require "google/cloud/trace"
369
+ #
370
+ # trace = Google::Cloud::Trace.new
371
+ # root1 = trace.create_span "root_span_1"
372
+ # root2 = trace.create_span "root_span_2"
373
+ # subspan = root1.create_span "subspan"
374
+ # subspan.move_under root2
375
+ #
376
+ def move_under new_parent
377
+ ensure_exists!
378
+ ensure_no_cycle! new_parent
379
+ if parent
380
+ parent.remove_child self
381
+ else
382
+ trace.remove_root self
383
+ end
384
+ if new_parent
385
+ new_parent.add_child self
386
+ @parent_span_id = new_parent.span_id
387
+ else
388
+ trace.add_root self
389
+ @parent_span_id = 0
390
+ end
391
+ @parent = new_parent
392
+ self
393
+ end
394
+
395
+ ##
396
+ # Add the given span to this span's child list.
397
+ #
398
+ # @private
399
+ #
400
+ def add_child child
401
+ @children << child
402
+ end
403
+
404
+ ##
405
+ # Remove the given span from this span's child list.
406
+ #
407
+ # @private
408
+ #
409
+ def remove_child child
410
+ @children.delete child
411
+ end
412
+
413
+ ##
414
+ # Ensure this span exists (i.e. has not been deleted) and throw a
415
+ # RuntimeError if not.
416
+ #
417
+ # @private
418
+ #
419
+ def ensure_exists!
420
+ fail "Span has been deleted" unless trace
421
+ end
422
+
423
+ ##
424
+ # Ensure moving this span under the given parent would not result
425
+ # in a cycle, and throw a RuntimeError if it would.
426
+ #
427
+ # @private
428
+ #
429
+ def ensure_no_cycle! new_parent
430
+ ptr = new_parent
431
+ until ptr.nil?
432
+ fail "Move would result in a cycle" if ptr.equal?(self)
433
+ ptr = ptr.parent
434
+ end
435
+ end
436
+
437
+ ##
438
+ # Returns true if this span has the same children as the given other.
439
+ #
440
+ # @private
441
+ #
442
+ def same_children? other
443
+ child_ids = @children.map(&:span_id)
444
+ other_child_ids = other.children.map(&:span_id)
445
+ ::Set.new(child_ids) == ::Set.new(other_child_ids)
446
+ end
447
+ end
448
+ end
449
+ end
450
+ end