ddtrace 1.5.0 → 1.5.1

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.
@@ -16,8 +16,10 @@ module Datadog
16
16
  module Watcher
17
17
  # rubocop:disable Metrics/AbcSize
18
18
  # rubocop:disable Metrics/MethodLength
19
+ # rubocop:disable Metrics/CyclomaticComplexity
20
+ # rubocop:disable Metrics/PerceivedComplexity
19
21
  def self.watch
20
- Instrumentation.gateway.watch('rack.request') do |stack, request|
22
+ Instrumentation.gateway.watch('rack.request', :appsec) do |stack, request|
21
23
  block = false
22
24
  event = nil
23
25
  waf_context = request.env['datadog.waf.context']
@@ -26,23 +28,24 @@ module Datadog
26
28
  trace = active_trace
27
29
  span = active_span
28
30
 
29
- Rack::Reactive::Request.subscribe(op, waf_context) do |action, result, _block|
30
- record = [:block, :monitor].include?(action)
31
- if record
31
+ Rack::Reactive::Request.subscribe(op, waf_context) do |result, _block|
32
+ if result.status == :match
32
33
  # TODO: should this hash be an Event instance instead?
33
34
  event = {
34
35
  waf_result: result,
35
36
  trace: trace,
36
37
  span: span,
37
38
  request: request,
38
- action: action
39
+ actions: result.actions
39
40
  }
40
41
 
42
+ span.set_tag('appsec.event', 'true') if span
43
+
41
44
  waf_context.events << event
42
45
  end
43
46
  end
44
47
 
45
- _action, _result, block = Rack::Reactive::Request.publish(op, request)
48
+ _result, block = Rack::Reactive::Request.publish(op, request)
46
49
  end
47
50
 
48
51
  next [nil, [[:block, event]]] if block
@@ -57,7 +60,7 @@ module Datadog
57
60
  [ret, res]
58
61
  end
59
62
 
60
- Instrumentation.gateway.watch('rack.response') do |stack, response|
63
+ Instrumentation.gateway.watch('rack.response', :appsec) do |stack, response|
61
64
  block = false
62
65
  event = nil
63
66
  waf_context = response.instance_eval { @waf_context }
@@ -66,23 +69,24 @@ module Datadog
66
69
  trace = active_trace
67
70
  span = active_span
68
71
 
69
- Rack::Reactive::Response.subscribe(op, waf_context) do |action, result, _block|
70
- record = [:block, :monitor].include?(action)
71
- if record
72
+ Rack::Reactive::Response.subscribe(op, waf_context) do |result, _block|
73
+ if result.status == :match
72
74
  # TODO: should this hash be an Event instance instead?
73
75
  event = {
74
76
  waf_result: result,
75
77
  trace: trace,
76
78
  span: span,
77
79
  response: response,
78
- action: action
80
+ actions: result.actions
79
81
  }
80
82
 
83
+ span.set_tag('appsec.event', 'true') if span
84
+
81
85
  waf_context.events << event
82
86
  end
83
87
  end
84
88
 
85
- _action, _result, block = Rack::Reactive::Response.publish(op, response)
89
+ _result, block = Rack::Reactive::Response.publish(op, response)
86
90
  end
87
91
 
88
92
  next [nil, [[:block, event]]] if block
@@ -97,7 +101,7 @@ module Datadog
97
101
  [ret, res]
98
102
  end
99
103
 
100
- Instrumentation.gateway.watch('rack.request.body') do |stack, request|
104
+ Instrumentation.gateway.watch('rack.request.body', :appsec) do |stack, request|
101
105
  block = false
102
106
  event = nil
103
107
  waf_context = request.env['datadog.waf.context']
@@ -106,23 +110,24 @@ module Datadog
106
110
  trace = active_trace
107
111
  span = active_span
108
112
 
109
- Rack::Reactive::RequestBody.subscribe(op, waf_context) do |action, result, _block|
110
- record = [:block, :monitor].include?(action)
111
- if record
113
+ Rack::Reactive::RequestBody.subscribe(op, waf_context) do |result, _block|
114
+ if result.status == :match
112
115
  # TODO: should this hash be an Event instance instead?
