ddtrace 0.30.1 → 0.31.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 (85) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +28 -0
  3. data/.circleci/images/primary/Dockerfile-2.7.0 +73 -0
  4. data/Appraisals +111 -2
  5. data/CHANGELOG.md +33 -1
  6. data/Rakefile +69 -1
  7. data/ddtrace.gemspec +1 -0
  8. data/docker-compose.yml +30 -0
  9. data/docs/GettingStarted.md +28 -3
  10. data/lib/ddtrace.rb +6 -0
  11. data/lib/ddtrace/buffer.rb +3 -3
  12. data/lib/ddtrace/configuration/base.rb +2 -1
  13. data/lib/ddtrace/configuration/settings.rb +15 -2
  14. data/lib/ddtrace/context.rb +62 -57
  15. data/lib/ddtrace/context_flush.rb +51 -114
  16. data/lib/ddtrace/context_provider.rb +45 -0
  17. data/lib/ddtrace/contrib/action_cable/configuration/settings.rb +25 -0
  18. data/lib/ddtrace/contrib/action_cable/event.rb +65 -0
  19. data/lib/ddtrace/contrib/action_cable/events.rb +33 -0
  20. data/lib/ddtrace/contrib/action_cable/events/broadcast.rb +49 -0
  21. data/lib/ddtrace/contrib/action_cable/events/perform_action.rb +52 -0
  22. data/lib/ddtrace/contrib/action_cable/events/transmit.rb +50 -0
  23. data/lib/ddtrace/contrib/action_cable/ext.rb +23 -0
  24. data/lib/ddtrace/contrib/action_cable/instrumentation.rb +31 -0
  25. data/lib/ddtrace/contrib/action_cable/integration.rb +36 -0
  26. data/lib/ddtrace/contrib/action_cable/patcher.rb +27 -0
  27. data/lib/ddtrace/contrib/action_pack/action_controller/instrumentation.rb +2 -2
  28. data/lib/ddtrace/contrib/action_view/events/render_partial.rb +5 -3
  29. data/lib/ddtrace/contrib/action_view/events/render_template.rb +5 -3
  30. data/lib/ddtrace/contrib/action_view/instrumentation/partial_renderer.rb +2 -1
  31. data/lib/ddtrace/contrib/action_view/instrumentation/template_renderer.rb +4 -2
  32. data/lib/ddtrace/contrib/action_view/patcher.rb +1 -1
  33. data/lib/ddtrace/contrib/active_record/events/instantiation.rb +1 -1
  34. data/lib/ddtrace/contrib/active_record/events/sql.rb +1 -1
  35. data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +2 -2
  36. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +2 -2
  37. data/lib/ddtrace/contrib/dalli/patcher.rb +1 -1
  38. data/lib/ddtrace/contrib/dalli/quantize.rb +1 -1
  39. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +1 -1
  40. data/lib/ddtrace/contrib/excon/middleware.rb +3 -3
  41. data/lib/ddtrace/contrib/faraday/connection.rb +18 -0
  42. data/lib/ddtrace/contrib/faraday/integration.rb +1 -1
  43. data/lib/ddtrace/contrib/faraday/patcher.rb +3 -3
  44. data/lib/ddtrace/contrib/grape/endpoint.rb +5 -5
  45. data/lib/ddtrace/contrib/grape/patcher.rb +1 -1
  46. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +1 -1
  47. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +2 -2
  48. data/lib/ddtrace/contrib/grpc/patcher.rb +1 -1
  49. data/lib/ddtrace/contrib/http/instrumentation.rb +1 -1
  50. data/lib/ddtrace/contrib/mongodb/subscribers.rb +2 -2
  51. data/lib/ddtrace/contrib/patchable.rb +1 -1
  52. data/lib/ddtrace/contrib/patcher.rb +1 -1
  53. data/lib/ddtrace/contrib/rack/middlewares.rb +2 -2
  54. data/lib/ddtrace/contrib/rack/patcher.rb +2 -2
  55. data/lib/ddtrace/contrib/rack/request_queue.rb +1 -1
  56. data/lib/ddtrace/contrib/rails/configuration/settings.rb +1 -0
  57. data/lib/ddtrace/contrib/rails/framework.rb +12 -0
  58. data/lib/ddtrace/contrib/rake/instrumentation.rb +2 -2
  59. data/lib/ddtrace/contrib/redis/quantize.rb +1 -1
  60. data/lib/ddtrace/contrib/sinatra/tracer.rb +1 -1
  61. data/lib/ddtrace/ext/forced_tracing.rb +1 -1
  62. data/lib/ddtrace/ext/sampling.rb +3 -0
  63. data/lib/ddtrace/logger.rb +42 -0
  64. data/lib/ddtrace/metrics.rb +5 -5
  65. data/lib/ddtrace/monkey.rb +1 -1
  66. data/lib/ddtrace/pin.rb +1 -1
  67. data/lib/ddtrace/pipeline.rb +1 -1
  68. data/lib/ddtrace/propagation/http_propagator.rb +2 -2
  69. data/lib/ddtrace/runtime/cgroup.rb +1 -1
  70. data/lib/ddtrace/runtime/container.rb +1 -1
  71. data/lib/ddtrace/runtime/metrics.rb +1 -1
  72. data/lib/ddtrace/sampler.rb +1 -1
  73. data/lib/ddtrace/sampling/rule.rb +1 -1
  74. data/lib/ddtrace/sampling/rule_sampler.rb +4 -4
  75. data/lib/ddtrace/span.rb +24 -6
  76. data/lib/ddtrace/sync_writer.rb +4 -3
  77. data/lib/ddtrace/tracer.rb +37 -77
  78. data/lib/ddtrace/transport/http/client.rb +2 -2
  79. data/lib/ddtrace/utils.rb +1 -1
  80. data/lib/ddtrace/version.rb +2 -2
  81. data/lib/ddtrace/workers.rb +3 -3
  82. data/lib/ddtrace/writer.rb +3 -2
  83. metadata +44 -6
  84. data/lib/ddtrace/contrib/faraday/rack_builder.rb +0 -18
  85. data/lib/ddtrace/provider.rb +0 -21
