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.
- checksums.yaml +7 -0
- data/.yardopts +7 -0
- data/LICENSE +201 -0
- data/README.md +45 -0
- data/lib/google-cloud-trace.rb +97 -0
- data/lib/google/cloud/trace.rb +340 -0
- data/lib/google/cloud/trace/credentials.rb +41 -0
- data/lib/google/cloud/trace/label_key.rb +130 -0
- data/lib/google/cloud/trace/middleware.rb +358 -0
- data/lib/google/cloud/trace/notifications.rb +115 -0
- data/lib/google/cloud/trace/project.rb +219 -0
- data/lib/google/cloud/trace/rails.rb +231 -0
- data/lib/google/cloud/trace/result_set.rb +199 -0
- data/lib/google/cloud/trace/service.rb +166 -0
- data/lib/google/cloud/trace/span.rb +450 -0
- data/lib/google/cloud/trace/span_kind.rb +80 -0
- data/lib/google/cloud/trace/time_sampler.rb +104 -0
- data/lib/google/cloud/trace/trace_record.rb +332 -0
- data/lib/google/cloud/trace/utils.rb +46 -0
- data/lib/google/cloud/trace/v1.rb +16 -0
- data/lib/google/cloud/trace/v1/doc/google/devtools/cloudtrace/v1/trace.rb +187 -0
- data/lib/google/cloud/trace/v1/doc/google/protobuf/timestamp.rb +83 -0
- data/lib/google/cloud/trace/v1/trace_service_api.rb +307 -0
- data/lib/google/cloud/trace/v1/trace_service_client_config.json +43 -0
- data/lib/google/cloud/trace/version.rb +22 -0
- data/lib/google/devtools/cloudtrace/v1/trace_pb.rb +78 -0
- data/lib/google/devtools/cloudtrace/v1/trace_services_pb.rb +57 -0
- metadata +294 -0
@@ -0,0 +1,80 @@
|
|
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
|
+
# SpanKind represents values for the "kind" field of span.
|
21
|
+
#
|
22
|
+
class SpanKind
|
23
|
+
@@mapping = {}
|
24
|
+
|
25
|
+
##
|
26
|
+
# Create a new SpanKind.
|
27
|
+
#
|
28
|
+
# @private
|
29
|
+
#
|
30
|
+
def initialize name
|
31
|
+
@name = name
|
32
|
+
@@mapping[name] = self
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# The `:SPAN_KIND_UNSPECIFIED` value
|
37
|
+
#
|
38
|
+
UNSPECIFIED = new :SPAN_KIND_UNSPECIFIED
|
39
|
+
|
40
|
+
##
|
41
|
+
# The `:RPC_SERVER` value
|
42
|
+
#
|
43
|
+
RPC_SERVER = new :RPC_SERVER
|
44
|
+
|
45
|
+
##
|
46
|
+
# The `:RPC_CLIENT` value
|
47
|
+
#
|
48
|
+
RPC_CLIENT = new :RPC_CLIENT
|
49
|
+
|
50
|
+
##
|
51
|
+
# Returns the symbolic representation of this SpanKind
|
52
|
+
#
|
53
|
+
# @return [Symbol] Symbol representation.
|
54
|
+
#
|
55
|
+
def to_sym
|
56
|
+
@name
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Returns the string representation of this SpanKind
|
61
|
+
#
|
62
|
+
# @return [String] String representation.
|
63
|
+
#
|
64
|
+
def to_s
|
65
|
+
to_sym.to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Returns the SpanKind given a symbol or string representation.
|
70
|
+
#
|
71
|
+
# @param [String, Symbol] name The name of the SpanKind.
|
72
|
+
# @return [SpanKind] The SpanKind, or `nil` if not known.
|
73
|
+
#
|
74
|
+
def self.get name
|
75
|
+
@@mapping[name.to_sym]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# Copyright 2016 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
|
+
module Google
|
16
|
+
module Cloud
|
17
|
+
module Trace
|
18
|
+
##
|
19
|
+
# A sampler determines whether a given request's latency trace should
|
20
|
+
# actually be reported. It is usually not necessary to trace every
|
21
|
+
# request, especially for an application serving heavy traffic. You may
|
22
|
+
# use a sampler to decide, for a given request, whether to report its
|
23
|
+
# trace. A sampler is simply a Proc that takes the Rack environment as an
|
24
|
+
# argument and returns a boolean indicating whether or not to sample the
|
25
|
+
# current request. Alternately, it could be an object that duck-types the
|
26
|
+
# Proc interface by implementing the `call` method.
|
27
|
+
#
|
28
|
+
# TimeSampler is the default sampler. It bases its sampling decision on
|
29
|
+
# two considerations:
|
30
|
+
#
|
31
|
+
# 1. It allows you to blacklist certain URI paths that should never be
|
32
|
+
# traced. For example, the Google App Engine health check request
|
33
|
+
# path `/_ah/health` is blacklisted by default.
|
34
|
+
# 2. It spaces samples out by delaying a minimum time between each
|
35
|
+
# sample. This enforces a maximum QPS for this Ruby process.
|
36
|
+
#
|
37
|
+
class TimeSampler
|
38
|
+
##
|
39
|
+
# Default list of paths for which to disable traces. Currently includes
|
40
|
+
# App Engine Flex health checks.
|
41
|
+
DEFAULT_PATH_BLACKLIST = ["/_ah/health"].freeze
|
42
|
+
|
43
|
+
##
|
44
|
+
# Create a TimeSampler for the given QPS.
|
45
|
+
#
|
46
|
+
# @param [Number] qps Samples per second. Default is 0.1.
|
47
|
+
# @param [Array{String,Regex}] path_blacklist An array of paths or
|
48
|
+
# path patterns indicating URIs that should never be traced.
|
49
|
+
# Default is DEFAULT_PATH_BLACKLIST.
|
50
|
+
#
|
51
|
+
def initialize qps: 0.1, path_blacklist: DEFAULT_PATH_BLACKLIST
|
52
|
+
@delay_secs = 1.0 / qps
|
53
|
+
@last_time = ::Time.now.to_f - @delay_secs
|
54
|
+
@path_blacklist = path_blacklist
|
55
|
+
end
|
56
|
+
|
57
|
+
@default = new
|
58
|
+
|
59
|
+
##
|
60
|
+
# Get the default global TimeSampler.
|
61
|
+
#
|
62
|
+
# @return [TimeSampler]
|
63
|
+
#
|
64
|
+
def self.default
|
65
|
+
@default
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Implements the sampler contract. Checks to see whether a sample
|
70
|
+
# should be taken at this time.
|
71
|
+
#
|
72
|
+
# @param [Hash] env Rack environment.
|
73
|
+
# @return [Boolean] Whether to sample at this time.
|
74
|
+
#
|
75
|
+
def call env
|
76
|
+
return false if path_blacklisted? env
|
77
|
+
time = ::Time.now.to_f
|
78
|
+
delays = (time - @last_time) / @delay_secs
|
79
|
+
if delays >= 2.0
|
80
|
+
@last_time = time - @delay_secs
|
81
|
+
true
|
82
|
+
elsif delays >= 1.0
|
83
|
+
@last_time += @delay_secs
|
84
|
+
true
|
85
|
+
else
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Determines if the URI path in the given Rack environment is
|
92
|
+
# blacklisted in this sampler.
|
93
|
+
#
|
94
|
+
# @private
|
95
|
+
#
|
96
|
+
def path_blacklisted? env
|
97
|
+
path = "#{env['SCRIPT_NAME']}#{env['PATH_INFO']}"
|
98
|
+
path = "/#{path}" unless path.start_with? "/"
|
99
|
+
@path_blacklist.find { |p| p === path }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,332 @@
|
|
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 "date"
|
17
|
+
require "google/devtools/cloudtrace/v1/trace_pb"
|
18
|
+
require "stackdriver/core/trace_context"
|
19
|
+
|
20
|
+
module Google
|
21
|
+
module Cloud
|
22
|
+
module Trace
|
23
|
+
##
|
24
|
+
# Trace represents an entire trace record.
|
25
|
+
#
|
26
|
+
# A trace has an ID and contains a forest of spans. The trace object
|
27
|
+
# methods may be used to walk or manipulate the set of spans.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# require "google/cloud/trace"
|
31
|
+
#
|
32
|
+
# env = my_get_rack_environment
|
33
|
+
# trace_context = Stackdriver::Core::TraceContext.parse_rack_env env
|
34
|
+
#
|
35
|
+
# trace = Google::Cloud::Trace.new "my-project", trace_context
|
36
|
+
# span = trace.create_span "root_span"
|
37
|
+
# subspan = span.create_span "subspan"
|
38
|
+
#
|
39
|
+
# trace_proto = trace.to_grpc
|
40
|
+
#
|
41
|
+
class TraceRecord
|
42
|
+
##
|
43
|
+
# Create an empty Trace object. If a trace context is provided, it is
|
44
|
+
# used to locate this trace within that context.
|
45
|
+
#
|
46
|
+
# @param [String] project The ID of the project containing this trace.
|
47
|
+
# @param [Stackdriver::Core::TraceContext] trace_context The context
|
48
|
+
# within which to locate this trace (i.e. sets the trace ID and
|
49
|
+
# the context parent span, if present.) If no context is provided,
|
50
|
+
# a new trace with a new trace ID is created.
|
51
|
+
#
|
52
|
+
def initialize project, trace_context = nil, span_id_generator: nil
|
53
|
+
@project = project
|
54
|
+
@trace_context = trace_context || Stackdriver::Core::TraceContext.new
|
55
|
+
@root_spans = []
|
56
|
+
@spans_by_id = {}
|
57
|
+
@span_id_generator =
|
58
|
+
span_id_generator || ::Proc.new { rand(0xffffffffffffffff) + 1 }
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Standard value equality check for this object.
|
63
|
+
#
|
64
|
+
# @param [Object] other Object to compare with
|
65
|
+
# @return [Boolean]
|
66
|
+
#
|
67
|
+
def eql? other
|
68
|
+
other.is_a?(Google::Cloud::Trace::TraceRecord) &&
|
69
|
+
trace_context == other.trace_context &&
|
70
|
+
@spans_by_id == other.instance_variable_get(:@spans_by_id)
|
71
|
+
end
|
72
|
+
alias_method :==, :eql?
|
73
|
+
|
74
|
+
##
|
75
|
+
# Create a new Trace object from a trace protobuf.
|
76
|
+
#
|
77
|
+
# @param [Google::Devtools::Cloudtrace::V1::Trace] trace_proto The
|
78
|
+
# trace protobuf from the V1 gRPC Trace API.
|
79
|
+
# @return [Trace, nil] A corresponding Trace object, or `nil` if the
|
80
|
+
# proto does not represent an existing trace object.
|
81
|
+
#
|
82
|
+
def self.from_grpc trace_proto
|
83
|
+
trace_id = trace_proto.trace_id.to_s
|
84
|
+
return nil if trace_id.empty?
|
85
|
+
|
86
|
+
span_protos = trace_proto.spans
|
87
|
+
parent_span_ids = find_root_span_ids span_protos
|
88
|
+
|
89
|
+
span_id = parent_span_ids.size == 1 ? parent_span_ids.first : 0
|
90
|
+
span_id = nil if span_id == 0
|
91
|
+
tc = Stackdriver::Core::TraceContext.new trace_id: trace_id,
|
92
|
+
span_id: span_id
|
93
|
+
trace = new trace_proto.project_id, tc
|
94
|
+
|
95
|
+
until parent_span_ids.empty?
|
96
|
+
parent_span_ids = trace.add_span_protos span_protos, parent_span_ids
|
97
|
+
end
|
98
|
+
trace
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Convert this Trace object to an equivalent Trace protobuf suitable
|
103
|
+
# for the V1 gRPC Trace API.
|
104
|
+
#
|
105
|
+
# @return [Google::Devtools::Cloudtrace::V1::Trace] The generated
|
106
|
+
# protobuf.
|
107
|
+
#
|
108
|
+
def to_grpc
|
109
|
+
span_protos = @spans_by_id.values.map do |span|
|
110
|
+
span.to_grpc trace_context.span_id.to_i
|
111
|
+
end
|
112
|
+
Google::Devtools::Cloudtrace::V1::Trace.new \
|
113
|
+
project_id: project,
|
114
|
+
trace_id: trace_id,
|
115
|
+
spans: span_protos
|
116
|
+
end
|
117
|
+
|
118
|
+
##
|
119
|
+
# The project ID for this trace.
|
120
|
+
#
|
121
|
+
# @return [String]
|
122
|
+
#
|
123
|
+
attr_reader :project
|
124
|
+
|
125
|
+
##
|
126
|
+
# The context for this trace.
|
127
|
+
#
|
128
|
+
# @return [Stackdriver::Core::TraceContext]
|
129
|
+
#
|
130
|
+
attr_reader :trace_context
|
131
|
+
|
132
|
+
##
|
133
|
+
# The ID string for the trace.
|
134
|
+
#
|
135
|
+
# @return [String]
|
136
|
+
#
|
137
|
+
def trace_id
|
138
|
+
trace_context.trace_id
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Returns an array of all spans in this trace, not in any particular
|
143
|
+
# order
|
144
|
+
#
|
145
|
+
# @return [Array{TraceSpan}]
|
146
|
+
#
|
147
|
+
def all_spans
|
148
|
+
@spans_by_id.values
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# Returns an array of all root spans in this trace, not in any
|
153
|
+
# particular order
|
154
|
+
#
|
155
|
+
# @return [Array{TraceSpan}]
|
156
|
+
#
|
157
|
+
def root_spans
|
158
|
+
@root_spans.dup
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Creates a new span in this trace.
|
163
|
+
#
|
164
|
+
# @param [String] name The name of the span.
|
165
|
+
# @param [Integer] span_id The numeric ID of the span, or nil to
|
166
|
+
# generate a new random unique ID. Optional (defaults to nil).
|
167
|
+
# @param [Integer] parent_span_id The span ID of the parent span, or 0
|
168
|
+
# if this should be a new root span within the context. Note that
|
169
|
+
# a root span would not necessarily end up with a parent ID of 0 if
|
170
|
+
# the trace context specifies a different context span ID. Optional
|
171
|
+
# (defaults to 0).
|
172
|
+
# @param [SpanKind] kind The kind of span. Optional.
|
173
|
+
# @param [Time] start_time The starting timestamp, or nil if not yet
|
174
|
+
# specified. Optional (defaults to nil).
|
175
|
+
# @param [Time] end_time The ending timestamp, or nil if not yet
|
176
|
+
# specified. Optional (defaults to nil).
|
177
|
+
# @param [Hash{String=>String}] labels The span properties. Optional
|
178
|
+
# (defaults to empty).
|
179
|
+
# @return [TraceSpan] The created span.
|
180
|
+
#
|
181
|
+
# @example
|
182
|
+
# require "google/cloud/trace"
|
183
|
+
#
|
184
|
+
# trace = Google::Cloud::Trace.new trace_context
|
185
|
+
# span = trace.create_span "root_span"
|
186
|
+
#
|
187
|
+
def create_span name, span_id: nil, parent_span_id: 0,
|
188
|
+
kind: SpanKind::UNSPECIFIED,
|
189
|
+
start_time: nil, end_time: nil,
|
190
|
+
labels: {}
|
191
|
+
parent_span_id = parent_span_id.to_i
|
192
|
+
parent_span_id = trace_context.span_id.to_i if parent_span_id == 0
|
193
|
+
parent_span = @spans_by_id[parent_span_id]
|
194
|
+
if parent_span
|
195
|
+
parent_span.create_span name,
|
196
|
+
span_id: span_id,
|
197
|
+
kind: kind,
|
198
|
+
start_time: start_time,
|
199
|
+
end_time: end_time,
|
200
|
+
labels: labels
|
201
|
+
else
|
202
|
+
internal_create_span nil, span_id, parent_span_id, name, kind,
|
203
|
+
start_time, end_time, labels
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
##
|
208
|
+
# Creates a root span around the given block. Automatically populates
|
209
|
+
# the start and end timestamps. The span (with start time but not end
|
210
|
+
# time populated) is yielded to the block.
|
211
|
+
#
|
212
|
+
# @param [String] name The name of the span.
|
213
|
+
# @param [SpanKind] kind The kind of span. Optional.
|
214
|
+
# @param [Hash{String=>String}] labels The span properties. Optional
|
215
|
+
# (defaults to empty).
|
216
|
+
# @return [TraceSpan] The created span.
|
217
|
+
#
|
218
|
+
# @example
|
219
|
+
# require "google/cloud/trace"
|
220
|
+
#
|
221
|
+
# trace = Google::Cloud::Trace.new trace_context
|
222
|
+
# trace.in_span "root_span" do |span|
|
223
|
+
# # Do stuff...
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
def in_span name, kind: SpanKind::UNSPECIFIED, labels: {}
|
227
|
+
span = create_span name, kind: kind, labels: labels
|
228
|
+
span.start!
|
229
|
+
yield span
|
230
|
+
ensure
|
231
|
+
span.finish!
|
232
|
+
end
|
233
|
+
|
234
|
+
##
|
235
|
+
# Internal implementation of span creation. Ensures that a span ID has
|
236
|
+
# been allocated, and that the span appears in the internal indexes.
|
237
|
+
#
|
238
|
+
# @private
|
239
|
+
#
|
240
|
+
def internal_create_span parent, span_id, parent_span_id, name, kind,
|
241
|
+
start_time, end_time, labels
|
242
|
+
span_id = span_id.to_i
|
243
|
+
parent_span_id = parent_span_id.to_i
|
244
|
+
span_id = unique_span_id if span_id == 0
|
245
|
+
span = Google::Cloud::Trace::Span.new \
|
246
|
+
self, span_id, parent_span_id, parent, name, kind,
|
247
|
+
start_time, end_time, labels
|
248
|
+
@root_spans << span if parent.nil?
|
249
|
+
@spans_by_id[span_id] = span
|
250
|
+
span
|
251
|
+
end
|
252
|
+
|
253
|
+
##
|
254
|
+
# Generates and returns a span ID that is unique in this trace.
|
255
|
+
#
|
256
|
+
# @private
|
257
|
+
#
|
258
|
+
def unique_span_id
|
259
|
+
loop do
|
260
|
+
id = @span_id_generator.call
|
261
|
+
return id if !@spans_by_id.include?(id) &&
|
262
|
+
id != trace_context.span_id.to_i
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
##
|
267
|
+
# Add the given span to the list of root spans.
|
268
|
+
#
|
269
|
+
# @private
|
270
|
+
#
|
271
|
+
def add_root span
|
272
|
+
@root_spans << span
|
273
|
+
end
|
274
|
+
|
275
|
+
##
|
276
|
+
# Remove the given span from the list of root spans.
|
277
|
+
#
|
278
|
+
# @private
|
279
|
+
#
|
280
|
+
def remove_root span
|
281
|
+
@root_spans.delete span
|
282
|
+
end
|
283
|
+
|
284
|
+
##
|
285
|
+
# Remove the given span from the list of spans overall.
|
286
|
+
#
|
287
|
+
# @private
|
288
|
+
#
|
289
|
+
def remove_span span
|
290
|
+
@root_spans.delete span
|
291
|
+
@spans_by_id.delete span.span_id
|
292
|
+
end
|
293
|
+
|
294
|
+
##
|
295
|
+
# Given a list of span protobufs, find the "root" span IDs, i.e. all
|
296
|
+
# parent span IDs that don't correspond to actual spans in the set.
|
297
|
+
#
|
298
|
+
# @private
|
299
|
+
#
|
300
|
+
def self.find_root_span_ids span_protos
|
301
|
+
span_ids = ::Set.new span_protos.map(&:span_id)
|
302
|
+
root_protos = span_protos.find_all do |sp|
|
303
|
+
!span_ids.include? sp.parent_span_id
|
304
|
+
end
|
305
|
+
::Set.new root_protos.map(&:parent_span_id)
|
306
|
+
end
|
307
|
+
|
308
|
+
##
|
309
|
+
# Given a list of span protobufs and a set of parent span IDs, add
|
310
|
+
# for all spans whose parent is in the set, convert the span to a
|
311
|
+
# `TraceSpan` object and add it into this trace. Returns the IDs of
|
312
|
+
# the spans added, which may be used in a subsequent call to this
|
313
|
+
# method. Effectively, repeated calls to this method perform a
|
314
|
+
# breadth-first walk of the span protos and populate the TraceRecord
|
315
|
+
# accordingly.
|
316
|
+
#
|
317
|
+
# @private
|
318
|
+
#
|
319
|
+
def add_span_protos span_protos, parent_span_ids
|
320
|
+
new_span_ids = ::Set.new
|
321
|
+
span_protos.each do |span_proto|
|
322
|
+
if parent_span_ids.include? span_proto.parent_span_id
|
323
|
+
Google::Cloud::Trace::Span.from_grpc span_proto, self
|
324
|
+
new_span_ids.add span_proto.span_id
|
325
|
+
end
|
326
|
+
end
|
327
|
+
new_span_ids
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|