datadog-ci 1.14.0 → 1.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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -2
  3. data/lib/datadog/ci/async_writer.rb +112 -0
  4. data/lib/datadog/ci/configuration/components.rb +36 -6
  5. data/lib/datadog/ci/configuration/settings.rb +17 -0
  6. data/lib/datadog/ci/contrib/activesupport/configuration/settings.rb +25 -0
  7. data/lib/datadog/ci/contrib/activesupport/ext.rb +14 -0
  8. data/lib/datadog/ci/contrib/activesupport/integration.rb +43 -0
  9. data/lib/datadog/ci/contrib/activesupport/logs_formatter.rb +41 -0
  10. data/lib/datadog/ci/contrib/activesupport/patcher.rb +50 -0
  11. data/lib/datadog/ci/contrib/lograge/configuration/settings.rb +25 -0
  12. data/lib/datadog/ci/contrib/lograge/ext.rb +14 -0
  13. data/lib/datadog/ci/contrib/lograge/integration.rb +43 -0
  14. data/lib/datadog/ci/contrib/lograge/log_subscriber.rb +41 -0
  15. data/lib/datadog/ci/contrib/lograge/patcher.rb +32 -0
  16. data/lib/datadog/ci/contrib/minitest/runner.rb +4 -1
  17. data/lib/datadog/ci/contrib/parallel_tests/cli.rb +84 -0
  18. data/lib/datadog/ci/contrib/parallel_tests/configuration/settings.rb +32 -0
  19. data/lib/datadog/ci/contrib/parallel_tests/ext.rb +16 -0
  20. data/lib/datadog/ci/contrib/parallel_tests/integration.rb +42 -0
  21. data/lib/datadog/ci/contrib/parallel_tests/patcher.rb +23 -0
  22. data/lib/datadog/ci/contrib/rspec/example.rb +7 -0
  23. data/lib/datadog/ci/contrib/rspec/example_group.rb +18 -8
  24. data/lib/datadog/ci/contrib/rspec/helpers.rb +18 -0
  25. data/lib/datadog/ci/contrib/rspec/runner.rb +2 -0
  26. data/lib/datadog/ci/contrib/semantic_logger/configuration/settings.rb +25 -0
  27. data/lib/datadog/ci/contrib/semantic_logger/ext.rb +14 -0
  28. data/lib/datadog/ci/contrib/semantic_logger/integration.rb +42 -0
  29. data/lib/datadog/ci/contrib/semantic_logger/logger.rb +32 -0
  30. data/lib/datadog/ci/contrib/semantic_logger/patcher.rb +32 -0
  31. data/lib/datadog/ci/ext/settings.rb +3 -0
  32. data/lib/datadog/ci/ext/test.rb +23 -2
  33. data/lib/datadog/ci/ext/transport.rb +2 -0
  34. data/lib/datadog/ci/git/local_repository.rb +1 -1
  35. data/lib/datadog/ci/git/tree_uploader.rb +9 -0
  36. data/lib/datadog/ci/logs/component.rb +46 -0
  37. data/lib/datadog/ci/logs/transport.rb +73 -0
  38. data/lib/datadog/ci/readonly_test_module.rb +28 -0
  39. data/lib/datadog/ci/readonly_test_session.rb +31 -0
  40. data/lib/datadog/ci/remote/component.rb +43 -16
  41. data/lib/datadog/ci/test.rb +10 -0
  42. data/lib/datadog/ci/test_management/component.rb +34 -1
  43. data/lib/datadog/ci/test_management/tests_properties.rb +2 -1
  44. data/lib/datadog/ci/test_optimisation/component.rb +31 -5
  45. data/lib/datadog/ci/test_retries/driver/retry_new.rb +1 -1
  46. data/lib/datadog/ci/test_session.rb +7 -1
  47. data/lib/datadog/ci/test_visibility/component.rb +82 -28
  48. data/lib/datadog/ci/test_visibility/context.rb +77 -29
  49. data/lib/datadog/ci/test_visibility/null_component.rb +7 -1
  50. data/lib/datadog/ci/test_visibility/store/{local.rb → fiber_local.rb} +1 -1
  51. data/lib/datadog/ci/test_visibility/store/{global.rb → process.rb} +23 -18
  52. data/lib/datadog/ci/test_visibility/transport.rb +1 -2
  53. data/lib/datadog/ci/transport/api/agentless.rb +8 -1
  54. data/lib/datadog/ci/transport/api/base.rb +4 -0
  55. data/lib/datadog/ci/transport/api/builder.rb +5 -1
  56. data/lib/datadog/ci/transport/api/evp_proxy.rb +4 -0
  57. data/lib/datadog/ci/transport/http.rb +1 -1
  58. data/lib/datadog/ci/utils/file_storage.rb +57 -0
  59. data/lib/datadog/ci/utils/stateful.rb +52 -0
  60. data/lib/datadog/ci/version.rb +1 -1
  61. data/lib/datadog/ci.rb +7 -3
  62. metadata +32 -6
  63. data/lib/datadog/ci/test_optimisation/coverage/writer.rb +0 -116
  64. data/lib/datadog/ci/test_visibility/capabilities.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 694421f4e4621608a9aa6d8deb0b1407fa348fec68820a28ced1a567c56ed289
