ddtrace 1.5.2 → 1.6.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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -1
  3. data/ext/ddtrace_profiling_loader/ddtrace_profiling_loader.c +9 -2
  4. data/ext/ddtrace_profiling_loader/extconf.rb +17 -0
  5. data/ext/ddtrace_profiling_native_extension/NativeExtensionDesign.md +38 -2
  6. data/ext/ddtrace_profiling_native_extension/clock_id.h +1 -0
  7. data/ext/ddtrace_profiling_native_extension/clock_id_from_pthread.c +1 -0
  8. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.c +517 -42
  9. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time.h +3 -0
  10. data/ext/ddtrace_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +208 -30
  11. data/ext/ddtrace_profiling_native_extension/collectors_stack.c +156 -46
  12. data/ext/ddtrace_profiling_native_extension/collectors_stack.h +11 -2
  13. data/ext/ddtrace_profiling_native_extension/extconf.rb +11 -1
  14. data/ext/ddtrace_profiling_native_extension/http_transport.c +83 -64
  15. data/ext/ddtrace_profiling_native_extension/libdatadog_helpers.h +4 -4
  16. data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +3 -2
  17. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.c +59 -0
  18. data/ext/ddtrace_profiling_native_extension/private_vm_api_access.h +3 -0
  19. data/ext/ddtrace_profiling_native_extension/profiling.c +10 -0
  20. data/ext/ddtrace_profiling_native_extension/ruby_helpers.c +0 -1
  21. data/ext/ddtrace_profiling_native_extension/ruby_helpers.h +4 -2
  22. data/ext/ddtrace_profiling_native_extension/stack_recorder.c +45 -29
  23. data/ext/ddtrace_profiling_native_extension/stack_recorder.h +7 -7
  24. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +4 -0
  25. data/lib/datadog/appsec/event.rb +6 -0
  26. data/lib/datadog/core/configuration/components.rb +20 -14
  27. data/lib/datadog/core/configuration/settings.rb +42 -4
  28. data/lib/datadog/core/diagnostics/environment_logger.rb +5 -1
  29. data/lib/datadog/core/utils/compression.rb +5 -1
  30. data/lib/datadog/core.rb +0 -54
  31. data/lib/datadog/profiling/collectors/cpu_and_wall_time.rb +12 -2
  32. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +5 -3
  33. data/lib/datadog/profiling/exporter.rb +2 -4
  34. data/lib/datadog/profiling/http_transport.rb +1 -1
  35. data/lib/datadog/tracing/configuration/ext.rb +1 -0
  36. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +2 -0
  37. data/lib/datadog/tracing/contrib/dalli/ext.rb +1 -0
  38. data/lib/datadog/tracing/contrib/dalli/instrumentation.rb +4 -0
  39. data/lib/datadog/tracing/contrib/elasticsearch/ext.rb +2 -0
  40. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +3 -0
  41. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +2 -0
  42. data/lib/datadog/tracing/contrib/ethon/multi_patch.rb +2 -0
  43. data/lib/datadog/tracing/contrib/excon/middleware.rb +2 -0
  44. data/lib/datadog/tracing/contrib/ext.rb +6 -0
  45. data/lib/datadog/tracing/contrib/faraday/middleware.rb +2 -0
  46. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/client.rb +5 -0
  47. data/lib/datadog/tracing/contrib/grpc/datadog_interceptor/server.rb +7 -1
  48. data/lib/datadog/tracing/contrib/grpc/ext.rb +2 -0
  49. data/lib/datadog/tracing/contrib/hanami/action_tracer.rb +47 -0
  50. data/lib/datadog/tracing/contrib/hanami/configuration/settings.rb +22 -0
  51. data/lib/datadog/tracing/contrib/hanami/ext.rb +24 -0
  52. data/lib/datadog/tracing/contrib/hanami/integration.rb +44 -0
  53. data/lib/datadog/tracing/contrib/hanami/patcher.rb +33 -0
  54. data/lib/datadog/tracing/contrib/hanami/plugin.rb +23 -0
  55. data/lib/datadog/tracing/contrib/hanami/renderer_policy_tracing.rb +41 -0
  56. data/lib/datadog/tracing/contrib/hanami/router_tracing.rb +44 -0
  57. data/lib/datadog/tracing/contrib/http/instrumentation.rb +2 -0
  58. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +2 -0
  59. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +2 -0
  60. data/lib/datadog/tracing/contrib/mongodb/ext.rb +7 -0
  61. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +4 -0
  62. data/lib/datadog/tracing/contrib/mysql2/configuration/settings.rb +12 -0
  63. data/lib/datadog/tracing/contrib/mysql2/ext.rb +1 -0
  64. data/lib/datadog/tracing/contrib/mysql2/instrumentation.rb +16 -0
  65. data/lib/datadog/tracing/contrib/pg/configuration/settings.rb +12 -0
  66. data/lib/datadog/tracing/contrib/pg/ext.rb +2 -1
  67. data/lib/datadog/tracing/contrib/pg/instrumentation.rb +34 -18
  68. data/lib/datadog/tracing/contrib/propagation/sql_comment/comment.rb +43 -0
  69. data/lib/datadog/tracing/contrib/propagation/sql_comment/ext.rb +32 -0
  70. data/lib/datadog/tracing/contrib/propagation/sql_comment/mode.rb +28 -0
  71. data/lib/datadog/tracing/contrib/propagation/sql_comment.rb +49 -0
  72. data/lib/datadog/tracing/contrib/rack/middlewares.rb +11 -5
  73. data/lib/datadog/tracing/contrib/redis/ext.rb +2 -0
  74. data/lib/datadog/tracing/contrib/redis/instrumentation.rb +4 -2
  75. data/lib/datadog/tracing/contrib/redis/patcher.rb +41 -0
  76. data/lib/datadog/tracing/contrib/redis/tags.rb +5 -0
  77. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +2 -0
  78. data/lib/datadog/tracing/contrib/sinatra/env.rb +12 -23
  79. data/lib/datadog/tracing/contrib/sinatra/ext.rb +7 -3
  80. data/lib/datadog/tracing/contrib/sinatra/patcher.rb +2 -2
  81. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +8 -80
  82. data/lib/datadog/tracing/contrib/sinatra/tracer_middleware.rb +14 -9
  83. data/lib/datadog/tracing/contrib.rb +1 -0
  84. data/lib/datadog/tracing/distributed/datadog_tags_codec.rb +84 -0
  85. data/lib/datadog/tracing/distributed/headers/datadog.rb +122 -30
  86. data/lib/datadog/tracing/distributed/headers/ext.rb +2 -0
  87. data/lib/datadog/tracing/flush.rb +1 -1
  88. data/lib/datadog/tracing/metadata/ext.rb +8 -0
  89. data/lib/datadog/tracing/propagation/http.rb +9 -1
  90. data/lib/datadog/tracing/sampling/ext.rb +31 -0
  91. data/lib/datadog/tracing/sampling/priority_sampler.rb +46 -4
  92. data/lib/datadog/tracing/sampling/rate_by_key_sampler.rb +8 -9
  93. data/lib/datadog/tracing/sampling/rate_by_service_sampler.rb +29 -5
  94. data/lib/datadog/tracing/sampling/rate_sampler.rb +10 -3
  95. data/lib/datadog/tracing/sampling/rule_sampler.rb +4 -3
  96. data/lib/datadog/tracing/sampling/span/ext.rb +0 -4
  97. data/lib/datadog/tracing/sampling/span/rule.rb +1 -1
  98. data/lib/datadog/tracing/sampling/span/sampler.rb +14 -3
  99. data/lib/datadog/tracing/trace_digest.rb +3 -0
  100. data/lib/datadog/tracing/trace_operation.rb +10 -0
  101. data/lib/datadog/tracing/trace_segment.rb +6 -0
  102. data/lib/datadog/tracing/tracer.rb +3 -1
  103. data/lib/datadog/tracing/writer.rb +7 -0
  104. data/lib/ddtrace/transport/trace_formatter.rb +7 -0
  105. data/lib/ddtrace/transport/traces.rb +1 -1
  106. data/lib/ddtrace/version.rb +2 -2
  107. metadata +18 -14
  108. data/lib/datadog/profiling/old_ext.rb +0 -42
  109. data/lib/datadog/profiling/transport/http/api/endpoint.rb +0 -85
  110. data/lib/datadog/profiling/transport/http/api/instance.rb +0 -38
  111. data/lib/datadog/profiling/transport/http/api/spec.rb +0 -42
  112. data/lib/datadog/profiling/transport/http/api.rb +0 -45
  113. data/lib/datadog/profiling/transport/http/builder.rb +0 -30
  114. data/lib/datadog/profiling/transport/http/client.rb +0 -37
  115. data/lib/datadog/profiling/transport/http/response.rb +0 -21
  116. data/lib/datadog/profiling/transport/http.rb +0 -118
