ddtrace 1.15.0 → 1.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -98
- data/lib/datadog/appsec/configuration/settings.rb +6 -0
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +6 -2
- data/lib/datadog/appsec/contrib/rack/gateway/response.rb +46 -0
- data/lib/datadog/appsec/contrib/rack/reactive/response.rb +5 -0
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +11 -1
- data/lib/datadog/core/remote/worker.rb +3 -1
- data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +2 -1
- data/lib/datadog/profiling/profiler.rb +26 -2
- data/lib/datadog/profiling/scheduler.rb +16 -9
- data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/context_composite_executor_service.rb +14 -14
- data/lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb +3 -10
- data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +2 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb +8 -1
- data/lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb +22 -0
- data/lib/datadog/tracing/contrib/redis/configuration/settings.rb +1 -1
- data/lib/datadog/tracing/contrib/redis/instrumentation.rb +3 -38
- data/lib/datadog/tracing/contrib/redis/tags.rb +2 -2
- data/lib/datadog/tracing/contrib/redis/trace_middleware.rb +46 -33
- data/lib/datadog/tracing/diagnostics/environment_logger.rb +6 -0
- data/lib/ddtrace/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59aaa9c3c11af9219405c9eee4e318df4cafdaae57eb42c7b5105d46764d3293
|
4
|
+
data.tar.gz: ef0d6766221287a4e9d42bf42f43fd5ddd81990ea381e536b5083be8a3f0b94d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0201e1fd1e96ea0a076cf88af3824cb02f15862312eb26688db474caec2698bdfee9381b947e4ab278bbaa752aeb8a92df2f2188aa7e4ba988e5cdc31331f138
|
7
|
+
data.tar.gz: 2a034e4187f41b85a29d7003fbe1098552cdddf0be663e490ab2ca71c4da40a8ad122f3357b11286af10df988f0891cc8d2d71ca59d9949db790dda6011033d0
|
data/CHANGELOG.md
CHANGED
@@ -2,134 +2,90 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
-
## [1.
|
6
|
-
|
7
|
-
### Highlights
|
8
|
-
|
9
|
-
#### Timeline view for Profiler beta
|
10
|
-
|
11
|
-
As of ddtrace 1.15.0, the Profiler now supports gathering data for the new
|
12
|
-
[Timeline view](https://docs.datadoghq.com/profiler/profile_visualizations/#timeline-view).
|
5
|
+
## [1.16.0] - 2023-11-03
|
13
6
|
|
14
|
-
|
7
|
+
**This release includes a security change for the Tracing Redis integration:**
|
15
8
|
|
16
|
-
|
17
|
-
|
18
|
-
You can enable it:
|
19
|
-
|
20
|
-
* Using an environment variable by setting `DD_PROFILING_EXPERIMENTAL_TIMELINE_ENABLED=true`
|
21
|
-
* Or via code by adding to your `Datadog.configure` block:
|
22
|
-
|
23
|
-
```ruby
|
24
|
-
Datadog.configure do |c|
|
25
|
-
# … existing configuration …
|
26
|
-
c.profiling.advanced.experimental_timeline_enabled = true
|
27
|
-
end
|
28
|
-
```
|
9
|
+
Currently, the Datadog Agent removes command arguments from the resource name. However there are cases, like Redis compressed keys, where this obfuscation cannot correctly remove command arguments. To safeguard that situation, the resource name set by the tracer will only be the command (e.g. `SET`) with no arguments. To retain the previous behavior and keep arguments in the span resource, with the potential risk of some command arguments not being fully obfuscated, set ``DD_REDIS_COMMAND_ARGS=true`` or set the option `c.instrument :redis, command_args: true`.
|
29
10
|
|
30
|
-
|
31
|
-
|
32
|
-
(Note: We do not recommend enabling this feature prior to 1.15.0!)
|
33
|
-
|
34
|
-
#### google-protobuf dependency is no longer needed by the Profiler
|
35
|
-
|
36
|
-
As of ddtrace version 1.15.0, the `google-protobuf` gem is no longer needed to enable the Profiler.
|
37
|
-
|
38
|
-
If you've added this gem to your `Gemfile`/`gems.rb` file as part of enabling the Profiler, you can
|
39
|
-
remove it now. (If you're curious, we've internally replaced this dependency with the `libdatadog` gem.)
|
40
|
-
|
41
|
-
#### Configure blocking responses for AppSec via configuration or Remote Configuration
|
42
|
-
|
43
|
-
As of dd-trace-rb 1.15.0, AppSec supports configuring the blocking response.
|
11
|
+
### Added
|
44
12
|
|
45
|
-
|
46
|
-
|
47
|
-
- Via code by adding to your `Datadog.configure` block:
|
13
|
+
* Tracing: Propagate trace through `Concurrent::Promises.future` ([#1522][])
|
14
|
+
* Core: Name `Datadog::Core::Remote::Worker` thread ([#3207][])
|
48
15
|
|
49
|
-
|
50
|
-
Datadog.configure do |c|
|
51
|
-
# … existing configuration …
|
52
|
-
c.appsec.block.templates.html = "#{file_name}"
|
53
|
-
c.appsec.block.templates.json = "#{file_name}"
|
54
|
-
end
|
55
|
-
```
|
16
|
+
### Changed
|
56
17
|
|
57
|
-
|
58
|
-
|
18
|
+
* Tracing: Redis - Omit command arguments from span.resource by default ([#3235][])
|
19
|
+
* Ci-app: Bump `datadog-ci` dependency from 0.2.0 to 0.3.0 ([#3223][])
|
59
20
|
|
60
|
-
|
21
|
+
### Fixed
|
61
22
|
|
62
|
-
|
23
|
+
* Appsec: ASM parse response body ([#3153][])
|
24
|
+
* Appsec: ASM make sure to append content type and length information ([#3204][])
|
25
|
+
* Appsec: Make sure function that checks content-type header value accepts nil content-type header value ([#3234][])
|
26
|
+
* Profiling: Shut down profiler if any components failed ([#3197][])
|
27
|
+
* Tracing: Fix `ActiveSupport` instrumentation of custom cache stores ([#3206][])
|
63
28
|
|
64
|
-
|
65
|
-
- DD_CIVISIBILITY_AGENTLESS_ENABLED=true
|
66
|
-
- DD_API_KEY=<your_api_key>
|
29
|
+
## [1.15.0] - 2023-10-09
|
67
30
|
|
68
|
-
|
69
|
-
- DD_SITE (default: datadoghq.com)
|
31
|
+
### Highlights
|
70
32
|
|
71
|
-
|
33
|
+
* Timeline view for Profiler beta
|
34
|
+
* Configure AppSec blocking responses via configuration or Remote Configuration
|
35
|
+
* CI visibility to configure with agentless mode
|
72
36
|
|
73
|
-
|
74
|
-
Datadog.configure do |c|
|
75
|
-
# … existing configuration …
|
76
|
-
c.ci.agentless_mode_enabled = true
|
77
|
-
# don't forget to set DD_API_KEY env variable!
|
78
|
-
end
|
79
|
-
```
|
37
|
+
For more details, check the [release notes](https://github.com/DataDog/dd-trace-rb/releases/tag/v1.15.0)
|
80
38
|
|
81
39
|
### Added
|
82
|
-
|
83
|
-
* Tracing: Support Opensearch 3 ([#3189][])
|
84
|
-
* bump datadog-ci dependency to 0.2 ([#3186][])
|
40
|
+
|
85
41
|
* Enable allocation counting feature by default for some Ruby 3 versions ([#3176][])
|
86
|
-
*
|
87
|
-
*
|
88
|
-
* Appsec: Update AppSec rules to 1.7.2 ([#3139][])
|
89
|
-
* Appsec: ASM API security. Schema extraction ([#3131][], [#3166][], [#3177][])
|
90
|
-
* Tracing: peer.service adjustment for sql propagation with DBM ([#3127][])
|
91
|
-
* Ci-app: CI visibility: validate git tags ([#3100][])
|
92
|
-
* Appsec: Enable configuring blocking response via Remote Configuration ([#3099][])
|
42
|
+
* Detect `WebMock` `Cucumber` and `Rails.env` to disable telemetry and remote configuration for development environment ([#3065][], [#3062][], [#3145][])
|
43
|
+
* Profiling: Import java-profiler PID controller and port it to C ([#3190][])
|
93
44
|
* Profiling: Record allocation type when sampling objects ([#3096][])
|
94
|
-
*
|
95
|
-
*
|
96
|
-
*
|
97
|
-
*
|
45
|
+
* Profiling: Include `ruby vm type` in profiler allocation samples ([#3074][])
|
46
|
+
* Tracing: Support `Rack` 3 ([#3132][])
|
47
|
+
* Tracing: Support `Opensearch` 3 ([#3189][])
|
48
|
+
* Tracing: `grpc` adds `client_error_handler` option ([#3095][])
|
49
|
+
* Tracing: Add `async` option for `test_mode` configuration ([#3158][])
|
98
50
|
* Tracing: Implements `_dd.base_service` tag ([#3018][])
|
99
51
|
* Appsec: Allow blocking response template configuration via ENV variables ([#2975][])
|
100
|
-
*
|
52
|
+
* Appsec: ASM API security. Schema extraction ([#3131][], [#3166][], [#3177][])
|
53
|
+
* Appsec: Enable configuring blocking response via Remote Configuration ([#3099][])
|
54
|
+
* Ci-app: Validate git tags ([#3100][])
|
55
|
+
* Ci-app: Add agentless mode ([#3186][])
|
101
56
|
|
102
57
|
### Changed
|
103
|
-
|
104
|
-
*
|
105
|
-
* Profiling: Upgrade to libdatadog 5 ([#3169][])
|
58
|
+
|
59
|
+
* Appsec: Skip passing waf addresses when the value is empty ([#3188][])
|
106
60
|
* Profiling: Restore support for Ruby 3.3 ([#3167][])
|
107
|
-
* Bump debase-ruby_core_source dependency to 3.2.2 ([#3163][])
|
108
61
|
* Profiling: Add approximate thread state categorization for timeline ([#3162][])
|
109
|
-
* Tracing: remove variable helpers module from our configuration DSL ([#3152][])
|
110
|
-
* Profiling: Tracing: ekump/decouple core transport ([#3150][])
|
111
|
-
* Test:Remove explicit dependency on `addressable` ([#3148][])
|
112
|
-
* Detect Cucumber as a development environment ([#3145][])
|
113
|
-
* Tracing: rename core configuration option on_set to after_set ([#3107][])
|
114
|
-
* Profiling: Upgrade to libdatadog 4 ([#3104][])
|
115
62
|
* Profiling: Wire up allocation sampling into `CpuAndWallTimeWorker` ([#3103][])
|
116
|
-
* Tracing:
|
117
|
-
* remove `delegate_to` configuration option from our DSL ([#3086][])
|
118
|
-
* Ci-app: Fix Datadog::CI::Environment to support the new CI specs ([#3080][])
|
63
|
+
* Tracing: `dalli` disable memcached command tag by default ([#3171][])
|
119
64
|
* Tracing: Use first valid extracted style for distributed tracing ([#2879][])
|
65
|
+
* Tracing: Rename configuration option `on_set` to `after_set` ([#3107][])
|
66
|
+
* Tracing: Rename `experimental_default_proc` to `default_proc` ([#3091][])
|
67
|
+
* Tracing: Use `peer.service` for sql comment propagation ([#3127][])
|
68
|
+
* Ci-app: Fix `Datadog::CI::Environment` to support the new CI specs ([#3080][])
|
69
|
+
* Bump `datadog-ci` dependency to 0.2 ([#3186][])
|
70
|
+
* Bump `debase-ruby_core_source` dependency to 3.2.2 ([#3163][])
|
71
|
+
* Upgrade `libdatadog` 5 ([#3169][], [#3104][])
|
72
|
+
* Upgrade `libddwaf-rb` 1.11.0 ([#3087][])
|
73
|
+
* Update AppSec rules to 1.8.0 ([#3140][], [#3139][])
|
120
74
|
|
121
75
|
### Fixed
|
76
|
+
|
122
77
|
* Profiling: Add workaround for incorrect invoke location when logging gem is in use ([#3183][])
|
123
|
-
* Profiling: Fix missing endpoint profiling when request_queuing is enabled in rack instrumentation ([#3109][])
|
124
|
-
* Appsec:
|
78
|
+
* Profiling: Fix missing endpoint profiling when `request_queuing` is enabled in `rack` instrumentation ([#3109][])
|
79
|
+
* Appsec: Span tags reporting the number of WAF failed loaded rules ([#3106][])
|
125
80
|
* Tracing: Fix tagging with empty data ([#3102][])
|
126
|
-
* Tracing:
|
127
|
-
* Tracing: Correctly set `rails.cache.backend` span tag for multiple stores ([#3060][])
|
81
|
+
* Tracing: Fix `rails.cache.backend` span tag with multiple stores ([#3060][])
|
128
82
|
|
129
83
|
### Removed
|
84
|
+
|
130
85
|
* Profiling: Remove legacy profiler codepath ([#3172][])
|
131
|
-
* Ci-app:
|
132
|
-
* Tracing: Remove `depends_on` from
|
86
|
+
* Ci-app: Remove CI module and add a dependency on [`datadog-ci` gem](https://github.com/DataDog/datadog-ci-rb) ([#3128][])
|
87
|
+
* Tracing: Remove `depends_on` option from configuration DSL ([#3085][])
|
88
|
+
* Tracing: Remove `delegate_to` option from configuration DSL ([#3086][])
|
133
89
|
|
134
90
|
## [1.14.0] - 2023-08-24
|
135
91
|
|
@@ -2663,7 +2619,9 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
2663
2619
|
|
2664
2620
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
2665
2621
|
|
2666
|
-
|
2622
|
+
|
2623
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.0...master
|
2624
|
+
[1.16.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.15.0...v1.16.0
|
2667
2625
|
[1.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.14.0...v1.15.0
|
2668
2626
|
[1.14.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.13.1...1.14.0
|
2669
2627
|
[1.13.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.13.0...1.13.1
|
@@ -3401,6 +3359,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3401
3359
|
[#1509]: https://github.com/DataDog/dd-trace-rb/issues/1509
|
3402
3360
|
[#1510]: https://github.com/DataDog/dd-trace-rb/issues/1510
|
3403
3361
|
[#1511]: https://github.com/DataDog/dd-trace-rb/issues/1511
|
3362
|
+
[#1522]: https://github.com/DataDog/dd-trace-rb/issues/1522
|
3404
3363
|
[#1523]: https://github.com/DataDog/dd-trace-rb/issues/1523
|
3405
3364
|
[#1524]: https://github.com/DataDog/dd-trace-rb/issues/1524
|
3406
3365
|
[#1529]: https://github.com/DataDog/dd-trace-rb/issues/1529
|
@@ -3842,12 +3801,14 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3842
3801
|
[#3127]: https://github.com/DataDog/dd-trace-rb/issues/3127
|
3843
3802
|
[#3128]: https://github.com/DataDog/dd-trace-rb/issues/3128
|
3844
3803
|
[#3131]: https://github.com/DataDog/dd-trace-rb/issues/3131
|
3804
|
+
[#3132]: https://github.com/DataDog/dd-trace-rb/issues/3132
|
3845
3805
|
[#3139]: https://github.com/DataDog/dd-trace-rb/issues/3139
|
3846
3806
|
[#3140]: https://github.com/DataDog/dd-trace-rb/issues/3140
|
3847
3807
|
[#3145]: https://github.com/DataDog/dd-trace-rb/issues/3145
|
3848
3808
|
[#3148]: https://github.com/DataDog/dd-trace-rb/issues/3148
|
3849
3809
|
[#3150]: https://github.com/DataDog/dd-trace-rb/issues/3150
|
3850
3810
|
[#3152]: https://github.com/DataDog/dd-trace-rb/issues/3152
|
3811
|
+
[#3153]: https://github.com/DataDog/dd-trace-rb/issues/3153
|
3851
3812
|
[#3158]: https://github.com/DataDog/dd-trace-rb/issues/3158
|
3852
3813
|
[#3162]: https://github.com/DataDog/dd-trace-rb/issues/3162
|
3853
3814
|
[#3163]: https://github.com/DataDog/dd-trace-rb/issues/3163
|
@@ -3863,6 +3824,13 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3863
3824
|
[#3188]: https://github.com/DataDog/dd-trace-rb/issues/3188
|
3864
3825
|
[#3189]: https://github.com/DataDog/dd-trace-rb/issues/3189
|
3865
3826
|
[#3190]: https://github.com/DataDog/dd-trace-rb/issues/3190
|
3827
|
+
[#3197]: https://github.com/DataDog/dd-trace-rb/issues/3197
|
3828
|
+
[#3204]: https://github.com/DataDog/dd-trace-rb/issues/3204
|
3829
|
+
[#3206]: https://github.com/DataDog/dd-trace-rb/issues/3206
|
3830
|
+
[#3207]: https://github.com/DataDog/dd-trace-rb/issues/3207
|
3831
|
+
[#3223]: https://github.com/DataDog/dd-trace-rb/issues/3223
|
3832
|
+
[#3234]: https://github.com/DataDog/dd-trace-rb/issues/3234
|
3833
|
+
[#3235]: https://github.com/DataDog/dd-trace-rb/issues/3235
|
3866
3834
|
[@AdrianLC]: https://github.com/AdrianLC
|
3867
3835
|
[@Azure7111]: https://github.com/Azure7111
|
3868
3836
|
[@BabyGroot]: https://github.com/BabyGroot
|
@@ -40,9 +40,13 @@ module Datadog
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def headers
|
43
|
-
request.env.each_with_object({}) do |(k, v), h|
|
44
|
-
h[k.gsub(/^HTTP_/, '').downcase
|
43
|
+
result = request.env.each_with_object({}) do |(k, v), h|
|
44
|
+
h[k.gsub(/^HTTP_/, '').downcase!.tr('_', '-')] = v if k =~ /^HTTP_/
|
45
45
|
end
|
46
|
+
|
47
|
+
result['content-type'] = request.content_type if request.content_type
|
48
|
+
result['content-length'] = request.content_length if request.content_length
|
49
|
+
result
|
46
50
|
end
|
47
51
|
|
48
52
|
def body
|
@@ -19,9 +19,55 @@ module Datadog
|
|
19
19
|
@scope = scope
|
20
20
|
end
|
21
21
|
|
22
|
+
def parsed_body
|
23
|
+
return unless Datadog.configuration.appsec.parse_response_body
|
24
|
+
|
25
|
+
unless body.instance_of?(Array)
|
26
|
+
Datadog.logger.debug do
|
27
|
+
"Response body type unsupported: #{body.class}"
|
28
|
+
end
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
return unless json_content_type?
|
33
|
+
|
34
|
+
result = ''.dup
|
35
|
+
all_body_parts_are_string = true
|
36
|
+
|
37
|
+
body.each do |body_part|
|
38
|
+
if body_part.is_a?(String)
|
39
|
+
result.concat(body_part)
|
40
|
+
else
|
41
|
+
all_body_parts_are_string = false
|
42
|
+
break
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
return unless all_body_parts_are_string
|
47
|
+
|
48
|
+
begin
|
49
|
+
JSON.parse(result)
|
50
|
+
rescue JSON::ParserError => e
|
51
|
+
Datadog.logger.debug { "Failed to parse response body. Error #{e.class}. Message #{e.message}" }
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
22
56
|
def response
|
23
57
|
@response ||= ::Rack::Response.new(body, status, headers)
|
24
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
VALID_JSON_TYPES = [
|
63
|
+
'application/json',
|
64
|
+
'text/json'
|
65
|
+
].freeze
|
66
|
+
|
67
|
+
def json_content_type?
|
68
|
+
content_type = headers['content-type']
|
69
|
+
VALID_JSON_TYPES.include?(content_type)
|
70
|
+
end
|
25
71
|
end
|
26
72
|
end
|
27
73
|
end
|
@@ -10,6 +10,7 @@ module Datadog
|
|
10
10
|
ADDRESSES = [
|
11
11
|
'response.status',
|
12
12
|
'response.headers',
|
13
|
+
'response.body',
|
13
14
|
].freeze
|
14
15
|
private_constant :ADDRESSES
|
15
16
|
|
@@ -17,6 +18,7 @@ module Datadog
|
|
17
18
|
catch(:block) do
|
18
19
|
op.publish('response.status', gateway_response.status)
|
19
20
|
op.publish('response.headers', gateway_response.headers)
|
21
|
+
op.publish('response.body', gateway_response.parsed_body)
|
20
22
|
|
21
23
|
nil
|
22
24
|
end
|
@@ -29,6 +31,7 @@ module Datadog
|
|
29
31
|
response_status = values[0]
|
30
32
|
response_headers = values[1]
|
31
33
|
response_headers_no_cookies = response_headers.dup.tap { |h| h.delete('set-cookie') }
|
34
|
+
response_body = values[2]
|
32
35
|
|
33
36
|
waf_args = {
|
34
37
|
'server.response.status' => response_status.to_s,
|
@@ -36,6 +39,8 @@ module Datadog
|
|
36
39
|
'server.response.headers.no_cookies' => response_headers_no_cookies,
|
37
40
|
}
|
38
41
|
|
42
|
+
waf_args['server.response.body'] = response_body if response_body
|
43
|
+
|
39
44
|
waf_timeout = Datadog.configuration.appsec.waf_timeout
|
40
45
|
result = waf_context.run(waf_args, waf_timeout)
|
41
46
|
|
@@ -66,11 +66,21 @@ module Datadog
|
|
66
66
|
request_return = AppSec::Response.negotiate(env, blocked_event.last[:actions]).to_rack if blocked_event
|
67
67
|
end
|
68
68
|
|
69
|
+
if request_return[2].respond_to?(:to_ary)
|
70
|
+
# Following the Rack specification. The response body should only call :each once.
|
71
|
+
# Calling :to_ary returns an array with identical content as the produced when calling :each
|
72
|
+
# replacing request_return[2] with that new value allow us to safely operate on the response body.
|
73
|
+
# On Gateway::Response#parsed_body we might iterate over the reposne body using :each
|
74
|
+
# https://github.com/rack/rack/blob/main/SPEC.rdoc#enumerable-body-
|
75
|
+
consumed_body = request_return[2].to_ary
|
76
|
+
request_return[2] = consumed_body if consumed_body
|
77
|
+
end
|
78
|
+
|
69
79
|
gateway_response = Gateway::Response.new(
|
70
80
|
request_return[2],
|
71
81
|
request_return[0],
|
72
82
|
request_return[1],
|
73
|
-
scope: scope
|
83
|
+
scope: scope,
|
74
84
|
)
|
75
85
|
|
76
86
|
_response_return, response_response = Instrumentation.gateway.push('rack.response', gateway_response)
|
@@ -28,7 +28,9 @@ module Datadog
|
|
28
28
|
|
29
29
|
@starting = true
|
30
30
|
|
31
|
-
|
31
|
+
thread = Thread.new { poll(@interval) }
|
32
|
+
thread.name = self.class.name unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3')
|
33
|
+
@thr = thread
|
32
34
|
|
33
35
|
@started = true
|
34
36
|
@starting = false
|
@@ -53,7 +53,7 @@ module Datadog
|
|
53
53
|
@idle_sampling_helper = idle_sampling_helper
|
54
54
|
end
|
55
55
|
|
56
|
-
def start
|
56
|
+
def start(on_failure_proc: nil)
|
57
57
|
@start_stop_mutex.synchronize do
|
58
58
|
return if @worker_thread && @worker_thread.alive?
|
59
59
|
|
@@ -74,6 +74,7 @@ module Datadog
|
|
74
74
|
'CpuAndWallTimeWorker thread error. ' \
|
75
75
|
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
76
76
|
)
|
77
|
+
on_failure_proc&.call
|
77
78
|
end
|
78
79
|
end
|
79
80
|
@worker_thread.name = self.class.name # Repeated from above to make sure thread gets named asap
|
@@ -21,18 +21,42 @@ module Datadog
|
|
21
21
|
scheduler.reset_after_fork
|
22
22
|
end
|
23
23
|
|
24
|
-
worker.start
|
25
|
-
scheduler.start
|
24
|
+
worker.start(on_failure_proc: proc { component_failed(:worker) })
|
25
|
+
scheduler.start(on_failure_proc: proc { component_failed(:scheduler) })
|
26
26
|
end
|
27
27
|
|
28
28
|
def shutdown!
|
29
29
|
Datadog.logger.debug('Shutting down profiler')
|
30
30
|
|
31
|
+
stop_worker
|
32
|
+
stop_scheduler
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def stop_worker
|
31
38
|
worker.stop
|
39
|
+
end
|
32
40
|
|
41
|
+
def stop_scheduler
|
33
42
|
scheduler.enabled = false
|
34
43
|
scheduler.stop(true)
|
35
44
|
end
|
45
|
+
|
46
|
+
def component_failed(failed_component)
|
47
|
+
Datadog.logger.warn(
|
48
|
+
"Detected issue with profiler (#{failed_component} component), stopping profiling. " \
|
49
|
+
'See previous log messages for details.'
|
50
|
+
)
|
51
|
+
|
52
|
+
if failed_component == :worker
|
53
|
+
stop_scheduler
|
54
|
+
elsif failed_component == :scheduler
|
55
|
+
stop_worker
|
56
|
+
else
|
57
|
+
raise ArgumentError, "Unexpected failed_component: #{failed_component.inspect}"
|
58
|
+
end
|
59
|
+
end
|
36
60
|
end
|
37
61
|
end
|
38
62
|
end
|
@@ -45,20 +45,27 @@ module Datadog
|
|
45
45
|
self.enabled = enabled
|
46
46
|
end
|
47
47
|
|
48
|
-
def start
|
49
|
-
perform
|
48
|
+
def start(on_failure_proc: nil)
|
49
|
+
perform(on_failure_proc)
|
50
50
|
end
|
51
51
|
|
52
|
-
def perform
|
53
|
-
# A profiling flush may be called while the VM is shutting down, to report the last profile. When we do so,
|
54
|
-
# we impose a strict timeout. This means this last profile may or may not be sent, depending on if the flush can
|
55
|
-
# successfully finish in the strict timeout.
|
56
|
-
# This can be somewhat confusing (why did it not get reported?), so let's at least log what happened.
|
57
|
-
interrupted = true
|
58
|
-
|
52
|
+
def perform(on_failure_proc)
|
59
53
|
begin
|
54
|
+
# A profiling flush may be called while the VM is shutting down, to report the last profile. When we do so,
|
55
|
+
# we impose a strict timeout. This means this last profile may or may not be sent, depending on if the flush can
|
56
|
+
# successfully finish in the strict timeout.
|
57
|
+
# This can be somewhat confusing (why did it not get reported?), so let's at least log what happened.
|
58
|
+
interrupted = true
|
59
|
+
|
60
60
|
flush_and_wait
|
61
61
|
interrupted = false
|
62
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
63
|
+
Datadog.logger.warn(
|
64
|
+
'Profiling::Scheduler thread error. ' \
|
65
|
+
"Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
|
66
|
+
)
|
67
|
+
on_failure_proc&.call
|
68
|
+
raise
|
62
69
|
ensure
|
63
70
|
Datadog.logger.debug('#flush was interrupted or failed before it could complete') if interrupted
|
64
71
|
end
|
@@ -101,7 +101,9 @@ module Datadog
|
|
101
101
|
|
102
102
|
# DEV: String#underscore is available through ActiveSupport, and is
|
103
103
|
# DEV: the exact reverse operation to `#camelize`.
|
104
|
-
|
104
|
+
# DEV: String#demodulize is available through ActiveSupport, and is
|
105
|
+
# DEV: used to remove the module ('*::') part of a constant name.
|
106
|
+
@store_name = self.class.name.demodulize.underscore
|
105
107
|
end
|
106
108
|
end
|
107
109
|
|
@@ -6,7 +6,7 @@ module Datadog
|
|
6
6
|
module Tracing
|
7
7
|
module Contrib
|
8
8
|
module ConcurrentRuby
|
9
|
-
#
|
9
|
+
# Wraps existing executor to carry over trace context
|
10
10
|
class ContextCompositeExecutorService
|
11
11
|
include Concurrent::ExecutorService
|
12
12
|
|
@@ -16,20 +16,20 @@ module Datadog
|
|
16
16
|
@composited_executor = composited_executor
|
17
17
|
end
|
18
18
|
|
19
|
-
# post method runs the task within composited executor - in a different thread
|
19
|
+
# post method runs the task within composited executor - in a different thread. The original arguments are
|
20
|
+
# captured to be propagated to the composited executor post method
|
20
21
|
def post(*args, &task)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
22
|
+
digest = Tracing.active_trace.to_digest
|
23
|
+
executor = @composited_executor.is_a?(Symbol) ? Concurrent.executor(@composited_executor) : @composited_executor
|
24
|
+
|
25
|
+
# Pass the original arguments to the composited executor, which
|
26
|
+
# pushes them (possibly transformed) as block args
|
27
|
+
executor.post(*args) do |*block_args|
|
28
|
+
Tracing.continue_trace!(digest)
|
29
|
+
|
30
|
+
# Pass the executor-provided block args as they should have been
|
31
|
+
# originally passed without composition, see ChainPromise#on_resolvable
|
32
|
+
yield(*block_args)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -8,17 +8,10 @@ module Datadog
|
|
8
8
|
module ConcurrentRuby
|
9
9
|
# This patches the Future - to wrap executor service using ContextCompositeExecutorService
|
10
10
|
module FuturePatch
|
11
|
-
def
|
12
|
-
|
13
|
-
alias_method :ns_initialize_without_datadog, :ns_initialize
|
14
|
-
remove_method(:ns_initialize)
|
11
|
+
def ns_initialize(value, opts)
|
12
|
+
super(value, opts)
|
15
13
|
|
16
|
-
|
17
|
-
ns_initialize_without_datadog(value, opts)
|
18
|
-
|
19
|
-
@executor = ContextCompositeExecutorService.new(@executor)
|
20
|
-
end
|
21
|
-
end
|
14
|
+
@executor = ContextCompositeExecutorService.new(@executor)
|
22
15
|
end
|
23
16
|
end
|
24
17
|
end
|
@@ -20,7 +20,8 @@ module Datadog
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.loaded?
|
23
|
-
|
23
|
+
# Concurrent::Future is deprecated in favour of Concurrent::Promises::Future
|
24
|
+
!defined?(::Concurrent::Promises::Future).nil? || !defined?(::Concurrent::Future).nil?
|
24
25
|
end
|
25
26
|
|
26
27
|
def self.compatible?
|
@@ -19,11 +19,18 @@ module Datadog
|
|
19
19
|
def patch
|
20
20
|
require_relative 'future_patch'
|
21
21
|
patch_future
|
22
|
+
require_relative 'promises_future_patch'
|
23
|
+
patch_promises_future
|
22
24
|
end
|
23
25
|
|
24
26
|
# Propagate tracing context in Concurrent::Future
|
25
27
|
def patch_future
|
26
|
-
::Concurrent::Future.
|
28
|
+
::Concurrent::Future.prepend(FuturePatch) if defined?(::Concurrent::Future)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Propagate tracing context in Concurrent::Promises::Future
|
32
|
+
def patch_promises_future
|
33
|
+
::Concurrent::Promises.singleton_class.prepend(PromisesFuturePatch) if defined?(::Concurrent::Promises::Future)
|
27
34
|
end
|
28
35
|
end
|
29
36
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'context_composite_executor_service'
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module Tracing
|
7
|
+
module Contrib
|
8
|
+
module ConcurrentRuby
|
9
|
+
# This patches the Future - to wrap executor service using ContextCompositeExecutorService
|
10
|
+
module PromisesFuturePatch
|
11
|
+
def future_on(default_executor, *args, &task)
|
12
|
+
unless default_executor.is_a?(ContextCompositeExecutorService)
|
13
|
+
default_executor = ContextCompositeExecutorService.new(default_executor)
|
14
|
+
end
|
15
|
+
|
16
|
+
super(default_executor, *args, &task)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -3,6 +3,7 @@ require_relative 'configuration/resolver'
|
|
3
3
|
require_relative 'ext'
|
4
4
|
require_relative 'quantize'
|
5
5
|
require_relative 'tags'
|
6
|
+
require_relative 'trace_middleware'
|
6
7
|
|
7
8
|
module Datadog
|
8
9
|
module Tracing
|
@@ -17,31 +18,11 @@ module Datadog
|
|
17
18
|
# InstanceMethods - implementing instrumentation
|
18
19
|
module InstanceMethods
|
19
20
|
def call(*args, &block)
|
20
|
-
|
21
|
-
|
22
|
-
Tracing.trace(Contrib::Redis::Ext::SPAN_COMMAND) do |span|
|
23
|
-
span.service = service_name
|
24
|
-
span.span_type = Contrib::Redis::Ext::TYPE
|
25
|
-
span.resource = get_command(args, show_command_args)
|
26
|
-
Contrib::Redis::Tags.set_common_tags(self, span, show_command_args)
|
27
|
-
|
28
|
-
super
|
29
|
-
end
|
21
|
+
TraceMiddleware.call(self, args[0], service_name, command_args?) { super }
|
30
22
|
end
|
31
23
|
|
32
24
|
def call_pipeline(*args, &block)
|
33
|
-
|
34
|
-
|
35
|
-
Tracing.trace(Contrib::Redis::Ext::SPAN_COMMAND) do |span|
|
36
|
-
span.service = service_name
|
37
|
-
span.span_type = Contrib::Redis::Ext::TYPE
|
38
|
-
commands = get_pipeline_commands(args, show_command_args)
|
39
|
-
span.resource = commands.any? ? commands.join("\n") : '(none)'
|
40
|
-
span.set_metric Contrib::Redis::Ext::METRIC_PIPELINE_LEN, commands.length
|
41
|
-
Contrib::Redis::Tags.set_common_tags(self, span, show_command_args)
|
42
|
-
|
43
|
-
super
|
44
|
-
end
|
25
|
+
TraceMiddleware.call_pipelined(self, args[0].commands, service_name, command_args?) { super }
|
45
26
|
end
|
46
27
|
|
47
28
|
private
|
@@ -59,22 +40,6 @@ module Datadog
|
|
59
40
|
datadog_configuration[:service_name]
|
60
41
|
end
|
61
42
|
|
62
|
-
def get_command(args, show_command_args)
|
63
|
-
if show_command_args
|
64
|
-
Contrib::Redis::Quantize.format_command_args(*args)
|
65
|
-
else
|
66
|
-
Contrib::Redis::Quantize.get_verb(*args)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def get_pipeline_commands(args, show_command_args)
|
71
|
-
if show_command_args
|
72
|
-
args[0].commands.map { |c| Contrib::Redis::Quantize.format_command_args(c) }
|
73
|
-
else
|
74
|
-
args[0].commands.map { |c| Contrib::Redis::Quantize.get_verb(c) }
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
43
|
def datadog_configuration
|
79
44
|
Datadog.configuration.tracing[:redis, options]
|
80
45
|
end
|
@@ -12,7 +12,7 @@ module Datadog
|
|
12
12
|
# Tags handles generic common tags assignment.
|
13
13
|
module Tags
|
14
14
|
class << self
|
15
|
-
def set_common_tags(client, span,
|
15
|
+
def set_common_tags(client, span, raw_command)
|
16
16
|
if datadog_configuration[:peer_service]
|
17
17
|
span.set_tag(
|
18
18
|
Tracing::Metadata::Ext::TAG_PEER_SERVICE,
|
@@ -42,7 +42,7 @@ module Datadog
|
|
42
42
|
|
43
43
|
span.set_tag Ext::TAG_DATABASE_INDEX, client.db.to_s
|
44
44
|
span.set_tag Ext::TAG_DB, client.db
|
45
|
-
span.set_tag Ext::TAG_RAW_COMMAND,
|
45
|
+
span.set_tag Ext::TAG_RAW_COMMAND, raw_command
|
46
46
|
|
47
47
|
Contrib::SpanAttributeSchema.set_peer_service!(span, Ext::PEER_SERVICE_SOURCES)
|
48
48
|
end
|
@@ -9,55 +9,68 @@ module Datadog
|
|
9
9
|
module Redis
|
10
10
|
# Instrumentation for Redis 5+
|
11
11
|
module TraceMiddleware
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
# Instruments {RedisClient::ConnectionMixin#call}.
|
13
|
+
def call(command, redis_config)
|
14
|
+
config = resolve(redis_config)
|
15
|
+
TraceMiddleware.call(redis_config, command, config[:service_name], config[:command_args]) { super }
|
16
|
+
end
|
17
|
+
|
18
|
+
# Instruments {RedisClient::ConnectionMixin#call_pipelined}.
|
19
|
+
def call_pipelined(commands, redis_config)
|
20
|
+
config = resolve(redis_config)
|
21
|
+
TraceMiddleware.call_pipelined(redis_config, commands, config[:service_name], config[:command_args]) { super }
|
22
|
+
end
|
16
23
|
|
17
|
-
|
18
|
-
|
19
|
-
|
24
|
+
class << self
|
25
|
+
def call(client, command, service_name, command_args)
|
26
|
+
Tracing.trace(Redis::Ext::SPAN_COMMAND, type: Redis::Ext::TYPE, service: service_name) do |span|
|
27
|
+
raw_command = get_command(command, true)
|
28
|
+
span.resource = command_args ? raw_command : get_command(command, false)
|
20
29
|
|
21
|
-
|
30
|
+
Contrib::Redis::Tags.set_common_tags(client, span, raw_command)
|
22
31
|
|
23
|
-
|
32
|
+
yield
|
33
|
+
end
|
24
34
|
end
|
25
|
-
end
|
26
35
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
36
|
+
def call_pipelined(client, commands, service_name, command_args)
|
37
|
+
Tracing.trace(Redis::Ext::SPAN_COMMAND, type: Redis::Ext::TYPE, service: service_name) do |span|
|
38
|
+
raw_command = get_pipeline_commands(commands, true)
|
39
|
+
span.resource = command_args ? raw_command : get_pipeline_commands(commands, false)
|
31
40
|
|
32
|
-
|
33
|
-
span.span_type = Contrib::Redis::Ext::TYPE
|
34
|
-
span.resource = pipelined_commands.join("\n")
|
35
|
-
span.set_metric Contrib::Redis::Ext::METRIC_PIPELINE_LEN, pipelined_commands.length
|
41
|
+
span.set_metric Contrib::Redis::Ext::METRIC_PIPELINE_LEN, commands.length
|
36
42
|
|
37
|
-
|
43
|
+
Contrib::Redis::Tags.set_common_tags(client, span, raw_command)
|
38
44
|
|
39
|
-
|
45
|
+
yield
|
46
|
+
end
|
40
47
|
end
|
41
|
-
end
|
42
48
|
|
43
|
-
|
49
|
+
private
|
44
50
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
51
|
+
# Quantizes a single Redis command
|
52
|
+
def get_command(command, command_args)
|
53
|
+
if command_args
|
54
|
+
Contrib::Redis::Quantize.format_command_args(command)
|
55
|
+
else
|
56
|
+
Contrib::Redis::Quantize.get_verb(command)
|
57
|
+
end
|
50
58
|
end
|
51
|
-
end
|
52
59
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
60
|
+
# Quantizes a multi-command Redis pipeline execution
|
61
|
+
def get_pipeline_commands(commands, command_args)
|
62
|
+
list = if command_args
|
63
|
+
commands.map { |c| Contrib::Redis::Quantize.format_command_args(c) }
|
64
|
+
else
|
65
|
+
commands.map { |c| Contrib::Redis::Quantize.get_verb(c) }
|
66
|
+
end
|
67
|
+
|
68
|
+
list.empty? ? '(none)' : list.join("\n")
|
58
69
|
end
|
59
70
|
end
|
60
71
|
|
72
|
+
private
|
73
|
+
|
61
74
|
def resolve(redis_config)
|
62
75
|
custom = redis_config.custom[:datadog] || {}
|
63
76
|
|
@@ -137,6 +137,12 @@ module Datadog
|
|
137
137
|
private
|
138
138
|
|
139
139
|
def instrumented_integrations
|
140
|
+
# `instrumented_integrations` method is added only if tracing contrib extensions are required.
|
141
|
+
# If tracing is used in manual mode without integrations enabled this method does not exist.
|
142
|
+
# CI visibility gem datadog-ci uses Datadog::Tracer without requiring datadog/tracing/contrib folder
|
143
|
+
# nor enabling any integrations by default which causes EnvironmentCollector to fail.
|
144
|
+
return {} unless Datadog.configuration.tracing.respond_to?(:instrumented_integrations)
|
145
|
+
|
140
146
|
Datadog.configuration.tracing.instrumented_integrations
|
141
147
|
end
|
142
148
|
|
data/lib/ddtrace/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ddtrace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Datadog, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.
|
75
|
+
version: 0.3.0
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.
|
82
|
+
version: 0.3.0
|
83
83
|
description: |
|
84
84
|
ddtrace is Datadog's tracing client for Ruby. It is used to trace requests
|
85
85
|
as they flow across web servers, databases and microservices so that developers
|
@@ -514,6 +514,7 @@ files:
|
|
514
514
|
- lib/datadog/tracing/contrib/concurrent_ruby/future_patch.rb
|
515
515
|
- lib/datadog/tracing/contrib/concurrent_ruby/integration.rb
|
516
516
|
- lib/datadog/tracing/contrib/concurrent_ruby/patcher.rb
|
517
|
+
- lib/datadog/tracing/contrib/concurrent_ruby/promises_future_patch.rb
|
517
518
|
- lib/datadog/tracing/contrib/configurable.rb
|
518
519
|
- lib/datadog/tracing/contrib/configuration/resolver.rb
|
519
520
|
- lib/datadog/tracing/contrib/configuration/resolvers/pattern_resolver.rb
|
@@ -889,7 +890,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
889
890
|
- !ruby/object:Gem::Version
|
890
891
|
version: 2.0.0
|
891
892
|
requirements: []
|
892
|
-
rubygems_version: 3.4.
|
893
|
+
rubygems_version: 3.4.1
|
893
894
|
signing_key:
|
894
895
|
specification_version: 4
|
895
896
|
summary: Datadog tracing code for your Ruby applications
|