ddtrace 1.5.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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