@@ -5,6 +5,9 @@ require_relative '../analytics'
5
5
  require_relative '../ext'
6
6
  require_relative 'ext'
7
7
 
8
+ require_relative '../propagation/sql_comment'
9
+ require_relative '../propagation/sql_comment/mode'
10
+
8
11
  module Datadog
9
12
  module Tracing
10
13
  module Contrib
@@ -18,68 +21,77 @@ module Datadog
18
21
  # PG::Connection patch methods
19
22
  module InstanceMethods
20
23
  def exec(sql, *args)
21
- trace(Ext::SPAN_EXEC, resource: sql) do
22
- super(sql, *args)
24
+ trace(Ext::SPAN_EXEC, sql: sql) do |sql_statement|
25
+ super(sql_statement, *args)
23
26
  end
24
27
  end
25
28
 
26
29
  def exec_params(sql, params, *args)
27
- trace(Ext::SPAN_EXEC_PARAMS, resource: sql) do
28
- super(sql, params, *args)
30
+ trace(Ext::SPAN_EXEC_PARAMS, sql: sql) do |sql_statement|
31
+ super(sql_statement, params, *args)
29
32
  end
30
33
  end
31
34
 
32
35
  def exec_prepared(statement_name, params, *args)
33
- trace(Ext::SPAN_EXEC_PREPARED, resource: statement_name) do
36
+ trace(Ext::SPAN_EXEC_PREPARED, statement_name: statement_name) do
34
37
  super(statement_name, params, *args)