113
116
  event = {
114
117
  waf_result: result,
115
118
  trace: trace,
116
119
  span: span,
117
120
  request: request,
118
- action: action
121
+ actions: result.actions
119
122
  }
120
123
 
124
+ span.set_tag('appsec.event', 'true') if span
125
+
121
126
  waf_context.events << event
122
127
  end
123
128
  end
124
129
 
125
- _action, _result, block = Rack::Reactive::RequestBody.publish(op, request)
130
+ _result, block = Rack::Reactive::RequestBody.publish(op, request)
126
131
  end
127
132
 
128
133
  next [nil, [[:block, event]]] if block
@@ -137,6 +142,8 @@ module Datadog
137
142
  [ret, res]
138
143
  end
139
144
  end
145
+ # rubocop:enable Metrics/CyclomaticComplexity
146
+ # rubocop:enable Metrics/PerceivedComplexity
140
147
  # rubocop:enable Metrics/MethodLength
141
148
  # rubocop:enable Metrics/AbcSize
142
149
 
@@ -54,27 +54,27 @@ module Datadog
54
54
  }
55
55
 
56
56
  waf_timeout = Datadog::AppSec.settings.waf_timeout
57
- action, result = waf_context.run(waf_args, waf_timeout)
57
+ result = waf_context.run(waf_args, waf_timeout)
58
58
 
59
59
  Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
60
60
 
61
- # TODO: encapsulate return array in a type
62
- case action
63
- when :monitor
61
+ case result.status
62
+ when :match
64
63
  Datadog.logger.debug { "WAF: #{result.inspect}" }
65
- yield [action, result, false]
66
- when :block
67
- Datadog.logger.debug { "WAF: #{result.inspect}" }
68
- yield [action, result, true]
69
- throw(:block, [action, result, true])
70
- when :good
64
+
65
+ block = result.actions.include?('block')
66
+
67
+ yield [result, block]
68
+
69
+ throw(:block, [result, true]) if block
70
+ when :ok
71
71
  Datadog.logger.debug { "WAF OK: #{result.inspect}" }
72
72
  when :invalid_call
73
73
  Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
74
74
  when :invalid_rule, :invalid_flow, :no_rule
75
75
  Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
76
76
  else
77
- Datadog.logger.debug { "WAF UNKNOWN: #{action.inspect} #{result.inspect}" }
77
+ Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
78
78
  end
79
79
  end
80
80
  end
@@ -32,27 +32,27 @@ module Datadog
32
32
  }
33
33
 
34
34
  waf_timeout = Datadog::AppSec.settings.waf_timeout
35
- action, result = waf_context.run(waf_args, waf_timeout)
35
+ result = waf_context.run(waf_args, waf_timeout)
36
36
 
37
37
  Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
38
38
 
39
- # TODO: encapsulate return array in a type
40
- case action
41
- when :monitor
39
+ case result.status
40
+ when :match
42
41
  Datadog.logger.debug { "WAF: #{result.inspect}" }
43
- yield [action, result, false]
44
- when :block
45
- Datadog.logger.debug { "WAF: #{result.inspect}" }
46
- yield [action, result, true]
47
- throw(:block, [action, result, true])
48
- when :good
42
+
43
+ block = result.actions.include?('block')
44
+
45
+ yield [result, block]
46
+
47
+ throw(:block, [result, true]) if block
48
+ when :ok
49
49
  Datadog.logger.debug { "WAF OK: #{result.inspect}" }
50
50
  when :invalid_call
51
51
  Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
52
52
  when :invalid_rule, :invalid_flow, :no_rule
53
53
  Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
54
54
  else
55
- Datadog.logger.debug { "WAF UNKNOWN: #{action.inspect} #{result.inspect}" }
55
+ Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
56
56
  end
57
57
  end
58
58
  end
@@ -32,27 +32,27 @@ module Datadog
32
32
  }
33
33
 
34
34
  waf_timeout = Datadog::AppSec.settings.waf_timeout
35
- action, result = waf_context.run(waf_args, waf_timeout)
35
+ result = waf_context.run(waf_args, waf_timeout)
36
36
 
