opencensus 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rubocop.yml +48 -0
  4. data/.travis.yml +16 -0
  5. data/AUTHORS +1 -0
  6. data/CODE_OF_CONDUCT.md +43 -0
  7. data/CONTRIBUTING.md +34 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE +201 -0
  10. data/README.md +180 -0
  11. data/Rakefile +20 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/docs/.gitignore +3 -0
  15. data/docs/404.html +24 -0
  16. data/docs/Gemfile +31 -0
  17. data/docs/_config.yml +39 -0
  18. data/docs/_layouts/default.html +65 -0
  19. data/docs/index.md +151 -0
  20. data/lib/opencensus.rb +21 -0
  21. data/lib/opencensus/common.rb +24 -0
  22. data/lib/opencensus/common/config.rb +521 -0
  23. data/lib/opencensus/config.rb +54 -0
  24. data/lib/opencensus/context.rb +72 -0
  25. data/lib/opencensus/stats.rb +26 -0
  26. data/lib/opencensus/tags.rb +25 -0
  27. data/lib/opencensus/trace.rb +181 -0
  28. data/lib/opencensus/trace/annotation.rb +60 -0
  29. data/lib/opencensus/trace/config.rb +119 -0
  30. data/lib/opencensus/trace/exporters.rb +26 -0
  31. data/lib/opencensus/trace/exporters/logger.rb +149 -0
  32. data/lib/opencensus/trace/formatters.rb +29 -0
  33. data/lib/opencensus/trace/formatters/binary.rb +66 -0
  34. data/lib/opencensus/trace/formatters/cloud_trace.rb +102 -0
  35. data/lib/opencensus/trace/formatters/trace_context.rb +124 -0
  36. data/lib/opencensus/trace/integrations.rb +24 -0
  37. data/lib/opencensus/trace/integrations/faraday_middleware.rb +176 -0
  38. data/lib/opencensus/trace/integrations/rack_middleware.rb +127 -0
  39. data/lib/opencensus/trace/integrations/rails.rb +121 -0
  40. data/lib/opencensus/trace/link.rb +90 -0
  41. data/lib/opencensus/trace/message_event.rb +80 -0
  42. data/lib/opencensus/trace/samplers.rb +50 -0
  43. data/lib/opencensus/trace/samplers/always_sample.rb +34 -0
  44. data/lib/opencensus/trace/samplers/max_qps.rb +55 -0
  45. data/lib/opencensus/trace/samplers/never_sample.rb +34 -0
  46. data/lib/opencensus/trace/samplers/probability.rb +69 -0
  47. data/lib/opencensus/trace/span.rb +196 -0
  48. data/lib/opencensus/trace/span_builder.rb +560 -0
  49. data/lib/opencensus/trace/span_context.rb +308 -0
  50. data/lib/opencensus/trace/status.rb +49 -0
  51. data/lib/opencensus/trace/time_event.rb +38 -0
  52. data/lib/opencensus/trace/trace_context_data.rb +22 -0
  53. data/lib/opencensus/trace/truncatable_string.rb +61 -0
  54. data/lib/opencensus/version.rb +18 -0
  55. data/opencensus.gemspec +32 -0
  56. metadata +210 -0