@@ -30,7 +30,7 @@ module Datadog
30
30
  rescue StandardError => e
31
31
  # in case of an Exception we don't create a
32
32
  # `request.queuing` span
33
- Datadog::Tracer.log.debug("[rack] unable to parse request queue headers: #{e}")
33
+ Datadog::Logger.log.debug("[rack] unable to parse request queue headers: #{e}")
34
34
  nil
35
35
  end
36
36
  end
@@ -67,6 +67,7 @@ module Datadog
67
67
  option :tracer do |o|
68
68
  o.delegate_to { Datadog.tracer }
69
69
  o.on_set do |value|
70
+ Datadog.configuration[:action_cable][:tracer] = value
70
71
  Datadog.configuration[:active_record][:tracer] = value
71
72
  Datadog.configuration[:active_support][:tracer] = value
72
73
  Datadog.configuration[:action_pack][:tracer] = value
@@ -3,6 +3,7 @@ require 'ddtrace/ext/app_types'
3
3
 
4
4
  require 'ddtrace/contrib/active_record/integration'
5
5
  require 'ddtrace/contrib/active_support/integration'
6
+ require 'ddtrace/contrib/action_cable/integration'
6
7
  require 'ddtrace/contrib/action_pack/integration'
7
8
  require 'ddtrace/contrib/action_view/integration'
8
9
  require 'ddtrace/contrib/grape/endpoint'
@@ -23,6 +24,7 @@ module Datadog
23
24
  config = config_with_defaults
24
25
 
25
26
  activate_rack!(config)
27
+ activate_action_cable!(config)
26
28
  activate_active_support!(config)
27
29
  activate_action_pack!(config)
28
30
  activate_action_view!(config)
@@ -65,6 +67,16 @@ module Datadog
65
67
  )
66
68
  end
67
69
 
70
+ def self.activate_action_cable!(config)
71
+ return unless defined?(::ActionCable)
72
+
73
+ Datadog.configuration.use(
74
+ :action_cable,
75
+ service_name: "#{config[:service_name]}-#{Contrib::ActionCable::Ext::SERVICE_NAME}",
76
+ tracer: config[:tracer]
77
+ )
78
+ end
79
+
68
80
  def self.activate_action_pack!(config)
69
81
  return unless defined?(::ActionPack)
70
82
 
@@ -47,14 +47,14 @@ module Datadog
47
47
  span.set_tag(Ext::TAG_TASK_ARG_NAMES, arg_names)
48
48
  span.set_tag(Ext::TAG_INVOKE_ARGS, quantize_args(args)) unless args.nil?
49
49
  rescue StandardError => e
50
- Datadog::Tracer.log.debug("Error while tracing Rake invoke: #{e.message}")
50
+ Datadog::Logger.log.debug("Error while tracing Rake invoke: #{e.message}")
51
51
  end