37
37
  Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
38
38
 
39
- # TODO: encapsulate return array in a type
40
- case action
41
- when :monitor
39
+ case result.status
40
+ when :match
42
41
  Datadog.logger.debug { "WAF: #{result.inspect}" }
43
- yield [action, result, false]
44
- when :block
45
- Datadog.logger.debug { "WAF: #{result.inspect}" }
46
- yield [action, result, true]
47
- throw(:block, [action, result, true])
48
- when :good
42
+
43
+ block = result.actions.include?('block')
44
+
45
+ yield [result, block]
46
+
47
+ throw(:block, [result, true]) if block
48
+ when :ok
49
49
  Datadog.logger.debug { "WAF OK: #{result.inspect}" }
50
50
  when :invalid_call
51
51
  Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
52
52
  when :invalid_rule, :invalid_flow, :no_rule
53
53
  Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
54
54
  else
55
- Datadog.logger.debug { "WAF UNKNOWN: #{action.inspect} #{result.inspect}" }
55
+ Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
56
56
  end
57
57
  end
58
58
  end
@@ -47,6 +47,9 @@ module Datadog
47
47
  end
48
48
 
49
49
  def self.form_hash(request)
50
+ # force form data processing
51
+ request.POST if request.form_data?
52
+
50
53
  # usually Hash<String,String> but can be a more complex
51
54
  # Hash<String,String||Array||Hash> when e.g coming from JSON
52
55
  request.env['rack.request.form_hash']
@@ -21,7 +21,7 @@ module Datadog
21
21
  end
22
22
 
23
23
  def call(env)
24
- return @app.call(env) unless @processor.ready?
24
+ return @app.call(env) unless Datadog.configuration.appsec.enabled && @processor.ready?
25
25
 
26
26
  # TODO: handle exceptions, except for @app.call
27
27
 
@@ -57,6 +57,7 @@ module Datadog
57
57
  request_return
58
58
  ensure
59
59
  add_waf_runtime_tags(context) if context
60
+ context.finalize if context
60
61
  end
61
62
 
62
63
  private
@@ -13,7 +13,7 @@ module Datadog
13
13
  # Watcher for Rails gateway events
14
14
  module Watcher
15
15
  def self.watch
16
- Instrumentation.gateway.watch('rails.request.action') do |stack, request|
16
+ Instrumentation.gateway.watch('rails.request.action', :appsec) do |stack, request|
17
17
  block = false
18
18
  event = nil
19
19
  waf_context = request.env['datadog.waf.context']
@@ -22,23 +22,24 @@ module Datadog
22
22
  trace = active_trace
23
23
  span = active_span
24
24
 
25
- Rails::Reactive::Action.subscribe(op, waf_context) do |action, result, _block|
26
- record = [:block, :monitor].include?(action)
27
- if record
25
+ Rails::Reactive::Action.subscribe(op, waf_context) do |result, _block|
26
+ if result.status == :match
28
27
  # TODO: should this hash be an Event instance instead?
29
28
  event = {
30
29
  waf_result: result,
31
30
  trace: trace,
32
31
  span: span,
33
32
  request: request,
34
- action: action
33
+ actions: result.actions
35
34
  }
36
35
 
36
+ span.set_tag('appsec.event', 'true') if span
37
+
37
38
  waf_context.events << event
38
39
  end
39
40
  end
40
41
 
41
- _action, _result, block = Rails::Reactive::Action.publish(op, request)
42
+ _result, block = Rails::Reactive::Action.publish(op, request)
42
43
  end
43
44
 
44
45
  next [nil, [[:block, event]]] if block
@@ -36,27 +36,27 @@ module Datadog
36
36
  }
37
37
 
38
38
  waf_timeout = Datadog::AppSec.settings.waf_timeout
39
- action, result = waf_context.run(waf_args, waf_timeout)
39
+ result = waf_context.run(waf_args, waf_timeout)
40
40
 
41
41
  Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
42
42
 
43
- # TODO: encapsulate return array in a type
44
- case action
45
- when :monitor
43
+ case result.status
44
+ when :match
46
45
  Datadog.logger.debug { "WAF: #{result.inspect}" }
