ddtrace 0.15.0 → 0.16.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 +14 -2
- data/Rakefile +9 -1
- data/ddtrace.gemspec +2 -0
- data/docs/GettingStarted.md +72 -4
- data/lib/ddtrace/contrib/rack/patcher.rb +2 -1
- data/lib/ddtrace/contrib/rails/patcher.rb +39 -3
- data/lib/ddtrace/contrib/rails/railtie.rb +8 -5
- data/lib/ddtrace/opentracer.rb +40 -0
- data/lib/ddtrace/opentracer/binary_propagator.rb +24 -0
- data/lib/ddtrace/opentracer/carrier.rb +6 -0
- data/lib/ddtrace/opentracer/distributed_headers.rb +46 -0
- data/lib/ddtrace/opentracer/global_tracer.rb +15 -0
- data/lib/ddtrace/opentracer/propagator.rb +22 -0
- data/lib/ddtrace/opentracer/rack_propagator.rb +60 -0
- data/lib/ddtrace/opentracer/scope.rb +15 -0
- data/lib/ddtrace/opentracer/scope_manager.rb +6 -0
- data/lib/ddtrace/opentracer/span.rb +90 -0
- data/lib/ddtrace/opentracer/span_context.rb +14 -0
- data/lib/ddtrace/opentracer/span_context_factory.rb +23 -0
- data/lib/ddtrace/opentracer/text_map_propagator.rb +73 -0
- data/lib/ddtrace/opentracer/thread_local_scope.rb +30 -0
- data/lib/ddtrace/opentracer/thread_local_scope_manager.rb +40 -0
- data/lib/ddtrace/opentracer/tracer.rb +208 -0
- data/lib/ddtrace/version.rb +1 -1
- metadata +32 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e4c07e2d55c825aa80fda2d80abd0be7bce884c47a869d54fc5ca32f4e60653e
|
|
4
|
+
data.tar.gz: a58bd25922fa32c3c921395a9a00b37e5b0941399f3a48cf15735ef11935808f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd1c737a23055b67ccd2a0c081bfd64cd6156d744ca9c6b982623406b04be282de3c7b0328757dafef0bd9916f822c8a59a742be37f04f3225e192574fd7f0b9
|
|
7
|
+
data.tar.gz: 9418e24136ab3721c4404cce92dbf637d86139b5d574356e6918a5cf618de2a881add70f1420ca419afe6a751b1fd9a58871e780d22294187a5327787e5ebba4
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased (beta)]
|
|
6
6
|
|
|
7
|
+
## [0.16.0] - 2018-09-18
|
|
8
|
+
|
|
9
|
+
Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.16.0
|
|
10
|
+
|
|
11
|
+
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.15.0...v0.16.0
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- OpenTracing support (#517)
|
|
16
|
+
- `middleware` option for disabling Rails trace middleware. (#552)
|
|
17
|
+
|
|
7
18
|
## [0.15.0] - 2018-09-12
|
|
8
19
|
|
|
9
20
|
Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.15.0
|
|
@@ -500,8 +511,9 @@ Release notes: https://github.com/DataDog/dd-trace-rb/releases/tag/v0.3.1
|
|
|
500
511
|
|
|
501
512
|
Git diff: https://github.com/DataDog/dd-trace-rb/compare/v0.3.0...v0.3.1
|
|
502
513
|
|
|
503
|
-
[Unreleased (stable)]: https://github.com/DataDog/dd-trace-rb/compare/v0.
|
|
504
|
-
[Unreleased (beta)]: https://github.com/DataDog/dd-trace-rb/compare/v0.
|
|
514
|
+
[Unreleased (stable)]: https://github.com/DataDog/dd-trace-rb/compare/v0.16.0...master
|
|
515
|
+
[Unreleased (beta)]: https://github.com/DataDog/dd-trace-rb/compare/v0.16.0...0.17-dev
|
|
516
|
+
[0.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v0.15.0...v0.16.0
|
|
505
517
|
[0.15.0]: https://github.com/DataDog/dd-trace-rb/compare/v0.14.2...v0.15.0
|
|
506
518
|
[0.14.2]: https://github.com/DataDog/dd-trace-rb/compare/v0.14.1...v0.14.2
|
|
507
519
|
[0.14.1]: https://github.com/DataDog/dd-trace-rb/compare/v0.14.0...v0.14.1
|
data/Rakefile
CHANGED
|
@@ -15,7 +15,11 @@ namespace :spec do
|
|
|
15
15
|
|
|
16
16
|
RSpec::Core::RakeTask.new(:main) do |t|
|
|
17
17
|
t.pattern = 'spec/**/*_spec.rb'
|
|
18
|
-
t.exclude_pattern = 'spec/**/{contrib,benchmark,redis}/**/*_spec.rb'
|
|
18
|
+
t.exclude_pattern = 'spec/**/{contrib,benchmark,redis,opentracer}/**/*_spec.rb'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
RSpec::Core::RakeTask.new(:opentracer) do |t|
|
|
22
|
+
t.pattern = 'spec/ddtrace/opentracer/**/*_spec.rb'
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
RSpec::Core::RakeTask.new(:rails) do |t|
|
|
@@ -311,6 +315,7 @@ task :ci do
|
|
|
311
315
|
sh 'bundle exec rake test:main'
|
|
312
316
|
sh 'bundle exec rake spec:main'
|
|
313
317
|
sh 'bundle exec rake spec:contrib'
|
|
318
|
+
sh 'bundle exec rake spec:opentracer'
|
|
314
319
|
|
|
315
320
|
if RUBY_PLATFORM != 'java'
|
|
316
321
|
# Contrib minitests
|
|
@@ -366,6 +371,7 @@ task :ci do
|
|
|
366
371
|
sh 'bundle exec rake test:main'
|
|
367
372
|
sh 'bundle exec rake spec:main'
|
|
368
373
|
sh 'bundle exec rake spec:contrib'
|
|
374
|
+
sh 'bundle exec rake spec:opentracer'
|
|
369
375
|
|
|
370
376
|
if RUBY_PLATFORM != 'java'
|
|
371
377
|
# Contrib minitests
|
|
@@ -432,6 +438,7 @@ task :ci do
|
|
|
432
438
|
sh 'bundle exec rake test:main'
|
|
433
439
|
sh 'bundle exec rake spec:main'
|
|
434
440
|
sh 'bundle exec rake spec:contrib'
|
|
441
|
+
sh 'bundle exec rake spec:opentracer'
|
|
435
442
|
|
|
436
443
|
if RUBY_PLATFORM != 'java'
|
|
437
444
|
# Contrib minitests
|
|
@@ -497,6 +504,7 @@ task :ci do
|
|
|
497
504
|
sh 'bundle exec rake test:main'
|
|
498
505
|
sh 'bundle exec rake spec:main'
|
|
499
506
|
sh 'bundle exec rake spec:contrib'
|
|
507
|
+
sh 'bundle exec rake spec:opentracer'
|
|
500
508
|
|
|
501
509
|
if RUBY_PLATFORM != 'java'
|
|
502
510
|
# Contrib minitests
|
data/ddtrace.gemspec
CHANGED
|
@@ -33,6 +33,8 @@ Gem::Specification.new do |spec|
|
|
|
33
33
|
spec.require_paths = ['lib']
|
|
34
34
|
|
|
35
35
|
spec.add_dependency 'msgpack'
|
|
36
|
+
# TODO: Move this to Appraisals?
|
|
37
|
+
spec.add_dependency 'opentracing', '>= 0.4.1'
|
|
36
38
|
|
|
37
39
|
spec.add_development_dependency 'rake', '>= 10.5'
|
|
38
40
|
spec.add_development_dependency 'rubocop', '= 0.49.1' if RUBY_VERSION >= '2.1.0'
|
data/docs/GettingStarted.md
CHANGED
|
@@ -21,6 +21,7 @@ For descriptions of terminology used in APM, take a look at the [official docume
|
|
|
21
21
|
- [Installation](#installation)
|
|
22
22
|
- [Quickstart for Rails applications](#quickstart-for-rails-applications)
|
|
23
23
|
- [Quickstart for Ruby applications](#quickstart-for-ruby-applications)
|
|
24
|
+
- [Quickstart for OpenTracing](#quickstart-for-opentracing)
|
|
24
25
|
- [Manual instrumentation](#manual-instrumentation)
|
|
25
26
|
- [Integration instrumentation](#integration-instrumentation)
|
|
26
27
|
- [Active Record](#active-record)
|
|
@@ -59,6 +60,7 @@ For descriptions of terminology used in APM, take a look at the [official docume
|
|
|
59
60
|
- [Processing pipeline](#processing-pipeline)
|
|
60
61
|
- [Filtering](#filtering)
|
|
61
62
|
- [Processing](#processing)
|
|
63
|
+
- [OpenTracing](#opentracing)
|
|
62
64
|
|
|
63
65
|
## Compatibility
|
|
64
66
|
|
|
@@ -75,10 +77,6 @@ For descriptions of terminology used in APM, take a look at the [official docume
|
|
|
75
77
|
| | | 2.4 | Full |
|
|
76
78
|
| JRuby | http://jruby.org/ | 9.1.5 | Experimental |
|
|
77
79
|
|
|
78
|
-
*Full* support indicates all tracer features are available.
|
|
79
|
-
|
|
80
|
-
*Experimental* indicates most features should be available, but unverified.
|
|
81
|
-
|
|
82
80
|
**Supported web servers**:
|
|
83
81
|
|
|
84
82
|
| Type | Documentation | Version | Support type |
|
|
@@ -87,6 +85,16 @@ For descriptions of terminology used in APM, take a look at the [official docume
|
|
|
87
85
|
| Unicorn | https://bogomips.org/unicorn/ | 4.8+ / 5.1+ | Full |
|
|
88
86
|
| Passenger | https://www.phusionpassenger.com/ | 5.0+ | Full |
|
|
89
87
|
|
|
88
|
+
**Supported tracing frameworks**:
|
|
89
|
+
|
|
90
|
+
| Type | Documentation | Version | Support type |
|
|
91
|
+
| ----------- | ----------------------------------------------- | --------------------- | ------------ |
|
|
92
|
+
| OpenTracing | https://github.com/opentracing/opentracing-ruby | 0.4.1+ (w/ Ruby 2.1+) | Experimental |
|
|
93
|
+
|
|
94
|
+
*Full* support indicates all tracer features are available.
|
|
95
|
+
|
|
96
|
+
*Experimental* indicates most features should be available, but unverified.
|
|
97
|
+
|
|
90
98
|
## Installation
|
|
91
99
|
|
|
92
100
|
The following steps will help you quickly start tracing your Ruby application.
|
|
@@ -136,6 +144,36 @@ The Ruby APM tracer sends trace data through the Datadog Agent.
|
|
|
136
144
|
1. Activate integration instrumentation (see [Integration instrumentation](#integration-instrumentation))
|
|
137
145
|
2. Add manual instrumentation around your code (see [Manual instrumentation](#manual-instrumentation))
|
|
138
146
|
|
|
147
|
+
### Quickstart for OpenTracing
|
|
148
|
+
|
|
149
|
+
1. Install the gem with `gem install ddtrace`
|
|
150
|
+
2. To your OpenTracing configuration file, add the following:
|
|
151
|
+
|
|
152
|
+
```ruby
|
|
153
|
+
require 'opentracing'
|
|
154
|
+
require 'ddtrace'
|
|
155
|
+
require 'ddtrace/opentracer'
|
|
156
|
+
|
|
157
|
+
# Activate the Datadog tracer for OpenTracing
|
|
158
|
+
OpenTracing.global_tracer = Datadog::OpenTracer::Tracer.new
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
3. (Optional) Add a configuration block to your Ruby application to configure Datadog with:
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
Datadog.configure do |c|
|
|
165
|
+
# Configure the Datadog tracer here.
|
|
166
|
+
# Activate integrations, change tracer settings, etc...
|
|
167
|
+
# By default without additional configuration,
|
|
168
|
+
# no additional integrations will be traced, only
|
|
169
|
+
# what you have instrumented with OpenTracing.
|
|
170
|
+
end
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
4. (Optional) Add or activate additional instrumentation by doing either of the following:
|
|
174
|
+
1. Activate Datadog integration instrumentation (see [Integration instrumentation](#integration-instrumentation))
|
|
175
|
+
2. Add Datadog manual instrumentation around your code (see [Manual instrumentation](#manual-instrumentation))
|
|
176
|
+
|
|
139
177
|
### Final steps for installation
|
|
140
178
|
|
|
141
179
|
After setting up, your services will appear on the [APM services page](https://app.datadoghq.com/apm/services) within a few minutes. Learn more about [using the APM UI][visualization docs].
|
|
@@ -869,6 +907,7 @@ Where `options` is an optional `Hash` that accepts the following parameters:
|
|
|
869
907
|
| ``database_service`` | Database service name used when tracing database activity | ``<app_name>-<adapter_name>`` |
|
|
870
908
|
| ``exception_controller`` | Class or Module which identifies a custom exception controller class. Tracer provides improved error behavior when it can identify custom exception controllers. By default, without this option, it 'guesses' what a custom exception controller looks like. Providing this option aids this identification. | ``nil`` |
|
|
871
909
|
| ``distributed_tracing`` | Enables [distributed tracing](#distributed-tracing) so that this service trace is connected with a trace of another service if tracing headers are received | `false` |
|
|
910
|
+
| ``middleware`` | Add the trace middleware to the Rails application. Set to `false` if you don't want the middleware to load. | `true` |
|
|
872
911
|
| ``middleware_names`` | Enables any short-circuited middleware requests to display the middleware name as resource for the trace. | `false` |
|
|
873
912
|
| ``template_base_path`` | Used when the template name is parsed. If you don't store your templates in the ``views/`` folder, you may need to change this value | ``views/`` |
|
|
874
913
|
| ``tracer`` | A ``Datadog::Tracer`` instance used to instrument the application. Usually you don't need to set that. | ``Datadog.tracer`` |
|
|
@@ -1510,3 +1549,32 @@ Datadog::Pipeline.before_flush(
|
|
|
1510
1549
|
Datadog::Pipeline::SpanProcessor.new { |span| span.resource.gsub!(/password=.*/, '') }
|
|
1511
1550
|
)
|
|
1512
1551
|
```
|
|
1552
|
+
|
|
1553
|
+
### OpenTracing
|
|
1554
|
+
|
|
1555
|
+
For setting up Datadog with OpenTracing, see out [Quickstart for OpenTracing](#quickstart-for-opentracing) section for details.
|
|
1556
|
+
|
|
1557
|
+
**Configuring Datadog tracer settings**
|
|
1558
|
+
|
|
1559
|
+
The underlying Datadog tracer can be configured by passing options (which match `Datadog::Tracer`) when configuring the global tracer:
|
|
1560
|
+
|
|
1561
|
+
```ruby
|
|
1562
|
+
# Where `options` is a Hash of options provided to Datadog::Tracer
|
|
1563
|
+
OpenTracing.global_tracer = Datadog::OpenTracer::Tracer.new(options)
|
|
1564
|
+
```
|
|
1565
|
+
|
|
1566
|
+
It can also be configured by using `Datadog.configure` described in the [Tracer settings](#tracer-settings) section.
|
|
1567
|
+
|
|
1568
|
+
**Activating and configuring integrations**
|
|
1569
|
+
|
|
1570
|
+
By default, configuring OpenTracing with Datadog will not automatically activate any additional instrumentation provided by Datadog. You will only receive spans and traces from OpenTracing instrumentation you have in your application.
|
|
1571
|
+
|
|
1572
|
+
However, additional instrumentation provided by Datadog can be activated alongside OpenTracing using `Datadog.configure`, which can be used to further enhance your tracing. To activate this, see [Integration instrumentation](#integration-instrumentation) for more details.
|
|
1573
|
+
|
|
1574
|
+
**Supported serialization formats**
|
|
1575
|
+
|
|
1576
|
+
| Type | Supported? | Additional information |
|
|
1577
|
+
| ------------------------------ | ---------- | ---------------------- |
|
|
1578
|
+
| `OpenTracing::FORMAT_TEXT_MAP` | Yes | |
|
|
1579
|
+
| `OpenTracing::FORMAT_RACK` | Yes | Because of the loss of resolution in the Rack format, please note that baggage items with names containing either upper case characters or `-` will be converted to lower case and `_` in a round-trip respectively. We recommend avoiding these characters, or accommodating accordingly on the receiving end. |
|
|
1580
|
+
| `OpenTracing::FORMAT_BINARY` | No | |
|
|
@@ -39,7 +39,8 @@ module Datadog
|
|
|
39
39
|
@patched = true
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
if
|
|
42
|
+
if (!instance_variable_defined?(:@middleware_patched) || !@middleware_patched) \
|
|
43
|
+
&& get_option(:middleware_names)
|
|
43
44
|
if get_option(:application)
|
|
44
45
|
enable_middleware_names
|
|
45
46
|
@middleware_patched = true
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
require 'ddtrace/contrib/rails/utils'
|
|
2
|
+
require 'ddtrace/contrib/rails/framework'
|
|
3
|
+
require 'ddtrace/contrib/rails/middlewares'
|
|
4
|
+
require 'ddtrace/contrib/rack/middlewares'
|
|
2
5
|
|
|
3
6
|
module Datadog
|
|
4
7
|
module Contrib
|
|
@@ -17,6 +20,7 @@ module Datadog
|
|
|
17
20
|
Datadog.configuration[:active_record][:service_name] = value
|
|
18
21
|
end
|
|
19
22
|
end
|
|
23
|
+
option :middleware, default: true
|
|
20
24
|
option :middleware_names, default: false
|
|
21
25
|
option :distributed_tracing, default: false
|
|
22
26
|
option :template_base_path, default: 'views/'
|
|
@@ -28,7 +32,41 @@ module Datadog
|
|
|
28
32
|
class << self
|
|
29
33
|
def patch
|
|
30
34
|
return @patched if patched? || !compatible?
|
|
31
|
-
|
|
35
|
+
|
|
36
|
+
# Add a callback hook to add the trace middleware before the application initializes.
|
|
37
|
+
# Otherwise the middleware stack will be frozen.
|
|
38
|
+
do_once(:rails_before_initialize_hook) do
|
|
39
|
+
::ActiveSupport.on_load(:before_initialize) do
|
|
40
|
+
# Sometimes we don't want to activate middleware e.g. OpenTracing, etc.
|
|
41
|
+
if Datadog.configuration[:rails][:middleware]
|
|
42
|
+
# Add trace middleware
|
|
43
|
+
config.middleware.insert_before(0, Datadog::Contrib::Rack::TraceMiddleware)
|
|
44
|
+
|
|
45
|
+
# Insert right after Rails exception handling middleware, because if it's before,
|
|
46
|
+
# it catches and swallows the error. If it's too far after, custom middleware can find itself
|
|
47
|
+
# between, and raise exceptions that don't end up getting tagged on the request properly.
|
|
48
|
+
# e.g lost stack trace.
|
|
49
|
+
config.middleware.insert_after(
|
|
50
|
+
ActionDispatch::ShowExceptions,
|
|
51
|
+
Datadog::Contrib::Rails::ExceptionMiddleware
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Add a callback hook to finish configuring the tracer after the application is initialized.
|
|
58
|
+
# We need to wait for some things, like application name, middleware stack, etc.
|
|
59
|
+
do_once(:rails_after_initialize_hook) do
|
|
60
|
+
::ActiveSupport.on_load(:after_initialize) do
|
|
61
|
+
Datadog::Contrib::Rails::Framework.setup
|
|
62
|
+
|
|
63
|
+
# Add instrumentation to Rails components
|
|
64
|
+
Datadog::Contrib::Rails::ActionController.instrument
|
|
65
|
+
Datadog::Contrib::Rails::ActionView.instrument
|
|
66
|
+
Datadog::Contrib::Rails::ActiveSupport.instrument
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
32
70
|
@patched = true
|
|
33
71
|
rescue => e
|
|
34
72
|
Datadog::Tracer.log.error("Unable to apply Rails integration: #{e}")
|
|
@@ -49,5 +87,3 @@ module Datadog
|
|
|
49
87
|
end
|
|
50
88
|
end
|
|
51
89
|
end
|
|
52
|
-
|
|
53
|
-
require 'ddtrace/contrib/rails/railtie' if Datadog.registry[:rails].compatible?
|
|
@@ -5,11 +5,14 @@ require 'ddtrace/contrib/rack/middlewares'
|
|
|
5
5
|
module Datadog
|
|
6
6
|
# Railtie class initializes
|
|
7
7
|
class Railtie < Rails::Railtie
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
# Add the trace middleware to the application stack
|
|
9
|
+
initializer 'datadog.add_middleware' do |app|
|
|
10
|
+
app.middleware.insert_before(0, Datadog::Contrib::Rack::TraceMiddleware)
|
|
11
|
+
# Insert right after Rails exception handling middleware, because if it's before,
|
|
12
|
+
# it catches and swallows the error. If it's too far after, custom middleware can find itself
|
|
13
|
+
# between, and raise exceptions that don't end up getting tagged on the request properly (e.g lost stack trace.)
|
|
14
|
+
app.middleware.insert_after(ActionDispatch::ShowExceptions, Datadog::Contrib::Rails::ExceptionMiddleware)
|
|
15
|
+
end
|
|
13
16
|
|
|
14
17
|
config.after_initialize do
|
|
15
18
|
Datadog::Contrib::Rails::Framework.setup
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
# Namespace for ddtrace OpenTracing implementation
|
|
3
|
+
module OpenTracer
|
|
4
|
+
module_function
|
|
5
|
+
|
|
6
|
+
def supported?
|
|
7
|
+
Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.1')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def load_opentracer
|
|
11
|
+
require 'opentracing'
|
|
12
|
+
require 'opentracing/carrier'
|
|
13
|
+
require 'ddtrace'
|
|
14
|
+
require 'ddtrace/opentracer/carrier'
|
|
15
|
+
require 'ddtrace/opentracer/tracer'
|
|
16
|
+
require 'ddtrace/opentracer/span'
|
|
17
|
+
require 'ddtrace/opentracer/span_context'
|
|
18
|
+
require 'ddtrace/opentracer/span_context_factory'
|
|
19
|
+
require 'ddtrace/opentracer/scope'
|
|
20
|
+
require 'ddtrace/opentracer/scope_manager'
|
|
21
|
+
require 'ddtrace/opentracer/thread_local_scope'
|
|
22
|
+
require 'ddtrace/opentracer/thread_local_scope_manager'
|
|
23
|
+
require 'ddtrace/opentracer/distributed_headers'
|
|
24
|
+
require 'ddtrace/opentracer/propagator'
|
|
25
|
+
require 'ddtrace/opentracer/text_map_propagator'
|
|
26
|
+
require 'ddtrace/opentracer/binary_propagator'
|
|
27
|
+
require 'ddtrace/opentracer/rack_propagator'
|
|
28
|
+
require 'ddtrace/opentracer/global_tracer'
|
|
29
|
+
|
|
30
|
+
# Modify the OpenTracing module functions
|
|
31
|
+
OpenTracing.module_eval do
|
|
32
|
+
class << self
|
|
33
|
+
prepend Datadog::OpenTracer::GlobalTracer
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
load_opentracer if supported?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module OpenTracer
|
|
3
|
+
# OpenTracing propagator for Datadog::OpenTracer::Tracer
|
|
4
|
+
module BinaryPropagator
|
|
5
|
+
extend Propagator
|
|
6
|
+
|
|
7
|
+
# Inject a SpanContext into the given carrier
|
|
8
|
+
#
|
|
9
|
+
# @param span_context [SpanContext]
|
|
10
|
+
# @param carrier [Carrier] A carrier object of Binary type
|
|
11
|
+
def self.inject(span_context, carrier)
|
|
12
|
+
nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Extract a SpanContext in Binary format from the given carrier.
|
|
16
|
+
#
|
|
17
|
+
# @param carrier [Carrier] A carrier object of Binary type
|
|
18
|
+
# @return [SpanContext, nil] the extracted SpanContext or nil if none could be found
|
|
19
|
+
def self.extract(carrier)
|
|
20
|
+
SpanContext::NOOP_INSTANCE
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'ddtrace/span'
|
|
2
|
+
require 'ddtrace/ext/distributed'
|
|
3
|
+
|
|
4
|
+
module Datadog
|
|
5
|
+
module OpenTracer
|
|
6
|
+
# DistributedHeaders provides easy access and validation to headers
|
|
7
|
+
class DistributedHeaders
|
|
8
|
+
include Datadog::Ext::DistributedTracing
|
|
9
|
+
|
|
10
|
+
def initialize(carrier)
|
|
11
|
+
@carrier = carrier
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def valid?
|
|
15
|
+
# Sampling priority is optional.
|
|
16
|
+
!trace_id.nil? && !parent_id.nil?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def trace_id
|
|
20
|
+
id HTTP_HEADER_TRACE_ID
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def parent_id
|
|
24
|
+
id HTTP_HEADER_PARENT_ID
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def sampling_priority
|
|
28
|
+
hdr = @carrier[HTTP_HEADER_SAMPLING_PRIORITY]
|
|
29
|
+
# It's important to make a difference between no header,
|
|
30
|
+
# and a header defined to zero.
|
|
31
|
+
return unless hdr
|
|
32
|
+
value = hdr.to_i
|
|
33
|
+
return if value < 0
|
|
34
|
+
value
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def id(header)
|
|
40
|
+
value = @carrier[header].to_i
|
|
41
|
+
return if value.zero? || value >= Datadog::Span::MAX_ID
|
|
42
|
+
value < 0 ? value + 0x1_0000_0000_0000_0000 : value
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module OpenTracer
|
|
3
|
+
# Patch for OpenTracing module
|
|
4
|
+
module GlobalTracer
|
|
5
|
+
def global_tracer=(tracer)
|
|
6
|
+
super.tap do
|
|
7
|
+
if tracer.class <= Datadog::OpenTracer::Tracer
|
|
8
|
+
# Update the Datadog global tracer, too.
|
|
9
|
+
Datadog.instance_variable_set(:@tracer, tracer.datadog_tracer)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module OpenTracer
|
|
3
|
+
# OpenTracing propagator for Datadog::OpenTracer::Tracer
|
|
4
|
+
module Propagator
|
|
5
|
+
# Inject a SpanContext into the given carrier
|
|
6
|
+
#
|
|
7
|
+
# @param span_context [SpanContext]
|
|
8
|
+
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
|
9
|
+
def inject(span_context, carrier)
|
|
10
|
+
raise NotImplementedError
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Extract a SpanContext in the given format from the given carrier.
|
|
14
|
+
#
|
|
15
|
+
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
|
16
|
+
# @return [SpanContext, nil] the extracted SpanContext or nil if none could be found
|
|
17
|
+
def extract(carrier)
|
|
18
|
+
raise NotImplementedError
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'ddtrace/propagation/http_propagator'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module OpenTracer
|
|
5
|
+
# OpenTracing propagator for Datadog::OpenTracer::Tracer
|
|
6
|
+
module RackPropagator
|
|
7
|
+
extend Propagator
|
|
8
|
+
extend Datadog::Ext::DistributedTracing
|
|
9
|
+
include Datadog::Ext::DistributedTracing
|
|
10
|
+
|
|
11
|
+
BAGGAGE_PREFIX = 'ot-baggage-'.freeze
|
|
12
|
+
BAGGAGE_PREFIX_FORMATTED = 'HTTP_OT_BAGGAGE_'.freeze
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
# Inject a SpanContext into the given carrier
|
|
16
|
+
#
|
|
17
|
+
# @param span_context [SpanContext]
|
|
18
|
+
# @param carrier [Carrier] A carrier object of Rack type
|
|
19
|
+
def inject(span_context, carrier)
|
|
20
|
+
# Inject Datadog trace properties
|
|
21
|
+
Datadog::HTTPPropagator.inject!(span_context.datadog_context, carrier)
|
|
22
|
+
|
|
23
|
+
# Inject baggage
|
|
24
|
+
span_context.baggage.each do |key, value|
|
|
25
|
+
carrier[BAGGAGE_PREFIX + key] = value
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Extract a SpanContext in Rack format from the given carrier.
|
|
32
|
+
#
|
|
33
|
+
# @param carrier [Carrier] A carrier object of Rack type
|
|
34
|
+
# @return [SpanContext, nil] the extracted SpanContext or nil if none could be found
|
|
35
|
+
def extract(carrier)
|
|
36
|
+
# First extract & build a Datadog context
|
|
37
|
+
datadog_context = Datadog::HTTPPropagator.extract(carrier)
|
|
38
|
+
|
|
39
|
+
# Then extract any other baggage
|
|
40
|
+
baggage = {}
|
|
41
|
+
carrier.each do |key, value|
|
|
42
|
+
baggage[header_to_baggage(key)] = value if baggage_header?(key)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
SpanContextFactory.build(datadog_context: datadog_context, baggage: baggage)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def baggage_header?(header)
|
|
51
|
+
header.to_s.start_with?(BAGGAGE_PREFIX_FORMATTED)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def header_to_baggage(key)
|
|
55
|
+
key[BAGGAGE_PREFIX_FORMATTED.length, key.length].downcase
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module OpenTracer
|
|
3
|
+
# OpenTracing adapter for Datadog::Span
|
|
4
|
+
class Span < ::OpenTracing::Span
|
|
5
|
+
attr_reader \
|
|
6
|
+
:datadog_span
|
|
7
|
+
|
|
8
|
+
def initialize(datadog_span:, span_context:)
|
|
9
|
+
@datadog_span = datadog_span
|
|
10
|
+
@span_context = span_context
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Set the name of the operation
|
|
14
|
+
#
|
|
15
|
+
# @param [String] name
|
|
16
|
+
def operation_name=(name)
|
|
17
|
+
datadog_span.name = name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Span Context
|
|
21
|
+
#
|
|
22
|
+
# @return [SpanContext]
|
|
23
|
+
def context
|
|
24
|
+
@span_context
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Set a tag value on this span
|
|
28
|
+
# @param key [String] the key of the tag
|
|
29
|
+
# @param value [String, Numeric, Boolean] the value of the tag. If it's not
|
|
30
|
+
# a String, Numeric, or Boolean it will be encoded with to_s
|
|
31
|
+
def set_tag(key, value)
|
|
32
|
+
tap { datadog_span.set_tag(key, value) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Set a baggage item on the span
|
|
36
|
+
# @param key [String] the key of the baggage item
|
|
37
|
+
# @param value [String] the value of the baggage item
|
|
38
|
+
def set_baggage_item(key, value)
|
|
39
|
+
tap do
|
|
40
|
+
# SpanContext is immutable, so to make changes
|
|
41
|
+
# build a new span context.
|
|
42
|
+
@span_context = SpanContextFactory.clone(
|
|
43
|
+
span_context: context,
|
|
44
|
+
baggage: { key => value }
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Get a baggage item
|
|
50
|
+
# @param key [String] the key of the baggage item
|
|
51
|
+
# @return [String] value of the baggage item
|
|
52
|
+
def get_baggage_item(key)
|
|
53
|
+
context.baggage[key]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @deprecated Use {#log_kv} instead.
|
|
57
|
+
# Reason: event is an optional standard log field defined in spec and not required. Also,
|
|
58
|
+
# method name {#log_kv} is more consistent with other language implementations such as Python and Go.
|
|
59
|
+
#
|
|
60
|
+
# Add a log entry to this span
|
|
61
|
+
# @param event [String] event name for the log
|
|
62
|
+
# @param timestamp [Time] time of the log
|
|
63
|
+
# @param fields [Hash] Additional information to log
|
|
64
|
+
def log(event: nil, timestamp: Time.now, **fields)
|
|
65
|
+
super # Log deprecation warning
|
|
66
|
+
|
|
67
|
+
# If the fields specify an error
|
|
68
|
+
if fields.key?(:'error.object')
|
|
69
|
+
datadog_span.set_error(fields[:'error.object'])
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Add a log entry to this span
|
|
74
|
+
# @param timestamp [Time] time of the log
|
|
75
|
+
# @param fields [Hash] Additional information to log
|
|
76
|
+
def log_kv(timestamp: Time.now, **fields)
|
|
77
|
+
# If the fields specify an error
|
|
78
|
+
if fields.key?(:'error.object')
|
|
79
|
+
datadog_span.set_error(fields[:'error.object'])
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Finish the {Span}
|
|
84
|
+
# @param end_time [Time] custom end time, if not now
|
|
85
|
+
def finish(end_time: Time.now)
|
|
86
|
+
datadog_span.finish(end_time)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module OpenTracer
|
|
3
|
+
# OpenTracing adapter for SpanContext
|
|
4
|
+
class SpanContext < ::OpenTracing::SpanContext
|
|
5
|
+
attr_reader \
|
|
6
|
+
:datadog_context
|
|
7
|
+
|
|
8
|
+
def initialize(datadog_context:, baggage: {})
|
|
9
|
+
@datadog_context = datadog_context
|
|
10
|
+
@baggage = baggage.freeze
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module OpenTracer
|
|
3
|
+
# Creates new Datadog::OpenTracer::SpanContext
|
|
4
|
+
module SpanContextFactory
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def build(datadog_context:, baggage: {})
|
|
8
|
+
SpanContext.new(
|
|
9
|
+
datadog_context: datadog_context,
|
|
10
|
+
baggage: baggage.dup
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def clone(span_context:, baggage: {})
|
|
15
|
+
SpanContext.new(
|
|
16
|
+
datadog_context: span_context.datadog_context,
|
|
17
|
+
# Merge baggage from previous SpanContext
|
|
18
|
+
baggage: span_context.baggage.merge(baggage)
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'ddtrace/ext/distributed'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module OpenTracer
|
|
5
|
+
# OpenTracing propagator for Datadog::OpenTracer::Tracer
|
|
6
|
+
module TextMapPropagator
|
|
7
|
+
extend Propagator
|
|
8
|
+
extend Datadog::Ext::DistributedTracing
|
|
9
|
+
include Datadog::Ext::DistributedTracing
|
|
10
|
+
|
|
11
|
+
BAGGAGE_PREFIX = 'ot-baggage-'.freeze
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
# Inject a SpanContext into the given carrier
|
|
15
|
+
#
|
|
16
|
+
# @param span_context [SpanContext]
|
|
17
|
+
# @param carrier [Carrier] A carrier object of Rack type
|
|
18
|
+
def inject(span_context, carrier)
|
|
19
|
+
# Inject Datadog trace properties
|
|
20
|
+
span_context.datadog_context.tap do |datadog_context|
|
|
21
|
+
carrier[HTTP_HEADER_TRACE_ID] = datadog_context.trace_id
|
|
22
|
+
carrier[HTTP_HEADER_PARENT_ID] = datadog_context.span_id
|
|
23
|
+
carrier[HTTP_HEADER_SAMPLING_PRIORITY] = datadog_context.sampling_priority
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Inject baggage
|
|
27
|
+
span_context.baggage.each do |key, value|
|
|
28
|
+
carrier[BAGGAGE_PREFIX + key] = value
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Extract a SpanContext in TextMap format from the given carrier.
|
|
35
|
+
#
|
|
36
|
+
# @param carrier [Carrier] A carrier object of TextMap type
|
|
37
|
+
# @return [SpanContext, nil] the extracted SpanContext or nil if none could be found
|
|
38
|
+
def extract(carrier)
|
|
39
|
+
# First extract & build a Datadog context
|
|
40
|
+
headers = DistributedHeaders.new(carrier)
|
|
41
|
+
|
|
42
|
+
datadog_context = if headers.valid?
|
|
43
|
+
Datadog::Context.new(
|
|
44
|
+
trace_id: headers.trace_id,
|
|
45
|
+
span_id: headers.parent_id,
|
|
46
|
+
sampling_priority: headers.sampling_priority
|
|
47
|
+
)
|
|
48
|
+
else
|
|
49
|
+
Datadog::Context.new
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Then extract any other baggage
|
|
53
|
+
baggage = {}
|
|
54
|
+
carrier.each do |key, value|
|
|
55
|
+
baggage[item_to_baggage(key)] = value if baggage_item?(key)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
SpanContextFactory.build(datadog_context: datadog_context, baggage: baggage)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def baggage_item?(item)
|
|
64
|
+
item.to_s.start_with?(BAGGAGE_PREFIX)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def item_to_baggage(key)
|
|
68
|
+
key[BAGGAGE_PREFIX.length, key.length]
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module OpenTracer
|
|
3
|
+
# OpenTracing adapter for thread local scopes
|
|
4
|
+
class ThreadLocalScope < Scope
|
|
5
|
+
attr_reader \
|
|
6
|
+
:finish_on_close
|
|
7
|
+
|
|
8
|
+
def initialize(
|
|
9
|
+
manager:,
|
|
10
|
+
span:,
|
|
11
|
+
finish_on_close: true
|
|
12
|
+
)
|
|
13
|
+
super(manager: manager, span: span)
|
|
14
|
+
@finish_on_close = finish_on_close
|
|
15
|
+
@previous_scope = manager.active
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Mark the end of the active period for the current thread and Scope,
|
|
19
|
+
# updating the ScopeManager#active in the process.
|
|
20
|
+
#
|
|
21
|
+
# NOTE: Calling close more than once on a single Scope instance leads to
|
|
22
|
+
# undefined behavior.
|
|
23
|
+
def close
|
|
24
|
+
return unless equal?(manager.active)
|
|
25
|
+
span.finish if finish_on_close
|
|
26
|
+
manager.send(:set_scope, @previous_scope)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Datadog
|
|
2
|
+
module OpenTracer
|
|
3
|
+
# OpenTracing adapter for thread local scope management
|
|
4
|
+
class ThreadLocalScopeManager < ScopeManager
|
|
5
|
+
# Make a span instance active.
|
|
6
|
+
#
|
|
7
|
+
# @param span [Span] the Span that should become active
|
|
8
|
+
# @param finish_on_close [Boolean] whether the Span should automatically be
|
|
9
|
+
# finished when Scope#close is called
|
|
10
|
+
# @return [Scope] instance to control the end of the active period for the
|
|
11
|
+
# Span. It is a programming error to neglect to call Scope#close on the
|
|
12
|
+
# returned instance.
|
|
13
|
+
def activate(span, finish_on_close: true)
|
|
14
|
+
ThreadLocalScope.new(
|
|
15
|
+
manager: self,
|
|
16
|
+
span: span,
|
|
17
|
+
finish_on_close: finish_on_close
|
|
18
|
+
).tap do |scope|
|
|
19
|
+
set_scope(scope)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Scope] the currently active Scope which can be used to access the
|
|
24
|
+
# currently active Span.
|
|
25
|
+
#
|
|
26
|
+
# If there is a non-null Scope, its wrapped Span becomes an implicit parent
|
|
27
|
+
# (as Reference#CHILD_OF) of any newly-created Span at Tracer#start_active_span
|
|
28
|
+
# or Tracer#start_span time.
|
|
29
|
+
def active
|
|
30
|
+
Thread.current[object_id.to_s]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def set_scope(scope)
|
|
36
|
+
Thread.current[object_id.to_s] = scope
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
require 'ddtrace/tracer'
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module OpenTracer
|
|
5
|
+
# OpenTracing adapter for Datadog::Tracer
|
|
6
|
+
class Tracer < ::OpenTracing::Tracer
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
attr_reader \
|
|
10
|
+
:datadog_tracer
|
|
11
|
+
|
|
12
|
+
def_delegators \
|
|
13
|
+
:datadog_tracer,
|
|
14
|
+
:configure
|
|
15
|
+
|
|
16
|
+
def initialize(options = {})
|
|
17
|
+
super()
|
|
18
|
+
@datadog_tracer = Datadog::Tracer.new(options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @return [ScopeManager] the current ScopeManager.
|
|
22
|
+
def scope_manager
|
|
23
|
+
@scope_manager ||= ThreadLocalScopeManager.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns a newly started and activated Scope.
|
|
27
|
+
#
|
|
28
|
+
# If the Tracer's ScopeManager#active is not nil, no explicit references
|
|
29
|
+
# are provided, and `ignore_active_scope` is false, then an inferred
|
|
30
|
+
# References#CHILD_OF reference is created to the ScopeManager#active's
|
|
31
|
+
# SpanContext when start_active is invoked.
|
|
32
|
+
#
|
|
33
|
+
# @param operation_name [String] The operation name for the Span
|
|
34
|
+
# @param child_of [SpanContext, Span] SpanContext that acts as a parent to
|
|
35
|
+
# the newly-started Span. If a Span instance is provided, its
|
|
36
|
+
# context is automatically substituted. See [Reference] for more
|
|
37
|
+
# information.
|
|
38
|
+
#
|
|
39
|
+
# If specified, the `references` parameter must be omitted.
|
|
40
|
+
# @param references [Array<Reference>] An array of reference
|
|
41
|
+
# objects that identify one or more parent SpanContexts.
|
|
42
|
+
# @param start_time [Time] When the Span started, if not now
|
|
43
|
+
# @param tags [Hash] Tags to assign to the Span at start time
|
|
44
|
+
# @param ignore_active_scope [Boolean] whether to create an implicit
|
|
45
|
+
# References#CHILD_OF reference to the ScopeManager#active.
|
|
46
|
+
# @param finish_on_close [Boolean] whether span should automatically be
|
|
47
|
+
# finished when Scope#close is called
|
|
48
|
+
# @yield [Scope] If an optional block is passed to start_active it will
|
|
49
|
+
# yield the newly-started Scope. If `finish_on_close` is true then the
|
|
50
|
+
# Span will be finished automatically after the block is executed.
|
|
51
|
+
# @return [Scope] The newly-started and activated Scope
|
|
52
|
+
def start_active_span(operation_name,
|
|
53
|
+
child_of: nil,
|
|
54
|
+
references: nil,
|
|
55
|
+
start_time: Time.now,
|
|
56
|
+
tags: nil,
|
|
57
|
+
ignore_active_scope: false,
|
|
58
|
+
finish_on_close: true)
|
|
59
|
+
|
|
60
|
+
# When meant to automatically determine the parent,
|
|
61
|
+
# Use the active scope first, otherwise fall back to any
|
|
62
|
+
# context generated by Datadog, so as to append to it and gain
|
|
63
|
+
# the benefit of any out-of-the-box tracing from Datadog preceding
|
|
64
|
+
# the OpenTracer::Tracer.
|
|
65
|
+
#
|
|
66
|
+
# We do this here instead of in #start_span because #start_span generates
|
|
67
|
+
# spans that are not assigned to a scope, a.k.a not supposed to be used by
|
|
68
|
+
# subsequent spans implicitly. By using the existing Datadog context, the span
|
|
69
|
+
# effectively ends up "assigned to a scope", by virtue of being added to the
|
|
70
|
+
# Context. Hence, it would behave more like an active span, which is why it
|
|
71
|
+
# should only be here.
|
|
72
|
+
unless child_of || ignore_active_scope
|
|
73
|
+
child_of = if scope_manager.active
|
|
74
|
+
scope_manager.active.span.context
|
|
75
|
+
else
|
|
76
|
+
SpanContextFactory.build(datadog_context: datadog_tracer.call_context)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Create the span, and auto-add it to the Datadog context.
|
|
81
|
+
span = start_span(
|
|
82
|
+
operation_name,
|
|
83
|
+
child_of: child_of,
|
|
84
|
+
references: references,
|
|
85
|
+
start_time: start_time,
|
|
86
|
+
tags: tags,
|
|
87
|
+
ignore_active_scope: ignore_active_scope
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Overwrite the tracer context with the OpenTracing managed context.
|
|
91
|
+
# This is mostly for the benefit of any out-of-the-box tracing from Datadog,
|
|
92
|
+
# such that spans generated by that tracing will be attached to the OpenTracer
|
|
93
|
+
# parent span.
|
|
94
|
+
datadog_tracer.provider.context = span.datadog_span.context
|
|
95
|
+
|
|
96
|
+
scope_manager.activate(span, finish_on_close: finish_on_close).tap do |scope|
|
|
97
|
+
if block_given?
|
|
98
|
+
begin
|
|
99
|
+
yield(scope)
|
|
100
|
+
ensure
|
|
101
|
+
scope.close
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Like #start_active_span, but the returned Span has not been registered via the
|
|
108
|
+
# ScopeManager.
|
|
109
|
+
#
|
|
110
|
+
# @param operation_name [String] The operation name for the Span
|
|
111
|
+
# @param child_of [SpanContext, Span] SpanContext that acts as a parent to
|
|
112
|
+
# the newly-started Span. If a Span instance is provided, its
|
|
113
|
+
# context is automatically substituted. See [Reference] for more
|
|
114
|
+
# information.
|
|
115
|
+
#
|
|
116
|
+
# If specified, the `references` parameter must be omitted.
|
|
117
|
+
# @param references [Array<Reference>] An array of reference
|
|
118
|
+
# objects that identify one or more parent SpanContexts.
|
|
119
|
+
# @param start_time [Time] When the Span started, if not now
|
|
120
|
+
# @param tags [Hash] Tags to assign to the Span at start time
|
|
121
|
+
# @param ignore_active_scope [Boolean] whether to create an implicit
|
|
122
|
+
# References#CHILD_OF reference to the ScopeManager#active.
|
|
123
|
+
# @return [Span] the newly-started Span instance, which has not been
|
|
124
|
+
# automatically registered via the ScopeManager
|
|
125
|
+
def start_span(operation_name,
|
|
126
|
+
child_of: nil,
|
|
127
|
+
references: nil,
|
|
128
|
+
start_time: Time.now,
|
|
129
|
+
tags: nil,
|
|
130
|
+
ignore_active_scope: false)
|
|
131
|
+
|
|
132
|
+
# Derive the OpenTracer::SpanContext to inherit from.
|
|
133
|
+
parent_span_context = inherited_span_context(child_of, ignore_active_scope: ignore_active_scope)
|
|
134
|
+
|
|
135
|
+
# Retrieve Datadog::Context from parent SpanContext.
|
|
136
|
+
datadog_context = parent_span_context.nil? ? nil : parent_span_context.datadog_context
|
|
137
|
+
|
|
138
|
+
# Build the new Datadog span
|
|
139
|
+
datadog_span = datadog_tracer.start_span(
|
|
140
|
+
operation_name,
|
|
141
|
+
child_of: datadog_context,
|
|
142
|
+
start_time: start_time,
|
|
143
|
+
tags: tags || {}
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Build or extend the OpenTracer::SpanContext
|
|
147
|
+
span_context = if parent_span_context
|
|
148
|
+
SpanContextFactory.clone(span_context: parent_span_context)
|
|
149
|
+
else
|
|
150
|
+
SpanContextFactory.build(datadog_context: datadog_span.context)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Wrap the Datadog span and OpenTracer::Span context in a OpenTracer::Span
|
|
154
|
+
Span.new(datadog_span: datadog_span, span_context: span_context)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Inject a SpanContext into the given carrier
|
|
158
|
+
#
|
|
159
|
+
# @param span_context [SpanContext]
|
|
160
|
+
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
|
|
161
|
+
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
|
162
|
+
def inject(span_context, format, carrier)
|
|
163
|
+
case format
|
|
164
|
+
when OpenTracing::FORMAT_TEXT_MAP
|
|
165
|
+
TextMapPropagator.inject(span_context, carrier)
|
|
166
|
+
when OpenTracing::FORMAT_BINARY
|
|
167
|
+
BinaryPropagator.inject(span_context, carrier)
|
|
168
|
+
when OpenTracing::FORMAT_RACK
|
|
169
|
+
RackPropagator.inject(span_context, carrier)
|
|
170
|
+
else
|
|
171
|
+
warn 'Unknown inject format'
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Extract a SpanContext in the given format from the given carrier.
|
|
176
|
+
#
|
|
177
|
+
# @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
|
|
178
|
+
# @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
|
|
179
|
+
# @return [SpanContext, nil] the extracted SpanContext or nil if none could be found
|
|
180
|
+
def extract(format, carrier)
|
|
181
|
+
case format
|
|
182
|
+
when OpenTracing::FORMAT_TEXT_MAP
|
|
183
|
+
TextMapPropagator.extract(carrier)
|
|
184
|
+
when OpenTracing::FORMAT_BINARY
|
|
185
|
+
BinaryPropagator.extract(carrier)
|
|
186
|
+
when OpenTracing::FORMAT_RACK
|
|
187
|
+
RackPropagator.extract(carrier)
|
|
188
|
+
else
|
|
189
|
+
warn 'Unknown extract format'
|
|
190
|
+
nil
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
private
|
|
195
|
+
|
|
196
|
+
def inherited_span_context(parent, ignore_active_scope: false)
|
|
197
|
+
case parent
|
|
198
|
+
when Span
|
|
199
|
+
parent.context
|
|
200
|
+
when SpanContext
|
|
201
|
+
parent
|
|
202
|
+
else
|
|
203
|
+
ignore_active_scope ? nil : scope_manager.active && scope_manager.active.span.context
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
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: 0.
|
|
4
|
+
version: 0.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Datadog, Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-09-
|
|
11
|
+
date: 2018-09-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: msgpack
|
|
@@ -24,6 +24,20 @@ dependencies:
|
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: opentracing
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.4.1
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.4.1
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: rake
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -400,6 +414,22 @@ files:
|
|
|
400
414
|
- lib/ddtrace/ext/sql.rb
|
|
401
415
|
- lib/ddtrace/logger.rb
|
|
402
416
|
- lib/ddtrace/monkey.rb
|
|
417
|
+
- lib/ddtrace/opentracer.rb
|
|
418
|
+
- lib/ddtrace/opentracer/binary_propagator.rb
|
|
419
|
+
- lib/ddtrace/opentracer/carrier.rb
|
|
420
|
+
- lib/ddtrace/opentracer/distributed_headers.rb
|
|
421
|
+
- lib/ddtrace/opentracer/global_tracer.rb
|
|
422
|
+
- lib/ddtrace/opentracer/propagator.rb
|
|
423
|
+
- lib/ddtrace/opentracer/rack_propagator.rb
|
|
424
|
+
- lib/ddtrace/opentracer/scope.rb
|
|
425
|
+
- lib/ddtrace/opentracer/scope_manager.rb
|
|
426
|
+
- lib/ddtrace/opentracer/span.rb
|
|
427
|
+
- lib/ddtrace/opentracer/span_context.rb
|
|
428
|
+
- lib/ddtrace/opentracer/span_context_factory.rb
|
|
429
|
+
- lib/ddtrace/opentracer/text_map_propagator.rb
|
|
430
|
+
- lib/ddtrace/opentracer/thread_local_scope.rb
|
|
431
|
+
- lib/ddtrace/opentracer/thread_local_scope_manager.rb
|
|
432
|
+
- lib/ddtrace/opentracer/tracer.rb
|
|
403
433
|
- lib/ddtrace/patcher.rb
|
|
404
434
|
- lib/ddtrace/pin.rb
|
|
405
435
|
- lib/ddtrace/pipeline.rb
|