@@ -0,0 +1,560 @@
1
+ # Copyright 2017 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 Trace
17
+ ##
18
+ # Span represents a single span within a request trace.
19
+ #
20
+ class SpanBuilder
21
+ ## The type of a message event or link is unknown.
22
+ TYPE_UNSPECIFIED = :TYPE_UNSPECIFIED
23
+
24
+ ## Indicates a sent message.
25
+ SENT = :SENT
26
+
27
+ ## Indicates a received message.
28
+ RECEIVED = :RECEIVED
29
+
30
+ ## The linked span is a child of the current span.
31
+ CHILD_LINKED_SPAN = :CHILD_LINKED_SPAN
32
+
33
+ ## The linked span is a parent of the current span.
34
+ PARENT_LINKED_SPAN = :PARENT_LINKED_SPAN
35
+
36
+ ##
37
+ # The context that can build children of this span.
38
+ #
39
+ # @return [SpanContext]
40
+ #
41
+ attr_reader :context
42
+
43
+ ##
44
+ # The trace ID, as a 32-character hex string.
45
+ #
46
+ # @return [String]
47
+ #
48
+ def trace_id
49
+ context.trace_id
50
+ end
51
+
52
+ ##
53
+ # The span ID, as a 16-character hex string.
54
+ #
55
+ # @return [String]
56
+ #
57
+ def span_id
58
+ context.span_id
59
+ end
60
+
61
+ ##
62
+ # The span ID of the parent, as a 16-character hex string, or the empty
63
+ # string if this is a root span.
64
+ #
65
+ # @return [String]
66
+ #
67
+ def parent_span_id
68
+ context.parent.span_id
69
+ end
70
+
71
+ ##
72
+ # Sampling decision for this span. Generally this field is set when the
73
+ # span is first created. However, you can also change it after the fact.
74
+ #
75
+ # @return [boolean]
76
+ #
77
+ attr_accessor :sampled
78
+
79
+ ##
80
+ # A description of the span's operation.
81
+ #
82
+ # For example, the name can be a qualified method name or a file name and
83
+ # a line number where the operation is called. A best practice is to use
84
+ # the same display name at the same call point in an application.
85
+ # This makes it easier to correlate spans in different traces.
86
+ #
87
+ # This field is required.
88
+ #
89
+ # @return [String, TruncatableString]
90
+ #
91
+ attr_accessor :name
92
+
93
+ ##
94
+ # The start time of the span. On the client side, this is the time kept
95
+ # by the local machine where the span execution starts. On the server
96
+ # side, this is the time when the server's application handler starts
97
+ # running.
98
+ #
99
+ # In Ruby, this is represented by a Time object in UTC, or `nil` if the
100
+ # starting timestamp has not yet been populated.
101
+ #
102
+ # @return [Time, nil]
103
+ #
104
+ attr_accessor :start_time
105
+
106
+ ##
107
+ # The end time of the span. On the client side, this is the time kept by
108
+ # the local machine where the span execution ends. On the server side,
109
+ # this is the time when the server application handler stops running.
110
+ #
111
+ # In Ruby, this is represented by a Time object in UTC, or `nil` if the
112
+ # starting timestamp has not yet been populated.
113
+ #
114
+ # @return [Time, nil]
115
+ #
116
+ attr_accessor :end_time
117
+
118
+ ##
119
+ # Whether this span is finished (i.e. has both a start and end time)
120
+ #
121
+ # @return [boolean]
122
+ #
123
+ def finished?
124
+ !start_time.nil? && !end_time.nil?
125
+ end
126
+
127
+ ##
128
+ # Start this span by setting the start time to the current time.
129
+ # Raises an exception if the start time is already set.
130
+ #
131
+ def start!
132
+ raise "Span already started" unless start_time.nil?
133
+ @start_time = Time.now.utc
134
+ self
135
+ end
136
+
137
+ ##
138
+ # Finish this span by setting the end time to the current time.
139
+ # Raises an exception if the start time is not yet set, or the end time
140
+ # is already set.
141
+ #
142
+ def finish!
143
+ raise "Span not yet started" if start_time.nil?
144
+ raise "Span already finished" unless end_time.nil?
145
+ @end_time = Time.now.utc
146
+ self
147
+ end
148
+
149
+ ##
150
+ # Add an attribute to this span.
151
+ #
152
+ # Attributes are key-value pairs representing properties of this span.
153
+ # You could, for example, add an attribute indicating the URL for the
154
+ # request being handled, the user-agent, the database query being run,
155
+ # the ID of the logged-in user, or any other relevant information.
156
+ #
157
+ # Keys must be strings.
158
+ # Values may be String, TruncatableString, Integer, or Boolean.
159
+ # The valid integer range is 64-bit signed `(-2^63..2^63-1)`.
160
+ #
161
+ # @param [String, Symbol] key
162
+ # @param [String, TruncatableString, Integer, boolean] value
163
+ #
164
+ def put_attribute key, value
165
+ @attributes[key.to_s] = value
166
+ self
167
+ end
168
+
169
+ ##
170
+ # Add an event annotation with a timestamp.
171
+ #
172
+ # @param [String] description Description of the event
173
+ # @param [Hash] attributes Key-value pairs providing additional
174
+ # properties of the event. Keys must be strings, and values are
175
+ # restricted to the same types as attributes (see #put_attribute).
176
+ # @param [Time, nil] time Timestamp of the event. Optional, defaults to
177
+ # the current time.
178
+ #
179
+ def put_annotation description, attributes = {}, time: nil
180
+ time ||= Time.now.utc
181
+ annotation = AnnotationBuilder.new time, description, attributes
182
+ @annotations << annotation
183
+ self
184
+ end
185
+
186
+ ##
187
+ # Add an event describing a message sent/received between spans.
188
+ #
189
+ # @param [Symbol] type The type of MessageEvent. Indicates whether the
190
+ # message was sent or received. Valid values are `SpanBuilder::SENT`
191
+ # `SpanBuilder::RECEIVED`, and `SpanBuilder::TYPE_UNSPECIFIED`.
192
+ # @param [Integer] id An identifier for the MessageEvent's message that
193
+ # can be used to match SENT and RECEIVED events. For example, this
194
+ # field could represent a sequence ID for a streaming RPC. It is
195
+ # recommended to be unique within a Span. The valid range is 64-bit
196
+ # unsigned `(0..2^64-1)`
197
+ # @param [Integer] uncompressed_size The number of uncompressed bytes
198
+ # sent or received.
199
+ # @param [Integer, nil] compressed_size The number of compressed bytes
200
+ # sent or received. Optional.
201
+ # @param [Time, nil] time Timestamp of the event. Optional, defaults to
202
+ # the current time.
203
+ #
204
+ def put_message_event type, id, uncompressed_size,
205
+ compressed_size: nil, time: nil
206
+ time ||= Time.now.utc
207
+ message_event =
208
+ MessageEventBuilder.new time, type, id, uncompressed_size,
209
+ compressed_size
210
+ @message_events << message_event
211
+ self
212
+ end
213
+
214
+ ##
215
+ # Add a pointer from the current span to another span, which may be in
216
+ # the same trace or in a different trace. For example, this can be used
217
+ # in batching operations, where a single batch handler processes multiple
218
+ # requests from different traces or when the handler receives a request
219
+ # from a different project.
220
+ #
221
+ # @param [String] trace_id The unique identifier for a trace. A 16-byte
222
+ # array expressed as 32 hex digits.
223
+ # @param [String] span_id The unique identifier for a span within a trace.
224
+ # An 8-byte array expressed as 16 hex digits.
225
+ # @param [Symbol] type The relationship of the current span relative to
226
+ # the linked span. Valid values are `SpanBuilder::CHILD_LINKED_SPAN`,
227
+ # `SpanBuilder::PARENT_LINKED_SPAN`, and
228
+ # `SpanBuilder::TYPE_UNSPECIFIED`.
229
+ # @param [String] attributes Key-value pairs providing additional
230
+ # properties of the link. Keys must be strings, and values are
231
+ # restricted to the same types as attributes (see #put_attribute).
232
+ #
233
+ def put_link trace_id, span_id, type, attributes = {}
234
+ link = LinkBuilder.new trace_id, span_id, type, attributes
235
+ @links << link
236
+ self
237
+ end
238
+
239
+ ##
240
+ # Set the optional final status for the span.
241
+ #
242
+ # @param [Integer] code Status code as a 32-bit signed integer
243
+ # @param [String] message A developer-facing error message, which should
244
+ # be in English.
245
+ def set_status code, message = ""
246
+ @status_code = code
247
+ @status_message = message
248
+ self
249
+ end
250
+
251
+ ##
252
+ # Set the stack trace for this span.
253
+ # You may call this in one of three ways:
254
+ #
255
+ # * Pass in no argument to use the caller's stack trace.
256
+ # * Pass in an integer to use the caller's stack trace, but skip
257
+ # additional stack frames.
258
+ # * Pass in an explicit array of Thread::Backtrace::Location as
259
+ # returned from Kernel#caller_locations
260
+ #
261
+ # @param [Array<Thread::Backtrace::Location>, Integer] stack_trace
262
+ #
263
+ def update_stack_trace stack_trace = 0
264
+ @stack_trace =
265
+ case stack_trace
266
+ when Integer
267
+ caller_locations(stack_trace + 2)
268
+ when Array
269
+ stack_trace
270
+ else
271
+ raise ArgumentError, "Unknown stack trace type: #{stack_trace}"
272
+ end
273
+ self
274
+ end
275
+
276
+ # rubocop:disable Metrics/MethodLength
277
+ # rubocop:disable Metrics/AbcSize
278
+
279
+ ##
280
+ # Return a read-only version of this span
281
+ #
282
+ # @return [Span]
283
+ #
284
+ def to_span max_attributes: nil,
285
+ max_stack_frames: nil,
286
+ max_annotations: nil,
287
+ max_message_events: nil,
288
+ max_links: nil,
289
+ max_string_length: nil,
290
+ same_process_as_parent_span: nil
291
+
292
+ raise "Span must have start_time" unless @start_time
293
+ raise "Span must have end_time" unless @end_time
294
+
295
+ builder = PieceBuilder.new max_attributes: max_attributes,
296
+ max_stack_frames: max_stack_frames,
297
+ max_annotations: max_annotations,
298
+ max_message_events: max_message_events,
299
+ max_links: max_links,
300
+ max_string_length: max_string_length
301
+
302
+ built_name = builder.truncatable_string name
303
+ built_attributes = builder.convert_attributes @attributes
304
+ dropped_attributes_count = @attributes.size - built_attributes.size
305
+ built_stack_trace = builder.truncate_stack_trace @stack_trace
306
+ dropped_frames_count = @stack_trace.size - built_stack_trace.size
307
+ built_annotations = builder.convert_annotations @annotations
308
+ dropped_annotations_count = @annotations.size - built_annotations.size
309
+ built_message_events = builder.convert_message_events @message_events
310
+ dropped_message_events_count =
311
+ @message_events.size - built_message_events.size
312
+ built_links = builder.convert_links @links
313
+ dropped_links_count = @links.size - built_links.size
314
+ built_status = builder.convert_status @status_code, @status_message
315
+
316
+ Span.new trace_id, span_id, built_name, @start_time, @end_time,
317
+ parent_span_id: parent_span_id,
318
+ attributes: built_attributes,
319
+ dropped_attributes_count: dropped_attributes_count,
320
+ stack_trace: built_stack_trace,
321
+ dropped_frames_count: dropped_frames_count,
322
+ time_events: built_annotations + built_message_events,
323
+ dropped_annotations_count: dropped_annotations_count,
324
+ dropped_message_events_count: dropped_message_events_count,
325
+ links: built_links,
326
+ dropped_links_count: dropped_links_count,
327
+ status: built_status,
328
+ same_process_as_parent_span: same_process_as_parent_span
329
+ end
330
+
331
+ # rubocop:enable Metrics/MethodLength
332
+ # rubocop:enable Metrics/AbcSize
333
+
334
+ ##
335
+ # Initializer.
336
+ #
337
+ # @private
338
+ #
339
+ def initialize span_context, sampled, skip_frames: 0
340
+ @context = span_context
341
+ @sampled = sampled
342
+ @name = ""
343
+ @start_time = nil
344
+ @end_time = nil
345
+ @attributes = {}
346
+ @annotations = []
347
+ @message_events = []
348
+ @links = []
349
+ @status_code = nil
350
+ @status_message = nil
351
+ @stack_trace = caller_locations(skip_frames + 2)
352
+ end
353
+
354
+ ##
355
+ # Internal structure for holding annotations.
356
+ #
357
+ # @private
358
+ #
359
+ AnnotationBuilder = Struct.new :time, :description, :attributes
360
+
361
+ ##
362
+ # Internal structure for holding message events.
363
+ #
364
+ # @private
365
+ #
366
+ MessageEventBuilder = Struct.new :time, :type, :id, :uncompressed_size,
367
+ :compressed_size
368
+ ##
369
+ # Internal structure for holding links.
370
+ #
371
+ # @private
372
+ #
373
+ LinkBuilder = Struct.new :trace_id, :span_id, :type, :attributes
374
+
375
+ ##
376
+ # Internal class that builds pieces of a span, honoring limits.
377
+ #
378
+ # @private
379
+ #
380
+ class PieceBuilder
381
+ ##
382
+ # Minimum value of int64
383
+ # @private
384
+ #
385
+ MIN_INT = -0x10000000000000000
386
+
387
+ ##
388
+ # Maximum value of int64
389
+ # @private
390
+ #
391
+ MAX_INT = 0xffffffffffffffff
392
+
393
+ ##
394
+ # Initializer for PieceBuilder
395
+ # @private
396
+ #
397
+ def initialize max_attributes: nil,
398
+ max_stack_frames: nil,
399
+ max_annotations: nil,
400
+ max_message_events: nil,
401
+ max_links: nil,
402
+ max_string_length: nil
403
+ config = OpenCensus::Trace.config
404
+ @max_attributes = max_attributes || config.default_max_attributes
405
+ @max_stack_frames =
406
+ max_stack_frames || config.default_max_stack_frames
407
+ @max_annotations = max_annotations || config.default_max_annotations
408
+ @max_message_events =
409
+ max_message_events || config.default_max_message_events
410
+ @max_links = max_links || config.default_max_links
411
+ @max_string_length =
412
+ max_string_length || config.default_max_string_length
413
+ end
414
+
415
+ ##
416
+ # Build a canonical attributes hash, truncating if necessary
417
+ # @private
418
+ #
419
+ def convert_attributes attrs
420
+ result = {}
421
+ attrs.each do |k, v|
422
+ break if @max_attributes != 0 && result.size >= @max_attributes
423
+ result[k.to_s] =
424
+ case v
425
+ when Integer
426
+ if v >= MIN_INT && v <= MAX_INT
427
+ v
428
+ else
429
+ truncatable_string v.to_s
430
+ end
431
+ when true, false, TruncatableString
432
+ v
433
+ else
434
+ truncatable_string v.to_s
435
+ end
436
+ end
437
+ result
438
+ end
439
+
440
+ ##
441
+ # Build a canonical stack trace, truncating if necessary
442
+ # @private
443
+ #
444
+ def truncate_stack_trace raw_trace
445
+ if @max_stack_frames.zero? || raw_trace.size <= @max_stack_frames
446
+ raw_trace
447
+ else
448
+ raw_trace[0, @max_stack_frames]
449
+ end
450
+ end
451
+
452
+ ##
453
+ # Build a canonical annotations list, truncating if necessary
454
+ # @private
455
+ #
456
+ def convert_annotations raw_annotations
457
+ result = []
458
+ raw_annotations.each do |ann|
459
+ break if @max_annotations != 0 && result.size >= @max_annotations
460
+ attrs = convert_attributes ann.attributes
461
+ dropped_attributes_count = ann.attributes.size - attrs.size
462
+ result <<
463
+ OpenCensus::Trace::Annotation.new(
464
+ truncatable_string(ann.description),
465
+ attributes: attrs,
466
+ dropped_attributes_count: dropped_attributes_count,
467
+ time: ann.time
468
+ )
469
+ end
470
+ result
471
+ end
472
+
473
+ ##
474
+ # Build a canonical message list, truncating if necessary
475
+ # @private
476
+ #
477
+ def convert_message_events raw_message_events
478
+ result = []
479
+ raw_message_events.each do |evt|
480
+ break if @max_message_events != 0 &&
481
+ result.size >= @max_message_events
482
+ result <<
483
+ OpenCensus::Trace::MessageEvent.new(
484
+ evt.type,
485
+ evt.id,
486
+ evt.uncompressed_size,
487
+ compressed_size: evt.compressed_size,
488
+ time: evt.time
489
+ )
490
+ end
491
+ result
492
+ end
493
+
494
+ ##
495
+ # Build a canonical links list, truncating if necessary
496
+ # @private
497
+ #
498
+ def convert_links raw_links
499
+ result = []
500
+ raw_links.each do |lnk|
501
+ break if @max_links != 0 && result.size >= @max_links
502
+ attrs = convert_attributes lnk.attributes
503
+ dropped_attributes_count = lnk.attributes.size - attrs.size
504
+ result <<
505
+ OpenCensus::Trace::Link.new(
506
+ lnk.trace_id,
507
+ lnk.span_id,
508
+ type: lnk.type,
509
+ attributes: attrs,
510
+ dropped_attributes_count: dropped_attributes_count
511
+ )
512
+ end
513
+ result
514
+ end
515
+
516
+ ##
517
+ # Build a canonical status object
518
+ # @private
519
+ #
520
+ def convert_status status_code, status_message
521
+ return nil unless status_code || status_message
522
+ Status.new status_code.to_i, status_message.to_s
523
+ end
524
+
525
+ ##
526
+ # Build a truncatable string
527
+ # @private
528
+ #
529
+ def truncatable_string str
530
+ return str if str.is_a? TruncatableString
531
+ orig_str = str.encode Encoding::UTF_8,
532
+ invalid: :replace,
533
+ undef: :replace
534
+ if @max_string_length != 0 && @max_string_length < str.bytesize
535
+ str = truncate_str orig_str, @max_string_length
536
+ truncated_bytes = orig_str.bytesize - str.bytesize
537
+ TruncatableString.new str, truncated_byte_count: truncated_bytes
538
+ else
539
+ TruncatableString.new orig_str
540
+ end
541
+ end
542
+
543
+ private
544
+
545
+ def truncate_str str, target_bytes
546
+ tstr = str.dup
547
+ tstr.force_encoding Encoding::ASCII_8BIT
548
+ tstr.slice! target_bytes..-1
549
+ tstr.force_encoding Encoding::UTF_8
550
+ until tstr.valid_encoding?
551
+ tstr.force_encoding Encoding::ASCII_8BIT
552
+ tstr.slice!(-1..-1)
553
+ tstr.force_encoding Encoding::UTF_8
554
+ end
555
+ tstr
556
+ end
557
+ end
558
+ end
559
+ end
560
+ end