Skip to content

Commit d17fc75

Browse files
committed
Encapsulate inferred route reading and writing
1 parent e5a8edd commit d17fc75

File tree

7 files changed

+60
-23
lines changed

7 files changed

+60
-23
lines changed

lib/datadog/appsec/api_security/route_extractor.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
require_relative '../../tracing/contrib/rack/route_from_path_inference'
3+
require_relative '../../tracing/contrib/rack/route_inference'
44

55
module Datadog
66
module AppSec
@@ -68,9 +68,7 @@ def self.route_pattern(request)
6868
# to generic request path
6969
(pattern || request.path).delete_suffix(RAILS_FORMAT_SUFFIX)
7070
else
71-
Tracing::Contrib::Rack::RouteFromPathInference.infer(request.path).tap do |inferred_route|
72-
request.env[Tracing::Contrib::Rack::Ext::DATADOG_INFERRED_ROUTE] = inferred_route
73-
end
71+
Tracing::Contrib::Rack::RouteInference.read_or_infer(request.env)
7472
end
7573
end
7674
end

lib/datadog/tracing/contrib/rack/ext.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ module Ext
1212
ENV_ANALYTICS_ENABLED = 'DD_TRACE_RACK_ANALYTICS_ENABLED'
1313
ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_RACK_ANALYTICS_SAMPLE_RATE'
1414
RACK_ENV_REQUEST_SPAN = 'datadog.rack_request_span'
15-
DATADOG_INFERRED_ROUTE = 'datadog.inferred_route'
1615
SPAN_HTTP_PROXY_REQUEST = 'http.proxy.request'
1716
SPAN_HTTP_PROXY_QUEUE = 'http.proxy.queue'
1817
SPAN_REQUEST = 'rack.request'

lib/datadog/tracing/contrib/rack/middlewares.rb

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
require_relative 'header_collection'
1414
require_relative 'header_tagging'
1515
require_relative 'request_queue'
16-
require_relative 'route_from_path_inference'
16+
require_relative 'route_inference'
1717
require_relative 'trace_proxy_middleware'
1818

1919
module Datadog
@@ -235,7 +235,7 @@ def set_route_and_endpoint_tags(trace:, request_span:, status:, env:)
235235
# we infer the route from the full request path.
236236
if last_script_name == '' && env['SCRIPT_NAME'] != '' &&
237237
!Datadog.configuration.tracing.resource_renaming.always_simplified_endpoint &&
238-
(inferred_route = RouteFromPathInference.infer(env['PATH_INFO']))
238+
(inferred_route = RouteInference.infer(env['PATH_INFO']))
239239
set_endpoint_tag(request_span, last_route + inferred_route)
240240
end
241241

@@ -250,16 +250,9 @@ def set_route_and_endpoint_tags(trace:, request_span:, status:, env:)
250250

251251
if Datadog.configuration.tracing.resource_renaming.always_simplified_endpoint ||
252252
request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_ROUTE).nil?
253-
# when http.route tag wasn't set or resource_renaming.always_simplified_endpoint is set to true,
254-
# we will try to infer the path for the full request path,
255-
# which is SCRIPT_NAME + PATH_INFO for mounted rack applications
256-
full_path = env['SCRIPT_NAME'].to_s + env['PATH_INFO'].to_s
257-
258-
# Inferred route calculation might have been done already for AppSec API Security sampling,
259-
# in such case the calculation result is stored in request env
260-
inferred_route = env[Tracing::Contrib::Rack::Ext::DATADOG_INFERRED_ROUTE] || RouteFromPathInference.infer(full_path)
261-
262-
set_endpoint_tag(request_span, inferred_route) if inferred_route
253+
if (inferred_route = RouteInference.read_or_infer(env))
254+
set_endpoint_tag(request_span, inferred_route) if inferred_route
255+
end
263256
elsif !request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_ENDPOINT)
264257
set_endpoint_tag(request_span, request_span.get_tag(Tracing::Metadata::Ext::HTTP::TAG_ROUTE))
265258
end

lib/datadog/tracing/contrib/rack/route_from_path_inference.rb renamed to lib/datadog/tracing/contrib/rack/route_inference.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module Contrib
66
module Rack
77
# This module provides logic for inferring HTTP route pattern
88
# from an HTTP path.
9-
module RouteFromPathInference
9+
module RouteInference
1010
MAX_NUMBER_OF_SEGMENTS = 8
1111