35
38
  end
36
39
  end
37
40
 
38
41
  def async_exec(sql, *args)
39
- trace(Ext::SPAN_ASYNC_EXEC, resource: sql) do
40
- super(sql, *args)
42
+ trace(Ext::SPAN_ASYNC_EXEC, sql: sql) do |sql_statement|
43
+ super(sql_statement, *args)
41
44
  end
42
45
  end
43
46
 
44
47
  def async_exec_params(sql, params, *args)
45
- trace(Ext::SPAN_ASYNC_EXEC_PARAMS, resource: sql) do
46
- super(sql, params, *args)
48
+ trace(Ext::SPAN_ASYNC_EXEC_PARAMS, sql: sql) do |sql_statement|
49
+ super(sql_statement, params, *args)
47
50
  end
48
51
  end
49
52
 
50
53
  def async_exec_prepared(statement_name, params, *args)
51
- trace(Ext::SPAN_ASYNC_EXEC_PREPARED, resource: statement_name) do
54
+ trace(Ext::SPAN_ASYNC_EXEC_PREPARED, statement_name: statement_name) do
52
55
  super(statement_name, params, *args)
53
56
  end
54
57
  end
55
58
 
56
59
  def sync_exec(sql, *args)
57
- trace(Ext::SPAN_SYNC_EXEC, resource: sql) do
58
- super(sql, *args)
60
+ trace(Ext::SPAN_SYNC_EXEC, sql: sql) do |sql_statement|
61
+ super(sql_statement, *args)
59
62
  end
60
63
  end
61
64
 
62
65
  def sync_exec_params(sql, params, *args)
63
- trace(Ext::SPAN_SYNC_EXEC_PARAMS, resource: sql) do
64
- super(sql, params, *args)
66
+ trace(Ext::SPAN_SYNC_EXEC_PARAMS, sql: sql) do |sql_statement|
67
+ super(sql_statement, params, *args)
65
68
  end
66
69
  end
67
70
 
68
71
  def sync_exec_prepared(statement_name, params, *args)
69
- trace(Ext::SPAN_SYNC_EXEC_PREPARED, resource: statement_name) do
72
+ trace(Ext::SPAN_SYNC_EXEC_PREPARED, statement_name: statement_name) do
70
73
  super(statement_name, params, *args)
71
74
  end
72
75
  end
73
76
 
74
77
  private
75
78
 
76
- def trace(name, resource:)
79
+ def trace(name, sql: nil, statement_name: nil)
77
80
  service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name]
81
+ resource = statement_name || sql
82
+
78
83
  Tracing.trace(name, service: service, resource: resource, type: Tracing::Metadata::Ext::SQL::TYPE) do |span|
79
84
  annotate_span_with_query!(span, service)
80
85
  # Set analytics sample rate
81
86
  Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
82
- result = yield
87
+
88
+ if sql
89
+ propagation_mode = Contrib::Propagation::SqlComment::Mode.new(comment_propagation)
90
+ Contrib::Propagation::SqlComment.annotate!(span, propagation_mode)
91
+ propagated_sql_statement = Contrib::Propagation::SqlComment.prepend_comment(sql, span, propagation_mode)
92
+ end
93
+
94
+ result = yield(propagated_sql_statement)
83
95
  annotate_span_with_result!(span, result)
84
96
  result