47
- yield [action, result, false]
48
- when :block
49
- Datadog.logger.debug { "WAF: #{result.inspect}" }
50
- yield [action, result, true]
51
- throw(:block, [action, result, true])
52
- when :good
46
+
47
+ block = result.actions.include?('block')
48
+
49
+ yield [result, block]
50
+
51
+ throw(:block, [result, true]) if block
52
+ when :ok
53
53
  Datadog.logger.debug { "WAF OK: #{result.inspect}" }
54
54
  when :invalid_call
55
55
  Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
56
56
  when :invalid_rule, :invalid_flow, :no_rule
57
57
  Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
58
58
  else
59
- Datadog.logger.debug { "WAF UNKNOWN: #{action.inspect} #{result.inspect}" }
59
+ Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
60
60
  end
61
61
  end
62
62
  end
@@ -7,6 +7,9 @@ module Datadog
7
7
  # Normalized extration of data from ActionDispatch::Request
8
8
  module Request
9
9
  def self.parsed_body(request)
10
+ # force body parameter parsing, which is done lazily by Rails
11
+ request.parameters
12
+
10
13
  # usually Hash<String,String> but can be a more complex
11
14
  # Hash<String,String||Array||Hash> when e.g coming from JSON or
12
15
  # with Rails advanced param square bracket parsing
@@ -15,7 +15,7 @@ module Datadog
15
15
  module Watcher
16
16
  # rubocop:disable Metrics/MethodLength
17
17
  def self.watch
18
- Instrumentation.gateway.watch('sinatra.request.dispatch') do |stack, request|
18
+ Instrumentation.gateway.watch('sinatra.request.dispatch', :appsec) do |stack, request|
19
19
  block = false
20
20
  event = nil
21
21
  waf_context = request.env['datadog.waf.context']
@@ -24,23 +24,24 @@ module Datadog
24
24
  trace = active_trace
25
25
  span = active_span
26
26
 
27
- Rack::Reactive::RequestBody.subscribe(op, waf_context) do |action, result, _block|
28
- record = [:block, :monitor].include?(action)
29
- if record
27
+ Rack::Reactive::RequestBody.subscribe(op, waf_context) do |result, _block|
28
+ if result.status == :match
30
29
  # TODO: should this hash be an Event instance instead?
31
30
  event = {
32
31
  waf_result: result,
33
32
  trace: trace,
34
33
  span: span,
35
34
  request: request,
36
- action: action
35
+ actions: result.actions
37
36
  }
38
37
 
38
+ span.set_tag('appsec.event', 'true') if span
39
+
39
40
  waf_context.events << event
40
41
  end
41
42
  end
42
43
 
43
- _action, _result, block = Rack::Reactive::RequestBody.publish(op, request)
44
+ _result, block = Rack::Reactive::RequestBody.publish(op, request)
44
45
  end
45
46
 
46
47
  next [nil, [[:block, event]]] if block
@@ -55,7 +56,7 @@ module Datadog
55
56
  [ret, res]
56
57
  end
57
58
 
58
- Instrumentation.gateway.watch('sinatra.request.routed') do |stack, (request, route_params)|
59
+ Instrumentation.gateway.watch('sinatra.request.routed', :appsec) do |stack, (request, route_params)|
59
60
  block = false
60
61
  event = nil
61
62
  waf_context = request.env['datadog.waf.context']
@@ -64,23 +65,24 @@ module Datadog
64
65
  trace = active_trace
65
66
  span = active_span
66
67
 
67
- Sinatra::Reactive::Routed.subscribe(op, waf_context) do |action, result, _block|
68
- record = [:block, :monitor].include?(action)
69
- if record
68
+ Sinatra::Reactive::Routed.subscribe(op, waf_context) do |result, _block|
69
+ if result.status == :match
70
70
  # TODO: should this hash be an Event instance instead?
71
71
  event = {
72
72
  waf_result: result,
73
73
  trace: trace,
74
74
  span: span,
75
75
  request: request,
76
- action: action
76
+ actions: result.actions
77
77
  }
78
78
 
