ddtrace 1.15.0 → 1.16.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +73 -95
- 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 +2 -2
- 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: a4e85c12caf77e324eee9de8f9ddf143b0e49c3487230ff841ab7a5be05e4c7d
|
4
|
+
data.tar.gz: 44d799e085ae66280177800c136c656085d6f1fc5d32085c2852158c4290ef59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c651f6acbdff86fac984f61df4f2322eb449e3355220810a955496c51d33565ddbd6d15f3ca5049f9f0738c93508db9def7c24f046a51d3ef616b6182a1ca4d
|
7
|
+
data.tar.gz: 75fc3aa27da60ec0998087a814f77fe33a4f4c0bcbbda52b647cc00552945e412fa8d7e276d69d470b258da8c204db5186f24118cf4e0dc24bec9c1681ed1c33
|
data/CHANGELOG.md
CHANGED
@@ -2,134 +2,97 @@
|
|
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).
|
13
|
-
|
14
|
-
The Timeline view allows you to look at time-based patterns and work distribution over the period of a single profile: you can look at what individual threads were doing, and when 🎉
|
15
|
-
|
16
|
-
You can use the timeline view both when looking at individual profiles, as well as when scoped to a given trace.
|
17
|
-
|
18
|
-
You can enable it:
|
5
|
+
## [1.16.1] - 2023-11-08
|
19
6
|
|
20
|
-
|
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
|
-
```
|
29
|
-
|
30
|
-
Give it a try, let us know what you think!
|
31
|
-
|
32
|
-
(Note: We do not recommend enabling this feature prior to 1.15.0!)
|
7
|
+
### Fixed
|
33
8
|
|
34
|
-
|
9
|
+
* Tracing: Fix `concurrent-ruby` future propagation without `active_trace` ([#3242][])
|
10
|
+
* Tracing: Fix host injection error handling ([#3240][])
|
35
11
|
|
36
|
-
|
12
|
+
## [1.16.0] - 2023-11-03
|
37
13
|
|
38
|
-
|
39
|
-
remove it now. (If you're curious, we've internally replaced this dependency with the `libdatadog` gem.)
|
14
|
+
**This release includes a security change for the Tracing Redis integration:**
|
40
15
|
|
41
|
-
|
16
|
+
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`.
|
42
17
|
|
43
|
-
|
18
|
+
### Added
|
44
19
|
|
45
|
-
|
46
|
-
|
47
|
-
- Via code by adding to your `Datadog.configure` block:
|
20
|
+
* Tracing: Propagate trace through `Concurrent::Promises.future` ([#1522][])
|
21
|
+
* Core: Name `Datadog::Core::Remote::Worker` thread ([#3207][])
|
48
22
|
|
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
|
-
```
|
23
|
+
### Changed
|
56
24
|
|
57
|
-
|
58
|
-
|
25
|
+
* Tracing: Redis - Omit command arguments from span.resource by default ([#3235][])
|
26
|
+
* Ci-app: Bump `datadog-ci` dependency from 0.2.0 to 0.3.0 ([#3223][])
|
59
27
|
|
60
|
-
|
28
|
+
### Fixed
|
61
29
|
|
62
|
-
|
30
|
+
* Appsec: ASM parse response body ([#3153][])
|
31
|
+
* Appsec: ASM make sure to append content type and length information ([#3204][])
|
32
|
+
* Appsec: Make sure function that checks content-type header value accepts nil content-type header value ([#3234][])
|
33
|
+
* Profiling: Shut down profiler if any components failed ([#3197][])
|
34
|
+
* Tracing: Fix `ActiveSupport` instrumentation of custom cache stores ([#3206][])
|
63
35
|
|
64
|
-
|
65
|
-
- DD_CIVISIBILITY_AGENTLESS_ENABLED=true
|
66
|
-
- DD_API_KEY=<your_api_key>
|
36
|
+
## [1.15.0] - 2023-10-09
|
67
37
|
|
68
|
-
|
69
|
-
- DD_SITE (default: datadoghq.com)
|
38
|
+
### Highlights
|
70
39
|
|
71
|
-
|
40
|
+
* Timeline view for Profiler beta
|
41
|
+
* Configure AppSec blocking responses via configuration or Remote Configuration
|
42
|
+
* CI visibility to configure with agentless mode
|
72
43
|
|
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
|
-
```
|
44
|
+
For more details, check the [release notes](https://github.com/DataDog/dd-trace-rb/releases/tag/v1.15.0)
|
80
45
|
|
81
46
|
### Added
|
82
|
-
|
83
|
-
* Tracing: Support Opensearch 3 ([#3189][])
|
84
|
-
* bump datadog-ci dependency to 0.2 ([#3186][])
|
47
|
+
|
85
48
|
* 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][])
|
49
|
+
* Detect `WebMock` `Cucumber` and `Rails.env` to disable telemetry and remote configuration for development environment ([#3065][], [#3062][], [#3145][])
|
50
|
+
* Profiling: Import java-profiler PID controller and port it to C ([#3190][])
|
93
51
|
* Profiling: Record allocation type when sampling objects ([#3096][])
|
94
|
-
*
|
95
|
-
*
|
96
|
-
*
|
97
|
-
*
|
52
|
+
* Profiling: Include `ruby vm type` in profiler allocation samples ([#3074][])
|
53
|
+
* Tracing: Support `Rack` 3 ([#3132][])
|
54
|
+
* Tracing: Support `Opensearch` 3 ([#3189][])
|
55
|
+
* Tracing: `grpc` adds `client_error_handler` option ([#3095][])
|
56
|
+
* Tracing: Add `async` option for `test_mode` configuration ([#3158][])
|
98
57
|
* Tracing: Implements `_dd.base_service` tag ([#3018][])
|
99
58
|
* Appsec: Allow blocking response template configuration via ENV variables ([#2975][])
|
100
|
-
*
|
59
|
+
* Appsec: ASM API security. Schema extraction ([#3131][], [#3166][], [#3177][])
|
60
|
+
* Appsec: Enable configuring blocking response via Remote Configuration ([#3099][])
|
61
|
+
* Ci-app: Validate git tags ([#3100][])
|
62
|
+
* Ci-app: Add agentless mode ([#3186][])
|
101
63
|
|
102
64
|
### Changed
|
103
|
-
|
104
|
-
*
|
105
|
-
* Profiling: Upgrade to libdatadog 5 ([#3169][])
|
65
|
+
|
66
|
+
* Appsec: Skip passing waf addresses when the value is empty ([#3188][])
|
106
67
|
* Profiling: Restore support for Ruby 3.3 ([#3167][])
|
107
|
-
* Bump debase-ruby_core_source dependency to 3.2.2 ([#3163][])
|
108
68
|
* 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
69
|
* 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][])
|
70
|
+
* Tracing: `dalli` disable memcached command tag by default ([#3171][])
|
119
71
|
* Tracing: Use first valid extracted style for distributed tracing ([#2879][])
|
72
|
+
* Tracing: Rename configuration option `on_set` to `after_set` ([#3107][])
|
73
|
+
* Tracing: Rename `experimental_default_proc` to `default_proc` ([#3091][])
|
74
|
+
* Tracing: Use `peer.service` for sql comment propagation ([#3127][])
|
75
|
+
* Ci-app: Fix `Datadog::CI::Environment` to support the new CI specs ([#3080][])
|
76
|
+
* Bump `datadog-ci` dependency to 0.2 ([#3186][])
|
77
|
+
* Bump `debase-ruby_core_source` dependency to 3.2.2 ([#3163][])
|
78
|
+
* Upgrade `libdatadog` 5 ([#3169][], [#3104][])
|
79
|
+
* Upgrade `libddwaf-rb` 1.11.0 ([#3087][])
|
80
|
+
* Update AppSec rules to 1.8.0 ([#3140][], [#3139][])
|
120
81
|
|
121
82
|
### Fixed
|
83
|
+
|
122
84
|
* 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:
|
85
|
+
* Profiling: Fix missing endpoint profiling when `request_queuing` is enabled in `rack` instrumentation ([#3109][])
|
86
|
+
* Appsec: Span tags reporting the number of WAF failed loaded rules ([#3106][])
|
125
87
|
* Tracing: Fix tagging with empty data ([#3102][])
|
126
|
-
* Tracing:
|
127
|
-
* Tracing: Correctly set `rails.cache.backend` span tag for multiple stores ([#3060][])
|
88
|
+
* Tracing: Fix `rails.cache.backend` span tag with multiple stores ([#3060][])
|
128
89
|
|
129
90
|
### Removed
|
91
|
+
|
130
92
|
* Profiling: Remove legacy profiler codepath ([#3172][])
|
131
|
-
* Ci-app:
|
132
|
-
* Tracing: Remove `depends_on` from
|
93
|
+
* Ci-app: Remove CI module and add a dependency on [`datadog-ci` gem](https://github.com/DataDog/datadog-ci-rb) ([#3128][])
|
94
|
+
* Tracing: Remove `depends_on` option from configuration DSL ([#3085][])
|
95
|
+
* Tracing: Remove `delegate_to` option from configuration DSL ([#3086][])
|
133
96
|
|
134
97
|
## [1.14.0] - 2023-08-24
|
135
98
|
|
@@ -2663,7 +2626,10 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
2663
2626
|
|
2664
2627
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
2665
2628
|
|
2666
|
-
|
2629
|
+
|
2630
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.1...master
|
2631
|
+
[1.16.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.0...v1.16.1
|
2632
|
+
[1.16.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.15.0...v1.16.0
|
2667
2633
|
[1.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.14.0...v1.15.0
|
2668
2634
|
[1.14.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.13.1...1.14.0
|
2669
2635
|
[1.13.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.13.0...1.13.1
|
@@ -3401,6 +3367,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3401
3367
|
[#1509]: https://github.com/DataDog/dd-trace-rb/issues/1509
|
3402
3368
|
[#1510]: https://github.com/DataDog/dd-trace-rb/issues/1510
|
3403
3369
|
[#1511]: https://github.com/DataDog/dd-trace-rb/issues/1511
|
3370
|
+
[#1522]: https://github.com/DataDog/dd-trace-rb/issues/1522
|
3404
3371
|
[#1523]: https://github.com/DataDog/dd-trace-rb/issues/1523
|
3405
3372
|
[#1524]: https://github.com/DataDog/dd-trace-rb/issues/1524
|
3406
3373
|
[#1529]: https://github.com/DataDog/dd-trace-rb/issues/1529
|
@@ -3842,12 +3809,14 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3842
3809
|
[#3127]: https://github.com/DataDog/dd-trace-rb/issues/3127
|
3843
3810
|
[#3128]: https://github.com/DataDog/dd-trace-rb/issues/3128
|
3844
3811
|
[#3131]: https://github.com/DataDog/dd-trace-rb/issues/3131
|
3812
|
+
[#3132]: https://github.com/DataDog/dd-trace-rb/issues/3132
|
3845
3813
|
[#3139]: https://github.com/DataDog/dd-trace-rb/issues/3139
|
3846
3814
|
[#3140]: https://github.com/DataDog/dd-trace-rb/issues/3140
|
3847
3815
|
[#3145]: https://github.com/DataDog/dd-trace-rb/issues/3145
|
3848
3816
|
[#3148]: https://github.com/DataDog/dd-trace-rb/issues/3148
|
3849
3817
|
[#3150]: https://github.com/DataDog/dd-trace-rb/issues/3150
|
3850
3818
|
[#3152]: https://github.com/DataDog/dd-trace-rb/issues/3152
|
3819
|
+
[#3153]: https://github.com/DataDog/dd-trace-rb/issues/3153
|
3851
3820
|
[#3158]: https://github.com/DataDog/dd-trace-rb/issues/3158
|
3852
3821
|
[#3162]: https://github.com/DataDog/dd-trace-rb/issues/3162
|
3853
3822
|
[#3163]: https://github.com/DataDog/dd-trace-rb/issues/3163
|
@@ -3863,6 +3832,15 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3863
3832
|
[#3188]: https://github.com/DataDog/dd-trace-rb/issues/3188
|
3864
3833
|
[#3189]: https://github.com/DataDog/dd-trace-rb/issues/3189
|
3865
3834
|
[#3190]: https://github.com/DataDog/dd-trace-rb/issues/3190
|
3835
|
+
[#3197]: https://github.com/DataDog/dd-trace-rb/issues/3197
|
3836
|
+
[#3204]: https://github.com/DataDog/dd-trace-rb/issues/3204
|
3837
|
+
[#3206]: https://github.com/DataDog/dd-trace-rb/issues/3206
|
3838
|
+
[#3207]: https://github.com/DataDog/dd-trace-rb/issues/3207
|
3839
|
+
[#3223]: https://github.com/DataDog/dd-trace-rb/issues/3223
|
3840
|
+
[#3234]: https://github.com/DataDog/dd-trace-rb/issues/3234
|
3841
|
+
[#3235]: https://github.com/DataDog/dd-trace-rb/issues/3235
|
3842
|
+
[#3240]: https://github.com/DataDog/dd-trace-rb/issues/3240
|
3843
|
+
[#3242]: https://github.com/DataDog/dd-trace-rb/issues/3242
|
3866
3844
|
[@AdrianLC]: https://github.com/AdrianLC
|
3867
3845
|
[@Azure7111]: https://github.com/Azure7111
|
3868
3846
|
[@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 && 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.1
|
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-08 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.10
|
893
894
|
signing_key:
|
894
895
|
specification_version: 4
|
895
896
|
summary: Datadog tracing code for your Ruby applications
|