4
- data.tar.gz: 12b586d1eabe233af428c7294564f8b7a46ff8bbb64d44f222762afd371a2c1c
3
+ metadata.gz: 4f7cf7ed07d7a4543498333996a19347f64010eef7900f53d5790ad6e4fe2aaf
4
+ data.tar.gz: 7b3ebdaaf30c557ac23f3720f72ef56ab1b9c1f9686e8f62dc597e3c938cfe35
5
5
  SHA512:
6
- metadata.gz: 81c173cb2b22a8e0e3853d21d4e1ac023569142d51bb266c287ef7d4c7c5f2dfd97d2f3914acd1ac766d3e60ac15929cbee849b7284d300644113e6a14dea331
7
- data.tar.gz: c1f1f93f35850cf9b6d1e360d53f2a26e2e46961aeed8e69f216327513e4001c45a42c363c20609ad0b525a4aeaf0fdec59e32f38d9302289c9e256ccf5aa81c
6
+ metadata.gz: 9412f518c4bba62d062448950f10b956abebe22e33680341454f60f67fd48c25b155d9e0ed3f7d378bcb33f21ee0fa586bee2ff03f3a2ad3f4b753a8a24bb36c
7
+ data.tar.gz: eb8710ab135550d9c26e1742aefb5ebb05b2c8a1f91e9175e44b0181c4934f1ff5453749820b8720e1febe5c79502e2489d46442f80c4836e56a394c931f7143
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.16.0] - 2025-04-15
4
+
5
+
6
+ ### Added
7
+
8
+ * agentless logs submission for tests ([#306][])
9
+ * lograge support for agentless logs feature ([#308][])
10
+ * semantic_logger instrumentation for agentless logs feature ([#311][])
11
+ * retry reason "external" ([#312][])
12
+
13
+ ## [1.15.0] - 2025-03-25
14
+
15
+
16
+ ### Added
17
+
18
+ * parallel tests gem support ([#299][])
19
+ * implemented attempt to fix flow V2 ([#298][])
20
+
21
+ ### Fixed
22
+
23
+ * Fix: prevent test impact analysis from skipping flaky tests that are attempted to be fixed ([#301][])
24
+ * Fix git commit message extraction to extract multiline commit messages correctly ([#300][])
25
+
3
26
  ## [1.14.0] - 2025-03-11
4
27
 
5
28
  ### Added
@@ -404,7 +427,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
404
427
 
405
428
  - Ruby versions < 2.7 no longer supported ([#8][])
406
429
 
407
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.14.0...main
430
+ [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.16.0...main
431
+ [1.16.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.15.0...v1.16.0
432
+ [1.15.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.14.0...v1.15.0
408
433
  [1.14.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.13.0...v1.14.0
409
434
  [1.13.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.12.0...v1.13.0
410
435
  [1.12.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.11.0...v1.12.0
@@ -579,4 +604,12 @@ Currently test suite level visibility is not used by our instrumentation: it wil
579
604
  [#289]: https://github.com/DataDog/datadog-ci-rb/issues/289
580
605
  [#292]: https://github.com/DataDog/datadog-ci-rb/issues/292
581
606
  [#294]: https://github.com/DataDog/datadog-ci-rb/issues/294
582
- [#295]: https://github.com/DataDog/datadog-ci-rb/issues/295
607
+ [#295]: https://github.com/DataDog/datadog-ci-rb/issues/295
608
+ [#298]: https://github.com/DataDog/datadog-ci-rb/issues/298
609
+ [#299]: https://github.com/DataDog/datadog-ci-rb/issues/299
610
+ [#300]: https://github.com/DataDog/datadog-ci-rb/issues/300
611
+ [#301]: https://github.com/DataDog/datadog-ci-rb/issues/301
612
+ [#306]: https://github.com/DataDog/datadog-ci-rb/issues/306
613
+ [#308]: https://github.com/DataDog/datadog-ci-rb/issues/308
614
+ [#311]: https://github.com/DataDog/datadog-ci-rb/issues/311
615
+ [#312]: https://github.com/DataDog/datadog-ci-rb/issues/312
@@ -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
@@ -4,6 +4,8 @@ require "datadog/core/telemetry/ext"
4
4
 
5
5
  require_relative "../ext/settings"
6
6
  require_relative "../git/tree_uploader"
7
+ require_relative "../logs/component"
8
+ require_relative "../logs/transport"
7
9
  require_relative "../remote/component"
8
10
  require_relative "../remote/library_settings_client"
9
11
  require_relative "../test_management/component"
@@ -11,7 +13,6 @@ require_relative "../test_management/null_component"
11
13
  require_relative "../test_management/tests_properties"
12
14
  require_relative "../test_optimisation/component"
13
15
  require_relative "../test_optimisation/coverage/transport"
14
- require_relative "../test_optimisation/coverage/writer"
15
16
  require_relative "../test_retries/component"
16
17
  require_relative "../test_retries/null_component"
17
18
  require_relative "../test_visibility/component"
@@ -20,12 +21,13 @@ require_relative "../test_visibility/known_tests"
20
21
  require_relative "../test_visibility/null_component"
21
22
  require_relative "../test_visibility/serializers/factories/test_level"
22
23
  require_relative "../test_visibility/serializers/factories/test_suite_level"
24
+ require_relative "../test_visibility/null_transport"
23
25
  require_relative "../test_visibility/transport"
24
26
  require_relative "../transport/adapters/telemetry_webmock_safe_adapter"
25
- require_relative "../test_visibility/null_transport"
26
27
  require_relative "../transport/api/builder"
27
28
  require_relative "../utils/parsing"
28
29
  require_relative "../utils/test_run"
30
+ require_relative "../async_writer"
29
31
  require_relative "../worker"
30
32
 
31
33
  module Datadog
@@ -33,7 +35,8 @@ module Datadog
33
35
  module Configuration
34
36
  # Adds CI behavior to Datadog trace components
35
37
  module Components
36
- attr_reader :test_visibility, :test_optimisation, :git_tree_upload_worker, :ci_remote, :test_retries, :test_management
38
+ attr_reader :test_visibility, :test_optimisation, :git_tree_upload_worker, :ci_remote, :test_retries,
39
+ :test_management, :agentless_logs_submission
37
40
 
38
41
  def initialize(settings)
39
42
  @test_optimisation = nil
@@ -56,6 +59,7 @@ module Datadog
56
59
 
57
60
  @test_visibility&.shutdown!
58
61
  @test_optimisation&.shutdown!
62
+ @agentless_logs_submission&.shutdown!
59
63
  @git_tree_upload_worker&.stop
60
64
  end
61
65
 
@@ -129,8 +133,11 @@ module Datadog
129
133
  @test_visibility = TestVisibility::Component.new(
130
134
  test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility,
131
135
  logical_test_session_name: settings.ci.test_session_name,
132
- known_tests_client: build_known_tests_client(settings, test_visibility_api)
136
+ known_tests_client: build_known_tests_client(settings, test_visibility_api),
137
+ context_service_uri: settings.ci.test_visibility_drb_server_uri
133
138
  )
139
+
140
+ @agentless_logs_submission = build_agentless_logs_component(settings, test_visibility_api)
134
141
  end
135
142
 
136
143
  def build_test_optimisation(settings, test_visibility_api)
@@ -223,7 +230,7 @@ module Datadog
223
230
  # nil means that coverage event will be ignored
224
231
  return nil if api.nil? || settings.ci.discard_traces
225
232
 
226
- TestOptimisation::Coverage::Writer.new(
233
+ AsyncWriter.new(
227
234
  transport: TestOptimisation::Coverage::Transport.new(api: api)
228
235
  )
229
236
  end
@@ -255,6 +262,29 @@ module Datadog
255
262
  )
256
263
  end
257
264
 
265
+ def build_agentless_logs_component(settings, api)
266
+ if settings.ci.agentless_logs_submission_enabled && !settings.ci.agentless_mode_enabled
267
+ Datadog.logger.warn(
268
+ "Agentless logs submission is enabled but agentless mode is not enabled. " \
269
+ "Logs will not be submitted. " \
270
+ "Please make sure to set DD_CIVISIBILITY_AGENTLESS_ENABLED to true if you want to submit logs in agentless mode. " \
271
+ "Otherwise, set DD_AGENTLESS_LOG_SUBMISSION_ENABLED to 0 and use Datadog Agent to submit logs."
272
+ )
273
+ settings.ci.agentless_logs_submission_enabled = false
274
+ end
275
+
276
+ Logs::Component.new(
277
+ enabled: settings.ci.agentless_logs_submission_enabled,
278
+ writer: build_logs_writer(settings, api)
279
+ )
280
+ end
281
+
282
+ def build_logs_writer(settings, api)
283
+ return nil if api.nil? || settings.ci.discard_traces
284
+
285
+ AsyncWriter.new(transport: Logs::Transport.new(api: api), options: {buffer_size: 1024})
286
+ end
287
+
258
288
  # fetch custom tags provided by the user in DD_TAGS env var
259
289
  # with prefix test.configuration.
260
290
  def custom_configuration(settings)
@@ -297,7 +327,7 @@ module Datadog
297
327
 
298
328
  # patch gem's telemetry transport layer to use Net::HTTP instead of WebMock's Net::HTTP
299
329
  Core::Telemetry::Http::Adapters::Net.include(CI::Transport::Adapters::TelemetryWebmockSafeAdapter)
300
- rescue => e
330
+ rescue LoadError, StandardError => e
301
331
  Datadog.logger.warn("Failed to patch Datadog gem's telemetry layer: #{e}")
302
332
  end
303
333
  end
@@ -128,12 +128,29 @@ 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
134
145
  o.default false
135
146
  end
136
147
 
148
+ # internal only
149
+ option :test_visibility_drb_server_uri do |o|
150
+ o.type :string, nilable: true
151
+ o.env CI::Ext::Settings::ENV_TEST_VISIBILITY_DRB_SERVER_URI
152
+ end
153
+
137
154
  define_method(:instrument) do |integration_name, options = {}, &block|
138
155
  return unless enabled
139
156
 
@@ -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
@@ -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
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Contrib
6
+ module Lograge
7
+ module LogSubscriber
8
+ def self.included(base)
9
+ base.prepend(InstanceMethods)
10
+ end
11
+
12
+ module InstanceMethods
13
+ private
14
+
15
+ def before_format(data, payload)
16
+ return super unless datadog_logs_component.enabled
17
+ return super unless datadog_configuration[:enabled]
18
+
19
+ result = super
20
+
21
+ if result.fetch(:dd, {}).fetch(:trace_id, nil).nil?
22
+ Datadog.logger.debug { "Discarding uncorrelated log event: #{result.inspect}" }
23
+ return result
24
+ end
25
+ datadog_logs_component.write(result)
26
+ result
27
+ end
28
+
29
+ def datadog_logs_component
30
+ Datadog.send(:components).agentless_logs_submission
31
+ end
32
+
33
+ def datadog_configuration
34
+ Datadog.configuration.ci[:lograge]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../patcher"
4
+ require_relative "log_subscriber"
5
+
6
+ module Datadog
7
+ module CI
8
+ module Contrib
9
+ module Lograge
10
+ # Patcher enables patching of lograge 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 lograge patching")
19
+ return
20
+ end
21
+
22
+ ::Lograge::LogSubscribers::Base.include(LogSubscriber)
23
+ end
24
+
25
+ def datadog_logs_component
26
+ Datadog.send(:components).agentless_logs_submission
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -27,7 +27,10 @@ module Datadog
27
27
  CI::Ext::Test::TAG_FRAMEWORK_VERSION => datadog_integration.version.to_s
28
28
  },
29
29
  service: datadog_configuration[:service_name],
30
- estimated_total_tests_count: tests_count
30
+ estimated_total_tests_count: tests_count,
31
+ # if minitest is being used with a parallel runner, then tests split will happen by example, not by test suite
32
+ # we need to always start/stop test suites in the parent process in this case
33
+ local_test_suites_mode: false
31
34
  )
32
35
  test_visibility_component.start_test_module(Ext::FRAMEWORK)
33
36
  end