opencensus 0.1.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.
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