1212
INT_PARAM_REGEX = /\A[0-9]+\z/.freeze
@@ -15,8 +15,15 @@ module RouteFromPathInference
1515
HEX_ID_PARAM_REGEX = /\A(?=.*\d)[A-Fa-f0-9._-]{6,}\z/.freeze
1616
STRING_PARAM_REGEX = /\A.{20,}|.*[%&'()*+,:=@].*\z/.freeze
1717

18+
DATADOG_INFERRED_ROUTE_ENV_KEY = 'datadog.inferred_route'
19+
1820
module_function
1921

22+
def read_or_infer(request_env)
23+
request_env[DATADOG_INFERRED_ROUTE_ENV_KEY] ||=
24+
infer(request_env['SCRIPT_NAME'].to_s + request_env['PATH_INFO'].to_s)
25+
end
26+
2027
def infer(path)
2128
segments = path.delete_prefix('/').split('/', MAX_NUMBER_OF_SEGMENTS + 1).first(MAX_NUMBER_OF_SEGMENTS)
2229

sig/datadog/tracing/contrib/rack/ext.rbs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ module Datadog
1111

1212
RACK_ENV_REQUEST_SPAN: "datadog.rack_request_span"
1313

14-
DATADOG_INFERRED_ROUTE: ::String
15-
1614
SPAN_HTTP_PROXY_REQUEST: "http.proxy.request"
1715

1816
SPAN_HTTP_PROXY_QUEUE: "http.proxy.queue"

sig/datadog/tracing/contrib/rack/route_from_path_inference.rbs renamed to sig/datadog/tracing/contrib/rack/route_inference.rbs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Datadog
22
module Tracing
33
module Contrib
44
module Rack
5-
module RouteFromPathInference
5+
module RouteInference
66
MAX_NUMBER_OF_SEGMENTS: ::Integer
77

88
INT_PARAM_REGEX: ::Regexp
@@ -11,6 +11,10 @@ module Datadog
1111
HEX_ID_PARAM_REGEX: ::Regexp
1212
STRING_PARAM_REGEX: ::Regexp
1313

14+
DATADOG_INFERRED_ROUTE_ENV_KEY: ::String
15+
16+
def self.read_or_infer: (Hash[::String, untyped] request_env) -> ::String?
17+
1418
def self.infer: (::String path) -> ::String?
1519
end
1620
end

spec/datadog/tracing/contrib/rack/route_from_path_inference_spec.rb renamed to spec/datadog/tracing/contrib/rack/route_inference_spec.rb

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,46 @@
11
require 'datadog/tracing/contrib/support/spec_helper'
22

3-
require 'datadog/tracing/contrib/rack/route_from_path_inference'
3+
require 'datadog/tracing/contrib/rack/route_inference'
4+
5+
RSpec.describe Datadog::Tracing::Contrib::Rack::RouteInference do
6+
describe '.read_or_infer' do
7+
context 'when inferred route was not yet persisted in request env' do
8+
let(:env) do
9+
{
10+
'SCRIPT_NAME' => '/api',
11+
'PATH_INFO' => '/users/1'
12+
}
13+
end
14+
15+
it 'returns inferred route' do
16+
expect(described_class.read_or_infer(env)).to eq('/api/users/{param:int}')
17+
end
18+
19+
it 'persists inferred route in request env' do
20+
expect { described_class.read_or_infer(env) }.to change { env['datadog.inferred_route'] }
21+
.from(nil).to('/api/users/{param:int}')
22+
end
23+
end
24+
25+
context 'when inferred route already persisted in request env' do
26+
let(:env) do
27+
{
28+
'SCRIPT_NAME' => '/api',
29+
'PATH_INFO' => '/users/1',
30+
'datadog.inferred_route' => '/some_route'
31+
}
32+
end
33+
34+
it 'returns persisted inferred route' do
35+
expect(described_class.read_or_infer(env)).to eq('/some_route')
36+
end
37+
38+
it 'does not change inferred route value in request env' do
39+
expect { described_class.read_or_infer(env) }.not_to change { env['datadog.inferred_route'] }
40+
end
41+
end
42+
end
443

5-
RSpec.describe Datadog::Tracing::Contrib::Rack::RouteFromPathInference do
644
describe '.infer' do
745
it 'works with an empty path' do
846
expect(described_class.infer('/')).to eq('/')

0 commit comments

Comments
 (0)