ddtrace 0.37.0 → 0.42.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +56 -0
  3. data/.gitignore +2 -0
  4. data/.gitlab-ci.yml +1 -0
  5. data/.simplecov +38 -0
  6. data/Appraisals +186 -11
  7. data/CHANGELOG.md +188 -1
  8. data/CONTRIBUTING.md +1 -1
  9. data/Rakefile +518 -482
  10. data/ddtrace.gemspec +3 -0
  11. data/docker-compose.yml +2 -2
  12. data/docs/DevelopmentGuide.md +26 -0
  13. data/docs/GettingStarted.md +188 -78
  14. data/lib/ddtrace.rb +4 -0
  15. data/lib/ddtrace/buffer.rb +259 -52
  16. data/lib/ddtrace/configuration.rb +39 -5
  17. data/lib/ddtrace/configuration/components.rb +4 -7
  18. data/lib/ddtrace/configuration/options.rb +3 -1
  19. data/lib/ddtrace/configuration/settings.rb +32 -4
  20. data/lib/ddtrace/context_provider.rb +6 -5
  21. data/lib/ddtrace/contrib/action_cable/configuration/settings.rb +7 -2
  22. data/lib/ddtrace/contrib/action_cable/ext.rb +5 -2
  23. data/lib/ddtrace/contrib/action_pack/configuration/settings.rb +7 -2
  24. data/lib/ddtrace/contrib/action_pack/ext.rb +5 -2
  25. data/lib/ddtrace/contrib/action_view/configuration/settings.rb +7 -2
  26. data/lib/ddtrace/contrib/action_view/ext.rb +5 -2
  27. data/lib/ddtrace/contrib/active_model_serializers/configuration/settings.rb +7 -2
  28. data/lib/ddtrace/contrib/active_model_serializers/ext.rb +5 -2
  29. data/lib/ddtrace/contrib/active_record/configuration/settings.rb +7 -2
  30. data/lib/ddtrace/contrib/active_record/events/sql.rb +4 -0
  31. data/lib/ddtrace/contrib/active_record/ext.rb +5 -2
  32. data/lib/ddtrace/contrib/active_support/configuration/settings.rb +7 -2
  33. data/lib/ddtrace/contrib/active_support/ext.rb +5 -2
  34. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +3 -3
  35. data/lib/ddtrace/contrib/aws/configuration/settings.rb +7 -2
  36. data/lib/ddtrace/contrib/aws/ext.rb +5 -2
  37. data/lib/ddtrace/contrib/aws/instrumentation.rb +4 -0
  38. data/lib/ddtrace/contrib/concurrent_ruby/configuration/settings.rb +5 -0
  39. data/lib/ddtrace/contrib/concurrent_ruby/ext.rb +1 -0
  40. data/lib/ddtrace/contrib/configuration/settings.rb +1 -0
  41. data/lib/ddtrace/contrib/dalli/configuration/settings.rb +7 -2
  42. data/lib/ddtrace/contrib/dalli/ext.rb +5 -2
  43. data/lib/ddtrace/contrib/dalli/instrumentation.rb +4 -0
  44. data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +8 -2
  45. data/lib/ddtrace/contrib/delayed_job/ext.rb +7 -2
  46. data/lib/ddtrace/contrib/delayed_job/plugin.rb +37 -15
  47. data/lib/ddtrace/contrib/elasticsearch/configuration/settings.rb +7 -2
  48. data/lib/ddtrace/contrib/elasticsearch/ext.rb +5 -2
  49. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +4 -0
  50. data/lib/ddtrace/contrib/ethon/configuration/settings.rb +7 -2
  51. data/lib/ddtrace/contrib/ethon/easy_patch.rb +4 -2
  52. data/lib/ddtrace/contrib/ethon/ext.rb +5 -2
  53. data/lib/ddtrace/contrib/ethon/multi_patch.rb +4 -0
  54. data/lib/ddtrace/contrib/excon/configuration/settings.rb +7 -2
  55. data/lib/ddtrace/contrib/excon/ext.rb +5 -2
  56. data/lib/ddtrace/contrib/excon/middleware.rb +4 -0
  57. data/lib/ddtrace/contrib/extensions.rb +11 -1
  58. data/lib/ddtrace/contrib/faraday/configuration/settings.rb +7 -2
  59. data/lib/ddtrace/contrib/faraday/ext.rb +5 -2
  60. data/lib/ddtrace/contrib/faraday/middleware.rb +9 -3
  61. data/lib/ddtrace/contrib/faraday/patcher.rb +12 -0
  62. data/lib/ddtrace/contrib/grape/configuration/settings.rb +7 -3
  63. data/lib/ddtrace/contrib/grape/endpoint.rb +6 -4
  64. data/lib/ddtrace/contrib/grape/ext.rb +5 -2
  65. data/lib/ddtrace/contrib/graphql/configuration/settings.rb +7 -2
  66. data/lib/ddtrace/contrib/graphql/ext.rb +5 -2
  67. data/lib/ddtrace/contrib/grpc/configuration/settings.rb +7 -2
  68. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +6 -4
  69. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +4 -0
  70. data/lib/ddtrace/contrib/grpc/ext.rb +5 -2
  71. data/lib/ddtrace/contrib/http/configuration/settings.rb +7 -2
  72. data/lib/ddtrace/contrib/http/ext.rb +5 -2
  73. data/lib/ddtrace/contrib/http/instrumentation.rb +4 -0
  74. data/lib/ddtrace/contrib/httprb/configuration/settings.rb +32 -0
  75. data/lib/ddtrace/contrib/httprb/ext.rb +17 -0
  76. data/lib/ddtrace/contrib/httprb/instrumentation.rb +163 -0
  77. data/lib/ddtrace/contrib/httprb/integration.rb +43 -0
  78. data/lib/ddtrace/contrib/httprb/patcher.rb +35 -0
  79. data/lib/ddtrace/contrib/kafka/configuration/settings.rb +30 -0
  80. data/lib/ddtrace/contrib/kafka/consumer_event.rb +14 -0
  81. data/lib/ddtrace/contrib/kafka/consumer_group_event.rb +14 -0
  82. data/lib/ddtrace/contrib/kafka/event.rb +51 -0
  83. data/lib/ddtrace/contrib/kafka/events.rb +44 -0
  84. data/lib/ddtrace/contrib/kafka/events/connection/request.rb +34 -0
  85. data/lib/ddtrace/contrib/kafka/events/consumer/process_batch.rb +41 -0
  86. data/lib/ddtrace/contrib/kafka/events/consumer/process_message.rb +39 -0
  87. data/lib/ddtrace/contrib/kafka/events/consumer_group/heartbeat.rb +39 -0
  88. data/lib/ddtrace/contrib/kafka/events/consumer_group/join_group.rb +29 -0
  89. data/lib/ddtrace/contrib/kafka/events/consumer_group/leave_group.rb +29 -0
  90. data/lib/ddtrace/contrib/kafka/events/consumer_group/sync_group.rb +29 -0
  91. data/lib/ddtrace/contrib/kafka/events/produce_operation/send_messages.rb +32 -0
  92. data/lib/ddtrace/contrib/kafka/events/producer/deliver_messages.rb +35 -0
  93. data/lib/ddtrace/contrib/kafka/ext.rb +41 -0
  94. data/lib/ddtrace/contrib/kafka/integration.rb +39 -0
  95. data/lib/ddtrace/contrib/kafka/patcher.rb +26 -0
  96. data/lib/ddtrace/contrib/mongodb/configuration/settings.rb +7 -2
  97. data/lib/ddtrace/contrib/mongodb/ext.rb +5 -2
  98. data/lib/ddtrace/contrib/mongodb/subscribers.rb +4 -0
  99. data/lib/ddtrace/contrib/mysql2/configuration/settings.rb +7 -2
  100. data/lib/ddtrace/contrib/mysql2/ext.rb +5 -2
  101. data/lib/ddtrace/contrib/mysql2/instrumentation.rb +4 -0
  102. data/lib/ddtrace/contrib/presto/configuration/settings.rb +7 -2
  103. data/lib/ddtrace/contrib/presto/ext.rb +5 -2
  104. data/lib/ddtrace/contrib/presto/instrumentation.rb +3 -0
  105. data/lib/ddtrace/contrib/que/configuration/settings.rb +42 -0
  106. data/lib/ddtrace/contrib/que/ext.rb +30 -0
  107. data/lib/ddtrace/contrib/que/integration.rb +42 -0
  108. data/lib/ddtrace/contrib/que/patcher.rb +24 -0
  109. data/lib/ddtrace/contrib/que/tracer.rb +56 -0
  110. data/lib/ddtrace/contrib/racecar/configuration/settings.rb +7 -2
  111. data/lib/ddtrace/contrib/racecar/event.rb +4 -0
  112. data/lib/ddtrace/contrib/racecar/events.rb +2 -0
  113. data/lib/ddtrace/contrib/racecar/events/consume.rb +27 -0
  114. data/lib/ddtrace/contrib/racecar/ext.rb +6 -2
  115. data/lib/ddtrace/contrib/rack/configuration/settings.rb +7 -2
  116. data/lib/ddtrace/contrib/rack/ext.rb +5 -2
  117. data/lib/ddtrace/contrib/rack/middlewares.rb +17 -12
  118. data/lib/ddtrace/contrib/rails/configuration/settings.rb +12 -2
  119. data/lib/ddtrace/contrib/rails/ext.rb +6 -2
  120. data/lib/ddtrace/contrib/rails/log_injection.rb +81 -0
  121. data/lib/ddtrace/contrib/rails/middlewares.rb +7 -2
  122. data/lib/ddtrace/contrib/rails/patcher.rb +26 -0
  123. data/lib/ddtrace/contrib/rake/configuration/settings.rb +7 -3
  124. data/lib/ddtrace/contrib/rake/ext.rb +5 -2
  125. data/lib/ddtrace/contrib/redis/configuration/settings.rb +7 -2
  126. data/lib/ddtrace/contrib/redis/ext.rb +5 -2
  127. data/lib/ddtrace/contrib/redis/tags.rb +4 -0
  128. data/lib/ddtrace/contrib/resque/configuration/settings.rb +7 -2
  129. data/lib/ddtrace/contrib/resque/ext.rb +5 -2
  130. data/lib/ddtrace/contrib/resque/integration.rb +1 -1
  131. data/lib/ddtrace/contrib/rest_client/configuration/settings.rb +7 -2
  132. data/lib/ddtrace/contrib/rest_client/ext.rb +5 -2
  133. data/lib/ddtrace/contrib/rest_client/request_patch.rb +6 -2
  134. data/lib/ddtrace/contrib/sequel/configuration/settings.rb +7 -2
  135. data/lib/ddtrace/contrib/sequel/database.rb +3 -1
  136. data/lib/ddtrace/contrib/sequel/dataset.rb +3 -2
  137. data/lib/ddtrace/contrib/sequel/ext.rb +6 -2
  138. data/lib/ddtrace/contrib/sequel/utils.rb +35 -6
  139. data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +7 -2
  140. data/lib/ddtrace/contrib/shoryuken/ext.rb +5 -2
  141. data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +7 -2
  142. data/lib/ddtrace/contrib/sidekiq/ext.rb +6 -2
  143. data/lib/ddtrace/contrib/sidekiq/patcher.rb +8 -1
  144. data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +1 -0
  145. data/lib/ddtrace/contrib/sinatra/configuration/settings.rb +7 -2
  146. data/lib/ddtrace/contrib/sinatra/env.rb +5 -4
  147. data/lib/ddtrace/contrib/sinatra/ext.rb +5 -2
  148. data/lib/ddtrace/contrib/sinatra/tracer.rb +21 -42
  149. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +50 -23
  150. data/lib/ddtrace/contrib/sneakers/configuration/settings.rb +32 -0
  151. data/lib/ddtrace/contrib/sneakers/ext.rb +22 -0
  152. data/lib/ddtrace/contrib/sneakers/integration.rb +41 -0
  153. data/lib/ddtrace/contrib/sneakers/patcher.rb +24 -0
  154. data/lib/ddtrace/contrib/sneakers/tracer.rb +58 -0
  155. data/lib/ddtrace/contrib/sucker_punch/configuration/settings.rb +7 -2
  156. data/lib/ddtrace/contrib/sucker_punch/ext.rb +5 -2
  157. data/lib/ddtrace/diagnostics/environment_logger.rb +278 -0
  158. data/lib/ddtrace/environment.rb +17 -3
  159. data/lib/ddtrace/ext/diagnostics.rb +3 -0
  160. data/lib/ddtrace/ext/environment.rb +2 -0
  161. data/lib/ddtrace/ext/integration.rb +8 -0
  162. data/lib/ddtrace/ext/runtime.rb +1 -0
  163. data/lib/ddtrace/ext/transport.rb +1 -0
  164. data/lib/ddtrace/logger.rb +1 -1
  165. data/lib/ddtrace/opentracer/distributed_headers.rb +1 -1
  166. data/lib/ddtrace/pipeline/span_filter.rb +15 -15
  167. data/lib/ddtrace/propagation/grpc_propagator.rb +18 -6
  168. data/lib/ddtrace/runtime/metrics.rb +24 -6
  169. data/lib/ddtrace/sampler.rb +4 -2
  170. data/lib/ddtrace/span.rb +162 -27
  171. data/lib/ddtrace/tracer.rb +24 -18
  172. data/lib/ddtrace/transport/http.rb +15 -0
  173. data/lib/ddtrace/transport/http/adapters/net.rb +16 -2
  174. data/lib/ddtrace/transport/http/adapters/test.rb +6 -0
  175. data/lib/ddtrace/transport/http/adapters/unix_socket.rb +4 -0
  176. data/lib/ddtrace/transport/http/statistics.rb +14 -1
  177. data/lib/ddtrace/transport/response.rb +11 -0
  178. data/lib/ddtrace/transport/traces.rb +7 -2
  179. data/lib/ddtrace/utils.rb +7 -3
  180. data/lib/ddtrace/version.rb +1 -1
  181. data/lib/ddtrace/workers/async.rb +2 -2
  182. data/lib/ddtrace/workers/loop.rb +1 -1
  183. data/lib/ddtrace/workers/polling.rb +1 -1
  184. data/lib/ddtrace/workers/trace_writer.rb +3 -0
  185. data/lib/ddtrace/writer.rb +33 -12
  186. metadata +81 -2
