ddtrace 1.4.2 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -3
- data/LICENSE-3rdparty.csv +1 -0
- data/ext/ddtrace_profiling_native_extension/native_extension_helpers.rb +0 -2
- data/lib/datadog/appsec/assets/waf_rules/recommended.json +1169 -275
- data/lib/datadog/appsec/assets/waf_rules/risky.json +78 -78
- data/lib/datadog/appsec/assets/waf_rules/strict.json +278 -88
- data/lib/datadog/appsec/configuration/settings.rb +0 -2
- data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +25 -20
- data/lib/datadog/appsec/contrib/rack/reactive/request.rb +11 -11
- data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +11 -11
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +11 -11
- data/lib/datadog/appsec/contrib/rack/request.rb +3 -0
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +2 -1
- data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -6
- data/lib/datadog/appsec/contrib/rails/integration.rb +1 -1
- data/lib/datadog/appsec/contrib/rails/reactive/action.rb +11 -11
- data/lib/datadog/appsec/contrib/rails/request.rb +3 -0
- data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +14 -12
- data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +11 -11
- data/lib/datadog/appsec/event.rb +0 -8
- data/lib/datadog/appsec/instrumentation/gateway.rb +16 -2
- data/lib/datadog/appsec/processor.rb +18 -2
- data/lib/datadog/ci/ext/environment.rb +16 -4
- data/lib/datadog/core/configuration/agent_settings_resolver.rb +0 -3
- data/lib/datadog/core/configuration/components.rb +8 -2
- data/lib/datadog/core/configuration/settings.rb +71 -4
- data/lib/datadog/core/configuration.rb +1 -1
- data/lib/datadog/core/header_collection.rb +41 -0
- data/lib/datadog/core/telemetry/collector.rb +0 -2
- data/lib/datadog/core/workers/async.rb +0 -2
- data/lib/datadog/profiling/collectors/old_stack.rb +1 -1
- data/lib/datadog/profiling.rb +1 -1
- data/lib/datadog/tracing/client_ip.rb +153 -0
- data/lib/datadog/tracing/configuration/ext.rb +12 -0
- data/lib/datadog/tracing/contrib/aws/services.rb +0 -2
- data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +0 -2
- data/lib/datadog/tracing/contrib/ext.rb +19 -0
- data/lib/datadog/tracing/contrib/faraday/middleware.rb +1 -2
- data/lib/datadog/tracing/contrib/grape/endpoint.rb +0 -2
- data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/pg/instrumentation.rb +5 -4
- data/lib/datadog/tracing/contrib/rack/header_collection.rb +35 -0
- data/lib/datadog/tracing/contrib/rack/middlewares.rb +92 -38
- data/lib/datadog/tracing/contrib/utils/quantization/http.rb +92 -10
- data/lib/datadog/tracing/flush.rb +57 -35
- data/lib/datadog/tracing/metadata/ext.rb +3 -9
- data/lib/datadog/tracing/metadata/tagging.rb +9 -0
- data/lib/datadog/tracing/sampling/rate_limiter.rb +3 -0
- data/lib/datadog/tracing/sampling/rate_sampler.rb +10 -0
- data/lib/datadog/tracing/sampling/span/ext.rb +29 -0
- data/lib/datadog/tracing/sampling/span/matcher.rb +9 -0
- data/lib/datadog/tracing/sampling/span/rule.rb +82 -0
- data/lib/datadog/tracing/sampling/span/rule_parser.rb +104 -0
- data/lib/datadog/tracing/sampling/span/sampler.rb +64 -0
- data/lib/datadog/tracing/span_operation.rb +0 -2
- data/lib/datadog/tracing/trace_operation.rb +22 -3
- data/lib/datadog/tracing/trace_segment.rb +1 -2
- data/lib/datadog/tracing/tracer.rb +31 -5
- data/lib/ddtrace/transport/traces.rb +2 -0
- data/lib/ddtrace/version.rb +2 -2
- metadata +21 -7
@@ -10,7 +10,6 @@ module Datadog
|
|
10
10
|
module CI
|
11
11
|
module Ext
|
12
12
|
# Defines constants for CI tags
|
13
|
-
# rubocop:disable Metrics/ModuleLength:
|
14
13
|
module Environment
|
15
14
|
include Kernel # Ensure that kernel methods are always available (https://sorbet.org/docs/error-reference#7003)
|
16
15
|
|
@@ -97,6 +96,12 @@ module Datadog
|
|
97
96
|
tag = env['APPVEYOR_REPO_TAG_NAME']
|
98
97
|
end
|
99
98
|
|
99
|
+
commit_message = env['APPVEYOR_REPO_COMMIT_MESSAGE']
|
100
|
+
if commit_message
|
101
|
+
extended = env['APPVEYOR_REPO_COMMIT_MESSAGE_EXTENDED']
|
102
|
+
commit_message = "#{commit_message}\n#{extended}" if extended
|
103
|
+
end
|
104
|
+
|
100
105
|
{
|
101
106
|
TAG_PROVIDER_NAME => 'appveyor',
|
102
107
|
Core::Git::Ext::TAG_REPOSITORY_URL => repository,
|
@@ -111,7 +116,7 @@ module Datadog
|
|
111
116
|
Core::Git::Ext::TAG_TAG => tag,
|
112
117
|
Core::Git::Ext::TAG_COMMIT_AUTHOR_NAME => env['APPVEYOR_REPO_COMMIT_AUTHOR'],
|
113
118
|
Core::Git::Ext::TAG_COMMIT_AUTHOR_EMAIL => env['APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL'],
|
114
|
-
Core::Git::Ext::TAG_COMMIT_MESSAGE =>
|
119
|
+
Core::Git::Ext::TAG_COMMIT_MESSAGE => commit_message
|
115
120
|
}
|
116
121
|
end
|
117
122
|
|
@@ -330,6 +335,10 @@ module Datadog
|
|
330
335
|
branch = (
|
331
336
|
env['BITRISEIO_GIT_BRANCH_DEST'] || env['BITRISE_GIT_BRANCH']
|
332
337
|
)
|
338
|
+
commiter_email = (
|
339
|
+
env['GIT_CLONE_COMMIT_COMMITER_EMAIL'] || env['GIT_CLONE_COMMIT_COMMITER_NAME']
|
340
|
+
)
|
341
|
+
|
333
342
|
{
|
334
343
|
TAG_PROVIDER_NAME => 'bitrise',
|
335
344
|
TAG_PIPELINE_ID => env['BITRISE_BUILD_SLUG'],
|
@@ -341,7 +350,11 @@ module Datadog
|
|
341
350
|
Core::Git::Ext::TAG_COMMIT_SHA => commit,
|
342
351
|
Core::Git::Ext::TAG_BRANCH => branch,
|
343
352
|
Core::Git::Ext::TAG_TAG => env['BITRISE_GIT_TAG'],
|
344
|
-
Core::Git::Ext::TAG_COMMIT_MESSAGE => env['BITRISE_GIT_MESSAGE']
|
353
|
+
Core::Git::Ext::TAG_COMMIT_MESSAGE => env['BITRISE_GIT_MESSAGE'],
|
354
|
+
Core::Git::Ext::TAG_COMMIT_AUTHOR_NAME => env['GIT_CLONE_COMMIT_AUTHOR_NAME'],
|
355
|
+
Core::Git::Ext::TAG_COMMIT_AUTHOR_EMAIL => env['GIT_CLONE_COMMIT_AUTHOR_EMAIL'],
|
356
|
+
Core::Git::Ext::TAG_COMMIT_COMMITTER_NAME => env['GIT_CLONE_COMMIT_COMMITER_NAME'],
|
357
|
+
Core::Git::Ext::TAG_COMMIT_COMMITTER_EMAIL => commiter_email
|
345
358
|
}
|
346
359
|
end
|
347
360
|
|
@@ -499,7 +512,6 @@ module Datadog
|
|
499
512
|
[nil, name_and_email]
|
500
513
|
end
|
501
514
|
end
|
502
|
-
# rubocop:enable Metrics/ModuleLength:
|
503
515
|
end
|
504
516
|
end
|
505
517
|
end
|
@@ -18,8 +18,6 @@ module Datadog
|
|
18
18
|
#
|
19
19
|
# Whenever there is a conflict (different configurations are provided in different orders), it MUST warn the users
|
20
20
|
# about it and pick a value based on the following priority: code > environment variable > defaults.
|
21
|
-
#
|
22
|
-
# rubocop:disable Metrics/ClassLength
|
23
21
|
class AgentSettingsResolver
|
24
22
|
AgentSettings = \
|
25
23
|
Struct.new(
|
@@ -359,7 +357,6 @@ module Datadog
|
|
359
357
|
end
|
360
358
|
end
|
361
359
|
end
|
362
|
-
# rubocop:enable Metrics/ClassLength
|
363
360
|
end
|
364
361
|
end
|
365
362
|
end
|
@@ -11,12 +11,13 @@ require_relative '../workers/runtime_metrics'
|
|
11
11
|
require_relative '../../tracing/tracer'
|
12
12
|
require_relative '../../tracing/flush'
|
13
13
|
require_relative '../../tracing/sync_writer'
|
14
|
+
require_relative '../../tracing/sampling/span/rule_parser'
|
15
|
+
require_relative '../../tracing/sampling/span/sampler'
|
14
16
|
|
15
17
|
module Datadog
|
16
18
|
module Core
|
17
19
|
module Configuration
|
18
20
|
# Global components for the trace library.
|
19
|
-
# rubocop:disable Metrics/ClassLength
|
20
21
|
class Components
|
21
22
|
class << self
|
22
23
|
def build_health_metrics(settings)
|
@@ -80,6 +81,7 @@ module Datadog
|
|
80
81
|
enabled: settings.tracing.enabled,
|
81
82
|
trace_flush: trace_flush,
|
82
83
|
sampler: sampler,
|
84
|
+
span_sampler: build_span_sampler(settings),
|
83
85
|
writer: writer,
|
84
86
|
tags: build_tracer_tags(settings),
|
85
87
|
)
|
@@ -183,6 +185,11 @@ module Datadog
|
|
183
185
|
end
|
184
186
|
end
|
185
187
|
|
188
|
+
def build_span_sampler(settings)
|
189
|
+
rules = Tracing::Sampling::Span::RuleParser.parse_json(settings.tracing.sampling.span_rules)
|
190
|
+
Tracing::Sampling::Span::Sampler.new(rules || [])
|
191
|
+
end
|
192
|
+
|
186
193
|
def build_profiler(settings, agent_settings, tracer)
|
187
194
|
return unless settings.profiling.enabled
|
188
195
|
|
@@ -423,7 +430,6 @@ module Datadog
|
|
423
430
|
telemetry.emit_closing! unless replacement
|
424
431
|
end
|
425
432
|
end
|
426
|
-
# rubocop:enable Metrics/ClassLength
|
427
433
|
end
|
428
434
|
end
|
429
435
|
end
|
@@ -15,7 +15,6 @@ module Datadog
|
|
15
15
|
# Global configuration settings for the trace library.
|
16
16
|
# @public_api
|
17
17
|
# rubocop:disable Metrics/BlockLength
|
18
|
-
# rubocop:disable Metrics/ClassLength
|
19
18
|
# rubocop:disable Layout/LineLength
|
20
19
|
class Settings
|
21
20
|
include Base
|
@@ -324,8 +323,8 @@ module Datadog
|
|
324
323
|
|
325
324
|
# Parse tags from environment
|
326
325
|
env_to_list(Core::Environment::Ext::ENV_TAGS, comma_separated_only: false).each do |tag|
|
327
|
-
|
328
|
-
tags[
|
326
|
+
key, value = tag.split(':', 2)
|
327
|
+
tags[key] = value if value && !value.empty?
|
329
328
|
end
|
330
329
|
|
331
330
|
# Override tags if defined
|
@@ -540,6 +539,7 @@ module Datadog
|
|
540
539
|
option :sampler
|
541
540
|
|
542
541
|
# Client-side sampling configuration.
|
542
|
+
# @see https://docs.datadoghq.com/tracing/trace_ingestion/mechanisms/
|
543
543
|
# @public_api
|
544
544
|
settings :sampling do
|
545
545
|
# Default sampling rate for the tracer.
|
@@ -566,6 +566,48 @@ module Datadog
|
|
566
566
|
o.default { env_to_float(Tracing::Configuration::Ext::Sampling::ENV_RATE_LIMIT, 100) }
|
567
567
|
o.lazy
|
568
568
|
end
|
569
|
+
|
570
|
+
# Single span sampling rules.
|
571
|
+
# These rules allow a span to be kept when its encompassing trace is dropped.
|
572
|
+
#
|
573
|
+
# The syntax for single span sampling rules can be found here:
|
574
|
+
# TODO: <Single Span Sampling documentation URL here>
|
575
|
+
#
|
576
|
+
# @default `DD_SPAN_SAMPLING_RULES` environment variable.
|
577
|
+
# Otherwise, `ENV_SPAN_SAMPLING_RULES_FILE` environment variable.
|
578
|
+
# Otherwise `nil`.
|
579
|
+
# @return [String,nil]
|
580
|
+
# @public_api
|
581
|
+
option :span_rules do |o|
|
582
|
+
o.default do
|
583
|
+
rules = ENV[Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES]
|
584
|
+
rules_file = ENV[Tracing::Configuration::Ext::Sampling::Span::ENV_SPAN_SAMPLING_RULES_FILE]
|
585
|
+
|
586
|
+
if rules
|
587
|
+
if rules_file
|
588
|
+
Datadog.logger.warn(
|
589
|
+
'Both DD_SPAN_SAMPLING_RULES and DD_SPAN_SAMPLING_RULES_FILE were provided: only ' \
|
590
|
+
'DD_SPAN_SAMPLING_RULES will be used. Please do not provide DD_SPAN_SAMPLING_RULES_FILE when ' \
|
591
|
+
'also providing DD_SPAN_SAMPLING_RULES as their configuration conflicts. ' \
|
592
|
+
"DD_SPAN_SAMPLING_RULES_FILE=#{rules_file} DD_SPAN_SAMPLING_RULES=#{rules}"
|
593
|
+
)
|
594
|
+
end
|
595
|
+
rules
|
596
|
+
elsif rules_file
|
597
|
+
begin
|
598
|
+
File.read(rules_file)
|
599
|
+
rescue => e
|
600
|
+
# `File#read` errors have clear and actionable messages, no need to add extra exception info.
|
601
|
+
Datadog.logger.warn(
|
602
|
+
"Cannot read span sampling rules file `#{rules_file}`: #{e.message}." \
|
603
|
+
'No span sampling rules will be applied.'
|
604
|
+
)
|
605
|
+
nil
|
606
|
+
end
|
607
|
+
end
|
608
|
+
end
|
609
|
+
o.lazy
|
610
|
+
end
|
569
611
|
end
|
570
612
|
|
571
613
|
# [Continuous Integration Visibility](https://docs.datadoghq.com/continuous_integration/) configuration.
|
@@ -618,6 +660,32 @@ module Datadog
|
|
618
660
|
# @default `{}`
|
619
661
|
# @return [Hash,nil]
|
620
662
|
option :writer_options, default: ->(_i) { {} }, lazy: true
|
663
|
+
|
664
|
+
# Client IP configuration
|
665
|
+
# @public_api
|
666
|
+
settings :client_ip do
|
667
|
+
# Whether client IP collection is enabled. When enabled client IPs from HTTP requests will
|
668
|
+
# be reported in traces.
|
669
|
+
#
|
670
|
+
# @see https://docs.datadoghq.com/tracing/configure_data_security#configuring-a-client-ip-header
|
671
|
+
#
|
672
|
+
# @default The negated value of the `DD_TRACE_CLIENT_IP_HEADER_DISABLED` environment
|
673
|
+
# variable or `true` if it doesn't exist.
|
674
|
+
# @return [Boolean]
|
675
|
+
option :enabled do |o|
|
676
|
+
o.default { !env_to_bool(Tracing::Configuration::Ext::ClientIp::ENV_DISABLED, false) }
|
677
|
+
o.lazy
|
678
|
+
end
|
679
|
+
|
680
|
+
# An optional name of a custom header to resolve the client IP from.
|
681
|
+
#
|
682
|
+
# @default `DD_TRACE_CLIENT_IP_HEADER` environment variable, otherwise `nil`.
|
683
|
+
# @return [String,nil]
|
684
|
+
option :header_name do |o|
|
685
|
+
o.default { ENV.fetch(Tracing::Configuration::Ext::ClientIp::ENV_HEADER_NAME, nil) }
|
686
|
+
o.lazy
|
687
|
+
end
|
688
|
+
end
|
621
689
|
end
|
622
690
|
|
623
691
|
# The `version` tag in Datadog. Use it to enable [Deployment Tracking](https://docs.datadoghq.com/tracing/deployment_tracking/).
|
@@ -645,7 +713,6 @@ module Datadog
|
|
645
713
|
end
|
646
714
|
end
|
647
715
|
# rubocop:enable Metrics/BlockLength
|
648
|
-
# rubocop:enable Metrics/ClassLength
|
649
716
|
# rubocop:enable Layout/LineLength
|
650
717
|
end
|
651
718
|
end
|
@@ -9,7 +9,7 @@ require_relative 'pin'
|
|
9
9
|
module Datadog
|
10
10
|
module Core
|
11
11
|
# Configuration provides a unique access point for configurations
|
12
|
-
module Configuration
|
12
|
+
module Configuration
|
13
13
|
include Kernel # Ensure that kernel methods are always available (https://sorbet.org/docs/error-reference#7003)
|
14
14
|
|
15
15
|
# Used to ensure that @components initialization/reconfiguration is performed one-at-a-time, by a single thread.
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Datadog
|
2
|
+
module Core
|
3
|
+
# A some-what abstract class representing a collection of headers.
|
4
|
+
#
|
5
|
+
# Use the `HeaderCollection.from_hash` function to create a header collection from a `Hash`.
|
6
|
+
# Another option is to use `HashHeaderCollection` directly.
|
7
|
+
class HeaderCollection
|
8
|
+
# Gets a single value of the header with the given name, case insensitive.
|
9
|
+
#
|
10
|
+
# @param [String] header_name Name of the header to get the value of.
|
11
|
+
# @returns [String, nil] A single value of the header, or nil if the header with
|
12
|
+
# the given name is missing from the collection.
|
13
|
+
def get(header_name)
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create a header collection that retrieves headers from the given Hash.
|
18
|
+
#
|
19
|
+
# This can be useful for testing or other trivial use cases.
|
20
|
+
#
|
21
|
+
# @param [Hash] hash Hash with the headers.
|
22
|
+
def self.from_hash(hash)
|
23
|
+
HashHeaderCollection.new(hash)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# A header collection implementation that looks up headers in a Hash.
|
28
|
+
class HashHeaderCollection < HeaderCollection
|
29
|
+
def initialize(hash)
|
30
|
+
super()
|
31
|
+
@hash = {}.tap do |res|
|
32
|
+
hash.each_pair { |key, value| res[key.downcase] = value }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def get(header_name)
|
37
|
+
@hash[header_name.downcase]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -18,7 +18,6 @@ module Datadog
|
|
18
18
|
module Core
|
19
19
|
module Telemetry
|
20
20
|
# Module defining methods for collecting metadata for telemetry
|
21
|
-
# rubocop:disable Metrics/ModuleLength
|
22
21
|
module Collector
|
23
22
|
include Datadog::Core::Configuration
|
24
23
|
|
@@ -228,7 +227,6 @@ module Datadog
|
|
228
227
|
end
|
229
228
|
end
|
230
229
|
end
|
231
|
-
# rubocop:enable Metrics/ModuleLength
|
232
230
|
end
|
233
231
|
end
|
234
232
|
end
|
@@ -8,7 +8,6 @@ module Datadog
|
|
8
8
|
module Async
|
9
9
|
# Adds threading behavior to workers
|
10
10
|
# to run tasks asynchronously.
|
11
|
-
# rubocop:disable Metrics/ModuleLength
|
12
11
|
module Thread
|
13
12
|
FORK_POLICY_STOP = :stop
|
14
13
|
FORK_POLICY_RESTART = :restart
|
@@ -175,7 +174,6 @@ module Datadog
|
|
175
174
|
end
|
176
175
|
end
|
177
176
|
end
|
178
|
-
# rubocop:enable Metrics/ModuleLength
|
179
177
|
end
|
180
178
|
end
|
181
179
|
end
|
@@ -15,7 +15,7 @@ module Datadog
|
|
15
15
|
# Runs on its own background thread.
|
16
16
|
#
|
17
17
|
# This class has the prefix "Old" because it will be deprecated by the new native CPU Profiler
|
18
|
-
class OldStack < Core::Worker
|
18
|
+
class OldStack < Core::Worker
|
19
19
|
include Core::Workers::Polling
|
20
20
|
|
21
21
|
DEFAULT_MAX_TIME_USAGE_PCT = 2.0
|
data/lib/datadog/profiling.rb
CHANGED
@@ -6,7 +6,7 @@ require_relative 'core/utils/only_once'
|
|
6
6
|
|
7
7
|
module Datadog
|
8
8
|
# Contains profiler for generating stack profiles, etc.
|
9
|
-
module Profiling
|
9
|
+
module Profiling
|
10
10
|
GOOGLE_PROTOBUF_MINIMUM_VERSION = Gem::Version.new('3.0')
|
11
11
|
private_constant :GOOGLE_PROTOBUF_MINIMUM_VERSION
|
12
12
|
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
3
|
+
require_relative '../core/configuration'
|
4
|
+
require_relative 'metadata/ext'
|
5
|
+
require_relative 'span'
|
6
|
+
|
7
|
+
require 'ipaddr'
|
8
|
+
|
9
|
+
module Datadog
|
10
|
+
module Tracing
|
11
|
+
# Common functions for supporting the `http.client_ip` span attribute.
|
12
|
+
module ClientIp
|
13
|
+
DEFAULT_IP_HEADERS_NAMES = %w[
|
14
|
+
x-forwarded-for
|
15
|
+
x-real-ip
|
16
|
+
x-client-ip
|
17
|
+
x-forwarded
|
18
|
+
x-cluster-client-ip
|
19
|
+
forwarded-for
|
20
|
+
forwarded
|
21
|
+
via
|
22
|
+
true-client-ip
|
23
|
+
].freeze
|
24
|
+
|
25
|
+
TAG_MULTIPLE_IP_HEADERS = '_dd.multiple-ip-headers'.freeze
|
26
|
+
|
27
|
+
# Sets the `http.client_ip` tag on the given span.
|
28
|
+
#
|
29
|
+
# This function respects the user's settings: if they disable the client IP tagging,
|
30
|
+
# or provide a different IP header name.
|
31
|
+
#
|
32
|
+
# If multiple IP headers are present in the request, this function will instead set
|
33
|
+
# the `_dd.multiple-ip-headers` tag with the names of the present headers,
|
34
|
+
# and **NOT** set the `http.client_ip` tag.
|
35
|
+
#
|
36
|
+
# @param [Span] span The span that's associated with the request.
|
37
|
+
# @param [HeaderCollection, #get, nil] headers A collection with the request headers.
|
38
|
+
# @param [String, nil] remote_ip The remote IP the request associated with the span is sent to.
|
39
|
+
def self.set_client_ip_tag(span, headers: nil, remote_ip: nil)
|
40
|
+
return unless configuration.enabled
|
41
|
+
|
42
|
+
result = raw_ip_from_request(headers, remote_ip)
|
43
|
+
|
44
|
+
if result.raw_ip
|
45
|
+
ip = strip_decorations(result.raw_ip)
|
46
|
+
return unless valid_ip?(ip)
|
47
|
+
|
48
|
+
span.set_tag(Tracing::Metadata::Ext::HTTP::TAG_CLIENT_IP, ip)
|
49
|
+
elsif result.multiple_ip_headers
|
50
|
+
span.set_tag(TAG_MULTIPLE_IP_HEADERS, result.multiple_ip_headers.keys.join(','))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
IpExtractionResult = Struct.new(:raw_ip, :multiple_ip_headers)
|
55
|
+
|
56
|
+
# Returns a result struct that holds the raw client IP associated with the request if it was
|
57
|
+
# retrieved successfully.
|
58
|
+
#
|
59
|
+
# The client IP is looked up by the following logic:
|
60
|
+
# * If the user has configured a header name, return that header's value.
|
61
|
+
# * If exactly one of the known IP headers is present, return that header's value.
|
62
|
+
# * If none of the known IP headers are present, return the remote IP from the request.
|
63
|
+
#
|
64
|
+
# If more than one of the known IP headers is present, the result will have a `multiple_ip_headers`
|
65
|
+
# field with the name of the present IP headers.
|
66
|
+
#
|
67
|
+
# @param [Datadog::Core::HeaderCollection, #get, nil] headers The request headers
|
68
|
+
# @param [String] remote_ip The remote IP of the request.
|
69
|
+
# @return [IpExtractionResult] A struct that holds the unprocessed IP value,
|
70
|
+
# or `nil` if it wasn't found. Additionally, the `multiple_ip_headers` fields will hold the
|
71
|
+
# name of known IP headers present in the request if more than one of these were found.
|
72
|
+
def self.raw_ip_from_request(headers, remote_ip)
|
73
|
+
return IpExtractionResult.new(headers && headers.get(configuration.header_name), nil) if configuration.header_name
|
74
|
+
|
75
|
+
headers_present = ip_headers(headers)
|
76
|
+
|
77
|
+
case headers_present.size
|
78
|
+
when 0
|
79
|
+
IpExtractionResult.new(remote_ip, nil)
|
80
|
+
when 1
|
81
|
+
IpExtractionResult.new(headers_present.values.first, nil)
|
82
|
+
else
|
83
|
+
IpExtractionResult.new(nil, headers_present)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Removes any port notations or zone specifiers from the IP address without
|
88
|
+
# verifying its validity.
|
89
|
+
def self.strip_decorations(address)
|
90
|
+
return strip_ipv4_port(address) if likely_ipv4?(address)
|
91
|
+
|
92
|
+
address = strip_ipv6_port(address)
|
93
|
+
|
94
|
+
strip_zone_specifier(address)
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.strip_zone_specifier(ipv6)
|
98
|
+
ipv6.gsub(/%.*/, '')
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.strip_ipv4_port(ip)
|
102
|
+
ip.gsub(/:\d+\z/, '')
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.strip_ipv6_port(ip)
|
106
|
+
if /\[(.*)\](?::\d+)?/ =~ ip
|
107
|
+
Regexp.last_match(1)
|
108
|
+
else
|
109
|
+
ip
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns whether the given value is more likely to be an IPv4 than an IPv6 address.
|
114
|
+
#
|
115
|
+
# This is done by checking if a dot (`'.'`) character appears before a colon (`':'`) in the value.
|
116
|
+
# The rationale is that in valid IPv6 addresses, colons will always preced dots,
|
117
|
+
# and in valid IPv4 addresses dots will always preced colons.
|
118
|
+
def self.likely_ipv4?(value)
|
119
|
+
dot_index = value.index('.') || value.size
|
120
|
+
colon_index = value.index(':') || value.size
|
121
|
+
|
122
|
+
dot_index < colon_index
|
123
|
+
end
|
124
|
+
|
125
|
+
# Determines whether the given string is a valid IPv4 or IPv6 address.
|
126
|
+
def self.valid_ip?(ip)
|
127
|
+
# Client IPs should not have subnet masks even though IPAddr can parse them.
|
128
|
+
return false if ip.include?('/')
|
129
|
+
|
130
|
+
begin
|
131
|
+
IPAddr.new(ip)
|
132
|
+
|
133
|
+
true
|
134
|
+
rescue IPAddr::Error
|
135
|
+
false
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.ip_headers(headers)
|
140
|
+
return {} unless headers
|
141
|
+
|
142
|
+
DEFAULT_IP_HEADERS_NAMES.each_with_object({}) do |name, result|
|
143
|
+
value = headers.get(name)
|
144
|
+
result[name] = value unless value.nil?
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.configuration
|
149
|
+
Datadog.configuration.tracing.client_ip
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -32,6 +32,12 @@ module Datadog
|
|
32
32
|
module Sampling
|
33
33
|
ENV_SAMPLE_RATE = 'DD_TRACE_SAMPLE_RATE'.freeze
|
34
34
|
ENV_RATE_LIMIT = 'DD_TRACE_RATE_LIMIT'.freeze
|
35
|
+
|
36
|
+
# @public_api
|
37
|
+
module Span
|
38
|
+
ENV_SPAN_SAMPLING_RULES = 'DD_SPAN_SAMPLING_RULES'.freeze
|
39
|
+
ENV_SPAN_SAMPLING_RULES_FILE = 'DD_SPAN_SAMPLING_RULES_FILE'.freeze
|
40
|
+
end
|
35
41
|
end
|
36
42
|
|
37
43
|
# @public_api
|
@@ -45,6 +51,12 @@ module Datadog
|
|
45
51
|
ENV_DEFAULT_PORT = 'DD_TRACE_AGENT_PORT'.freeze
|
46
52
|
ENV_DEFAULT_URL = 'DD_TRACE_AGENT_URL'.freeze
|
47
53
|
end
|
54
|
+
|
55
|
+
# @public_api
|
56
|
+
module ClientIp
|
57
|
+
ENV_DISABLED = 'DD_TRACE_CLIENT_IP_HEADER_DISABLED'.freeze
|
58
|
+
ENV_HEADER_NAME = 'DD_TRACE_CLIENT_IP_HEADER'.freeze
|
59
|
+
end
|
48
60
|
end
|
49
61
|
end
|
50
62
|
end
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module Datadog
|
4
4
|
module Tracing
|
5
5
|
module Contrib
|
6
|
-
# rubocop:disable Metrics/ModuleLength:
|
7
6
|
module Aws
|
8
7
|
SERVICES = %w[
|
9
8
|
ACM
|
@@ -117,7 +116,6 @@ module Datadog
|
|
117
116
|
XRay
|
118
117
|
].freeze
|
119
118
|
end
|
120
|
-
# rubocop:enable Metrics/ModuleLength:
|
121
119
|
end
|
122
120
|
end
|
123
121
|
end
|
@@ -18,7 +18,6 @@ module Datadog
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# InstanceMethods - implementing instrumentation
|
21
|
-
# rubocop:disable Metrics/ModuleLength
|
22
21
|
module InstanceMethods
|
23
22
|
include Contrib::HttpAnnotationHelper
|
24
23
|
|
@@ -168,7 +167,6 @@ module Datadog
|
|
168
167
|
datadog_configuration[:analytics_sample_rate]
|
169
168
|
end
|
170
169
|
end
|
171
|
-
# rubocop:enable Metrics/ModuleLength
|
172
170
|
end
|
173
171
|
end
|
174
172
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Tracing
|
5
|
+
module Contrib
|
6
|
+
# Contrib specific constants
|
7
|
+
module Ext
|
8
|
+
# @public_api
|
9
|
+
module DB
|
10
|
+
TAG_INSTANCE = 'db.instance'
|
11
|
+
TAG_USER = 'db.user'
|
12
|
+
TAG_SYSTEM = 'db.system'
|
13
|
+
TAG_STATEMENT = 'db.statement'
|
14
|
+
TAG_ROW_COUNT = 'db.row_count'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -39,8 +39,7 @@ module Datadog
|
|
39
39
|
|
40
40
|
def annotate!(span, env, options)
|
41
41
|
span.resource = resource_name(env)
|
42
|
-
service_name(env[:url].host, options)
|
43
|
-
span.service = options[:split_by_domain] ? env[:url].host : options[:service_name]
|
42
|
+
span.service = service_name(env[:url].host, options)
|
44
43
|
span.span_type = Tracing::Metadata::Ext::HTTP::TYPE_OUTBOUND
|
45
44
|
|
46
45
|
span.set_tag(Tracing::Metadata::Ext::TAG_COMPONENT, Ext::TAG_COMPONENT)
|
@@ -9,7 +9,6 @@ module Datadog
|
|
9
9
|
module Tracing
|
10
10
|
module Contrib
|
11
11
|
module Grape
|
12
|
-
# rubocop:disable Metrics/ModuleLength
|
13
12
|
# Endpoint module includes a list of subscribers to create
|
14
13
|
# traces when a Grape endpoint is hit
|
15
14
|
module Endpoint
|
@@ -245,7 +244,6 @@ module Datadog
|
|
245
244
|
end
|
246
245
|
end
|
247
246
|
end
|
248
|
-
# rubocop:enable Metrics/ModuleLength
|
249
247
|
end
|
250
248
|
end
|
251
249
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative '../../metadata/ext'
|
4
4
|
require_relative '../analytics'
|
5
|
+
require_relative '../ext'
|
5
6
|
require_relative 'ext'
|
6
7
|
|
7
8
|
module Datadog
|
@@ -95,9 +96,9 @@ module Datadog
|
|
95
96
|
span.set_tag(Tracing::Metadata::Ext::TAG_PEER_SERVICE, service)
|
96
97
|
span.set_tag(Tracing::Metadata::Ext::TAG_PEER_HOSTNAME, host)
|
97
98
|
|
98
|
-
span.set_tag(
|
99
|
-
span.set_tag(
|
100
|
-
span.set_tag(
|
99
|
+
span.set_tag(Contrib::Ext::DB::TAG_INSTANCE, db)
|
100
|
+
span.set_tag(Contrib::Ext::DB::TAG_USER, user)
|
101
|
+
span.set_tag(Contrib::Ext::DB::TAG_SYSTEM, Ext::SPAN_SYSTEM)
|
101
102
|
|
102
103
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_HOST, host)
|
103
104
|
span.set_tag(Tracing::Metadata::Ext::NET::TAG_TARGET_PORT, port)
|
@@ -106,7 +107,7 @@ module Datadog
|
|
106
107
|
end
|
107
108
|
|
108
109
|
def annotate_span_with_result!(span, result)
|
109
|
-
span.set_tag(
|
110
|
+
span.set_tag(Contrib::Ext::DB::TAG_ROW_COUNT, result.ntuples)
|
110
111
|
end
|
111
112
|
|
112
113
|
def datadog_configuration
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative '../../../core/header_collection'
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module Tracing
|
5
|
+
module Contrib
|
6
|
+
module Rack
|
7
|
+
# Classes and utilities for handling headers in Rack.
|
8
|
+
module Header
|
9
|
+
# An implementation of a header collection that looks up headers from a Rack environment.
|
10
|
+
class RequestHeaderCollection < Datadog::Core::HeaderCollection
|
11
|
+
# Creates a header collection from a rack environment.
|
12
|
+
def initialize(env)
|
13
|
+
super()
|
14
|
+
@env = env
|
15
|
+
end
|
16
|
+
|
17
|
+
# Gets the value of the header with the given name.
|
18
|
+
def get(header_name)
|
19
|
+
@env[Header.to_rack_header(header_name)]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Tests whether a header with the given name exists in the environment.
|
23
|
+
def key?(header_name)
|
24
|
+
@env.key?(Header.to_rack_header(header_name))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.to_rack_header(name)
|
29
|
+
"HTTP_#{name.to_s.upcase.gsub(/[-\s]/, '_')}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|