85
97
  end
@@ -98,7 +110,7 @@ module Datadog
98
110
 
99
111
  span.set_tag(Contrib::Ext::DB::TAG_INSTANCE, db)
100
112
  span.set_tag(Contrib::Ext::DB::TAG_USER, user)
101
- span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, Ext::SPAN_SYSTEM)
113
+ span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, Ext::TAG_SYSTEM)
102
114
 
103
115
  span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, host)
104
116
  span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, port)
@@ -121,6 +133,10 @@ module Datadog
121
133
  def analytics_sample_rate
122
134
  datadog_configuration[:analytics_sample_rate]
123
135
  end
136
+
137
+ def comment_propagation
138
+ datadog_configuration[:comment_propagation]
139
+ end
124
140
  end
125
141
  end
126
142
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # typed: false
4
+
5
+ require 'erb'
6
+
7
+ module Datadog
8
+ module Tracing
9
+ module Contrib
10
+ module Propagation
11
+ module SqlComment
12
+ # To be prepended to a sql statement.
13
+ class Comment
14
+ def initialize(hash)
15
+ @hash = hash
16
+ end
17
+
18
+ def to_s
19
+ @string ||= begin
20
+ ret = String.new
21
+
22
+ @hash.each do |key, value|
23
+ next if value.nil?
24
+
25
+ # Url encode
26
+ value = ERB::Util.url_encode(value)
27
+
28
+ # Escape SQL
29
+ ret << "#{key}='#{value}',"
30
+ end
31
+
32
+ # Remove the last `,`
33
+ ret.chop!
34
+
35
+ "/*#{ret}*/"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,32 @@
1
+ # typed: false
2
+
3
+ module Datadog
4
+ module Tracing
5
+ module Contrib
6
+ module Propagation
7
+ module SqlComment
8
+ module Ext
9
+ ENV_DBM_PROPAGATION_MODE = 'DD_DBM_PROPAGATION_MODE'.freeze
10
+
11
+ # The default mode for sql comment propagation
12
+ DISABLED = 'disabled'.freeze
13
+
14
+ # The `service` mode propagates service configuration
15
+ SERVICE = 'service'.freeze
16
+
17
+ # The `full` mode propagates service configuration + trace context
18
+ FULL = 'full'.freeze
19
+
20
+ # The value should be `true` when `full` mode
21
+ TAG_DBM_TRACE_INJECTED = '_dd.dbm_trace_injected'.freeze
22
+
23
+ KEY_DATABASE_SERVICE = 'dddbs'.freeze
24
+ KEY_ENVIRONMENT = 'dde'.freeze
25
+ KEY_PARENT_SERVICE = 'ddps'.freeze
26
+ KEY_VERSION = 'ddpv'.freeze
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ # typed: false
2
+
3
+ require_relative 'ext'
4
+
5
+ module Datadog
6
+ module Tracing
7
+ module Contrib
8
+ module Propagation
9
+ # Implements sql comment propagation related contracts.
10
+ module SqlComment
11
+ Mode = Struct.new(:mode) do
12
+ def enabled?
13
+ service? || full?
14
+ end
15
+
16
+ def service?
17
+ mode == Ext::SERVICE
18
+ end
19
+
20
+ def full?
21
+ mode == Ext::FULL
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,49 @@
1
+ # typed: false
2
+
3
+ require_relative 'sql_comment/comment'
4
+ require_relative 'sql_comment/ext'
5
+
6
+ module Datadog
7
+ module Tracing
8
+ module Contrib
9
+ module Propagation
10
+ # Implements sql comment propagation related contracts.
11
+ module SqlComment
12
+ def self.annotate!(span_op, mode)
13
+ return unless mode.enabled?
14
+
15
+ # PENDING: Until `traceparent`` implementation in `full` mode
16
+ # span_op.set_tag(Ext::TAG_DBM_TRACE_INJECTED, true) if mode.full?
17
+ end
18
+
19
+ def self.prepend_comment(sql, span_op, mode)
20
+ return sql unless mode.enabled?
21
+
22
+ tags = {
23
+ Ext::KEY_DATABASE_SERVICE => span_op.service,
24
+ Ext::KEY_ENVIRONMENT => datadog_configuration.env,
25
+ Ext::KEY_PARENT_SERVICE => datadog_configuration.service,
26
+ Ext::KEY_VERSION => datadog_configuration.version
27
+ }
28
+
29
+ # PENDING: Until `traceparent`` implementation in `full` mode
30
+ # tags.merge!(trace_context(span_op)) if mode.full?
31
+
32
+ "#{Comment.new(tags)} #{sql}"
33
+ end
34
+
35
+ def self.datadog_configuration
36
+ Datadog.configuration
37
+ end
38
+
39
+ # TODO: Derive from trace
40
+ def self.trace_context(_)
41
+ {
42
+ # traceparent: '00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01'
43
+ }.freeze
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -56,16 +56,18 @@ module Datadog
56
56
  # Find out if this is rack within rack