@@ -1,3 +1,4 @@
1
+ require 'ddtrace/ext/integration'
1
2
  require 'ddtrace/ext/runtime'
2
3
 
3
4
  require 'ddtrace/metrics'
@@ -25,8 +26,11 @@ module Datadog
25
26
  # Register service as associated with metrics
26
27
  register_service(span.service) unless span.service.nil?
27
28
 
28
- # Tag span with language and runtime ID for association with metrics
29
- span.set_tag(Ext::Runtime::TAG_LANG, Runtime::Identity.lang)
29
+ # Tag span with language and runtime ID for association with metrics.
30
+ # We only tag spans that performed internal application work.
31
+ unless span.get_tag(Datadog::Ext::Integration::TAG_PEER_SERVICE)
32
+ span.set_tag(Ext::Runtime::TAG_LANG, Runtime::Identity.lang)
33
+ end
30
34
  end
31
35
 
32
36
  # Associate service with runtime metrics
@@ -55,10 +59,8 @@ module Datadog
55
59
 
56
60
  def gc_metrics
57
61
  Hash[
58
- GC.stat.map do |k, v|
59
- next if v.is_a?(Hash) # TODO: JRuby supports additional nested metrics
60
-
61
- ["#{Ext::Runtime::Metrics::METRIC_GC_PREFIX}.#{k}", v]
62
+ GC.stat.flat_map do |k, v|
63
+ nested_gc_metric(Ext::Runtime::Metrics::METRIC_GC_PREFIX, k, v)
62
64
  end
63
65
  ]
