ddtrace 1.15.0 → 1.17.0
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 +105 -86
- data/lib/datadog/appsec/contrib/rack/gateway/request.rb +6 -2
- data/lib/datadog/appsec/contrib/rack/request_middleware.rb +1 -1
- data/lib/datadog/core/configuration/settings.rb +1 -1
- data/lib/datadog/core/remote/worker.rb +3 -1
- data/lib/datadog/opentelemetry/sdk/span_processor.rb +39 -8
- data/lib/datadog/opentelemetry/sdk/trace/span.rb +102 -3
- data/lib/datadog/opentracer/text_map_propagator.rb +2 -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/configuration/ext.rb +3 -0
- data/lib/datadog/tracing/configuration/settings.rb +18 -3
- 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/datadog/tracing/distributed/datadog.rb +0 -1
- data/lib/datadog/tracing/distributed/propagation.rb +25 -4
- data/lib/datadog/tracing/trace_digest.rb +31 -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: 2da890705f074bf11ffaa1b5099472a4695d318fc1a1a98238d61a061d6582ec
|
4
|
+
data.tar.gz: 8c6db62249ee456939c3eacdeddb0f985148e9daa78adb844144d8da1191e8bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a70b6856159a46f30a4ff67bc672011bb016b2aa7b1562834957a325eee90be681f9d0e153ef94c97a4ce675f7b63ac9f5a68f5573b4b9144ee40cf89a70395f
|
7
|
+
data.tar.gz: 0d8d1a5d2ee255e53daab1cea7e82ec6f61c8e4a67b89ab1293853786d634c6cde2407a1ea0ceb4ff8bbb3391940dec5bdcfc56dd4b55b7b3826e35bdcff84eb
|
data/CHANGELOG.md
CHANGED
@@ -2,134 +2,128 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
-
## [1.
|
5
|
+
## [1.17.0] - 2023-11-22
|
6
6
|
|
7
|
-
|
7
|
+
For W3C Trace Context, this release adds [`tracecontext`](https://www.w3.org/TR/trace-context/) to the default trace propagation extraction and injection styles. The new defaults are:
|
8
|
+
* Extraction: `Datadog,b3multi,b3,tracecontext`
|
9
|
+
* Injection: `Datadog,tracecontext`
|
8
10
|
|
9
|
-
|
11
|
+
And to increase interoperability with `tracecontext`, 128-bit Trace ID generation is now the default.
|
10
12
|
|
11
|
-
|
12
|
-
[Timeline view](https://docs.datadoghq.com/profiler/profile_visualizations/#timeline-view).
|
13
|
+
For OpenTelemetry, this release adds support for converting [OpenTelemetry Trace Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/general/trace/) into equivalent Datadog trace semantics. Also, it's now possible to configure top-level Datadog span fields using OpenTelemetry span attributes (https://github.com/DataDog/dd-trace-rb/pull/3262).
|
13
14
|
|
14
|
-
|
15
|
+
For CI Visibility, you can now manually create CI traces and spans with the [newly released API](https://github.com/DataDog/datadog-ci-rb/releases/tag/v0.4.0).
|
15
16
|
|
16
|
-
|
17
|
+
### Added
|
17
18
|
|
18
|
-
|
19
|
+
* OpenTelemetry: Parse OpenTelemetry semantic conventions to Datadog's ([#3273][])
|
20
|
+
* OpenTelemetry: Support span reserved attribute overrides ([#3262][])
|
21
|
+
* Tracing: Ensure W3C `tracestate` is always propagated ([#3255][])
|
19
22
|
|
20
|
-
|
21
|
-
* Or via code by adding to your `Datadog.configure` block:
|
23
|
+
### Changed
|
22
24
|
|
23
|
-
|
24
|
-
Datadog
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
```
|
25
|
+
* Tracing: Set 128-bit trace_id to true by default ([#3266][])
|
26
|
+
* Tracing: Default trace propagation styles to `Datadog,b3multi,b3,tracecontext` ([#3248][],#3267)
|
27
|
+
* Ci-App: Upgraded `datadog-ci` dependency to 0.4 ([#3270][])
|
28
|
+
|
29
|
+
## [1.16.2] - 2023-11-10
|
29
30
|
|
30
|
-
|
31
|
+
This release reverts a change to appsec response body parsing that was introduced in [1.16.0 ](https://github.com/DataDog/dd-trace-rb/releases/tag/v1.16.0) that may cause memory leaks.
|
31
32
|
|
32
|
-
|
33
|
+
### Fixed
|
34
|
+
* Appsec: [Revert parse response body fix introduced in 1.16.0](https://github.com/DataDog/dd-trace-rb/pull/3153) ([#3252][])
|
33
35
|
|
34
|
-
|
36
|
+
## [1.16.1] - 2023-11-08
|
35
37
|
|
36
|
-
|
38
|
+
### Fixed
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
+
* Tracing: Fix `concurrent-ruby` future propagation without `active_trace` ([#3242][])
|
41
|
+
* Tracing: Fix host injection error handling ([#3240][])
|
40
42
|
|
41
|
-
|
43
|
+
## [1.16.0] - 2023-11-03
|
42
44
|
|
43
|
-
|
45
|
+
**This release includes a security change for the Tracing Redis integration:**
|
44
46
|
|
45
|
-
|
46
|
-
- Using the ENV variables: `DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML=#{file_name}`, and `DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON=#{file_name}`
|
47
|
-
- Via code by adding to your `Datadog.configure` block:
|
47
|
+
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`.
|
48
48
|
|
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
|
-
```
|
49
|
+
### Added
|
56
50
|
|
57
|
-
|
58
|
-
|
51
|
+
* Tracing: Propagate trace through `Concurrent::Promises.future` ([#1522][])
|
52
|
+
* Core: Name `Datadog::Core::Remote::Worker` thread ([#3207][])
|
59
53
|
|
60
|
-
|
54
|
+
### Changed
|
61
55
|
|
62
|
-
|
56
|
+
* Tracing: Redis - Omit command arguments from span.resource by default ([#3235][])
|
57
|
+
* Ci-app: Bump `datadog-ci` dependency from 0.2.0 to 0.3.0 ([#3223][])
|
63
58
|
|
64
|
-
|
65
|
-
- DD_CIVISIBILITY_AGENTLESS_ENABLED=true
|
66
|
-
- DD_API_KEY=<your_api_key>
|
59
|
+
### Fixed
|
67
60
|
|
68
|
-
|
69
|
-
|
61
|
+
* Appsec: ASM parse response body ([#3153][])
|
62
|
+
* Appsec: ASM make sure to append content type and length information ([#3204][])
|
63
|
+
* Appsec: Make sure function that checks content-type header value accepts nil content-type header value ([#3234][])
|
64
|
+
* Profiling: Shut down profiler if any components failed ([#3197][])
|
65
|
+
* Tracing: Fix `ActiveSupport` instrumentation of custom cache stores ([#3206][])
|
70
66
|
|
71
|
-
|
67
|
+
## [1.15.0] - 2023-10-09
|
72
68
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
69
|
+
### Highlights
|
70
|
+
|
71
|
+
* Timeline view for Profiler beta
|
72
|
+
* Configure AppSec blocking responses via configuration or Remote Configuration
|
73
|
+
* CI visibility to configure with agentless mode
|
74
|
+
|
75
|
+
For more details, check the [release notes](https://github.com/DataDog/dd-trace-rb/releases/tag/v1.15.0)
|
80
76
|
|
81
77
|
### Added
|
82
|
-
|
83
|
-
* Tracing: Support Opensearch 3 ([#3189][])
|
84
|
-
* bump datadog-ci dependency to 0.2 ([#3186][])
|
78
|
+
|
85
79
|
* 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][])
|
80
|
+
* Detect `WebMock` `Cucumber` and `Rails.env` to disable telemetry and remote configuration for development environment ([#3065][], [#3062][], [#3145][])
|
81
|
+
* Profiling: Import java-profiler PID controller and port it to C ([#3190][])
|
93
82
|
* Profiling: Record allocation type when sampling objects ([#3096][])
|
94
|
-
*
|
95
|
-
*
|
96
|
-
*
|
97
|
-
*
|
83
|
+
* Profiling: Include `ruby vm type` in profiler allocation samples ([#3074][])
|
84
|
+
* Tracing: Support `Rack` 3 ([#3132][])
|
85
|
+
* Tracing: Support `Opensearch` 3 ([#3189][])
|
86
|
+
* Tracing: `grpc` adds `client_error_handler` option ([#3095][])
|
87
|
+
* Tracing: Add `async` option for `test_mode` configuration ([#3158][])
|
98
88
|
* Tracing: Implements `_dd.base_service` tag ([#3018][])
|
99
89
|
* Appsec: Allow blocking response template configuration via ENV variables ([#2975][])
|
100
|
-
*
|
90
|
+
* Appsec: ASM API security. Schema extraction ([#3131][], [#3166][], [#3177][])
|
91
|
+
* Appsec: Enable configuring blocking response via Remote Configuration ([#3099][])
|
92
|
+
* Ci-app: Validate git tags ([#3100][])
|
93
|
+
* Ci-app: Add agentless mode ([#3186][])
|
101
94
|
|
102
95
|
### Changed
|
103
|
-
|
104
|
-
*
|
105
|
-
* Profiling: Upgrade to libdatadog 5 ([#3169][])
|
96
|
+
|
97
|
+
* Appsec: Skip passing waf addresses when the value is empty ([#3188][])
|
106
98
|
* Profiling: Restore support for Ruby 3.3 ([#3167][])
|
107
|
-
* Bump debase-ruby_core_source dependency to 3.2.2 ([#3163][])
|
108
99
|
* 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
100
|
* 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][])
|
101
|
+
* Tracing: `dalli` disable memcached command tag by default ([#3171][])
|
119
102
|
* Tracing: Use first valid extracted style for distributed tracing ([#2879][])
|
103
|
+
* Tracing: Rename configuration option `on_set` to `after_set` ([#3107][])
|
104
|
+
* Tracing: Rename `experimental_default_proc` to `default_proc` ([#3091][])
|
105
|
+
* Tracing: Use `peer.service` for sql comment propagation ([#3127][])
|
106
|
+
* Ci-app: Fix `Datadog::CI::Environment` to support the new CI specs ([#3080][])
|
107
|
+
* Bump `datadog-ci` dependency to 0.2 ([#3186][])
|
108
|
+
* Bump `debase-ruby_core_source` dependency to 3.2.2 ([#3163][])
|
109
|
+
* Upgrade `libdatadog` 5 ([#3169][], [#3104][])
|
110
|
+
* Upgrade `libddwaf-rb` 1.11.0 ([#3087][])
|
111
|
+
* Update AppSec rules to 1.8.0 ([#3140][], [#3139][])
|
120
112
|
|
121
113
|
### Fixed
|
114
|
+
|
122
115
|
* 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:
|
116
|
+
* Profiling: Fix missing endpoint profiling when `request_queuing` is enabled in `rack` instrumentation ([#3109][])
|
117
|
+
* Appsec: Span tags reporting the number of WAF failed loaded rules ([#3106][])
|
125
118
|
* Tracing: Fix tagging with empty data ([#3102][])
|
126
|
-
* Tracing:
|
127
|
-
* Tracing: Correctly set `rails.cache.backend` span tag for multiple stores ([#3060][])
|
119
|
+
* Tracing: Fix `rails.cache.backend` span tag with multiple stores ([#3060][])
|
128
120
|
|
129
121
|
### Removed
|
122
|
+
|
130
123
|
* Profiling: Remove legacy profiler codepath ([#3172][])
|
131
|
-
* Ci-app:
|
132
|
-
* Tracing: Remove `depends_on` from
|
124
|
+
* Ci-app: Remove CI module and add a dependency on [`datadog-ci` gem](https://github.com/DataDog/datadog-ci-rb) ([#3128][])
|
125
|
+
* Tracing: Remove `depends_on` option from configuration DSL ([#3085][])
|
126
|
+
* Tracing: Remove `delegate_to` option from configuration DSL ([#3086][])
|
133
127
|
|
134
128
|
## [1.14.0] - 2023-08-24
|
135
129
|
|
@@ -2663,7 +2657,12 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
2663
2657
|
|
2664
2658
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
2665
2659
|
|
2666
|
-
|
2660
|
+
|
2661
|
+
[Unreleased]: https://github.com/DataDog/dd-trace-rb/compare/v1.17.0...master
|
2662
|
+
[1.17.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.2...v1.17.0
|
2663
|
+
[1.16.2]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.1...v1.16.2
|
2664
|
+
[1.16.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.16.0...v1.16.1
|
2665
|
+
[1.16.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.15.0...v1.16.0
|
2667
2666
|
[1.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.14.0...v1.15.0
|
2668
2667
|
[1.14.0]: https://github.com/DataDog/dd-trace-rb/compare/v1.13.1...1.14.0
|
2669
2668
|
[1.13.1]: https://github.com/DataDog/dd-trace-rb/compare/v1.13.0...1.13.1
|
@@ -3401,6 +3400,7 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3401
3400
|
[#1509]: https://github.com/DataDog/dd-trace-rb/issues/1509
|
3402
3401
|
[#1510]: https://github.com/DataDog/dd-trace-rb/issues/1510
|
3403
3402
|
[#1511]: https://github.com/DataDog/dd-trace-rb/issues/1511
|
3403
|
+
[#1522]: https://github.com/DataDog/dd-trace-rb/issues/1522
|
3404
3404
|
[#1523]: https://github.com/DataDog/dd-trace-rb/issues/1523
|
3405
3405
|
[#1524]: https://github.com/DataDog/dd-trace-rb/issues/1524
|
3406
3406
|
[#1529]: https://github.com/DataDog/dd-trace-rb/issues/1529
|
@@ -3842,12 +3842,14 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3842
3842
|
[#3127]: https://github.com/DataDog/dd-trace-rb/issues/3127
|
3843
3843
|
[#3128]: https://github.com/DataDog/dd-trace-rb/issues/3128
|
3844
3844
|
[#3131]: https://github.com/DataDog/dd-trace-rb/issues/3131
|
3845
|
+
[#3132]: https://github.com/DataDog/dd-trace-rb/issues/3132
|
3845
3846
|
[#3139]: https://github.com/DataDog/dd-trace-rb/issues/3139
|
3846
3847
|
[#3140]: https://github.com/DataDog/dd-trace-rb/issues/3140
|
3847
3848
|
[#3145]: https://github.com/DataDog/dd-trace-rb/issues/3145
|
3848
3849
|
[#3148]: https://github.com/DataDog/dd-trace-rb/issues/3148
|
3849
3850
|
[#3150]: https://github.com/DataDog/dd-trace-rb/issues/3150
|
3850
3851
|
[#3152]: https://github.com/DataDog/dd-trace-rb/issues/3152
|
3852
|
+
[#3153]: https://github.com/DataDog/dd-trace-rb/issues/3153
|
3851
3853
|
[#3158]: https://github.com/DataDog/dd-trace-rb/issues/3158
|
3852
3854
|
[#3162]: https://github.com/DataDog/dd-trace-rb/issues/3162
|
3853
3855
|
[#3163]: https://github.com/DataDog/dd-trace-rb/issues/3163
|
@@ -3863,6 +3865,23 @@ Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
3863
3865
|
[#3188]: https://github.com/DataDog/dd-trace-rb/issues/3188
|
3864
3866
|
[#3189]: https://github.com/DataDog/dd-trace-rb/issues/3189
|
3865
3867
|
[#3190]: https://github.com/DataDog/dd-trace-rb/issues/3190
|
3868
|
+
[#3197]: https://github.com/DataDog/dd-trace-rb/issues/3197
|
3869
|
+
[#3204]: https://github.com/DataDog/dd-trace-rb/issues/3204
|
3870
|
+
[#3206]: https://github.com/DataDog/dd-trace-rb/issues/3206
|
3871
|
+
[#3207]: https://github.com/DataDog/dd-trace-rb/issues/3207
|
3872
|
+
[#3223]: https://github.com/DataDog/dd-trace-rb/issues/3223
|
3873
|
+
[#3234]: https://github.com/DataDog/dd-trace-rb/issues/3234
|
3874
|
+
[#3235]: https://github.com/DataDog/dd-trace-rb/issues/3235
|
3875
|
+
[#3240]: https://github.com/DataDog/dd-trace-rb/issues/3240
|
3876
|
+
[#3242]: https://github.com/DataDog/dd-trace-rb/issues/3242
|
3877
|
+
[#3248]: https://github.com/DataDog/dd-trace-rb/issues/3248
|
3878
|
+
[#3252]: https://github.com/DataDog/dd-trace-rb/issues/3252
|
3879
|
+
[#3255]: https://github.com/DataDog/dd-trace-rb/issues/3255
|
3880
|
+
[#3262]: https://github.com/DataDog/dd-trace-rb/issues/3262
|
3881
|
+
[#3266]: https://github.com/DataDog/dd-trace-rb/issues/3266
|
3882
|
+
[#3267]: https://github.com/DataDog/dd-trace-rb/issues/3267
|
3883
|
+
[#3270]: https://github.com/DataDog/dd-trace-rb/issues/3270
|
3884
|
+
[#3273]: https://github.com/DataDog/dd-trace-rb/issues/3273
|
3866
3885
|
[@AdrianLC]: https://github.com/AdrianLC
|
3867
3886
|
[@Azure7111]: https://github.com/Azure7111
|
3868
3887
|
[@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
|
@@ -330,7 +330,7 @@ module Datadog
|
|
330
330
|
# Caveat 3 (severe):
|
331
331
|
# Ruby 3.2.0 to 3.2.2 have a bug in the newobj tracepoint (https://bugs.ruby-lang.org/issues/19482,
|
332
332
|
# https://github.com/ruby/ruby/pull/7464) so that's an extra reason why it's not safe on those Rubies.
|
333
|
-
# This bug is fixed on Ruby versions 3.2.
|
333
|
+
# This bug is fixed on Ruby versions 3.2.3 and 3.3.0.
|
334
334
|
#
|
335
335
|
# @default `true` on Ruby 2.x and 3.1.4+, 3.2.3+ and 3.3.0+; `false` for Ruby 3.0 and unpatched Rubies.
|
336
336
|
option :allocation_counting_enabled do |o|
|
@@ -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
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'trace/span'
|
4
|
+
|
3
5
|
module Datadog
|
4
6
|
module OpenTelemetry
|
5
7
|
module SDK
|
@@ -76,16 +78,11 @@ module Datadog
|
|
76
78
|
end
|
77
79
|
|
78
80
|
def start_datadog_span(span)
|
79
|
-
|
81
|
+
attributes = span.attributes.dup # Dup to allow modification of frozen Hash
|
80
82
|
|
81
|
-
|
82
|
-
tags[Tracing::Metadata::Ext::TAG_KIND] = kind
|
83
|
+
name, kwargs = span_arguments(span, attributes)
|
83
84
|
|
84
|
-
datadog_span = Tracing.trace(
|
85
|
-
span.name,
|
86
|
-
tags: tags,
|
87
|
-
start_time: ns_to_time(span.start_timestamp)
|
88
|
-
)
|
85
|
+
datadog_span = Tracing.trace(name, **kwargs)
|
89
86
|
|
90
87
|
datadog_span.set_error([nil, span.status.description]) unless span.status.ok?
|
91
88
|
datadog_span.set_tags(span.attributes)
|
@@ -93,6 +90,40 @@ module Datadog
|
|
93
90
|
datadog_span
|
94
91
|
end
|
95
92
|
|
93
|
+
# Some special attributes can override Datadog Span fields
|
94
|
+
def span_arguments(span, attributes)
|
95
|
+
if attributes.key?('analytics.event') && (analytics_event = attributes['analytics.event']).respond_to?(:casecmp)
|
96
|
+
attributes[Tracing::Metadata::Ext::Analytics::TAG_SAMPLE_RATE] = analytics_event.casecmp('true') == 0 ? 1 : 0
|
97
|
+
end
|
98
|
+
attributes[Tracing::Metadata::Ext::TAG_KIND] = span.kind || 'internal'
|
99
|
+
|
100
|
+
kwargs = { start_time: ns_to_time(span.start_timestamp) }
|
101
|
+
|
102
|
+
name = if attributes.key?('operation.name')
|
103
|
+
attributes['operation.name']
|
104
|
+
elsif (rich_name = Datadog::OpenTelemetry::Trace::Span.enrich_name(span.kind, attributes))
|
105
|
+
rich_name.downcase
|
106
|
+
else
|
107
|
+
span.kind
|
108
|
+
end
|
109
|
+
|
110
|
+
kwargs[:resource] = attributes.key?('resource.name') ? attributes['resource.name'] : span.name
|
111
|
+
kwargs[:service] = attributes['service.name'] if attributes.key?('service.name')
|
112
|
+
kwargs[:type] = attributes['span.type'] if attributes.key?('span.type')
|
113
|
+
|
114
|
+
attributes.reject! { |key, _| OpenTelemetry::Trace::Span::DATADOG_SPAN_ATTRIBUTE_OVERRIDES.include?(key) }
|
115
|
+
|
116
|
+
# DEV: There's no `flat_map!`; we have to split it into two operations
|
117
|
+
attributes = attributes.map do |key, value|
|
118
|
+
Datadog::OpenTelemetry::Trace::Span.serialize_attribute(key, value)
|
119
|
+
end
|
120
|
+
attributes.flatten!(1)
|
121
|
+
|
122
|
+
kwargs[:tags] = attributes
|
123
|
+
|
124
|
+
[name, kwargs]
|
125
|
+
end
|
126
|
+
|
96
127
|
# From nanoseconds, used by OpenTelemetry, to a {Time} object, used by the Datadog Tracer.
|
97
128
|
def ns_to_time(timestamp_ns)
|
98
129
|
Time.at(timestamp_ns / 1000000000.0)
|
@@ -36,6 +36,78 @@ module Datadog
|
|
36
36
|
span.set_error(status.description) if status && status.code == ::OpenTelemetry::Trace::Status::ERROR
|
37
37
|
end
|
38
38
|
|
39
|
+
# Serialize values into Datadog span tags and metrics.
|
40
|
+
# Notably, arrays are exploded into many keys, each with
|
41
|
+
# a numeric suffix representing the array index, for example:
|
42
|
+
# `'foo' => ['a','b']` becomes `'foo.0' => 'a', 'foo.1' => 'b'`
|
43
|
+
def self.serialize_attribute(key, value)
|
44
|
+
if value.is_a?(Array)
|
45
|
+
value.flat_map.with_index do |v, idx|
|
46
|
+
serialize_attribute("#{key}.#{idx}", v)
|
47
|
+
end
|
48
|
+
elsif value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
49
|
+
[[key, value.to_s]]
|
50
|
+
else
|
51
|
+
[[key, value]]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create a meaningful Datadog operation name from the OpenTelemetry
|
56
|
+
# semantic convention for span kind and span attributes.
|
57
|
+
# @see https://opentelemetry.io/docs/specs/semconv/general/trace/
|
58
|
+
|
59
|
+
# rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
60
|
+
def self.enrich_name(kind, attrs)
|
61
|
+
if attrs.key?('http.request.method')
|
62
|
+
return 'http.server.request' if kind == :server
|
63
|
+
return 'http.client.request' if kind == :client
|
64
|
+
end
|
65
|
+
|
66
|
+
return "#{attrs['db.system']}.query" if attrs.key?('db.system') && kind == :client
|
67
|
+
|
68
|
+
if (attrs.key?('messaging.system') || attrs.key?('messaging.operation')) &&
|
69
|
+
[:consumer, :producer, :server, :client].include?(kind)
|
70
|
+
|
71
|
+
return "#{attrs['messaging.system']}.#{attrs['messaging.operation']}"
|
72
|
+
end
|
73
|
+
|
74
|
+
if attrs.key?('rpc.system')
|
75
|
+
if attrs['rpc.system'] == 'aws-api' && kind == :client
|
76
|
+
service = attrs['rpc.service']
|
77
|
+
return "aws.#{service || 'client'}.request"
|
78
|
+
end
|
79
|
+
|
80
|
+
if kind == :client
|
81
|
+
return "#{attrs['rpc.system']}.client.request"
|
82
|
+
elsif kind == :server
|
83
|
+
return "#{attrs['rpc.system']}.server.request"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
if attrs.key?('faas.invoked_provider') && attrs.key?('faas.invoked_name') && kind == :client
|
88
|
+
provider = attrs['faas.invoked_provider']
|
89
|
+
name = attrs['faas.invoked_name']
|
90
|
+
return "#{provider}.#{name}.invoke"
|
91
|
+
end
|
92
|
+
|
93
|
+
return "#{attrs['faas.trigger']}.invoke" if attrs.key?('faas.trigger') && kind == :server
|
94
|
+
|
95
|
+
return 'graphql.server.request' if attrs.key?('graphql.operation.type')
|
96
|
+
|
97
|
+
if kind == :server
|
98
|
+
protocol = attrs['network.protocol.name']
|
99
|
+
return protocol ? "#{protocol}.server.request" : 'server.request'
|
100
|
+
end
|
101
|
+
|
102
|
+
if kind == :client
|
103
|
+
protocol = attrs['network.protocol.name']
|
104
|
+
return protocol ? "#{protocol}.client.request" : 'client.request'
|
105
|
+
end
|
106
|
+
|
107
|
+
kind.to_s
|
108
|
+
end
|
109
|
+
# rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
110
|
+
|
39
111
|
private
|
40
112
|
|
41
113
|
def datadog_set_attribute(key)
|
@@ -46,10 +118,18 @@ module Datadog
|
|
46
118
|
# DEV: Accesses `@attributes` directly, since using `#attributes`
|
47
119
|
# DEV: clones the hash, causing unnecessary overhead.
|
48
120
|
if @attributes.key?(key)
|
49
|
-
|
50
|
-
|
121
|
+
# Try to find a richer operation name, unless an explicit override was provided.
|
122
|
+
if !@attributes.key?('operation.name') && (rich_name = Span.enrich_name(kind, @attributes))
|
123
|
+
span.name = rich_name.downcase
|
124
|
+
end
|
125
|
+
|
126
|
+
Span.serialize_attribute(key, @attributes[key]).each do |new_key, value|
|
127
|
+
override_datadog_values(span, new_key, value)
|
51
128
|
|
52
|
-
|
129
|
+
# When an attribute is used to override a Datadog Span property,
|
130
|
+
# it should NOT be set as a Datadog Span tag.
|
131
|
+
span.set_tag(new_key, value) unless DATADOG_SPAN_ATTRIBUTE_OVERRIDES.include?(new_key)
|
132
|
+
end
|
53
133
|
else
|
54
134
|
span.clear_tag(key)
|
55
135
|
|
@@ -61,6 +141,25 @@ module Datadog
|
|
61
141
|
end
|
62
142
|
end
|
63
143
|
|
144
|
+
# Some special attributes can override Datadog Span fields beyond tags and metrics.
|
145
|
+
# @return [Boolean] true if the key is a Datadog Span override attribute, false otherwise
|
146
|
+
def override_datadog_values(span, key, value)
|
147
|
+
span.name = value if key == 'operation.name'
|
148
|
+
span.resource = value if key == 'resource.name'
|
149
|
+
span.service = value if key == 'service.name'
|
150
|
+
span.type = value if key == 'span.type'
|
151
|
+
|
152
|
+
if key == 'analytics.event' && value.respond_to?(:casecmp)
|
153
|
+
Datadog::Tracing::Analytics.set_sample_rate(
|
154
|
+
span,
|
155
|
+
value.casecmp('true') == 0 ? 1 : 0
|
156
|
+
)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
DATADOG_SPAN_ATTRIBUTE_OVERRIDES = ['analytics.event', 'operation.name', 'resource.name', 'service.name',
|
161
|
+
'span.type'].freeze
|
162
|
+
|
64
163
|
::OpenTelemetry::SDK::Trace::Span.prepend(self)
|
65
164
|
end
|
66
165
|
end
|
@@ -33,7 +33,8 @@ module Datadog
|
|
33
33
|
carrier[Tracing::Distributed::Datadog::ORIGIN_KEY] = digest.trace_origin
|
34
34
|
carrier[Tracing::Distributed::Datadog::PARENT_ID_KEY] = digest.span_id
|
35
35
|
carrier[Tracing::Distributed::Datadog::SAMPLING_PRIORITY_KEY] = digest.trace_sampling_priority
|
36
|
-
carrier[Tracing::Distributed::Datadog::TRACE_ID_KEY] =
|
36
|
+
carrier[Tracing::Distributed::Datadog::TRACE_ID_KEY] =
|
37
|
+
Datadog::Tracing::Utils::TraceId.to_low_order(digest.trace_id)
|
37
38
|
|
38
39
|
nil
|
39
40
|
end
|
@@ -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
|
@@ -62,6 +62,9 @@ module Datadog
|
|
62
62
|
# @see https://opentelemetry.io/docs/concepts/sdk-configuration/general-sdk-configuration/#get_otel__propagators
|
63
63
|
PROPAGATION_STYLE_NONE = 'none'
|
64
64
|
|
65
|
+
# Strictly stop at the first successfully serialized style.
|
66
|
+
EXTRACT_FIRST = 'DD_TRACE_PROPAGATION_EXTRACT_FIRST'
|
67
|
+
|
65
68
|
ENV_X_DATADOG_TAGS_MAX_LENGTH = 'DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH'
|
66
69
|
end
|
67
70
|
|
@@ -63,6 +63,7 @@ module Datadog
|
|
63
63
|
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG,
|
64
64
|
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_MULTI_HEADER,
|
65
65
|
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_B3_SINGLE_HEADER,
|
66
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_TRACE_CONTEXT,
|
66
67
|
]
|
67
68
|
)
|
68
69
|
o.after_set do |styles|
|
@@ -93,7 +94,10 @@ module Datadog
|
|
93
94
|
o.deprecated_env Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_INJECT_OLD
|
94
95
|
o.env Tracing::Configuration::Ext::Distributed::ENV_PROPAGATION_STYLE_INJECT
|
95
96
|
# DEV-2.0: Change default value to `tracecontext, Datadog`.
|
96
|
-
o.default [
|
97
|
+
o.default [
|
98
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_DATADOG,
|
99
|
+
Tracing::Configuration::Ext::Distributed::PROPAGATION_STYLE_TRACE_CONTEXT,
|
100
|
+
]
|
97
101
|
o.after_set do |styles|
|
98
102
|
# Modernize B3 options
|
99
103
|
# DEV-2.0: Can be removed with the removal of deprecated B3 constants.
|
@@ -142,6 +146,17 @@ module Datadog
|
|
142
146
|
set_option(:propagation_inject_style, styles)
|
143
147
|
end
|
144
148
|
end
|
149
|
+
|
150
|
+
# Strictly stop at the first successfully serialized style.
|
151
|
+
# This prevents the tracer from enriching the extracted context with information from
|
152
|
+
# other valid propagations styles present in the request.
|
153
|
+
# @default `DD_TRACE_PROPAGATION_EXTRACT_FIRST` environment variable, otherwise `false`.
|
154
|
+
# @return [Boolean]
|
155
|
+
option :propagation_extract_first do |o|
|
156
|
+
o.env Tracing::Configuration::Ext::Distributed::EXTRACT_FIRST
|
157
|
+
o.default false
|
158
|
+
o.type :bool
|
159
|
+
end
|
145
160
|
end
|
146
161
|
|
147
162
|
# Enable trace collection and span generation.
|
@@ -177,11 +192,11 @@ module Datadog
|
|
177
192
|
|
178
193
|
# Enable 128 bit trace id generation.
|
179
194
|
#
|
180
|
-
# @default `DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED` environment variable, otherwise `
|
195
|
+
# @default `DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED` environment variable, otherwise `true`
|
181
196
|
# @return [Boolean]
|
182
197
|
option :trace_id_128_bit_generation_enabled do |o|
|
183
198
|
o.env Tracing::Configuration::Ext::ENV_TRACE_ID_128_BIT_GENERATION_ENABLED
|
184
|
-
o.default
|
199
|
+
o.default true
|
185
200
|
o.type :bool
|
186
201
|
end
|
187
202
|
|
@@ -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
|
|
@@ -83,19 +83,40 @@ module Datadog
|
|
83
83
|
|
84
84
|
extracted_trace_digest = nil
|
85
85
|
|
86
|
-
::Datadog.configuration.tracing.distributed_tracing
|
86
|
+
config = ::Datadog.configuration.tracing.distributed_tracing
|
87
|
+
|
88
|
+
config.propagation_extract_style.each do |style|
|
87
89
|
propagator = @propagation_styles[style]
|
88
90
|
next if propagator.nil?
|
89
91
|
|
90
92
|
begin
|
91
|
-
extracted_trace_digest
|
93
|
+
if extracted_trace_digest
|
94
|
+
# Return if we are only inspecting the first valid style.
|
95
|
+
next if config.propagation_extract_first
|
96
|
+
|
97
|
+
# Continue parsing styles to find the W3C `tracestate` header, if present.
|
98
|
+
# `tracestate` must always be propagated, as it might contain pass-through data that we don't control.
|
99
|
+
# @see https://www.w3.org/TR/2021/REC-trace-context-1-20211123/#mutating-the-tracestate-field
|
100
|
+
next if style != Configuration::Ext::Distributed::PROPAGATION_STYLE_TRACE_CONTEXT
|
101
|
+
|
102
|
+
if (tracecontext_digest = propagator.extract(data))
|
103
|
+
# Only parse if it represent the same trace as the successfully extracted one
|
104
|
+
next unless tracecontext_digest.trace_id == extracted_trace_digest.trace_id
|
105
|
+
|
106
|
+
# Preserve the `tracestate`
|
107
|
+
extracted_trace_digest = extracted_trace_digest.merge(
|
108
|
+
trace_state: tracecontext_digest.trace_state,
|
109
|
+
trace_state_unknown_fields: tracecontext_digest.trace_state_unknown_fields
|
110
|
+
)
|
111
|
+
end
|
112
|
+
else
|
113
|
+
extracted_trace_digest = propagator.extract(data)
|
114
|
+
end
|
92
115
|
rescue => e
|
93
116
|
::Datadog.logger.error(
|
94
117
|
"Error extracting distributed trace data. Cause: #{e} Location: #{Array(e.backtrace).first}"
|
95
118
|
)
|
96
119
|
end
|
97
|
-
|
98
|
-
break if extracted_trace_digest
|
99
120
|
end
|
100
121
|
|
101
122
|
extracted_trace_digest
|
@@ -141,6 +141,37 @@ module Datadog
|
|
141
141
|
|
142
142
|
freeze
|
143
143
|
end
|
144
|
+
|
145
|
+
# Creates a copy of this object, modifying the provided fields.
|
146
|
+
# @param field_value_pairs [Hash<String>] the fields to be overwritten
|
147
|
+
# @return [TraceDigest] returns a copy of this object with the `field_value_pairs` modified
|
148
|
+
def merge(field_value_pairs)
|
149
|
+
# DEV: Because we want to sometimes freeze the values provided to `TraceDigest`, it's best
|
150
|
+
# DEV: to let `#initialize` decide how to handle each field, instead of duplicating that logic here.
|
151
|
+
TraceDigest.new(
|
152
|
+
**{
|
153
|
+
span_id: span_id,
|
154
|
+
span_name: span_name,
|
155
|
+
span_resource: span_resource,
|
156
|
+
span_service: span_service,
|
157
|
+
span_type: span_type,
|
158
|
+
trace_distributed_tags: trace_distributed_tags,
|
159
|
+
trace_hostname: trace_hostname,
|
160
|
+
trace_id: trace_id,
|
161
|
+
trace_name: trace_name,
|
162
|
+
trace_origin: trace_origin,
|
163
|
+
trace_process_id: trace_process_id,
|
164
|
+
trace_resource: trace_resource,
|
165
|
+
trace_runtime_id: trace_runtime_id,
|
166
|
+
trace_sampling_priority: trace_sampling_priority,
|
167
|
+
trace_service: trace_service,
|
168
|
+
trace_distributed_id: trace_distributed_id,
|
169
|
+
trace_flags: trace_flags,
|
170
|
+
trace_state: trace_state,
|
171
|
+
trace_state_unknown_fields: trace_state_unknown_fields,
|
172
|
+
}.merge!(field_value_pairs)
|
173
|
+
)
|
174
|
+
end
|
144
175
|
end
|
145
176
|
end
|
146
177
|
end
|
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.17.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-22 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.4.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.4.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
|