79
+ span.set_tag('appsec.event', 'true') if span
80
+
79
81
  waf_context.events << event
80
82
  end
81
83
  end
82
84
 
83
- _action, _result, block = Sinatra::Reactive::Routed.publish(op, [request, route_params])
85
+ _result, block = Sinatra::Reactive::Routed.publish(op, [request, route_params])
84
86
  end
85
87
 
86
88
  next [nil, [[:block, event]]] if block
@@ -31,27 +31,27 @@ module Datadog
31
31
  }
32
32
 
33
33
  waf_timeout = Datadog::AppSec.settings.waf_timeout
34
- action, result = waf_context.run(waf_args, waf_timeout)
34
+ result = waf_context.run(waf_args, waf_timeout)
35
35
 
36
36
  Datadog.logger.debug { "WAF TIMEOUT: #{result.inspect}" } if result.timeout
37
37
 
38
- # TODO: encapsulate return array in a type
39
- case action
40
- when :monitor
38
+ case result.status
39
+ when :match
41
40
  Datadog.logger.debug { "WAF: #{result.inspect}" }
42
- yield [action, result, false]
43
- when :block
44
- Datadog.logger.debug { "WAF: #{result.inspect}" }
45
- yield [action, result, true]
46
- throw(:block, [action, result, true])
47
- when :good
41
+
42
+ block = result.actions.include?('block')
43
+
44
+ yield [result, block]
45
+
46
+ throw(:block, [result, true]) if block
47
+ when :ok
48
48
  Datadog.logger.debug { "WAF OK: #{result.inspect}" }
49
49
  when :invalid_call
50
50
  Datadog.logger.debug { "WAF CALL ERROR: #{result.inspect}" }
51
51
  when :invalid_rule, :invalid_flow, :no_rule
52
52
  Datadog.logger.debug { "WAF RULE ERROR: #{result.inspect}" }
53
53
  else
54
- Datadog.logger.debug { "WAF UNKNOWN: #{action.inspect} #{result.inspect}" }
54
+ Datadog.logger.debug { "WAF UNKNOWN: #{result.status.inspect} #{result.inspect}" }
55
55
  end
56
56
  end
57
57
  end
@@ -51,8 +51,6 @@ module Datadog
51
51
  end
52
52
  end
53
53
 
54
- # rubocop:disable Metrics/AbcSize
55
- # rubocop:disable Metrics/MethodLength
56
54
  def self.record_via_span(*events)
57
55
  events.group_by { |e| e[:trace] }.each do |trace, event_group|
58
56
  unless trace
@@ -64,10 +62,6 @@ module Datadog
64
62
 
65
63
  # prepare and gather tags to apply
66
64
  trace_tags = event_group.each_with_object({}) do |event, tags|
67
- span = event[:span]
68
-
69
- span.set_tag('appsec.event', 'true') if span
70
-
71
65
  # TODO: assume HTTP request context for now
72
66
 
73
67
  if (request = event[:request])
@@ -114,8 +108,6 @@ module Datadog
114
108
  end
115
109
  end
116
110
  end
117
- # rubocop:enable Metrics/MethodLength
118
- # rubocop:enable Metrics/AbcSize
119
111
  end
120
112
  end
121
113
  end
@@ -6,6 +6,20 @@ module Datadog
6
6
  module Instrumentation
7
7
  # Instrumentation gateway implementation
8
8
  class Gateway
9
+ # Instrumentation gateway middleware
10
+ class Middleware
11
+ attr_reader :key, :block
12
+
13
+ def initialize(key, &block)
14
+ @key = key
15
+ @block = block
16
+ end
17
+
18
+ def call(*args, **kwargs, &block)
19
+ @block.call(*args, **kwargs, &block)
20
+ end
21
+ end
22
+
9
23
  def initialize
10
24
  @middlewares = Hash.new { |h, k| h[k] = [] }
11
25
  end
@@ -31,8 +45,8 @@ module Datadog
31
45
  stack.call(env)
32
46
  end
33
47
 