64
66
  end
@@ -91,6 +93,22 @@ module Datadog
91
93
  "#{Ext::Runtime::Metrics::TAG_SERVICE}:#{service}".freeze
92
94
  end
93
95
  end
96
+
97
+ def nested_gc_metric(prefix, k, v)
98
+ path = "#{prefix}.#{k}"
99
+
100
+ if v.is_a?(Hash)
101
+ v.flat_map do |key, value|
102
+ nested_gc_metric(path, key, value)
103
+ end
104
+ else
105
+ [[to_metric_name(path), v]]
106
+ end
107
+ end
108
+
109
+ def to_metric_name(str)
110
+ str.downcase.gsub(/[-\s]/, '_')
111
+ end
94
112
  end
95
113
  end
96
114
  end
@@ -61,11 +61,11 @@ module Datadog
61
61
 
62
62
  def sample_rate=(sample_rate)
63
63
  @sample_rate = sample_rate
64
- @sampling_id_threshold = sample_rate * Span::MAX_ID
64
+ @sampling_id_threshold = sample_rate * Span::EXTERNAL_MAX_ID
65
65
  end
66
66
 
67
67
  def sample?(span)
68
- ((span.trace_id * KNUTH_FACTOR) % Datadog::Span::MAX_ID) <= @sampling_id_threshold
68
+ ((span.trace_id * KNUTH_FACTOR) % Datadog::Span::EXTERNAL_MAX_ID) <= @sampling_id_threshold
69
69
  end