57
57
  previous_request_span = env[Ext::RACK_ENV_REQUEST_SPAN]
58
58
 
59
+ return @app.call(env) if previous_request_span
60
+
59
61
  # Extract distributed tracing context before creating any spans,
60
62
  # so that all spans will be added to the distributed trace.
61
- if configuration[:distributed_tracing] && previous_request_span.nil?
63
+ if configuration[:distributed_tracing]
62
64
  trace_digest = Tracing::Propagation::HTTP.extract(env)
63
65
  Tracing.continue_trace!(trace_digest)
64
66
  end
65
67
 
66
68
  # Create a root Span to keep track of frontend web servers
67
69
  # (i.e. Apache, nginx) if the header is properly set
68
- frontend_span = compute_queue_time(env) if previous_request_span.nil?
70
+ frontend_span = compute_queue_time(env)
69
71
 
70
72
  trace_options = { span_type: Tracing::Metadata::Ext::HTTP::TYPE_INBOUND }
71
73
  trace_options[:service] = configuration[:service_name] if configuration[:service_name]
@@ -127,6 +129,10 @@ module Datadog
127
129
  request_headers_tags = parse_request_headers(request_header_collection)
128
130
  response_headers_tags = parse_response_headers(headers || {})
129
131
 
132
+ # Since it could be mutated, it would be more accurate to fetch from the original env,
133
+ # e.g. ActionDispatch::ShowExceptions middleware with Rails exceptions_app configuration
134
+ original_request_method = original_env['REQUEST_METHOD']
135
+
130
136
  # request_headers is subject to filtering and configuration so we
131
137
  # get the user agent separately
132
138
  user_agent = parse_user_agent_header(request_header_collection)
@@ -138,11 +144,11 @@ module Datadog
138
144
  # 4. Fallback with verb + status, eq `GET 200`
139
145
  request_span.resource ||=
140
146
  if configuration[:middleware_names] && env['RESPONSE_MIDDLEWARE']
141
- "#{env['RESPONSE_MIDDLEWARE']}##{env['REQUEST_METHOD']}"
147
+ "#{env['RESPONSE_MIDDLEWARE']}##{original_request_method}"
142
148
  elsif trace.resource_override?
143
149
  trace.resource
144
150
  else
145
- "#{env['REQUEST_METHOD']} #{status}".strip
151
+ "#{original_request_method} #{status}".strip
146
152
  end
147
153
 
148
154
  # Overrides the trace resource if it never been set
@@ -161,7 +167,7 @@ module Datadog
161
167
  Contrib::Analytics.set_measured(request_span)
162
168
 
163
169
  if request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD).nil?
164
- request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, env['REQUEST_METHOD'])
170
+ request_span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_METHOD, original_request_method)
165
171
  end
166
172
 
167
173
  url = parse_url(env, original_env)
@@ -19,6 +19,8 @@ module Datadog
19
19
  TYPE = 'redis'.freeze
20
20
  TAG_COMPONENT = 'redis'.freeze
21
21
  TAG_OPERATION_COMMAND = 'command'.freeze
22
+ TAG_SYSTEM = 'redis'.freeze
23
+ TAG_DATABASE_INDEX = 'db.redis.database_index'.freeze
22
24
  end
23
25
  end
24
26
  end
@@ -21,7 +21,8 @@ module Datadog
21
21
  def call(*args, &block)
22
22
  response = nil
23
23
  Tracing.trace(Contrib::Redis::Ext::SPAN_COMMAND) do |span|
24
- span.service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name]
24
+ span.service = Datadog.configuration_for(redis_instance, :service_name) ||
25
+ datadog_configuration[:service_name]
25
26
  span.span_type = Contrib::Redis::Ext::TYPE
26
27
  span.resource = get_command(args)
27
28
  Contrib::Redis::Tags.set_common_tags(self, span)
@@ -35,7 +36,8 @@ module Datadog
35
36
  def call_pipeline(*args, &block)
36
37
  response = nil
37
38
  Tracing.trace(Contrib::Redis::Ext::SPAN_COMMAND) do |span|