34
- def watch(name, &block)
35
- @middlewares[name] << block
48
+ def watch(name, key, &block)
49
+ @middlewares[name] << Middleware.new(key, &block) unless @middlewares[name].any? { |m| m.key == key }
36
50
  end
37
51
  end
38
52
 
@@ -31,7 +31,7 @@ module Datadog
31
31
  def run(*args)
32
32
  start_ns = Core::Utils::Time.get_time(:nanosecond)
33
33
 
34
- ret, res = @context.run(*args)
34
+ _code, res = @context.run(*args)
35
35
 
36
36
  stop_ns = Core::Utils::Time.get_time(:nanosecond)
37
37
 
@@ -39,7 +39,11 @@ module Datadog
39
39
  @time_ext_ns += (stop_ns - start_ns)
40
40
  @timeouts += 1 if res.timeout
41
41
 
42
- [ret, res]
42
+ res
43
+ end
44
+
45
+ def finalize
46
+ @context.finalize
43
47
  end
44
48
  end
45
49
 
@@ -64,6 +68,18 @@ module Datadog
64
68
  Context.new(self)
65
69
  end
66
70
 
71
+ def update_rule_data(data)
72
+ @handle.update_rule_data(data)
73
+ end
74
+
75
+ def toggle_rules(map)
76
+ @handle.toggle_rules(map)
77
+ end
78
+
79
+ def finalize
80
+ @handle.finalize
81
+ end
82
+
67
83
  protected
68
84
 
69
85
  attr_reader :handle
@@ -323,8 +323,8 @@ module Datadog
323
323
 
324
324
  # Parse tags from environment
325
325
  env_to_list(Core::Environment::Ext::ENV_TAGS, comma_separated_only: false).each do |tag|
326
- pair = tag.split(':')
327
- tags[pair.first] = pair.last if pair.length == 2
326
+ key, value = tag.split(':', 2)
327
+ tags[key] = value if value && !value.empty?
328
328
  end
329
329
 
330
330
  # Override tags if defined
@@ -271,7 +271,7 @@ module Datadog
271
271
  request_uri
272
272
  end
273
273
 
274
- base_url + fullpath
274
+ ::URI.join(base_url, fullpath).to_s
275
275
  end
276
276
 
277
277
  def parse_user_agent_header(headers)
@@ -14,20 +14,28 @@ module Datadog
14
14
 
15
15
  PLACEHOLDER = '?'.freeze
16
16
 
17
+ # taken from Ruby https://github.com/ruby/uri/blob/ffbab83de6d8748c9454414e02db5317609166eb/lib/uri/rfc3986_parser.rb
18
+ # but adjusted to parse only <scheme>://<host>:<port>/ components
19
+ # and stop there, since we don't care about the path, query string,
20
+ # and fragment components
21
+ RFC3986_URL_BASE = /\A(?<URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))(?::(?<port>\d*))?)))(?:\/|\z)/.freeze # rubocop:disable Style/RegexpLiteral, Layout/LineLength
22
+
17
23
  module_function
18
24
 
19
25
  def url(url, options = {})
20
26
  url!(url, options)
21
27
  rescue StandardError
22
- options[:placeholder] || PLACEHOLDER
28
+ placeholder = options[:placeholder] || PLACEHOLDER
29
+
30
+ options[:base] == :exclude ? placeholder : "#{base_url(url)}/#{placeholder}"
23
31
  end
24
32
 
25
33
  def base_url(url, options = {})
26
- URI.parse(url).tap do |uri|
27
- uri.path = ''
28
- uri.query = nil
29
- uri.fragment = nil
30
- end.to_s
34
+ if (m = RFC3986_URL_BASE.match(url))
35
+ m[1]
36
+ else
37
+ ''
38
+ end
31
39
  end
32
40
 
33
41
  def url!(url, options = {})
@@ -101,6 +101,8 @@ module Datadog
101
101
  # Make the trace serializable
102
102
  serializable_trace = SerializableTrace.new(trace)
103
103
 
104
+ Datadog.logger.debug { "Flushing trace: #{JSON.dump(serializable_trace)}" }
105
+
104
106
  # Encode the trace
105
107
  encoder.encode(serializable_trace)
106
108
  end