52
52
 
53
53
  def annotate_execute!(span, args)
54
54
  span.resource = name
55
55
  span.set_tag(Ext::TAG_EXECUTE_ARGS, quantize_args(args.to_hash)) unless args.nil?
56
56
  rescue StandardError => e
57
- Datadog::Tracer.log.debug("Error while tracing Rake execute: #{e.message}")
57
+ Datadog::Logger.log.debug("Error while tracing Rake execute: #{e.message}")
58
58
  end
59
59
 
60
60
  def quantize_args(args)
@@ -15,7 +15,7 @@ module Datadog
15
15
  str = Utils.utf8_encode(str, binary: true, placeholder: PLACEHOLDER)
16
16
  Utils.truncate(str, VALUE_MAX_LEN, TOO_LONG_MARK)
17
17
  rescue => e
18
- Datadog::Tracer.log.debug("non formattable Redis arg #{str}: #{e}")
18
+ Datadog::Logger.log.debug("non formattable Redis arg #{str}: #{e}")
19
19
  PLACEHOLDER
20
20
  end
21
21
 
@@ -68,7 +68,7 @@ module Datadog
68
68
  span = Sinatra::Env.datadog_span(env)
69
69
 
70
70
  unless span
71
- Datadog::Tracer.log.error('missing request span in :after hook')
71
+ Datadog::Logger.log.error('missing request span in :after hook')
72
72
  return
73
73
  end
74
74
 
@@ -12,7 +12,7 @@ module Datadog
12
12
 
13
13
  # Only log each deprecation warning once (safeguard against log spam)
14
14
  unless @deprecation_warning_shown
