ddtrace 0.46.0 → 0.47.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 +5 -5
- data/.circleci/config.yml +52 -12
- data/.circleci/images/primary/{Dockerfile-jruby-9.2 → Dockerfile-jruby-9.2-latest} +2 -1
- data/.circleci/images/primary/Dockerfile-jruby-9.2.0.0 +73 -0
- data/.circleci/images/primary/Dockerfile-truffleruby-21.0.0 +73 -0
- data/.github/workflows/create-next-milestone.yml +2 -2
- data/.rubocop_todo.yml +3 -2
- data/.simplecov +6 -0
- data/Appraisals +1 -1
- data/CHANGELOG.md +83 -1
- data/Gemfile +19 -4
- data/LICENSE-3rdparty.csv +2 -0
- data/docker-compose.yml +75 -7
- data/docs/GettingStarted.md +61 -8
- data/lib/ddtrace/configuration.rb +92 -23
- data/lib/ddtrace/configuration/options.rb +2 -4
- data/lib/ddtrace/context_provider.rb +0 -2
- data/lib/ddtrace/contrib/active_record/configuration/resolver.rb +97 -26
- data/lib/ddtrace/contrib/aws/services.rb +1 -0
- data/lib/ddtrace/contrib/configurable.rb +63 -39
- data/lib/ddtrace/contrib/configuration/resolver.rb +70 -5
- data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +19 -17
- data/lib/ddtrace/contrib/configuration/settings.rb +7 -6
- data/lib/ddtrace/contrib/elasticsearch/patcher.rb +1 -0
- data/lib/ddtrace/contrib/extensions.rb +26 -3
- data/lib/ddtrace/contrib/httpclient/instrumentation.rb +12 -16
- data/lib/ddtrace/contrib/httpclient/patcher.rb +5 -2
- data/lib/ddtrace/contrib/httprb/instrumentation.rb +12 -17
- data/lib/ddtrace/contrib/httprb/patcher.rb +5 -2
- data/lib/ddtrace/contrib/patcher.rb +8 -5
- data/lib/ddtrace/contrib/presto/patcher.rb +5 -2
- data/lib/ddtrace/contrib/rails/patcher.rb +6 -2
- data/lib/ddtrace/contrib/redis/configuration/resolver.rb +11 -4
- data/lib/ddtrace/contrib/resque/integration.rb +1 -1
- data/lib/ddtrace/ext/runtime.rb +2 -0
- data/lib/ddtrace/patcher.rb +23 -1
- data/lib/ddtrace/pin.rb +5 -9
- data/lib/ddtrace/runtime/cgroup.rb +1 -1
- data/lib/ddtrace/runtime/container.rb +25 -27
- data/lib/ddtrace/runtime/identity.rb +8 -0
- data/lib/ddtrace/sync_writer.rb +5 -2
- data/lib/ddtrace/tracer.rb +6 -4
- data/lib/ddtrace/transport/http.rb +14 -5
- data/lib/ddtrace/transport/http/adapters/net.rb +18 -4
- data/lib/ddtrace/transport/http/builder.rb +5 -1
- data/lib/ddtrace/transport/http/env.rb +8 -0
- data/lib/ddtrace/transport/io/response.rb +1 -3
- data/lib/ddtrace/transport/io/traces.rb +6 -0
- data/lib/ddtrace/transport/traces.rb +15 -1
- data/lib/ddtrace/utils/compression.rb +27 -0
- data/lib/ddtrace/utils/object_set.rb +41 -0
- data/lib/ddtrace/utils/only_once.rb +40 -0
- data/lib/ddtrace/utils/sequence.rb +17 -0
- data/lib/ddtrace/utils/string_table.rb +45 -0
- data/lib/ddtrace/utils/time.rb +7 -0
- data/lib/ddtrace/vendor/multipart-post/LICENSE +11 -0
- data/lib/ddtrace/vendor/multipart-post/multipart.rb +12 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post.rb +8 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/composite_read_io.rb +116 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/multipartable.rb +57 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/parts.rb +135 -0
- data/lib/ddtrace/vendor/multipart-post/multipart/post/version.rb +9 -0
- data/lib/ddtrace/vendor/multipart-post/net/http/post/multipart.rb +32 -0
- data/lib/ddtrace/version.rb +1 -1
- data/lib/ddtrace/workers/async.rb +3 -3
- data/lib/ddtrace/workers/loop.rb +14 -3
- data/lib/ddtrace/workers/queue.rb +1 -0
- data/lib/ddtrace/workers/trace_writer.rb +1 -0
- data/lib/ddtrace/writer.rb +4 -1
- metadata +21 -4
data/Gemfile
CHANGED
@@ -16,9 +16,15 @@ gem 'minitest', '= 5.10.1'
|
|
16
16
|
gem 'minitest-around', '0.5.0'
|
17
17
|
gem 'minitest-stub_any_instance', '1.0.2'
|
18
18
|
gem 'pimpmychangelog', '>= 0.1.2'
|
19
|
-
gem 'pry'
|
20
|
-
|
21
|
-
|
19
|
+
gem 'pry'
|
20
|
+
if RUBY_PLATFORM != 'java'
|
21
|
+
# There's a few incompatibilities between pry/pry-byebug on older Rubies
|
22
|
+
gem 'pry-byebug' if RUBY_VERSION >= '2.6.0' && RUBY_ENGINE != 'truffleruby'
|
23
|
+
gem 'pry-nav' if RUBY_VERSION < '2.6.0'
|
24
|
+
gem 'pry-stack_explorer'
|
25
|
+
else
|
26
|
+
gem 'pry-debugger-jruby'
|
27
|
+
end
|
22
28
|
gem 'rake', '>= 10.5'
|
23
29
|
gem 'redcarpet', '~> 3.4' if RUBY_PLATFORM != 'java'
|
24
30
|
gem 'rspec', '~> 3.10'
|
@@ -26,7 +32,16 @@ gem 'rspec-collection_matchers', '~> 1.1'
|
|
26
32
|
gem 'rspec_junit_formatter', '>= 0.4.1'
|
27
33
|
gem 'rspec_n', '~> 1.3' if RUBY_VERSION >= '2.3.0'
|
28
34
|
gem 'ruby-prof', '~> 1.4' if RUBY_PLATFORM != 'java' && RUBY_VERSION >= '2.4.0'
|
29
|
-
|
35
|
+
if RUBY_VERSION >= '2.5.0'
|
36
|
+
# Merging branch coverage results does not work for old, unsupported rubies.
|
37
|
+
# We have a fix up for review, https://github.com/simplecov-ruby/simplecov/pull/972,
|
38
|
+
# but given it only affects unsupported version of Ruby, it might not get merged.
|
39
|
+
gem 'simplecov', git: 'https://github.com/DataDog/simplecov', ref: '3bb6b7ee58bf4b1954ca205f50dd44d6f41c57db'
|
40
|
+
else
|
41
|
+
# Compatible with older rubies. This version still produces compatible output
|
42
|
+
# with a newer version when the reports are merged.
|
43
|
+
gem 'simplecov', '~> 0.17'
|
44
|
+
end
|
30
45
|
gem 'warning', '~> 1' if RUBY_VERSION >= '2.5.0'
|
31
46
|
gem 'webmock', '>= 3.10.0'
|
32
47
|
gem 'webrick', '>= 1.7.0' if RUBY_VERSION >= '3.0.0' # No longer bundled by default since Ruby 3.0
|
data/docker-compose.yml
CHANGED
@@ -277,8 +277,8 @@ services:
|
|
277
277
|
- bundle-3.0:/usr/local/bundle
|
278
278
|
- gemfiles-3.0:/app/gemfiles
|
279
279
|
# JRuby
|
280
|
-
tracer-jruby-9.2:
|
281
|
-
image: marcotc/docker-library:
|
280
|
+
tracer-jruby-9.2.0.0:
|
281
|
+
image: marcotc/docker-library:ddtrace_rb_jruby_9_2_0_0
|
282
282
|
command: /bin/bash
|
283
283
|
depends_on:
|
284
284
|
- ddagent
|
@@ -306,8 +306,71 @@ services:
|
|
306
306
|
tty: true
|
307
307
|
volumes:
|
308
308
|
- .:/app
|
309
|
-
- bundle-jruby-9.2:/usr/local/bundle
|
310
|
-
- gemfiles-jruby-9.2:/app/gemfiles
|
309
|
+
- bundle-jruby-9.2.0.0:/usr/local/bundle
|
310
|
+
- gemfiles-jruby-9.2.0.0:/app/gemfiles
|
311
|
+
tracer-jruby-9.2-latest:
|
312
|
+
image: marcotc/docker-library:ddtrace_rb_jruby_9_2_11_1
|
313
|
+
command: /bin/bash
|
314
|
+
depends_on:
|
315
|
+
- ddagent
|
316
|
+
- elasticsearch
|
317
|
+
- memcached
|
318
|
+
- mongodb
|
319
|
+
- mysql
|
320
|
+
- postgres
|
321
|
+
- presto
|
322
|
+
- redis
|
323
|
+
env_file: ./.env
|
324
|
+
environment:
|
325
|
+
- BUNDLE_GEMFILE=/app/Gemfile
|
326
|
+
- DD_AGENT_HOST=ddagent
|
327
|
+
- TEST_DATADOG_INTEGRATION=1
|
328
|
+
- TEST_ELASTICSEARCH_HOST=elasticsearch
|
329
|
+
- TEST_MEMCACHED_HOST=memcached
|
330
|
+
- TEST_MONGODB_HOST=mongodb
|
331
|
+
- TEST_MYSQL_HOST=mysql
|
332
|
+
- TEST_POSTGRES_HOST=postgres
|
333
|
+
- TEST_PRESTO_HOST=presto
|
334
|
+
- TEST_PRESTO_PORT=8080
|
335
|
+
- TEST_REDIS_HOST=redis
|
336
|
+
stdin_open: true
|
337
|
+
tty: true
|
338
|
+
volumes:
|
339
|
+
- .:/app
|
340
|
+
- bundle-jruby-9.2-latest:/usr/local/bundle
|
341
|
+
- gemfiles-jruby-9.2-latest:/app/gemfiles
|
342
|
+
# TruffleRuby
|
343
|
+
tracer-truffleruby-21.0.0:
|
344
|
+
image: ivoanjo/docker-library:ddtrace_rb_truffleruby_21_0_0
|
345
|
+
command: /bin/bash
|
346
|
+
depends_on:
|
347
|
+
- ddagent
|
348
|
+
- elasticsearch
|
349
|
+
- memcached
|
350
|
+
- mongodb
|
351
|
+
- mysql
|
352
|
+
- postgres
|
353
|
+
- presto
|
354
|
+
- redis
|
355
|
+
env_file: ./.env
|
356
|
+
environment:
|
357
|
+
- BUNDLE_GEMFILE=/app/Gemfile
|
358
|
+
- DD_AGENT_HOST=ddagent
|
359
|
+
- TEST_DATADOG_INTEGRATION=1
|
360
|
+
- TEST_ELASTICSEARCH_HOST=elasticsearch
|
361
|
+
- TEST_MEMCACHED_HOST=memcached
|
362
|
+
- TEST_MONGODB_HOST=mongodb
|
363
|
+
- TEST_MYSQL_HOST=mysql
|
364
|
+
- TEST_POSTGRES_HOST=postgres
|
365
|
+
- TEST_PRESTO_HOST=presto
|
366
|
+
- TEST_PRESTO_PORT=8080
|
367
|
+
- TEST_REDIS_HOST=redis
|
368
|
+
stdin_open: true
|
369
|
+
tty: true
|
370
|
+
volumes:
|
371
|
+
- .:/app
|
372
|
+
- bundle-truffleruby-21.0.0:/usr/local/bundle
|
373
|
+
- gemfiles-truffleruby-21.0.0:/app/gemfiles
|
311
374
|
ddagent:
|
312
375
|
image: datadog/agent
|
313
376
|
environment:
|
@@ -366,7 +429,8 @@ services:
|
|
366
429
|
ports:
|
367
430
|
- "${TEST_POSTGRES_PORT}:5432"
|
368
431
|
presto:
|
369
|
-
|
432
|
+
# Move to trinodb/trino after https://github.com/treasure-data/presto-client-ruby/issues/64 is resolved.
|
433
|
+
image: starburstdata/presto:332-e.9
|
370
434
|
expose:
|
371
435
|
- "8080"
|
372
436
|
ports:
|
@@ -387,7 +451,9 @@ volumes:
|
|
387
451
|
bundle-2.6:
|
388
452
|
bundle-2.7:
|
389
453
|
bundle-3.0:
|
390
|
-
bundle-jruby-9.2:
|
454
|
+
bundle-jruby-9.2.0.0:
|
455
|
+
bundle-jruby-9.2-latest:
|
456
|
+
bundle-truffleruby-21.0.0:
|
391
457
|
gemfiles-2.0:
|
392
458
|
gemfiles-2.1:
|
393
459
|
gemfiles-2.2:
|
@@ -397,4 +463,6 @@ volumes:
|
|
397
463
|
gemfiles-2.6:
|
398
464
|
gemfiles-2.7:
|
399
465
|
gemfiles-3.0:
|
400
|
-
gemfiles-jruby-9.2:
|
466
|
+
gemfiles-jruby-9.2.0.0:
|
467
|
+
gemfiles-jruby-9.2-latest:
|
468
|
+
gemfiles-truffleruby-21.0.0:
|
data/docs/GettingStarted.md
CHANGED
@@ -46,6 +46,7 @@ To contribute, check out the [contribution guidelines][contribution docs] and [d
|
|
46
46
|
- [gRPC](#grpc)
|
47
47
|
- [http.rb](#http-rb)
|
48
48
|
- [httpclient](#httpclient)
|
49
|
+
- [httpx](#httpx)
|
49
50
|
- [MongoDB](#mongodb)
|
50
51
|
- [MySQL2](#mysql2)
|
51
52
|
- [Net/HTTP](#net-http)
|
@@ -398,6 +399,7 @@ For a list of available integrations, and their configuration options, please re
|
|
398
399
|
| gRPC | `grpc` | `>= 1.7` | *gem not available* | *[Link](#grpc)* | *[Link](https://github.com/grpc/grpc/tree/master/src/rubyc)* |
|
399
400
|
| http.rb | `httprb` | `>= 2.0` | `>= 2.0` | *[Link](#http-rb)* | *[Link](https://github.com/httprb/http)* |
|
400
401
|
| httpclient | `httpclient` | `>= 2.2` | `>= 2.2` | *[Link](#httpclient)* | *[Link](https://github.com/nahi/httpclient)* |
|
402
|
+
| httpx | `httpx` | `>= 0.11` | `>= 0.11` | *[Link](#httpx)* | *[Link](https://gitlab.com/honeyryderchuck/httpx)* |
|
401
403
|
| Kafka | `ruby-kafka` | `>= 0.7.10` | `>= 0.7.10` | *[Link](#kafka)* | *[Link](https://github.com/zendesk/ruby-kafka)* |
|
402
404
|
| MongoDB | `mongo` | `>= 2.1` | `>= 2.1` | *[Link](#mongodb)* | *[Link](https://github.com/mongodb/mongo-ruby-driver)* |
|
403
405
|
| MySQL2 | `mysql2` | `>= 0.3.21` | *gem not available* | *[Link](#mysql2)* | *[Link](https://github.com/brianmario/mysql2)* |
|
@@ -546,17 +548,20 @@ Datadog.configure do |c|
|
|
546
548
|
# Symbol matching your database connection in config/database.yml
|
547
549
|
# Only available if you are using Rails with ActiveRecord.
|
548
550
|
c.use :active_record, describes: :secondary_database, service_name: 'secondary-db'
|
549
|
-
|
551
|
+
|
552
|
+
# Block configuration pattern.
|
550
553
|
c.use :active_record, describes: :secondary_database do |second_db|
|
551
554
|
second_db.service_name = 'secondary-db'
|
552
555
|
end
|
553
556
|
|
554
557
|
# Connection string with the following connection settings:
|
555
|
-
#
|
558
|
+
# adapter, username, host, port, database
|
559
|
+
# Other fields are ignored.
|
556
560
|
c.use :active_record, describes: 'mysql2://root@127.0.0.1:3306/mysql', service_name: 'secondary-db'
|
557
561
|
|
558
|
-
# Hash with following connection settings
|
559
|
-
#
|
562
|
+
# Hash with following connection settings:
|
563
|
+
# adapter, username, host, port, database
|
564
|
+
# Other fields are ignored.
|
560
565
|
c.use :active_record, describes: {
|
561
566
|
adapter: 'mysql2',
|
562
567
|
host: '127.0.0.1',
|
@@ -568,6 +573,27 @@ Datadog.configure do |c|
|
|
568
573
|
end
|
569
574
|
```
|
570
575
|
|
576
|
+
You can also create configurations based on partial matching of database connection fields:
|
577
|
+
|
578
|
+
```ruby
|
579
|
+
Datadog.configure do |c|
|
580
|
+
# Matches any connection on host `127.0.0.1`.
|
581
|
+
c.use :active_record, describes: { host: '127.0.0.1' }, service_name: 'local-db'
|
582
|
+
|
583
|
+
# Matches any `mysql2` connection.
|
584
|
+
c.use :active_record, describes: { adapter: 'mysql2'}, service_name: 'mysql-db'
|
585
|
+
|
586
|
+
# Matches any `mysql2` connection to the `reports` database.
|
587
|
+
#
|
588
|
+
# In case of multiple matching `describe` configurations, the latest one applies.
|
589
|
+
# In this case a connection with both adapter `mysql` and database `reports`
|
590
|
+
# will be configured `service_name: 'reports-db'`, not `service_name: 'mysql-db'`.
|
591
|
+
c.use :active_record, describes: { adapter: 'mysql2', database: 'reports'}, service_name: 'reports-db'
|
592
|
+
end
|
593
|
+
```
|
594
|
+
|
595
|
+
When multiple `describes` configurations match a connection, the latest configured rule that matches will be applied.
|
596
|
+
|
571
597
|
If ActiveRecord traces an event that uses a connection that matches a key defined by `describes`, it will use the trace settings assigned to that connection. If the connection does not match any of the described connections, it will use default settings defined by `c.use :active_record` instead.
|
572
598
|
|
573
599
|
### Active Support
|
@@ -1078,6 +1104,25 @@ Where `options` is an optional `Hash` that accepts the following parameters:
|
|
1078
1104
|
| `service_name` | Service name for `httpclient` instrumentation. | `'httpclient'` |
|
1079
1105
|
| `split_by_domain` | Uses the request domain as the service name when set to `true`. | `false` |
|
1080
1106
|
|
1107
|
+
### httpx
|
1108
|
+
|
1109
|
+
`httpx` maintains its [own integration with `ddtrace`](https://honeyryderchuck.gitlab.io/httpx/wiki/Datadog-Adapter):
|
1110
|
+
|
1111
|
+
```ruby
|
1112
|
+
require "ddtrace"
|
1113
|
+
require "httpx/adapters/datadog"
|
1114
|
+
|
1115
|
+
Datadog.configure do |c|
|
1116
|
+
c.use :httpx
|
1117
|
+
|
1118
|
+
# optionally, specify a different service name for hostnames matching a regex
|
1119
|
+
c.use :httpx, describes: /user-[^.]+\.example\.com/ do |http|
|
1120
|
+
http.service_name = 'user.example.com'
|
1121
|
+
http.split_by_domain = false # Only necessary if split_by_domain is true by default
|
1122
|
+
end
|
1123
|
+
end
|
1124
|
+
```
|
1125
|
+
|
1081
1126
|
### Kafka
|
1082
1127
|
|
1083
1128
|
The Kafka integration provides tracing of the `ruby-kafka` gem:
|
@@ -1537,12 +1582,17 @@ Datadog.configure do |c|
|
|
1537
1582
|
# The default configuration for any redis client
|
1538
1583
|
c.use :redis, service_name: 'redis-default'
|
1539
1584
|
|
1540
|
-
# The configuration matching a given unix socket
|
1585
|
+
# The configuration matching a given unix socket.
|
1541
1586
|
c.use :redis, describes: { url: 'unix://path/to/file' }, service_name: 'redis-unix'
|
1542
1587
|
|
1543
|
-
#
|
1544
|
-
|
1545
|
-
#
|
1588
|
+
# For network connections, only these fields are considered during matching:
|
1589
|
+
# scheme, host, port, db
|
1590
|
+
# Other fields are ignored.
|
1591
|
+
|
1592
|
+
# Network connection string
|
1593
|
+
c.use :redis, describes: 'redis://127.0.0.1:6379/0', service_name: 'redis-connection-string'
|
1594
|
+
c.use :redis, describes: { url: 'redis://127.0.0.1:6379/1' }, service_name: 'redis-connection-url'
|
1595
|
+
# Network client hash
|
1546
1596
|
c.use :redis, describes: { host: 'my-host.com', port: 6379, db: 1, scheme: 'redis' }, service_name: 'redis-connection-hash'
|
1547
1597
|
# Only a subset of the connection hash
|
1548
1598
|
c.use :redis, describes: { host: ENV['APP_CACHE_HOST'], port: ENV['APP_CACHE_PORT'] }, service_name: 'redis-cache'
|
@@ -1550,6 +1600,8 @@ Datadog.configure do |c|
|
|
1550
1600
|
end
|
1551
1601
|
```
|
1552
1602
|
|
1603
|
+
When multiple `describes` configurations match a connection, the latest configured rule that matches will be applied.
|
1604
|
+
|
1553
1605
|
### Resque
|
1554
1606
|
|
1555
1607
|
The Resque integration uses Resque hooks that wraps the `perform` method.
|
@@ -2087,6 +2139,7 @@ For more details on how to activate distributed tracing for integrations, see th
|
|
2087
2139
|
- [Sinatra](#sinatra)
|
2088
2140
|
- [http.rb](#http-rb)
|
2089
2141
|
- [httpclient](#httpclient)
|
2142
|
+
- [httpx](#httpx)
|
2090
2143
|
|
2091
2144
|
**Using the HTTP propagator**
|
2092
2145
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'forwardable'
|
2
|
-
|
3
2
|
require 'ddtrace/configuration/pin_setup'
|
4
3
|
require 'ddtrace/configuration/settings'
|
5
4
|
require 'ddtrace/configuration/components'
|
@@ -9,6 +8,33 @@ module Datadog
|
|
9
8
|
module Configuration
|
10
9
|
extend Forwardable
|
11
10
|
|
11
|
+
# Used to ensure that @components initialization/reconfiguration is performed one-at-a-time, by a single thread.
|
12
|
+
#
|
13
|
+
# This is important because components can end up being accessed from multiple application threads (for instance on
|
14
|
+
# a threaded webserver), and we don't want their initialization to clash (for instance, starting two profilers...).
|
15
|
+
#
|
16
|
+
# Note that a Mutex **IS NOT** reentrant: the same thread cannot grab the same Mutex more than once.
|
17
|
+
# This means below we are careful not to nest calls to methods that would trigger initialization and grab the lock.
|
18
|
+
#
|
19
|
+
# Every method that directly or indirectly mutates @components should be holding the lock (through
|
20
|
+
# #safely_synchronize) while doing so.
|
21
|
+
COMPONENTS_WRITE_LOCK = Mutex.new
|
22
|
+
private_constant :COMPONENTS_WRITE_LOCK
|
23
|
+
|
24
|
+
# We use a separate lock when reading the @components, so that they continue to be accessible during reconfiguration.
|
25
|
+
# This was needed because we ran into several issues where we still needed to read the old
|
26
|
+
# components while the COMPONENTS_WRITE_LOCK was being held (see https://github.com/DataDog/dd-trace-rb/pull/1387
|
27
|
+
# and https://github.com/DataDog/dd-trace-rb/pull/1373#issuecomment-799593022 ).
|
28
|
+
#
|
29
|
+
# Technically on MRI we could get away without this lock, but on non-MRI Rubies, we may run into issues because
|
30
|
+
# we fall into the "UnsafeDCLFactory" case of https://shipilev.net/blog/2014/safe-public-construction/ .
|
31
|
+
# Specifically, on JRuby reads from the @components do NOT have volatile semantics, and on TruffleRuby they do
|
32
|
+
# BUT just as an implementation detail, see https://github.com/jruby/jruby/wiki/Concurrency-in-jruby#volatility and
|
33
|
+
# https://github.com/DataDog/dd-trace-rb/pull/1329#issuecomment-776750377 .
|
34
|
+
# Concurrency is hard.
|
35
|
+
COMPONENTS_READ_LOCK = Mutex.new
|
36
|
+
private_constant :COMPONENTS_READ_LOCK
|
37
|
+
|
12
38
|
attr_writer :configuration
|
13
39
|
|
14
40
|
def configuration
|
@@ -19,13 +45,15 @@ module Datadog
|
|
19
45
|
if target.is_a?(Settings)
|
20
46
|
yield(target) if block_given?
|
21
47
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
48
|
+
safely_synchronize do |write_components|
|
49
|
+
write_components.call(
|
50
|
+
if components?
|
51
|
+
replace_components!(target, @components)
|
52
|
+
else
|
53
|
+
build_components(target)
|
54
|
+
end
|
55
|
+
)
|
56
|
+
end
|
29
57
|
|
30
58
|
target
|
31
59
|
else
|
@@ -40,18 +68,14 @@ module Datadog
|
|
40
68
|
:tracer
|
41
69
|
|
42
70
|
def logger
|
43
|
-
|
71
|
+
# avoid initializing components if they didn't already exist
|
72
|
+
current_components = components(allow_initialization: false)
|
73
|
+
|
74
|
+
if current_components
|
44
75
|
@temp_logger = nil
|
45
|
-
|
76
|
+
current_components.logger
|
46
77
|
else
|
47
|
-
|
48
|
-
# This prevents recursive loops while initializing.
|
49
|
-
# e.g. Get logger --> Build components --> Log message --> Repeat...
|
50
|
-
@temp_logger ||= begin
|
51
|
-
logger = configuration.logger.instance || Datadog::Logger.new($stdout)
|
52
|
-
logger.level = configuration.diagnostics.debug ? ::Logger::DEBUG : configuration.logger.level
|
53
|
-
logger
|
54
|
-
end
|
78
|
+
logger_without_components
|
55
79
|
end
|
56
80
|
end
|
57
81
|
|
@@ -65,7 +89,9 @@ module Datadog
|
|
65
89
|
#
|
66
90
|
# Components won't be automatically reinitialized after a shutdown.
|
67
91
|
def shutdown!
|
68
|
-
|
92
|
+
safely_synchronize do
|
93
|
+
@components.shutdown! if components?
|
94
|
+
end
|
69
95
|
end
|
70
96
|
|
71
97
|
# Gracefully shuts down the tracer and disposes of component references,
|
@@ -74,18 +100,51 @@ module Datadog
|
|
74
100
|
# In contrast with +#shutdown!+, components will be automatically
|
75
101
|
# reinitialized after a reset.
|
76
102
|
def reset!
|
77
|
-
|
78
|
-
|
103
|
+
safely_synchronize do |write_components|
|
104
|
+
@components.shutdown! if components?
|
105
|
+
write_components.call(nil)
|
106
|
+
end
|
79
107
|
end
|
80
108
|
|
81
109
|
protected
|
82
110
|
|
83
|
-
def components
|
84
|
-
@components
|
111
|
+
def components(allow_initialization: true)
|
112
|
+
current_components = COMPONENTS_READ_LOCK.synchronize { defined?(@components) && @components }
|
113
|
+
return current_components if current_components || !allow_initialization
|
114
|
+
|
115
|
+
safely_synchronize do |write_components|
|
116
|
+
(defined?(@components) && @components) || write_components.call(build_components(configuration))
|
117
|
+
end
|
85
118
|
end
|
86
119
|
|
87
120
|
private
|
88
121
|
|
122
|
+
def safely_synchronize
|
123
|
+
# Writes to @components should only happen through this proc. Because this proc is only accessible to callers of
|
124
|
+
# safely_synchronize, this forces all writers to go through this method.
|
125
|
+
write_components = proc do |new_value|
|
126
|
+
COMPONENTS_READ_LOCK.synchronize { @components = new_value }
|
127
|
+
end
|
128
|
+
|
129
|
+
COMPONENTS_WRITE_LOCK.synchronize do
|
130
|
+
begin
|
131
|
+
yield write_components
|
132
|
+
rescue ThreadError => e
|
133
|
+
logger_without_components.error(
|
134
|
+
'Detected deadlock during ddtrace initialization. ' \
|
135
|
+
'Please report this at https://github.com/DataDog/dd-trace-rb/blob/master/CONTRIBUTING.md#found-a-bug' \
|
136
|
+
"\n\tSource:\n\t#{e.backtrace.join("\n\t")}"
|
137
|
+
)
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def components?
|
144
|
+
# This does not need to grab the COMPONENTS_READ_LOCK because it's not returning the components
|
145
|
+
(defined?(@components) && @components) != nil
|
146
|
+
end
|
147
|
+
|
89
148
|
def build_components(settings)
|
90
149
|
components = Components.new(settings)
|
91
150
|
components.startup!(settings)
|
@@ -99,5 +158,15 @@ module Datadog
|
|
99
158
|
components.startup!(settings)
|
100
159
|
components
|
101
160
|
end
|
161
|
+
|
162
|
+
def logger_without_components
|
163
|
+
# Use default logger without initializing components.
|
164
|
+
# This enables logging during initialization, otherwise we'd run into deadlocks.
|
165
|
+
@temp_logger ||= begin
|
166
|
+
logger = configuration.logger.instance || Datadog::Logger.new($stdout)
|
167
|
+
logger.level = configuration.diagnostics.debug ? ::Logger::DEBUG : configuration.logger.level
|
168
|
+
logger
|
169
|
+
end
|
170
|
+
end
|
102
171
|
end
|
103
172
|
end
|