datadog-ci 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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -2
  3. data/lib/datadog/ci/async_writer.rb +112 -0
  4. data/lib/datadog/ci/codeowners/rule.rb +5 -0
  5. data/lib/datadog/ci/configuration/components.rb +50 -9
  6. data/lib/datadog/ci/configuration/settings.rb +17 -0
  7. data/lib/datadog/ci/contrib/activesupport/configuration/settings.rb +25 -0
  8. data/lib/datadog/ci/contrib/activesupport/ext.rb +14 -0
  9. data/lib/datadog/ci/contrib/activesupport/integration.rb +43 -0
  10. data/lib/datadog/ci/contrib/activesupport/logs_formatter.rb +41 -0
  11. data/lib/datadog/ci/contrib/activesupport/patcher.rb +50 -0
  12. data/lib/datadog/ci/contrib/knapsack/patcher.rb +1 -3
  13. data/lib/datadog/ci/contrib/knapsack/runner.rb +2 -0
  14. data/lib/datadog/ci/contrib/lograge/configuration/settings.rb +25 -0
  15. data/lib/datadog/ci/contrib/lograge/ext.rb +14 -0
  16. data/lib/datadog/ci/contrib/lograge/integration.rb +43 -0
  17. data/lib/datadog/ci/contrib/lograge/log_subscriber.rb +41 -0
  18. data/lib/datadog/ci/contrib/lograge/patcher.rb +32 -0
  19. data/lib/datadog/ci/contrib/minitest/runner.rb +1 -0
  20. data/lib/datadog/ci/contrib/minitest/test.rb +7 -2
  21. data/lib/datadog/ci/contrib/parallel_tests/patcher.rb +1 -4
  22. data/lib/datadog/ci/contrib/patcher.rb +4 -0
  23. data/lib/datadog/ci/contrib/rspec/helpers.rb +1 -3
  24. data/lib/datadog/ci/contrib/semantic_logger/configuration/settings.rb +25 -0
  25. data/lib/datadog/ci/contrib/semantic_logger/ext.rb +14 -0
  26. data/lib/datadog/ci/contrib/semantic_logger/integration.rb +42 -0
  27. data/lib/datadog/ci/contrib/semantic_logger/logger.rb +32 -0
  28. data/lib/datadog/ci/contrib/semantic_logger/patcher.rb +32 -0
  29. data/lib/datadog/ci/ext/environment/extractor.rb +4 -6
  30. data/lib/datadog/ci/ext/environment/providers/appveyor.rb +5 -0
  31. data/lib/datadog/ci/ext/environment/providers/base.rb +7 -2
  32. data/lib/datadog/ci/ext/environment/providers/bitbucket.rb +6 -0
  33. data/lib/datadog/ci/ext/environment/providers/bitrise.rb +7 -1
  34. data/lib/datadog/ci/ext/environment/providers/buddy.rb +5 -0
  35. data/lib/datadog/ci/ext/environment/providers/github_actions.rb +37 -18
  36. data/lib/datadog/ci/ext/environment/providers/gitlab.rb +13 -1
  37. data/lib/datadog/ci/ext/environment/providers/user_defined_tags.rb +12 -0
  38. data/lib/datadog/ci/ext/git.rb +3 -0
  39. data/lib/datadog/ci/ext/settings.rb +3 -0
  40. data/lib/datadog/ci/ext/telemetry.rb +4 -0
  41. data/lib/datadog/ci/ext/test.rb +7 -3
  42. data/lib/datadog/ci/ext/transport.rb +3 -0
  43. data/lib/datadog/ci/git/local_repository.rb +238 -4
  44. data/lib/datadog/ci/git/tree_uploader.rb +10 -3
  45. data/lib/datadog/ci/impacted_tests_detection/component.rb +83 -0
  46. data/lib/datadog/ci/impacted_tests_detection/telemetry.rb +16 -0
  47. data/lib/datadog/ci/logs/component.rb +46 -0
  48. data/lib/datadog/ci/logs/transport.rb +73 -0
  49. data/lib/datadog/ci/remote/component.rb +6 -1
  50. data/lib/datadog/ci/remote/library_settings.rb +8 -0
  51. data/lib/datadog/ci/span.rb +7 -0
  52. data/lib/datadog/ci/test.rb +16 -0
  53. data/lib/datadog/ci/test_management/tests_properties.rb +2 -1
  54. data/lib/datadog/ci/test_retries/component.rb +8 -17
  55. data/lib/datadog/ci/test_retries/driver/{retry_new.rb → retry_flake_detection.rb} +2 -2
  56. data/lib/datadog/ci/test_retries/strategy/{retry_new.rb → retry_flake_detection.rb} +4 -4
  57. data/lib/datadog/ci/test_visibility/component.rb +6 -0
  58. data/lib/datadog/ci/test_visibility/null_component.rb +3 -1
  59. data/lib/datadog/ci/transport/api/agentless.rb +8 -1
  60. data/lib/datadog/ci/transport/api/base.rb +4 -0
  61. data/lib/datadog/ci/transport/api/builder.rb +5 -1
  62. data/lib/datadog/ci/transport/api/evp_proxy.rb +4 -0
  63. data/lib/datadog/ci/version.rb +1 -1
  64. data/lib/datadog/ci.rb +3 -0
  65. metadata +25 -6
  66. data/lib/datadog/ci/test_optimisation/coverage/writer.rb +0 -116
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c4507da31359cd997cb38e73190a4e6514ad8c69d86f9ce1b0c47fd7764e5dbd
4
- data.tar.gz: 515872f426f95492fed9d1577f14bb7b1e447b0c011edf2bbfbb7ea23992d9cc
3
+ metadata.gz: 1d2afc6148658bb41352ad4040c483406594852787e35aa523063a6ae452ec17
4
+ data.tar.gz: 3b7f9b07092e33b016b94b25d4aae2b12ff442f458dac6bea7b987adef4ca345
5
5
  SHA512:
6
- metadata.gz: 3d0db7cb6a13a4c2f0b38b22c8dc2470a9ec760c38312c929a7b6224b118e18b279addf76901f7f094f60123a9e65d9afef06c15970bf01b247bc031bf80725d
7
- data.tar.gz: f731bc7979a69ae63362d06d0313754bd825a22baf934cb682c1dc2a16a8584d0c3ece806f2bfb75d42924c09fff6296bf8c5c1be142afbe3ab7716bcb753815
6
+ metadata.gz: 7b368e3e3a1c6004307fe834f6f6442f51f7ab538434fb9a34ea42c6fbefa90f7995e54ed35aded0ddfc9e21ff34e70d91e845e9b82009a9e2977f3de9205ff6
7
+ data.tar.gz: c56a90e2d3fcc755f9fc224ea8e385c8393a8252487132ca4287377375ac57e839171853391ad9bcb4577a422b0b7c154f32f15c91b69b2b7b17de86aa396ca6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.17.0] - 2025-05-19
4
+
5
+ ### Added
6
+
7
+ * Impacted tests detection ([#318][])
8
+
9
+ ### Changed
10
+
11
+ * flaky test management: add sha parameter to the tests_properties request ([#321][])
12
+ * Send `attempt_to_fix_passed:false` when attempt_to_fix_validation did not succeed ([#320][])
13
+
14
+ ### Fixed
15
+
16
+ * fix CODEOWNERS parsing issue where "**" wasn't matching zero folders ([#323][])
17
+ * fix webmock compatibility of internal telemetry ([#309][])
18
+
19
+ ## [1.16.0] - 2025-04-15
20
+
21
+
22
+ ### Added
23
+
24
+ * agentless logs submission for tests ([#306][])
25
+ * lograge support for agentless logs feature ([#308][])
26
+ * semantic_logger instrumentation for agentless logs feature ([#311][])
27
+ * retry reason "external" ([#312][])
28
+
3
29
  ## [1.15.0] - 2025-03-25
4
30
 
5
31
 
@@ -417,7 +443,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
417
443
 
418
444
  - Ruby versions < 2.7 no longer supported ([#8][])
419
445
 
420
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.15.0...main
446
+ [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.17.0...main
447
+ [1.17.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.16.0...v1.17.0
448
+ [1.16.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.15.0...v1.16.0
421
449
  [1.15.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.14.0...v1.15.0
422
450
  [1.14.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.13.0...v1.14.0
423
451
  [1.13.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.12.0...v1.13.0
@@ -597,4 +625,13 @@ Currently test suite level visibility is not used by our instrumentation: it wil
597
625
  [#298]: https://github.com/DataDog/datadog-ci-rb/issues/298
598
626
  [#299]: https://github.com/DataDog/datadog-ci-rb/issues/299
599
627
  [#300]: https://github.com/DataDog/datadog-ci-rb/issues/300
600
- [#301]: https://github.com/DataDog/datadog-ci-rb/issues/301
628
+ [#301]: https://github.com/DataDog/datadog-ci-rb/issues/301
629
+ [#306]: https://github.com/DataDog/datadog-ci-rb/issues/306
630
+ [#308]: https://github.com/DataDog/datadog-ci-rb/issues/308
631
+ [#309]: https://github.com/DataDog/datadog-ci-rb/issues/309
632
+ [#311]: https://github.com/DataDog/datadog-ci-rb/issues/311
633
+ [#312]: https://github.com/DataDog/datadog-ci-rb/issues/312
634
+ [#318]: https://github.com/DataDog/datadog-ci-rb/issues/318
635
+ [#320]: https://github.com/DataDog/datadog-ci-rb/issues/320
636
+ [#321]: https://github.com/DataDog/datadog-ci-rb/issues/321
637
+ [#323]: https://github.com/DataDog/datadog-ci-rb/issues/323
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/core/workers/async"
4
+ require "datadog/core/workers/queue"
5
+ require "datadog/core/workers/polling"
6
+
7
+ require "datadog/core/buffer/cruby"
8
+ require "datadog/core/buffer/thread_safe"
9
+
10
+ require "datadog/core/environment/ext"
11
+
12
+ module Datadog
13
+ module CI
14
+ class AsyncWriter
15
+ include Core::Workers::Queue
16
+ include Core::Workers::Polling
17
+
18
+ attr_reader :transport
19
+
20
+ DEFAULT_BUFFER_MAX_SIZE = 10_000
21
+ DEFAULT_SHUTDOWN_TIMEOUT = 60
22
+
23
+ DEFAULT_INTERVAL = 3
24
+
25
+ def initialize(transport:, options: {})
26
+ @transport = transport
27
+
28
+ # Workers::Polling settings
29
+ self.enabled = options.fetch(:enabled, true)
30
+
31
+ # Workers::Async::Thread settings
32
+ self.fork_policy = Core::Workers::Async::Thread::FORK_POLICY_RESTART
33
+
34
+ # Workers::IntervalLoop settings
35
+ self.loop_base_interval = options[:interval] || DEFAULT_INTERVAL
36
+ self.loop_back_off_ratio = options[:back_off_ratio] if options.key?(:back_off_ratio)
37
+ self.loop_back_off_max = options[:back_off_max] if options.key?(:back_off_max)
38
+
39
+ @buffer_size = options.fetch(:buffer_size, DEFAULT_BUFFER_MAX_SIZE)
40
+
41
+ self.buffer = buffer_klass.new(@buffer_size)
42
+
43
+ @shutdown_timeout = options.fetch(:shutdown_timeout, DEFAULT_SHUTDOWN_TIMEOUT)
44
+
45
+ @stopped = false
46
+ end
47
+
48
+ def write(event)
49
+ return if @stopped
50
+
51
+ # Start worker thread. If the process has forked, it will trigger #after_fork to
52
+ # reconfigure the worker accordingly.
53
+ perform
54
+
55
+ enqueue(event)
56
+ end
57
+
58
+ def perform(*events)
59
+ responses = transport.send_events(events)
60
+
61
+ if responses.find(&:server_error?)
62
+ loop_back_off!
63
+ Datadog.logger.warn { "Encountered server error while sending events: #{responses}" }
64
+ end
65
+
66
+ nil
67
+ rescue => e
68
+ Datadog.logger.warn { "Error while sending events: #{e}" }
69
+ loop_back_off!
70
+ end
71
+
72
+ def stop(force_stop = false, timeout = @shutdown_timeout)
73
+ @stopped = true
74
+
75
+ buffer.close if running?
76
+
77
+ super
78
+ end
79
+
80
+ def enqueue(event)
81
+ buffer.push(event)
82
+ end
83
+
84
+ def dequeue
85
+ buffer.pop
86
+ end
87
+
88
+ def work_pending?
89
+ !buffer.empty?
90
+ end
91
+
92
+ def async?
93
+ true
94
+ end
95
+
96
+ def after_fork
97
+ # In multiprocess environments, forks will share the same buffer until its written to.
98
+ # A.K.A. copy-on-write. We don't want forks to write events generated from another process.
99
+ # Instead, we reset it after the fork. (Make sure any enqueue operations happen after this.)
100
+ self.buffer = buffer_klass.new(@buffer_size)
101
+ end
102
+
103
+ def buffer_klass
104
+ if Core::Environment::Ext::RUBY_ENGINE == "ruby"
105
+ Core::Buffer::CRuby
106
+ else
107
+ Core::Buffer::ThreadSafe
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -24,7 +24,12 @@ module Datadog
24
24
  private
25
25
 
26
26
  def flags
27
+ # prevents /path/* from matching subfolders
27
28
  return ::File::FNM_PATHNAME if pattern.end_with?("#{::File::SEPARATOR}*")
29
+ # prevents /path/*.rb from matching Ruby files in subfolders
30
+ return ::File::FNM_PATHNAME if pattern.include?("*.")
31
+ # allows /path/**/subfolder to match both /path/subfolder and /path/a/b/c/subfolder
32
+ return ::File::FNM_PATHNAME if pattern.include?("#{::File::SEPARATOR}**#{::File::SEPARATOR}")
28
33
  0
29
34
  end
30
35
  end
@@ -4,6 +4,9 @@ require "datadog/core/telemetry/ext"
4
4
 
5
5
  require_relative "../ext/settings"
6
6
  require_relative "../git/tree_uploader"
7
+ require_relative "../impacted_tests_detection/component"
8
+ require_relative "../logs/component"
9
+ require_relative "../logs/transport"
7
10
  require_relative "../remote/component"
8
11
  require_relative "../remote/library_settings_client"
9
12
  require_relative "../test_management/component"
@@ -11,7 +14,6 @@ require_relative "../test_management/null_component"
11
14
  require_relative "../test_management/tests_properties"
12
15
  require_relative "../test_optimisation/component"
13
16
  require_relative "../test_optimisation/coverage/transport"
14
- require_relative "../test_optimisation/coverage/writer"
15
17
  require_relative "../test_retries/component"
16
18
  require_relative "../test_retries/null_component"
17
19
  require_relative "../test_visibility/component"
@@ -20,12 +22,13 @@ require_relative "../test_visibility/known_tests"
20
22
  require_relative "../test_visibility/null_component"
21
23
  require_relative "../test_visibility/serializers/factories/test_level"
22
24
  require_relative "../test_visibility/serializers/factories/test_suite_level"
25
+ require_relative "../test_visibility/null_transport"
23
26
  require_relative "../test_visibility/transport"
24
27
  require_relative "../transport/adapters/telemetry_webmock_safe_adapter"
25
- require_relative "../test_visibility/null_transport"
26
28
  require_relative "../transport/api/builder"
27
29
  require_relative "../utils/parsing"
28
30
  require_relative "../utils/test_run"
31
+ require_relative "../async_writer"
29
32
  require_relative "../worker"
30
33
 
31
34
  module Datadog
@@ -33,7 +36,8 @@ module Datadog
33
36
  module Configuration
34
37
  # Adds CI behavior to Datadog trace components
35
38
  module Components
36
- attr_reader :test_visibility, :test_optimisation, :git_tree_upload_worker, :ci_remote, :test_retries, :test_management
39
+ attr_reader :test_visibility, :test_optimisation, :git_tree_upload_worker, :ci_remote, :test_retries,
40
+ :test_management, :agentless_logs_submission, :impacted_tests_detection
37
41
 
38
42
  def initialize(settings)
39
43
  @test_optimisation = nil
@@ -42,6 +46,7 @@ module Datadog
42
46
  @ci_remote = nil
43
47
  @test_retries = TestRetries::NullComponent.new
44
48
  @test_management = TestManagement::NullComponent.new
49
+ @impacted_tests_detection = nil
45
50
 
46
51
  # Activate CI mode if enabled
47
52
  if settings.ci.enabled
@@ -56,6 +61,7 @@ module Datadog
56
61
 
57
62
  @test_visibility&.shutdown!
58
63
  @test_optimisation&.shutdown!
64
+ @agentless_logs_submission&.shutdown!
59
65
  @git_tree_upload_worker&.stop
60
66
  end
61
67
 
@@ -132,6 +138,10 @@ module Datadog
132
138
  known_tests_client: build_known_tests_client(settings, test_visibility_api),
133
139
  context_service_uri: settings.ci.test_visibility_drb_server_uri
134
140
  )
141
+
142
+ @agentless_logs_submission = build_agentless_logs_component(settings, test_visibility_api)
143
+
144
+ @impacted_tests_detection = ImpactedTestsDetection::Component.new(enabled: settings.ci.impacted_tests_detection_enabled)
135
145
  end
136
146
 
137
147
  def build_test_optimisation(settings, test_visibility_api)
@@ -224,14 +234,14 @@ module Datadog
224
234
  # nil means that coverage event will be ignored
225
235
  return nil if api.nil? || settings.ci.discard_traces
226
236
 
227
- TestOptimisation::Coverage::Writer.new(
237
+ AsyncWriter.new(
228
238
  transport: TestOptimisation::Coverage::Transport.new(api: api)
229
239
  )
230
240
  end
231
241
 
232
242
  def build_git_upload_worker(settings, api)
233
243
  if settings.ci.git_metadata_upload_enabled
234
- git_tree_uploader = Git::TreeUploader.new(api: api)
244
+ git_tree_uploader = Git::TreeUploader.new(api: api, force_unshallow: settings.ci.impacted_tests_detection_enabled)
235
245
  Worker.new do |repository_url|
236
246
  git_tree_uploader.call(repository_url)
237
247
  end
@@ -256,6 +266,29 @@ module Datadog
256
266
  )
257
267
  end
258
268
 
269
+ def build_agentless_logs_component(settings, api)
270
+ if settings.ci.agentless_logs_submission_enabled && !settings.ci.agentless_mode_enabled
271
+ Datadog.logger.warn(
272
+ "Agentless logs submission is enabled but agentless mode is not enabled. " \
273
+ "Logs will not be submitted. " \
274
+ "Please make sure to set DD_CIVISIBILITY_AGENTLESS_ENABLED to true if you want to submit logs in agentless mode. " \
275
+ "Otherwise, set DD_AGENTLESS_LOG_SUBMISSION_ENABLED to 0 and use Datadog Agent to submit logs."
276
+ )
277
+ settings.ci.agentless_logs_submission_enabled = false
278
+ end
279
+
280
+ Logs::Component.new(
281
+ enabled: settings.ci.agentless_logs_submission_enabled,
282
+ writer: build_logs_writer(settings, api)
283
+ )
284
+ end
285
+
286
+ def build_logs_writer(settings, api)
287
+ return nil if api.nil? || settings.ci.discard_traces
288
+
289
+ AsyncWriter.new(transport: Logs::Transport.new(api: api), options: {buffer_size: 1024})
290
+ end
291
+
259
292
  # fetch custom tags provided by the user in DD_TAGS env var
260
293
  # with prefix test.configuration.
261
294
  def custom_configuration(settings)
@@ -294,13 +327,21 @@ module Datadog
294
327
  settings.telemetry.shutdown_timeout_seconds = 60.0
295
328
 
296
329
  begin
297
- require "datadog/core/telemetry/http/adapters/net"
330
+ require "datadog/core/transport/http/adapters/net"
298
331
 
299
- # patch gem's telemetry transport layer to use Net::HTTP instead of WebMock's Net::HTTP
300
- Core::Telemetry::Http::Adapters::Net.include(CI::Transport::Adapters::TelemetryWebmockSafeAdapter)
301
- rescue => e
332
+ # patch gem's core transport layer to use Net::HTTP instead of WebMock's Net::HTTP
333
+ Core::Transport::HTTP::Adapters::Net.include(CI::Transport::Adapters::TelemetryWebmockSafeAdapter)
334
+ rescue LoadError, StandardError => e
302
335
  Datadog.logger.warn("Failed to patch Datadog gem's telemetry layer: #{e}")
303
336
  end
337
+
338
+ # for compatibility with old telemetry transport
339
+ begin
340
+ require "datadog/core/telemetry/http/adapters/net"
341
+ Core::Telemetry::Http::Adapters::Net.include(CI::Transport::Adapters::TelemetryWebmockSafeAdapter)
342
+ rescue LoadError, StandardError => e
343
+ Datadog.logger.debug("The old telemetry transport layer is not available: #{e}")
344
+ end
304
345
  end
305
346
 
306
347
  # When timecop is present:
@@ -128,6 +128,17 @@ module Datadog
128
128
  o.default 20
129
129
  end
130
130
 
131
+ option :agentless_logs_submission_enabled do |o|
132
+ o.type :bool
133
+ o.env CI::Ext::Settings::ENV_AGENTLESS_LOGS_SUBMISSION_ENABLED
134
+ o.default false
135
+ end
136
+
137
+ option :agentless_logs_submission_url do |o|
138
+ o.type :string, nilable: true
139
+ o.env CI::Ext::Settings::ENV_AGENTLESS_LOGS_SUBMISSION_URL
140
+ end
141
+
131
142
  # internal only
132
143
  option :discard_traces do |o|
133
144
  o.type :bool
@@ -140,6 +151,12 @@ module Datadog
140
151
  o.env CI::Ext::Settings::ENV_TEST_VISIBILITY_DRB_SERVER_URI
141
152
  end
142
153
 
154
+ option :impacted_tests_detection_enabled do |o|
155
+ o.type :bool
156
+ o.env CI::Ext::Settings::ENV_IMPACTED_TESTS_DETECTION_ENABLED
157
+ o.default false
158
+ end
159
+
143
160
  define_method(:instrument) do |integration_name, options = {}, &block|
144
161
  return unless enabled
145
162
 
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../ext"
4
+ require_relative "../../settings"
5
+ require_relative "../../../utils/configuration"
6
+
7
+ module Datadog
8
+ module CI
9
+ module Contrib
10
+ module ActiveSupport
11
+ module Configuration
12
+ # Custom settings for the ActiveSupport integration
13
+ # @public_api
14
+ class Settings < Datadog::CI::Contrib::Settings
15
+ option :enabled do |o|
16
+ o.type :bool
17
+ o.env Ext::ENV_ENABLED
18
+ o.default true
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Contrib
6
+ module ActiveSupport
7
+ # Datadog ActiveSupport integration constants
8
+ module Ext
9
+ ENV_ENABLED = "DD_CI_ACTIVESUPPORT_ENABLED"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../integration"
4
+ require_relative "configuration/settings"
5
+ require_relative "patcher"
6
+
7
+ module Datadog
8
+ module CI
9
+ module Contrib
10
+ module ActiveSupport
11
+ # Description of ActiveSupport integration
12
+ class Integration < Datadog::CI::Contrib::Integration
13
+ MINIMUM_VERSION = Gem::Version.new("5.0")
14
+
15
+ def version
16
+ Gem.loaded_specs["activesupport"]&.version
17
+ end
18
+
19
+ def loaded?
20
+ !defined?(::Rails).nil? && !defined?(::ActiveSupport).nil? && !defined?(::ActiveSupport::TaggedLogging).nil? &&
21
+ !defined?(::ActiveSupport::TaggedLogging::Formatter).nil?
22
+ end
23
+
24
+ def compatible?
25
+ super && version >= MINIMUM_VERSION
26
+ end
27
+
28
+ def late_instrument?
29
+ true
30
+ end
31
+
32
+ def new_configuration
33
+ Configuration::Settings.new
34
+ end
35
+
36
+ def patcher
37
+ Patcher
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Contrib
6
+ module ActiveSupport
7
+ module LogsFormatter
8
+ def call(severity, timestamp, progname, msg)
9
+ # don't even construct an object for every log message if agentless logs submission is not enabled
10
+ return super unless datadog_logs_component.enabled
11
+ return super unless datadog_configuration[:enabled]
12
+
13
+ # additional precaution because we cannot use targeted prepend in Ruby 2.7, so method :tags_text might
14
+ # not be available (highly unlikely, but not unimaginable)
15
+ #
16
+ # (see Datadog::CI::Contrib::ActiveSupport::Patcher for explanation)
17
+ return super unless respond_to?(:tags_text)
18
+
19
+ message = "#{msg} #{tags_text}"
20
+ return super unless message.include?("dd.trace_id")
21
+
22
+ datadog_logs_component.write({
23
+ message: message,
24
+ level: severity
25
+ })
26
+
27
+ super
28
+ end
29
+
30
+ def datadog_logs_component
31
+ Datadog.send(:components).agentless_logs_submission
32
+ end
33
+
34
+ def datadog_configuration
35
+ Datadog.configuration.ci[:activesupport]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../patcher"
4
+ require_relative "logs_formatter"
5
+
6
+ module Datadog
7
+ module CI
8
+ module Contrib
9
+ module ActiveSupport
10
+ # Patcher enables patching of activesupport module
11
+ module Patcher
12
+ include Datadog::CI::Contrib::Patcher
13
+
14
+ module_function
15
+
16
+ def patch
17
+ unless datadog_logs_component.enabled
18
+ Datadog.logger.debug("Datadog logs submission is disabled, skipping activesupport patching")
19
+ return
20
+ end
21
+
22
+ unless ::Rails.logger.formatter.is_a?(::ActiveSupport::TaggedLogging::Formatter)
23
+ Datadog.logger.debug {
24
+ "Rails logger formatter is not an instance of ActiveSupport::TaggedLogging::Formatter, skipping activesupport patching. " \
25
+ "Formatter: #{::Rails.logger.formatter.class}"
26
+ }
27
+ return
28
+ end
29
+
30
+ # Before Ruby 3.0, prepending to a module did not change existing instances where this module was included
31
+ # It means that for Ruby 2.7 we have to patch formatter's class directly
32
+ #
33
+ # Context:
34
+ # - https://bugs.ruby-lang.org/issues/9573
35
+ # - https://rubyreferences.github.io/rubychanges/3.0.html#include-and-prepend-now-affects-modules-including-the-receiver
36
+ if RUBY_VERSION.start_with?("2.7")
37
+ Rails.logger.formatter.class.prepend(LogsFormatter)
38
+ else
39
+ ::ActiveSupport::TaggedLogging::Formatter.prepend(LogsFormatter)
40
+ end
41
+ end
42
+
43
+ def datadog_logs_component
44
+ Datadog.send(:components).agentless_logs_submission
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -9,9 +9,7 @@ module Datadog
9
9
  module Patcher
10
10
  include Datadog::CI::Contrib::Patcher
11
11
 
12
- module_function
13
-
14
- def patch
12
+ def self.patch
15
13
  if ::RSpec::Core::Runner.ancestors.include?(::KnapsackPro::Extensions::RSpecExtension::Runner)
16
14
  # knapsack already patched rspec runner
17
15
  require_relative "runner"
@@ -19,6 +19,7 @@ module Datadog
19
19
  return super if ::RSpec.configuration.dry_run? && !datadog_configuration[:dry_run_enabled]
20
20
  return super unless datadog_configuration[:enabled]
21
21
 
22
+ # @type var test_session: Datadog::CI::TestSession?
22
23
  test_session = test_visibility_component.start_test_session(
23
24
  tags: {
24
25
  CI::Ext::Test::TAG_FRAMEWORK => CI::Contrib::RSpec::Ext::FRAMEWORK,
@@ -27,6 +28,7 @@ module Datadog
27
28
  service: datadog_configuration[:service_name]
28
29
  )
29
30
 
31
+ # @type var test_module: Datadog::CI::TestModule?
30
32
  test_module = test_visibility_component.start_test_module(CI::Contrib::RSpec::Ext::FRAMEWORK)
31
33
 
32
34
  result = super
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../ext"
4
+ require_relative "../../settings"
5
+ require_relative "../../../utils/configuration"
6
+
7
+ module Datadog
8
+ module CI
9
+ module Contrib
10
+ module Lograge
11
+ module Configuration
12
+ # Custom settings for the Lograge integration
13
+ # @public_api
14
+ class Settings < Datadog::CI::Contrib::Settings
15
+ option :enabled do |o|
16
+ o.type :bool
17
+ o.env Ext::ENV_ENABLED
18
+ o.default true
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Contrib
6
+ module Lograge
7
+ # Datadog Lograge integration constants
8
+ module Ext
9
+ ENV_ENABLED = "DD_CI_LOGRAGE_ENABLED"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../integration"
4
+ require_relative "configuration/settings"
5
+ require_relative "patcher"
6
+
7
+ module Datadog
8
+ module CI
9
+ module Contrib
10
+ module Lograge
11
+ # Description of Lograge integration
12
+ class Integration < Datadog::CI::Contrib::Integration
13
+ MINIMUM_VERSION = Gem::Version.new("0.14.0")
14
+
15
+ def version
16
+ Gem.loaded_specs["lograge"]&.version
17
+ end
18
+
19
+ def loaded?
20
+ !defined?(::Lograge).nil? && !defined?(::Lograge::LogSubscribers).nil? &&
21
+ !defined?(::Lograge::LogSubscribers::Base).nil?
22
+ end
23
+
24
+ def compatible?
25
+ super && version && version >= MINIMUM_VERSION
26
+ end
27
+
28
+ def late_instrument?
29
+ true
30
+ end
31
+
32
+ def new_configuration
33
+ Configuration::Settings.new
34
+ end
35
+
36
+ def patcher
37
+ Patcher
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end