38
- span.service = Datadog.configuration_for(self, :service_name) || datadog_configuration[:service_name]
39
+ span.service = Datadog.configuration_for(redis_instance, :service_name) ||
40
+ datadog_configuration[:service_name]
39
41
  span.span_type = Contrib::Redis::Ext::TYPE
40
42
  commands = get_pipeline_commands(args)
41
43
  span.resource = commands.any? ? commands.join("\n") : '(none)'
@@ -12,6 +12,42 @@ module Datadog
12
12
  module Patcher
13
13
  include Contrib::Patcher
14
14
 
15
+ # Patch for redis instance
16
+ module InstancePatch
17
+ def self.included(base)
18
+ base.prepend(InstanceMethods)
19
+ end
20
+
21
+ # Instance method patch for redis instance
22
+ module InstanceMethods
23
+ def initialize(options = {})
24
+ options[:redis_instance] = self
25
+
26
+ super(options)
27
+ end
28
+ end
29
+ end
30
+
31
+ # Patch for redis client
32
+ module ClientPatch
33
+ def self.included(base)
34
+ base.prepend(InstanceMethods)
35
+ end
36
+
37
+ # Instance method patch for redis client
38
+ module InstanceMethods
39
+ def initialize(options = {})
40
+ @redis_instance = options.delete(:redis_instance)
41
+
42
+ super(options)
43
+ end
44
+
45
+ private
46
+
47
+ attr_reader :redis_instance
48
+ end
49
+ end
50
+
15
51
  module_function
16
52
 
17
53
  def target_version
@@ -26,6 +62,11 @@ module Datadog
26
62
  require_relative 'quantize'
27
63
  require_relative 'instrumentation'
28
64
 
65
+ # InstancePatch and ClientPatch allows the client object to access pin on redis instance
66
+ ::Redis.include(InstancePatch)
67
+ ::Redis::Client.include(ClientPatch)
68
+
69
+ # TODO: To support redis-rb 5.x, Redis::Client -> RedisClient
29
70
  ::Redis::Client.include(Instrumentation)
30
71
  end
31
72
  end
@@ -3,6 +3,7 @@
3
3
  require_relative '../../metadata/ext'
4
4
  require_relative '../analytics'
5
5
  require_relative 'ext'
6
+ require_relative '../ext'
6
7
 
7
8
  module Datadog
8
9
  module Tracing
@@ -22,8 +23,12 @@ module Datadog
22
23
  # Set analytics sample rate
23
24
  Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
24
25
 
26
+ span.set_tag Contrib::Ext::DB::TAG_SYSTEM, Ext::TAG_SYSTEM
27
+
25
28
  span.set_tag Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, client.host
26
29
  span.set_tag Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, client.port
30
+
31
+ span.set_tag Ext::TAG_DATABASE_INDEX, client.db.to_s
27
32
  span.set_tag Ext::TAG_DB, client.db
28
33
  span.set_tag Ext::TAG_RAW_COMMAND, span.resource if show_command_args?
29
34
  end
@@ -34,6 +34,8 @@ module Datadog
34
34
  def datadog_tag_request(uri, span)
35
35
  span.resource = method.to_s.upcase
36
36
 
37
+ span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_CLIENT)
38
+
37
39
  span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
38
40
  span.set_tag(Tracing::Metadata::Ext::TAG_OPERATION, Ext::TAG_OPERATION_REQUEST)
39
41
 
@@ -13,14 +13,12 @@ module Datadog
13
13
  module Env
14
14
  module_function
15
15
 
16
- def datadog_span(env, app)
17
- request_span = env[Ext::RACK_ENV_REQUEST_SPAN]
18
- request_span && request_span[app]
16
+ def datadog_span(env)
17
+ env[Ext::RACK_ENV_SINATRA_REQUEST_SPAN]
19
18
  end
20
19
 
21
- def set_datadog_span(env, app, span)
22
- hash = (env[Ext::RACK_ENV_REQUEST_SPAN] ||= {})
23
- hash[app] = span
20
+ def set_datadog_span(env, span)
21
+ env[Ext::RACK_ENV_SINATRA_REQUEST_SPAN] = span
24
22
  end
25
23
 
26
24
  def request_header_tags(env, headers)
@@ -40,24 +38,15 @@ module Datadog
40
38
  "HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
41
39
  end
42
40
 
43
- # Was a Sinatra already traced in this request?
44
- # We don't want to create spans for intermediate Sinatra
45
- # middlewares that don't match the request at hand.
46
- def middleware_traced?(env)
47
- env[Ext::RACK_ENV_MIDDLEWARE_TRACED]
48
- end
49
-
50
- def set_middleware_traced(env, bool)
51
- env[Ext::RACK_ENV_MIDDLEWARE_TRACED] = bool
52
- end
41
+ def route_path(env, use_script_names: Datadog.configuration.tracing[:sinatra][:resource_script_names])
42
+ return unless env['sinatra.route']
53
43
 