70
70
 
71
71
  def sample!(span)
@@ -193,6 +193,8 @@ module Datadog
193
193
  class PrioritySampler
194
194
  extend Forwardable
195
195
 
196
+ attr_reader :pre_sampler, :priority_sampler
197
+
196
198
  SAMPLE_RATE_METRIC_KEY = '_sample_rate'.freeze
197
199
 
198
200
  def initialize(opts = {})
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'time'
2
4
  require 'thread'
3
5
 
@@ -8,6 +10,7 @@ require 'ddtrace/environment'
8
10
  require 'ddtrace/analytics'
9
11
  require 'ddtrace/forced_tracing'
10
12
  require 'ddtrace/diagnostics/health'
13
+ require 'ddtrace/utils/time'
11
14
 
12
15
  module Datadog
13
16
  # Represents a logical unit of work in the system. Each trace consists of one or more spans.
@@ -24,24 +27,26 @@ module Datadog
24
27
  # The max value for a \Span identifier.
25
28
  # Span and trace identifiers should be strictly positive and strictly inferior to this limit.
26
29
  #
27
- # Limited to 63-bit positive integers, as some other languages might be limited to this,
28
- # and IDs need to be easy to port across various languages and platforms.
29
- MAX_ID = 2**63
30
+ # Limited to +2<<62-1+ positive integers, as Ruby is able to represent such numbers "inline",
31
+ # inside a +VALUE+ scalar, thus not requiring memory allocation.
32
+ #
33
+ # The range of IDs also has to consider portability across different languages and platforms.
34
+ RUBY_MAX_ID = (1 << 62) - 1
30
35
 