15
- Datadog::Tracer.log.warn(
15
+ Datadog::Logger.log.warn(
16
16
  'forced tracing: Datadog::Ext::ForcedTracing has been renamed to Datadog::Ext::ManualTracing'
17
17
  )
18
18
  @deprecation_warning_shown = true
@@ -1,6 +1,9 @@
1
1
  module Datadog
2
2
  module Ext
3
3
  module Sampling
4
+ ENV_SAMPLE_RATE = 'DD_TRACE_SAMPLE_RATE'.freeze
5
+ ENV_RATE_LIMIT = 'DD_TRACE_RATE_LIMIT'.freeze
6
+
4
7
  # If rule sampling is applied to a span, set this metric the sample rate configured for that rule.
5
8
  # This should be done regardless of sampling outcome.
6
9
  RULE_SAMPLE_RATE = '_dd.rule_psr'.freeze
@@ -7,6 +7,48 @@ module Datadog
7
7
  # - progname defaults to ddtrace to clearly identify Datadog dd-trace-rb related messages
8
8
  # - adds last caller stack-trace info to know where the message comes from
9
9
  class Logger < ::Logger
10
+ # Global, memoized, lazy initialized instance of a logger that is used within the the Datadog
11
+ # namespace. This logger outputs to +STDOUT+ by default, and is considered thread-safe.
12
+ class << self
13
+ def log
14
+ unless defined? @logger
15
+ @logger = Datadog::Logger.new(STDOUT)
16
+ @logger.level = Logger::WARN
17
+ end
18
+ @logger
19
+ end
20
+
21
+ # Override the default logger with a custom one.
22
+ def log=(logger)
23
+ return unless logger
24
+ return unless logger.respond_to? :methods
25
+ return unless logger.respond_to? :error
26
+ if logger.respond_to? :methods
27
+ unimplemented = new(STDOUT).methods - logger.methods
28
+ unless unimplemented.empty?
29
+ logger.error("logger #{logger} does not implement #{unimplemented}")
30
+ return
31
+ end
32
+ end
33
+ @logger = logger
34
+ end
35
+
36
+ # Activate the debug mode providing more information related to tracer usage
37
+ # Default to Warn level unless using custom logger
38
+ def debug_logging=(value)
39
+ if value
40
+ log.level = Logger::DEBUG
41
+ elsif log.is_a?(Datadog::Logger)
42
+ log.level = Logger::WARN
43
+ end
44
+ end
45
+
46
+ # Return if the debug mode is activated or not
47
+ def debug_logging
48
+ log.level == Logger::DEBUG
49
+ end
50
+ end
51
+
10
52
  def initialize(*args, &block)
11
53
  super
12
54
  self.progname = LOG_PREFIX
@@ -62,7 +62,7 @@ module Datadog
62
62
 
63
63
  statsd.count(stat, value, metric_options(options))
64
64
  rescue StandardError => e
65
- Datadog::Tracer.log.error("Failed to send count stat. Cause: #{e.message} Source: #{e.backtrace.first}")
65
+ Datadog::Logger.log.error("Failed to send count stat. Cause: #{e.message} Source: #{e.backtrace.first}")
66
66
  end
67
67
 
68
68
  def distribution(stat, value = nil, options = nil, &block)
@@ -72,7 +72,7 @@ module Datadog
72
72
 
73
73
  statsd.distribution(stat, value, metric_options(options))
74
74
  rescue StandardError => e
75
- Datadog::Tracer.log.error("Failed to send distribution stat. Cause: #{e.message} Source: #{e.backtrace.first}")
75
+ Datadog::Logger.log.error("Failed to send distribution stat. Cause: #{e.message} Source: #{e.backtrace.first}")
76
76
  end
77
77
 
78
78
  def increment(stat, options = nil)
@@ -81,7 +81,7 @@ module Datadog
81
81
 
82
82
  statsd.increment(stat, metric_options(options))
83
83
  rescue StandardError => e
84
- Datadog::Tracer.log.error("Failed to send increment stat. Cause: #{e.message} Source: #{e.backtrace.first}")
84
+ Datadog::Logger.log.error("Failed to send increment stat. Cause: #{e.message} Source: #{e.backtrace.first}")
85
85
  end
86
86
 
87
87
  def gauge(stat, value = nil, options = nil, &block)
@@ -91,7 +91,7 @@ module Datadog
91
91
 
92
92
  statsd.gauge(stat, value, metric_options(options))
93
93
  rescue StandardError => e
94
- Datadog::Tracer.log.error("Failed to send gauge stat. Cause: #{e.message} Source: #{e.backtrace.first}")
94
+ Datadog::Logger.log.error("Failed to send gauge stat. Cause: #{e.message} Source: #{e.backtrace.first}")
95
95
  end
96
96
 
97
97
  def time(stat, options = nil)
@@ -107,7 +107,7 @@ module Datadog
107
107
  distribution(stat, ((finished - start) * 1000), options)
108
108
  end
109
109
  rescue StandardError => e
110
- Datadog::Tracer.log.error("Failed to send time stat. Cause: #{e.message} Source: #{e.backtrace.first}")
110
+ Datadog::Logger.log.error("Failed to send time stat. Cause: #{e.message} Source: #{e.backtrace.first}")
111
111
  end
112
112
  end
113
113
 
@@ -48,7 +48,7 @@ module Datadog
48
48
  end
49
49
 
50
50
  def log_deprecation_warning(method)
51
- Datadog::Tracer.log.warn("#{method}:#{DEPRECATION_WARNING}")
51
+ Datadog::Logger.log.warn("#{method}:#{DEPRECATION_WARNING}")
52
52
  end
53
53
 
54
54
  class << self
@@ -107,7 +107,7 @@ module Datadog
107
107
  def log_deprecation_warning(method_name)
108
108
  # Only log each deprecation warning once (safeguard against log spam)
109
109
  do_once(method_name) do
110
- Datadog::Tracer.log.warn("#{method_name}:#{DEPRECATION_WARNING}")
110
+ Datadog::Logger.log.warn("#{method_name}:#{DEPRECATION_WARNING}")
111
111
  end
112
112
  end
113
113
  end
@@ -34,7 +34,7 @@ module Datadog
34
34
 
35
35
  result || []
36
36
  rescue => e
37
- Datadog::Tracer.log.debug(
37
+ Datadog::Logger.log.debug(
38
38
  "trace dropped entirely due to `Pipeline.before_flush` error: #{e}"
39
39
  )
40
40
 
@@ -19,7 +19,7 @@ module Datadog
19
19
  def self.inject!(context, env)
20
20
  # Prevent propagation from being attempted if context provided is nil.
21
21
  if context.nil?
22
- ::Datadog::Tracer.log.debug('Cannot inject context into env to propagate over HTTP: context is nil.'.freeze)
22
+ ::Datadog::Logger.log.debug('Cannot inject context into env to propagate over HTTP: context is nil.'.freeze)
23
23
  return
24
24
  end
25
25
 
@@ -58,7 +58,7 @@ module Datadog
58
58
  # Return an empty/new context if we have a mismatch in values extracted
59
59
  msg = "#{context.trace_id} != #{extracted_context.trace_id} && " \
60
60
  "#{context.span_id} != #{extracted_context.span_id}"
61
- ::Datadog::Tracer.log.debug("Cannot extract context from HTTP: extracted contexts differ, #{msg}".freeze)
61
+ ::Datadog::Logger.log.debug("Cannot extract context from HTTP: extracted contexts differ, #{msg}".freeze)
62
62
  # DEV: This will return from `self.extract` not this `each` block
63
63
  return ::Datadog::Context.new
64
64
  end
@@ -27,7 +27,7 @@ module Datadog
27
27
  end
28
28
  end
29
29
  rescue StandardError => e
30
- Datadog::Tracer.log.error("Error while parsing cgroup. Cause: #{e.message} Location: #{e.backtrace.first}")
30
+ Datadog::Logger.log.error("Error while parsing cgroup. Cause: #{e.message} Location: #{e.backtrace.first}")
31
31
  end
32
32
  end
33
33
  end
@@ -61,7 +61,7 @@ module Datadog
61
61
  break
62
62
  end
63
63
  rescue StandardError => e
64
- Datadog::Tracer.log.error(
64
+ Datadog::Logger.log.error(
65
65
  "Error while parsing container info. Cause: #{e.message} Location: #{e.backtrace.first}"
66
66
  )
67
67
  end
@@ -63,7 +63,7 @@ module Datadog
63
63
  def try_flush
64
64
  yield
65
65
  rescue StandardError => e
66
- Datadog::Tracer.log.error("Error while sending runtime metric. Cause: #{e.message}")
66
+ Datadog::Logger.log.error("Error while sending runtime metric. Cause: #{e.message}")
67
67
  end
68
68
 
69
69
  def default_metric_options
@@ -48,7 +48,7 @@ module Datadog
48
48
  # sampled.
49
49
  def initialize(sample_rate = 1.0)
50
50
  unless sample_rate > 0.0 && sample_rate <= 1.0
51
- Datadog::Tracer.log.error('sample rate is not between 0 and 1, disabling the sampler')
51
+ Datadog::Logger.log.error('sample rate is not between 0 and 1, disabling the sampler')
52
52
  sample_rate = 1.0
53
53
  end
54
54
 
@@ -28,7 +28,7 @@ module Datadog
28
28
  def match?(span)
29
29
  @matcher.match?(span)
30
30
  rescue => e
31
- Datadog::Tracer.log.error("Matcher failed. Cause: #{e.message} Source: #{e.backtrace.first}")
31
+ Datadog::Logger.log.error("Matcher failed. Cause: #{e.message} Source: #{e.backtrace.first}")
32
32
  nil
33
33
  end
34
34
 
@@ -19,15 +19,15 @@ module Datadog
19
19
  attr_reader :rules, :rate_limiter, :default_sampler
20
20
 
21
21
  # @param rules [Array<Rule>] ordered list of rules to be applied to a span
22
- # @param rate_limit [Float] number of traces per second, defaults to 100
22
+ # @param rate_limit [Float] number of traces per second, defaults to +100+
23
23
  # @param rate_limiter [RateLimiter] limiter applied after rule matching
24
24
  # @param default_sample_rate [Float] fallback sample rate when no rules apply to a span,
25
25
  # between +[0,1]+, defaults to +1+
26
26
  # @param default_sampler [Sample] fallback strategy when no rules apply to a span
27
27
  def initialize(rules = [],
28
- rate_limit: nil,
28
+ rate_limit: Datadog.configuration.sampling.rate_limit,
29
29
  rate_limiter: nil,
30
- default_sample_rate: nil,
30
+ default_sample_rate: Datadog.configuration.sampling.default_rate,
31
31
  default_sampler: nil)
32
32
 
33
33
  @rules = rules
@@ -95,7 +95,7 @@ module Datadog
95
95
  set_limiter_metrics(span, rate_limiter.effective_rate)
96
96
  end
97
97
  rescue StandardError => e
98
- Datadog::Tracer.log.error("Rule sampling failed. Cause: #{e.message} Source: #{e.backtrace.first}")
98
+ Datadog::Logger.log.error("Rule sampling failed. Cause: #{e.message} Source: #{e.backtrace.first}")
99
99
  yield(span)
100
100
  end
101
101
 
@@ -31,6 +31,9 @@ module Datadog
31
31
  # parsing 64-bit integers for distributed tracing since an upstream system may generate one
32
32
  EXTERNAL_MAX_ID = 2**64
33
33
 
34
+ # This limit is for numeric tags because uint64 could end up rounded.
35
+ NUMERIC_TAG_SIZE_RANGE = (-2**53..2**53)
36
+
34
37
  attr_accessor :name, :service, :resource, :span_type,
35
38
  :start_time, :end_time,
36
39
  :span_id, :trace_id, :parent_id,
@@ -80,9 +83,21 @@ module Datadog
80
83
  #
81
84
  # span.set_tag('http.method', request.method)
82
85
  def set_tag(key, value = nil)
83
- @meta[key] = value.to_s
86
+ # Keys must be unique between tags and metrics
87
+ @metrics.delete(key)
88
+
89
+ # NOTE: Adding numeric tags as metrics is stop-gap support
90
+ # for numeric typed tags. Eventually they will become
91
+ # tags again.
92
+ # Any numeric that is not an integer greater than max size is logged as a metric.
93
+ # Everything else gets logged as a tag.
94
+ if value.is_a?(Numeric) && !(value.is_a?(Integer) && !NUMERIC_TAG_SIZE_RANGE.cover?(value))
95
+ set_metric(key, value)
96
+ else
97
+ @meta[key] = value.to_s
98
+ end
84
99
  rescue StandardError => e
85
- Datadog::Tracer.log.debug("Unable to set the tag #{key}, ignoring it. Caused by: #{e}")
100
+ Datadog::Logger.log.debug("Unable to set the tag #{key}, ignoring it. Caused by: #{e}")
86
101
  end
87
102
 
88
103
  # This method removes a tag for the given key.
@@ -92,17 +107,20 @@ module Datadog
92
107
 
93
108
  # Return the tag with the given key, nil if it doesn't exist.
94
109
  def get_tag(key)
95
- @meta[key]
110
+ @meta[key] || @metrics[key]
96
111
  end
97
112
 
98
113
  # This method sets a tag with a floating point value for the given key. It acts
99
114
  # like `set_tag()` and it simply add a tag without further processing.
100
115
  def set_metric(key, value)
116
+ # Keys must be unique between tags and metrics
117
+ @meta.delete(key)
118
+
101
119
  # enforce that the value is a floating point number
102
120
  value = Float(value)
103
121
  @metrics[key] = value
104
122
  rescue StandardError => e
105
- Datadog::Tracer.log.debug("Unable to set the metric #{key}, ignoring it. Caused by: #{e}")
123
+ Datadog::Logger.log.debug("Unable to set the metric #{key}, ignoring it. Caused by: #{e}")
106
124
  end
107
125
 
108
126
  # This method removes a metric for the given key. It acts like {#remove_tag}.
@@ -112,7 +130,7 @@ module Datadog
112
130
 
113
131
  # Return the metric with the given key, nil if it doesn't exist.
114
132
  def get_metric(key)
115
- @metrics[key]
133
+ @metrics[key] || @meta[key]
116
134
  end
117
135
 
118
136
  # Mark the span with the given error.
@@ -154,7 +172,7 @@ module Datadog
154
172
  @context.close_span(self)
155
173
  @tracer.record(self)
156
174
  rescue StandardError => e
157
- Datadog::Tracer.log.debug("error recording finished trace: #{e}")
175
+ Datadog::Logger.log.debug("error recording finished trace: #{e}")
158
176
  Diagnostics::Health.metrics.error_span_finish(1, tags: ["error:#{e.class.name}"])
159
177
  end
160
178
  self
@@ -27,7 +27,7 @@ module Datadog
27
27
  def write(trace, services = nil)
28
28
  unless services.nil?
29
29
  Datadog::Patcher.do_once('SyncWriter#write') do
30
- Datadog::Tracer.log.warn(%(
30
+ Datadog::Logger.log.warn(%(
31
31
  write: Writing services has been deprecated and no longer need to be provided.
32
32
  write(traces, services) can be updted to write(traces)
33
33
  ))
@@ -38,7 +38,7 @@ module Datadog
38
38
  proc { flush_trace(trace) }
39
39
  )
40
40
  rescue => e
41
- Tracer.log.debug(e)
41
+ Logger.log.debug(e)
42
42
  end
43
43
 
44
44
  private
@@ -49,8 +49,9 @@ module Datadog
49
49
 
50
50
  def flush_trace(trace)
51
51
  processed_traces = Pipeline.process!([trace])
52
+ return if processed_traces.empty?
52
53
  inject_hostname!(processed_traces.first) if Datadog.configuration.report_hostname
53
- transport.send(:traces, processed_traces)
54
+ transport.send_traces(processed_traces)
54
55
  end
55
56
 
56
57
  def inject_hostname!(trace)
@@ -5,8 +5,6 @@ require 'pathname'
5
5
 
6
6
  require 'ddtrace/span'
7
7
  require 'ddtrace/context'
8
- require 'ddtrace/context_flush'
9
- require 'ddtrace/provider'
10
8
  require 'ddtrace/logger'
11
9
  require 'ddtrace/writer'
12
10
  require 'ddtrace/sampler'
@@ -21,57 +19,17 @@ module Datadog
21
19
  # of these function calls and sub-requests would be encapsulated within a single trace.
22
20
  # rubocop:disable Metrics/ClassLength
23
21
  class Tracer
24
- attr_reader :sampler, :tags, :provider
22
+ attr_reader :sampler, :tags, :provider, :context_flush
25
23
  attr_accessor :enabled, :writer
26
24
  attr_writer :default_service
27
25
 
28
26
  ALLOWED_SPAN_OPTIONS = [:service, :resource, :span_type].freeze
29
27
  DEFAULT_ON_ERROR = proc { |span, error| span.set_error(error) unless span.nil? }
30
28
 
31
- # Global, memoized, lazy initialized instance of a logger that is used within the the Datadog
32
- # namespace. This logger outputs to +STDOUT+ by default, and is considered thread-safe.
33
- def self.log
34
- unless defined? @logger
35
- @logger = Datadog::Logger.new(STDOUT)
36
- @logger.level = Logger::WARN
37
- end
38
- @logger
39
- end
40
-
41
- # Override the default logger with a custom one.
42
- def self.log=(logger)
43
- return unless logger
44
- return unless logger.respond_to? :methods
45
- return unless logger.respond_to? :error
46
- if logger.respond_to? :methods
47
- unimplemented = Logger.new(STDOUT).methods - logger.methods
48
- unless unimplemented.empty?
49
- logger.error("logger #{logger} does not implement #{unimplemented}")
50
- return
51
- end
52
- end
53
- @logger = logger
54
- end
55
-
56
- # Activate the debug mode providing more information related to tracer usage
57
- # Default to Warn level unless using custom logger
58
- def self.debug_logging=(value)
59
- if value
60
- log.level = Logger::DEBUG
61
- elsif log.is_a?(Datadog::Logger)
62
- log.level = Logger::WARN
63
- end
64
- end
65
-
66
- # Return if the debug mode is activated or not
67
- def self.debug_logging
68
- log.level == Logger::DEBUG
69
- end
70
-
71
29
  def services
72
30
  # Only log each deprecation warning once (safeguard against log spam)
73
31
  Datadog::Patcher.do_once('Tracer#set_service_info') do
74
- Datadog::Tracer.log.warn('services: Usage of Tracer.services has been deprecated')
32
+ Datadog::Logger.log.warn('services: Usage of Tracer.services has been deprecated')
75
33
  end
76
34
 
77
35
  {}
@@ -90,8 +48,9 @@ module Datadog
90
48
  # tracer.shutdown!
91
49
  #
92
50
  def shutdown!
93
- return if !@enabled || @writer.worker.nil?
94
- @writer.worker.stop
51
+ return unless @enabled
52
+
53
+ @writer.stop unless @writer.nil?
95
54
  end
96
55
 
97
56
  # Return the current active \Context for this traced execution. This method is
@@ -117,7 +76,11 @@ module Datadog
117
76
  @provider = options.fetch(:context_provider, Datadog::DefaultContextProvider.new)
118
77
  @provider ||= Datadog::DefaultContextProvider.new # @provider should never be nil
119
78
 
120
- @context_flush = options[:partial_flush] ? Datadog::ContextFlush.new(options) : nil
79
+ @context_flush = if options[:partial_flush]
80
+ Datadog::ContextFlush::Partial.new(options)
81
+ else
82
+ Datadog::ContextFlush::Finished.new
83
+ end
121
84
 
122
85
  @mutex = Mutex.new
123
86
  @tags = {}
@@ -132,6 +95,7 @@ module Datadog
132
95
  # * +enabled+: set if the tracer submits or not spans to the trace agent
133
96
  # * +hostname+: change the location of the trace agent
134
97
  # * +port+: change the port of the trace agent
98
+ # * +partial_flush+: enable partial trace flushing
135
99
  #
136
100
  # For instance, if the trace agent runs in a different location, just:
137
101
  #
@@ -142,18 +106,17 @@ module Datadog
142
106
 
143
107
  # Those are rare "power-user" options.
144
108
  sampler = options.fetch(:sampler, nil)
145
- max_spans_before_partial_flush = options.fetch(:max_spans_before_partial_flush, nil)
146
- min_spans_before_partial_flush = options.fetch(:min_spans_before_partial_flush, nil)
147
- partial_flush_timeout = options.fetch(:partial_flush_timeout, nil)
148
109
 
149
110
  @enabled = enabled unless enabled.nil?
150
111
  @sampler = sampler unless sampler.nil?
151
112
 
152
113
  configure_writer(options)
153
114
 
154
- @context_flush = Datadog::ContextFlush.new(options) unless min_spans_before_partial_flush.nil? &&
155
- max_spans_before_partial_flush.nil? &&
156
- partial_flush_timeout.nil?
115
+ @context_flush = if options[:partial_flush]
116
+ Datadog::ContextFlush::Partial.new(options)
117
+ else
118
+ Datadog::ContextFlush::Finished.new
119
+ end
157
120
  end
158
121
 
159
122
  # Set the information about the given service. A valid example is:
@@ -164,7 +127,7 @@ module Datadog
164
127
  def set_service_info(service, app, app_type)
165
128
  # Only log each deprecation warning once (safeguard against log spam)
166
129
  Datadog::Patcher.do_once('Tracer#set_service_info') do
167
- Datadog::Tracer.log.warn(%(
130
+ Datadog::Logger.log.warn(%(
168
131
  set_service_info: Usage of set_service_info has been deprecated,
169
132
  service information no longer needs to be reported to the trace agent.
170
133
  ))
@@ -179,7 +142,7 @@ module Datadog
179
142
  begin
180
143
  @default_service = File.basename($PROGRAM_NAME, '.*')
181
144
  rescue StandardError => e
182
- Datadog::Tracer.log.error("unable to guess default service: #{e}")
145
+ Datadog::Logger.log.error("unable to guess default service: #{e}")
183
146
  @default_service = 'ruby'.freeze
184
147
  end
185
148
  @default_service
@@ -302,7 +265,7 @@ module Datadog
302
265
  span = start_span(name, options)
303
266
  # rubocop:disable Lint/UselessAssignment
304
267
  rescue StandardError => e
305
- Datadog::Tracer.log.debug('Failed to start span: #{e}')
268
+ Datadog::Logger.log.debug('Failed to start span: #{e}')
306
269
  ensure
307
270
  return_value = yield(span)
308
271
  end
@@ -332,24 +295,20 @@ module Datadog
332
295
  def record(context)
333
296
  context = context.context if context.is_a?(Datadog::Span)
334
297
  return if context.nil?
335
- trace, sampled = context.get
336
-
337
- # If context flushing is configured...
338
- if @context_flush
339
- if sampled
340
- if trace.nil? || trace.empty?
341
- @context_flush.each_partial_trace(context) do |t|
342
- write(t)
343
- end
344
- else
345
- write(trace)
346
- end
347
- end
348
- # Default behavior
349
- else
350
- ready = !trace.nil? && !trace.empty? && sampled
351
- write(trace) if ready
352
- end
298
+
299
+ record_context(context)
300
+ end
301
+
302
+ # Consume trace from +context+, according to +@context_flush+
303
+ # criteria.
304
+ #
305
+ # \ContextFlush#consume! can return nil or an empty list if the
306
+ # trace is not available to flush or if the trace has not been
307
+ # chosen to be sampled.
308
+ def record_context(context)
309
+ trace = @context_flush.consume!(context)
310
+
311
+ write(trace) if trace && !trace.empty?
353
312
  end
354
313
 
355
314
  # Return the current active span or +nil+.
@@ -372,11 +331,11 @@ module Datadog
372
331
  def write(trace)
373
332
  return if @writer.nil? || !@enabled
374
333
 
375
- if Datadog::Tracer.debug_logging
376
- Datadog::Tracer.log.debug("Writing #{trace.length} spans (enabled: #{@enabled})")
334
+ if Datadog::Logger.debug_logging
335
+ Datadog::Logger.log.debug("Writing #{trace.length} spans (enabled: #{@enabled})")
377
336
  str = String.new('')
378
337
  PP.pp(trace, str)
379
- Datadog::Tracer.log.debug(str)
338
+ Datadog::Logger.log.debug(str)
380
339
  end
381
340
 
382
341
  @writer.write(trace)
@@ -461,6 +420,7 @@ module Datadog
461
420
  :configure_writer,
462
421
  :deactivate_priority_sampling!,
463
422
  :guess_context_and_parent,
423
+ :record_context,
464
424
  :write
465
425
  end
466
426
  end