54
- # The start time of the top-most Sinatra middleware.
55
- def middleware_start_time(env)
56
- env[Ext::RACK_ENV_MIDDLEWARE_START_TIME]
57
- end
58
-
59
- def set_middleware_start_time(env, time = Time.now.utc)
60
- env[Ext::RACK_ENV_MIDDLEWARE_START_TIME] = time
44
+ _, path = env['sinatra.route'].split(' ', 2)
45
+ if use_script_names
46
+ env['SCRIPT_NAME'].to_s + path
47
+ else
48
+ path
49
+ end
61
50
  end
62
51
  end
63
52
  end
@@ -10,9 +10,7 @@ module Datadog
10
10
  ENV_ENABLED = 'DD_TRACE_SINATRA_ENABLED'.freeze
11
11
  ENV_ANALYTICS_ENABLED = 'DD_TRACE_SINATRA_ANALYTICS_ENABLED'.freeze
12
12
  ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_SINATRA_ANALYTICS_SAMPLE_RATE'.freeze
13
- RACK_ENV_REQUEST_SPAN = 'datadog.sinatra_request_span'.freeze
14
- RACK_ENV_MIDDLEWARE_START_TIME = 'datadog.sinatra_middleware_start_time'.freeze
15
- RACK_ENV_MIDDLEWARE_TRACED = 'datadog.sinatra_middleware_traced'.freeze
13
+ RACK_ENV_SINATRA_REQUEST_SPAN = 'datadog.sinatra_request_span'.freeze
16
14
  SPAN_RENDER_TEMPLATE = 'sinatra.render_template'.freeze
17
15
  SPAN_REQUEST = 'sinatra.request'.freeze
18
16
  SPAN_ROUTE = 'sinatra.route'.freeze
@@ -25,6 +23,12 @@ module Datadog
25
23
  TAG_SCRIPT_NAME = 'sinatra.script_name'.freeze
26
24
  TAG_TEMPLATE_ENGINE = 'sinatra.template_engine'.freeze
27
25
  TAG_TEMPLATE_NAME = 'sinatra.template_name'.freeze
26
+
27
+ # === Deprecated: To be removed ===
28
+ RACK_ENV_REQUEST_SPAN = 'datadog.sinatra_request_span'.freeze
29
+ RACK_ENV_MIDDLEWARE_START_TIME = 'datadog.sinatra_middleware_start_time'.freeze
30
+ RACK_ENV_MIDDLEWARE_TRACED = 'datadog.sinatra_middleware_traced'.freeze
31
+ # === Deprecated: To be removed ===
28
32
  end
29
33
  end
30
34
  end
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: false
2
2
 
3
3
  require_relative '../../../core/utils/only_once'
4
4
  require_relative '../patcher'
@@ -58,7 +58,7 @@ module Datadog
58
58
  end
59
59
 
60
60
  def register_tracer
61
- ::Sinatra.send(:register, Contrib::Sinatra::Tracer)
61
+ ::Sinatra::Base.register(Contrib::Sinatra::Tracer)
62
62
  ::Sinatra::Base.prepend(Sinatra::Tracer::Base)
63
63
  end
64
64
 
@@ -17,69 +17,12 @@ module Datadog
17
17
  # Datadog::Tracing::Contrib::Sinatra::Tracer is a Sinatra extension which traces
18
18
  # requests.
19
19
  module Tracer
20
- def route(verb, action, *)
21
- # Keep track of the route name when the app is instantiated for an
22
- # incoming request.
23
- condition do
24
- # If the option to prepend script names is enabled, then
25
- # prepend the script name from the request onto the action.
26
- #
27
- # DEV: env['sinatra.route'] already exists with very similar information,
28
- # DEV: but doesn't account for our `resource_script_names` logic.
29
- #
30
- @datadog_route = if Datadog.configuration.tracing[:sinatra][:resource_script_names]
31
- "#{request.script_name}#{action}"
32
- else
33
- action
34
- end
35
- end
36
-
37
- super
38
- end
39
-
40
20
  def self.registered(app)
41
21
  app.use TracerMiddleware, app_instance: app