31
36
  # While we only generate 63-bit integers due to limitations in other languages, we support
32
37
  # parsing 64-bit integers for distributed tracing since an upstream system may generate one
33
- EXTERNAL_MAX_ID = 2**64
38
+ EXTERNAL_MAX_ID = 1 << 64
34
39
 
35
40
  # This limit is for numeric tags because uint64 could end up rounded.
36
- NUMERIC_TAG_SIZE_RANGE = (-2**53..2**53)
41
+ NUMERIC_TAG_SIZE_RANGE = (-1 << 53..1 << 53)
37
42
 
38
43
  attr_accessor :name, :service, :resource, :span_type,
39
- :start_time, :end_time,
40
44
  :span_id, :trace_id, :parent_id,
41
45
  :status, :sampled,
42
- :tracer, :context
46
+ :tracer, :context, :duration, :start_time, :end_time
43
47
 
44
48
  attr_reader :parent
49
+
45
50
  # Create a new span linked to the given tracer. Call the \Tracer method <tt>start_span()</tt>
46
51
  # and then <tt>finish()</tt> once the tracer operation is over.
47
52
  #
@@ -72,11 +77,20 @@ module Datadog
72
77
  @parent = nil
73
78
  @sampled = true
74
79
 
75
- @start_time = nil # set by Tracer.start_span
76
- @end_time = nil # set by Span.finish
77
-
78
80
  @allocation_count_start = now_allocations
79
81
  @allocation_count_finish = @allocation_count_start
82
+
83
+ # start_time and end_time track wall clock. In Ruby, wall clock
84
+ # has less accuracy than monotonic clock, so if possible we look to only use wall clock
85
+ # to measure duration when a time is supplied by the user, or if monotonic clock
86
+ # is unsupported.
87
+ @start_time = nil
88
+ @end_time = nil
89
+
90
+ # duration_start and duration_end track monotonic clock, and may remain nil in cases where it
91
+ # is known that we have to use wall clock to measure duration.
92
+ @duration_start = nil
93
+ @duration_end = nil
80
94
  end
81
95
 
82
96
  # Set the given key / value tag pair on the span. Keys and values
