google-cloud-trace 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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