42
-
43
- app.after do
44
- next unless Tracing.enabled?
45
-
46
- span = Sinatra::Env.datadog_span(env, app)
47
-
48
- # TODO: `route` should *only* be populated if @datadog_route is defined.
49
- # TODO: If @datadog_route is not defined, then this Sinatra app is not responsible
50
- # TODO: for handling this request.
51
- # TODO:
52
- # TODO: This change would be BREAKING for any Sinatra app (classic or modular),
53
- # TODO: as it affects the `resource` value for requests not handled by the Sinatra app.
54
- # TODO: Currently we use "#{method} #{path}" in such aces, but `path` is the raw,
55
- # TODO: high-cardinality HTTP path, and can contain PII.
56
- # TODO:
57
- # TODO: The value we should use as the `resource` when the Sinatra app is not
58
- # TODO: responsible for the request is a tricky subject.
59
- # TODO: The best option is a value that clearly communicates that this app did not
60
- # TODO: handle this request. It's important to keep in mind that an unhandled request
61
- # TODO: by this Sinatra app might still be handled by another Rack middleware (which can
62
- # TODO: be a Sinatra app itself) or it might just 404 if not handled at all.
63
- # TODO:
64
- # TODO: A possible value for `resource` could set a high level description, e.g.
65
- # TODO: `request.request_method`, given we don't have the response object available yet.
66
- route = if defined?(@datadog_route)
67
- @datadog_route
68
- else
69
- # Fallback in case no routes have matched
70
- request.path
71
- end
72
-
73
- span.resource = "#{request.request_method} #{route}"
74
- span.set_tag(Ext::TAG_ROUTE_PATH, route)
75
- end
76
22
  end
77
23
 
78
24
  # Method overrides for Sinatra::Base
79
25
  module Base
80
- MISSING_REQUEST_SPAN_ONLY_ONCE = Core::Utils::OnlyOnce.new
81
- private_constant :MISSING_REQUEST_SPAN_ONLY_ONCE
82
-
83
26
  def render(engine, data, *)
84
27
  return super unless Tracing.enabled?
85
28
 
@@ -102,19 +45,21 @@ module Datadog
102
45
 
103
46
  # Invoked when a matching route is found.
104
47
  # This method yields directly to user code.
105
- # rubocop:disable Metrics/MethodLength
106
48
  def route_eval
107
49
  configuration = Datadog.configuration.tracing[:sinatra]
108
50
  return super unless Tracing.enabled?
109
51
 
52
+ datadog_route = Sinatra::Env.route_path(env)
53
+
110
54
  Tracing.trace(
111
55
  Ext::SPAN_ROUTE,
112
56
  service: configuration[:service_name],
113
57
  span_type: Tracing::Metadata::Ext::HTTP::TYPE_INBOUND,
114
- resource: "#{request.request_method} #{@datadog_route}",
58
+ resource: "#{request.request_method} #{datadog_route}",
115
59
  ) do |span, trace|
116
60
  span.set_tag(Ext::TAG_APP_NAME, settings.name || settings.superclass.name)
117
- span.set_tag(Ext::TAG_ROUTE_PATH, @datadog_route)
61
+ span.set_tag(Ext::TAG_ROUTE_PATH, datadog_route)
62
+
118
63
  if request.script_name && !request.script_name.empty?
119
64
  span.set_tag(Ext::TAG_SCRIPT_NAME, request.script_name)
120
65
  end
@@ -124,32 +69,15 @@ module Datadog
124
69
 
125
70
  trace.resource = span.resource
126
71
 
127
- sinatra_request_span =
128
- if self.class <= ::Sinatra::Application # Classic style (top-level) application
129
- Sinatra::Env.datadog_span(env, ::Sinatra::Application)
130
- else
131
- Sinatra::Env.datadog_span(env, self.class)
132
- end
133
- if sinatra_request_span
134
- sinatra_request_span.resource = span.resource
135
- else
136
- MISSING_REQUEST_SPAN_ONLY_ONCE.run do
137
- Datadog.logger.warn do
138
- 'Sinatra integration is misconfigured, reported traces will be missing request metadata ' \
139
- 'such as path and HTTP status code. ' \
140
- 'Did you forget to add `register Datadog::Tracing::Contrib::Sinatra::Tracer` to your ' \
141
- '`Sinatra::Base` subclass? ' \
142
- 'See <https://docs.datadoghq.com/tracing/setup_overview/setup/ruby/#sinatra> for more details.'
143
- end
144
- end
145
- end
72
+ sinatra_request_span = Sinatra::Env.datadog_span(env)
73
+
74
+ sinatra_request_span.resource = span.resource
146
75
 
147
76
  Contrib::Analytics.set_measured(span)
148
77
 
149
78
  super
150
79
  end
151
80
  end
152
- # rubocop:enable Metrics/MethodLength
153
81
  end
154
82
  end
155
83
  end