@@ -107,6 +121,16 @@ module Datadog
107
121
  Datadog.logger.debug("Unable to set the tag #{key}, ignoring it. Caused by: #{e}")
108
122
  end
109
123
 
124
+ # Sets tags from given hash, for each key in hash it sets the tag with that key
125
+ # and associated value from the hash. It is shortcut for `set_tag`. Keys and values
126
+ # of the hash must be strings. Note that nested hashes are not supported.
127
+ # A valid example is:
128
+ #
129
+ # span.set_tags({ "http.method" => "GET", "user.id" => "234" })
130
+ def set_tags(tags)
131
+ tags.each { |k, v| set_tag(k, v) }
132
+ end
133
+
110
134
  # This method removes a tag for the given key.
111
135
  def clear_tag(key)
112
136
  @meta.delete(key)
@@ -150,6 +174,28 @@ module Datadog
150
174
  set_tag(Ext::Errors::STACK, e.backtrace) unless e.backtrace.empty?
151
175
  end
152
176
 
177
+ # Mark the span started at the current time.
178
+ def start(start_time = nil)
179
+ # A span should not be started twice. However, this is existing
180
+ # behavior and so we maintain it for backward compatibility for those
181
+ # who are using async manual instrumentation that may rely on this
182
+
183
+ @start_time = start_time || Time.now.utc
184
+ @duration_start = start_time.nil? ? duration_marker : nil
185
+
186
+ self
187
+ end
188
+
189
+ # for backwards compatibility
190
+ def start_time=(time)
191
+ time.tap { start(time) }
192
+ end
193
+
194
+ # for backwards compatibility
195
+ def end_time=(time)
196
+ time.tap { finish(time) }
197
+ end
198
+
153
199
  # Mark the span finished at the current time and submit it.
154
200
  def finish(finish_time = nil)
155
201
  # A span should not be finished twice. Note that this is not thread-safe,
@@ -160,12 +206,15 @@ module Datadog
160
206
 
161
207
  @allocation_count_finish = now_allocations
162
208
 
163
- # Provide a default start_time if unset, but this should have been set by start_span.
164
- # Using now here causes 0-duration spans, still, this is expected, as we never
165
- # explicitely say when it started.
166
- @start_time ||= Time.now.utc
209
+ now = Time.now.utc
210
+
211
+ # Provide a default start_time if unset.
212
+ # Using `now` here causes duration to be 0; this is expected
213
+ # behavior when start_time is unknown.
214
+ start(finish_time || now) unless started?
167
215
 
168
- @end_time = finish_time.nil? ? Time.now.utc : finish_time # finish this
216
+ @end_time = finish_time || now
217
+ @duration_end = finish_time.nil? ? duration_marker : nil
169
218
 
170
219
  # Finish does not really do anything if the span is not bound to a tracer and a context.
171
220
  return self if @tracer.nil? || @context.nil?
@@ -185,11 +234,6 @@ module Datadog
185
234
  self
186
235
  end
187
236
 
188
- # Return whether the span is finished or not.
189
- def finished?
190
- !@end_time.nil?
191
- end
192
-
193
237
  # Return a string representation of the span.
194
238
  def to_s
195
239
  "Span(name:#{@name},sid:#{@span_id},tid:#{@trace_id},pid:#{@parent_id})"
@@ -236,19 +280,76 @@ module Datadog
236
280
  error: @status
237
281
  }
238
282
 
239
- if !@start_time.nil? && !@end_time.nil?
240
- h[:start] = (@start_time.to_f * 1e9).to_i
241
- h[:duration] = ((@end_time - @start_time) * 1e9).to_i
283
+ if finished?
284
+ h[:start] = start_time_nano
285
+ h[:duration] = duration_nano
242
286
  end
243
287
 
244
288
  h
245
289
  end
246
290
 
291
+ # MessagePack serializer interface. Making this object
292
+ # respond to `#to_msgpack` allows it to be automatically
293
+ # serialized by MessagePack.
294
+ #
295
+ # This is more efficient than doing +MessagePack.pack(span.to_hash)+
296
+ # as we don't have to create an intermediate Hash.
297
+ #
298
+ # @param packer [MessagePack::Packer] serialization buffer, can be +nil+ with JRuby
299
+ def to_msgpack(packer = nil)
300
+ # As of 1.3.3, JRuby implementation doesn't pass an existing packer
301
+ packer ||= MessagePack::Packer.new
302
+
303
+ if finished?
304
+ packer.write_map_header(13) # Set header with how many elements in the map
305
+
306
+ packer.write('start')
307
+ packer.write(start_time_nano)
308
+
309
+ packer.write('duration')
310
+ packer.write(duration_nano)
311
+ else
312
+ packer.write_map_header(11) # Set header with how many elements in the map
313
+ end
314
+
315
+ # DEV: We use strings as keys here, instead of symbols, as
316
+ # DEV: MessagePack will ultimately convert them to strings.
317
+ # DEV: By providing strings directly, we skip this indirection operation.
318
+ packer.write('span_id')
319
+ packer.write(@span_id)
320
+ packer.write('parent_id')
321
+ packer.write(@parent_id)
322
+ packer.write('trace_id')
323
+ packer.write(@trace_id)
324
+ packer.write('name')
325
+ packer.write(@name)
326
+ packer.write('service')
327
+ packer.write(@service)
328
+ packer.write('resource')
329
+ packer.write(@resource)
330
+ packer.write('type')
331
+ packer.write(@span_type)
332
+ packer.write('meta')
333
+ packer.write(@meta)
334
+ packer.write('metrics')
335
+ packer.write(@metrics)
336
+ packer.write('allocations')
337
+ packer.write(allocations)
338
+ packer.write('error')
339
+ packer.write(@status)
340
+ packer
341
+ end
342
+
343
+ # JSON serializer interface.
344
+ # Used by older version of the transport.
345
+ def to_json(*args)
346
+ to_hash.to_json(*args)
347
+ end
348
+
247
349
  # Return a human readable version of the span
248
350
  def pretty_print(q)
249
- start_time = (@start_time.to_f * 1e9).to_i rescue '-'
250
- end_time = (@end_time.to_f * 1e9).to_i rescue '-'
251
- duration = ((@end_time - @start_time) * 1e9).to_i rescue 0
351
+ start_time = (self.start_time.to_f * 1e9).to_i
352
+ end_time = (self.end_time.to_f * 1e9).to_i
252
353
  q.group 0 do
253
354
  q.breakable
254
355
  q.text "Name: #{@name}\n"
@@ -261,7 +362,7 @@ module Datadog
261
362
  q.text "Error: #{@status}\n"
262
363
  q.text "Start: #{start_time}\n"
263
364
  q.text "End: #{end_time}\n"
264
- q.text "Duration: #{duration}\n"
365
+ q.text "Duration: #{duration.to_f if finished?}\n"
265
366
  q.text "Allocations: #{allocations}\n"
266
367
  q.group(2, 'Tags: [', "]\n") do
267
368
  q.breakable
@@ -278,8 +379,30 @@ module Datadog
278
379
  end
279
380
  end
280
381
 
382
+ # Return whether the duration is started or not
383
+ def started?
384
+ !@start_time.nil?
385
+ end
386
+
387
+ # Return whether the duration is finished or not.
388
+ def finished?
389
+ !@end_time.nil?
390
+ end
391
+
392
+ def duration
393
+ if @duration_end.nil? || @duration_start.nil?
394
+ @end_time - @start_time
395
+ else
396
+ @duration_end - @duration_start
397
+ end
398
+ end
399
+
281
400
  private
282
401
 
402
+ def duration_marker
403
+ Utils::Time.get_time
404
+ end
405
+
283
406
  if defined?(JRUBY_VERSION) || Gem::Version.new(RUBY_VERSION) < Gem::Version.new(VERSION::MINIMUM_RUBY_VERSION)
284
407
  def now_allocations
285
408
  0
@@ -293,5 +416,17 @@ module Datadog
293
416
  GC.stat(:total_allocated_objects)
294
417
  end
295
418
  end
419
+
420
+ # Used for serialization
421
+ # @return [Integer] in nanoseconds since Epoch
422
+ def start_time_nano
423
+ @start_time.to_i * 1000000000 + @start_time.nsec
424
+ end
425
+
426
+ # Used for serialization
427
+ # @return [Integer] in nanoseconds since Epoch
428
+ def duration_nano
429
+ (duration * 1e9).to_i
430
+ end
296
431
  end
297
432
  end
@@ -1,4 +1,3 @@
1
- require 'pp'
2
1
  require 'thread'
3
2
  require 'logger'
4
3
  require 'pathname'
@@ -60,8 +59,8 @@ module Datadog
60
59
  #
61
60
  # This method makes use of a \ContextProvider that is automatically set during the tracer
62
61
  # initialization, or while using a library instrumentation.
63
- def call_context
64
- @provider.context
62
+ def call_context(key = nil)
63
+ @provider.context(key)
65
64
  end
66
65
 
67
66
  # Initialize a new \Tracer used to create, sample and submit spans that measure the
@@ -186,8 +185,7 @@ module Datadog
186
185
  # * +start_time+: when the span actually starts (defaults to \now)
187
186
  # * +tags+: extra tags which should be added to the span.
188
187
  def start_span(name, options = {})
189
- start_time = options.fetch(:start_time, Time.now.utc)
190
-
188
+ start_time = options[:start_time]
191
189
  tags = options.fetch(:tags, {})
192
190
 
193
191
  span_options = options.select do |k, _v|
@@ -212,9 +210,10 @@ module Datadog
212
210
  # child span
213
211
  span.parent = parent # sets service, trace_id, parent_id, sampled
214
212
  end
215
- @tags.each { |k, v| span.set_tag(k, v) } unless @tags.empty?
216
- tags.each { |k, v| span.set_tag(k, v) } unless tags.empty?
217
- span.start_time = start_time
213
+
214
+ span.set_tags(@tags) unless @tags.empty?
215
+ span.set_tags(tags) unless tags.empty?
216
+ span.start(start_time)
218
217
 
219
218
  # this could at some point be optional (start_active_span vs start_manual_span)
220
219
  ctx.add_span(span) unless ctx.nil?
@@ -255,9 +254,11 @@ module Datadog
255
254
  # * +service+: the service name for this span
256
255
  # * +resource+: the resource this span refers, or \name if it's missing
257
256
  # * +span_type+: the type of the span (such as \http, \db and so on)
257
+ # * +child_of+: a \Span or a \Context instance representing the parent for this span.
258
+ # If not set, defaults to Tracer.call_context
258
259
  # * +tags+: extra tags which should be added to the span.
259
260
  def trace(name, options = {})
260
- options[:child_of] = call_context
261
+ options[:child_of] ||= call_context
261
262
 
262
263
  # call the finish only if a block is given; this ensures
263
264
  # that a call to tracer.trace() without a block, returns
@@ -269,11 +270,16 @@ module Datadog
269
270
  begin
270
271
  begin
271
272
  span = start_span(name, options)
272
- # rubocop:disable Lint/UselessAssignment
273
273
  rescue StandardError => e
274
- Datadog.logger.debug('Failed to start span: #{e}')
274
+ Datadog.logger.debug("Failed to start span: #{e}")
275
275
  ensure
276
- return_value = yield(span)
276
+ # We should yield to the provided block when possible, as this
277
+ # block is application code that we don't want to hinder. We call:
278
+ # * `yield(span)` during normal execution.
279
+ # * `yield(nil)` if `start_span` fails with a runtime error.
280
+ # * We don't yield during a fatal error, as the application is likely trying to
281
+ # end its execution (either due to a system error or graceful shutdown).
282
+ return_value = yield(span) if span || e.is_a?(StandardError)
277
283
  end
278
284
  # rubocop:disable Lint/RescueException
279
285
  # Here we really want to catch *any* exception, not only StandardError,
@@ -318,18 +324,18 @@ module Datadog
318
324
  end
319
325
 
320
326
  # Return the current active span or +nil+.
321
- def active_span
322
- call_context.current_span
327
+ def active_span(key = nil)
328
+ call_context(key).current_span
323
329
  end
324
330
 
325
331
  # Return the current active root span or +nil+.
326
- def active_root_span
327
- call_context.current_root_span
332
+ def active_root_span(key = nil)
333
+ call_context(key).current_root_span
328
334
  end
329
335
 
330
336
  # Return a CorrelationIdentifier for active span
331
- def active_correlation
332
- Datadog::Correlation.identifier_from_context(call_context)
337
+ def active_correlation(key = nil)
338
+ Datadog::Correlation.identifier_from_context(call_context(key))
333
339
  end
334
340
 
335
341
  # Send the trace to the writer to enqueue the spans list in the agent