datadog-ci 1.15.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -2
  3. data/lib/datadog/ci/async_writer.rb +112 -0
  4. data/lib/datadog/ci/configuration/components.rb +34 -5
  5. data/lib/datadog/ci/configuration/settings.rb +11 -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/parallel_tests/patcher.rb +0 -1
  17. data/lib/datadog/ci/contrib/semantic_logger/configuration/settings.rb +25 -0
  18. data/lib/datadog/ci/contrib/semantic_logger/ext.rb +14 -0
  19. data/lib/datadog/ci/contrib/semantic_logger/integration.rb +42 -0
  20. data/lib/datadog/ci/contrib/semantic_logger/logger.rb +32 -0
  21. data/lib/datadog/ci/contrib/semantic_logger/patcher.rb +32 -0
  22. data/lib/datadog/ci/ext/settings.rb +2 -0
  23. data/lib/datadog/ci/ext/test.rb +3 -2
  24. data/lib/datadog/ci/ext/transport.rb +2 -0
  25. data/lib/datadog/ci/logs/component.rb +46 -0
  26. data/lib/datadog/ci/logs/transport.rb +73 -0
  27. data/lib/datadog/ci/test.rb +10 -0
  28. data/lib/datadog/ci/test_retries/driver/retry_new.rb +1 -1
  29. data/lib/datadog/ci/test_visibility/null_component.rb +3 -1
  30. data/lib/datadog/ci/transport/api/agentless.rb +8 -1
  31. data/lib/datadog/ci/transport/api/base.rb +4 -0
  32. data/lib/datadog/ci/transport/api/builder.rb +5 -1
  33. data/lib/datadog/ci/transport/api/evp_proxy.rb +4 -0
  34. data/lib/datadog/ci/version.rb +1 -1
  35. data/lib/datadog/ci.rb +3 -0
  36. metadata +20 -3
  37. 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: 4f7cf7ed07d7a4543498333996a19347f64010eef7900f53d5790ad6e4fe2aaf
4
+ data.tar.gz: 7b3ebdaaf30c557ac23f3720f72ef56ab1b9c1f9686e8f62dc597e3c938cfe35
5
5
  SHA512:
6
- metadata.gz: 3d0db7cb6a13a4c2f0b38b22c8dc2470a9ec760c38312c929a7b6224b118e18b279addf76901f7f094f60123a9e65d9afef06c15970bf01b247bc031bf80725d
7
- data.tar.gz: f731bc7979a69ae63362d06d0313754bd825a22baf934cb682c1dc2a16a8584d0c3ece806f2bfb75d42924c09fff6296bf8c5c1be142afbe3ab7716bcb753815
6
+ metadata.gz: 9412f518c4bba62d062448950f10b956abebe22e33680341454f60f67fd48c25b155d9e0ed3f7d378bcb33f21ee0fa586bee2ff03f3a2ad3f4b753a8a24bb36c
7
+ data.tar.gz: eb8710ab135550d9c26e1742aefb5ebb05b2c8a1f91e9175e44b0181c4934f1ff5453749820b8720e1febe5c79502e2489d46442f80c4836e56a394c931f7143
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
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
+
3
13
  ## [1.15.0] - 2025-03-25
4
14
 
5
15
 
@@ -417,7 +427,8 @@ Currently test suite level visibility is not used by our instrumentation: it wil
417
427
 
418
428
  - Ruby versions < 2.7 no longer supported ([#8][])
419
429
 
420
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.15.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
421
432
  [1.15.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.14.0...v1.15.0
422
433
  [1.14.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.13.0...v1.14.0
423
434
  [1.13.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.12.0...v1.13.0
@@ -597,4 +608,8 @@ Currently test suite level visibility is not used by our instrumentation: it wil
597
608
  [#298]: https://github.com/DataDog/datadog-ci-rb/issues/298
598
609
  [#299]: https://github.com/DataDog/datadog-ci-rb/issues/299
599
610
  [#300]: https://github.com/DataDog/datadog-ci-rb/issues/300
600
- [#301]: https://github.com/DataDog/datadog-ci-rb/issues/301
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
 
@@ -132,6 +136,8 @@ module Datadog
132
136
  known_tests_client: build_known_tests_client(settings, test_visibility_api),
133
137
  context_service_uri: settings.ci.test_visibility_drb_server_uri
134
138
  )
139
+
140
+ @agentless_logs_submission = build_agentless_logs_component(settings, test_visibility_api)
135
141
  end
136
142
 
137
143
  def build_test_optimisation(settings, test_visibility_api)
@@ -224,7 +230,7 @@ module Datadog
224
230
  # nil means that coverage event will be ignored
225
231
  return nil if api.nil? || settings.ci.discard_traces
226
232
 
227
- TestOptimisation::Coverage::Writer.new(
233
+ AsyncWriter.new(
228
234
  transport: TestOptimisation::Coverage::Transport.new(api: api)
229
235
  )
230
236
  end
@@ -256,6 +262,29 @@ module Datadog
256
262
  )
257
263
  end
258
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
+
259
288
  # fetch custom tags provided by the user in DD_TAGS env var
260
289
  # with prefix test.configuration.
261
290
  def custom_configuration(settings)
@@ -298,7 +327,7 @@ module Datadog
298
327
 
299
328
  # patch gem's telemetry transport layer to use Net::HTTP instead of WebMock's Net::HTTP
300
329
  Core::Telemetry::Http::Adapters::Net.include(CI::Transport::Adapters::TelemetryWebmockSafeAdapter)
301
- rescue => e
330
+ rescue LoadError, StandardError => e
302
331
  Datadog.logger.warn("Failed to patch Datadog gem's telemetry layer: #{e}")
303
332
  end
304
333
  end
@@ -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
@@ -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
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "cli"
4
- require_relative "integration"
5
4
  require_relative "../patcher"
6
5
 
7
6
  module Datadog
@@ -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 SemanticLogger
11
+ module Configuration
12
+ # Custom settings for the SemanticLogger 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 SemanticLogger
7
+ # Datadog SemanticLogger integration constants
8
+ module Ext
9
+ ENV_ENABLED = "DD_CI_SEMANTIC_LOGGER_ENABLED"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,42 @@
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 SemanticLogger
11
+ # Description of SemanticLogger integration
12
+ class Integration < Datadog::CI::Contrib::Integration
13
+ MINIMUM_VERSION = Gem::Version.new("4.0")
14
+
15
+ def version
16
+ Gem.loaded_specs["semantic_logger"]&.version
17
+ end
18
+
19
+ def loaded?
20
+ !defined?(::SemanticLogger).nil? && !defined?(::SemanticLogger::Logger).nil?
21
+ end
22
+
23
+ def compatible?
24
+ super && version >= MINIMUM_VERSION
25
+ end
26
+
27
+ def late_instrument?
28
+ true
29
+ end
30
+
31
+ def new_configuration
32
+ Configuration::Settings.new
33
+ end
34
+
35
+ def patcher
36
+ Patcher
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Contrib
6
+ module SemanticLogger
7
+ module Logger
8
+ def self.included(base)
9
+ base.prepend(InstanceMethods)
10
+ end
11
+
12
+ module InstanceMethods
13
+ def log(log, message = nil, progname = nil, &block)
14
+ return super unless log.is_a?(::SemanticLogger::Log)
15
+ return super unless datadog_logs_component.enabled
16
+
17
+ result = super
18
+
19
+ datadog_logs_component.write(log.to_h.clone)
20
+
21
+ result
22
+ end
23
+
24
+ def datadog_logs_component
25
+ Datadog.send(:components).agentless_logs_submission
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../patcher"
4
+ require_relative "logger"
5
+
6
+ module Datadog
7
+ module CI
8
+ module Contrib
9
+ module SemanticLogger
10
+ # Patcher enables patching of semantic_logger 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 semantic_logger patching")
19
+ return
20
+ end
21
+
22
+ ::SemanticLogger::Logger.include(Logger)
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
@@ -23,6 +23,8 @@ module Datadog
23
23
  ENV_TEST_MANAGEMENT_ENABLED = "DD_TEST_MANAGEMENT_ENABLED"
24
24
  ENV_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES = "DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES"
25
25
  ENV_TEST_VISIBILITY_DRB_SERVER_URI = "DD_TEST_VISIBILITY_DRB_SERVER_URI"
26
+ ENV_AGENTLESS_LOGS_SUBMISSION_ENABLED = "DD_AGENTLESS_LOG_SUBMISSION_ENABLED"
27
+ ENV_AGENTLESS_LOGS_SUBMISSION_URL = "DD_AGENTLESS_LOG_SUBMISSION_URL"
26
28
 
27
29
  # Source: https://docs.datadoghq.com/getting_started/site/
28
30
  DD_SITE_ALLOWLIST = %w[
@@ -151,9 +151,10 @@ module Datadog
151
151
 
152
152
  # possible reasons why a test was retried
153
153
  module RetryReason
154
- RETRY_NEW = "efd"
155
- RETRY_FAILED = "atr"
154
+ RETRY_DETECT_FLAKY = "early_flake_detection"
155
+ RETRY_FAILED = "auto_test_retries"
156
156
  RETRY_FLAKY_FIXED = "attempt_to_fix"
157
+ RETRY_EXTERNAL = "external"
157
158
  end
158
159
 
159
160
  # possible reasons why a test was skipped
@@ -28,6 +28,8 @@ module Datadog
28
28
  TEST_COVERAGE_INTAKE_HOST_PREFIX = "citestcov-intake"
29
29
  TEST_COVERAGE_INTAKE_PATH = "/api/v2/citestcov"
30
30
 
31
+ LOGS_INTAKE_HOST_PREFIX = "http-intake.logs"
32
+
31
33
  DD_API_HOST_PREFIX = "api"
32
34
 
33
35
  DD_API_SETTINGS_PATH = "/api/v2/libraries/tests/services/setting"
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/core/environment/platform"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Logs
8
+ class Component
9
+ attr_reader :enabled
10
+
11
+ def initialize(enabled:, writer:)
12
+ @enabled = enabled && !writer.nil?
13
+ @writer = writer
14
+ end
15
+
16
+ def write(event)
17
+ return unless enabled
18
+
19
+ add_common_tags!(event)
20
+ @writer&.write(event)
21
+
22
+ nil
23
+ end
24
+
25
+ def shutdown!
26
+ @writer&.stop
27
+ end
28
+
29
+ private
30
+
31
+ def add_common_tags!(event)
32
+ test_session = test_visibility.active_test_session
33
+
34
+ event[:ddsource] ||= "ruby"
35
+ event[:ddtags] ||= "datadog.product:citest"
36
+ event[:service] ||= test_session&.service
37
+ event[:hostname] ||= Datadog::Core::Environment::Platform.hostname
38
+ end
39
+
40
+ def test_visibility
41
+ ::Datadog.send(:components).test_visibility
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ require "datadog/core/chunker"
6
+
7
+ module Datadog
8
+ module CI
9
+ module Logs
10
+ class Transport
11
+ DEFAULT_MAX_PAYLOAD_SIZE = 4.5 * 1024 * 1024
12
+
13
+ attr_reader :api,
14
+ :max_payload_size
15
+
16
+ def initialize(api:, max_payload_size: DEFAULT_MAX_PAYLOAD_SIZE)
17
+ @api = api
18
+ @max_payload_size = max_payload_size
19
+ end
20
+
21
+ def send_events(events)
22
+ return [] if events.nil? || events.empty?
23
+
24
+ Datadog.logger.debug { "[#{self.class.name}] Sending #{events.count} events..." }
25
+
26
+ encoded_events = events.filter_map do |event|
27
+ encoded_event = event.to_json
28
+ if event_too_large?(event, encoded_event)
29
+ next
30
+ end
31
+
32
+ encoded_event
33
+ end
34
+
35
+ responses = []
36
+ Datadog::Core::Chunker.chunk_by_size(encoded_events, max_payload_size).map do |chunk|
37
+ encoded_payload = pack_events(chunk)
38
+ Datadog.logger.debug do
39
+ "[#{self.class.name}] Send chunk of #{chunk.count} events; payload size #{encoded_payload.size}"
40
+ end
41
+
42
+ response = send_payload(encoded_payload)
43
+
44
+ responses << response
45
+ end
46
+
47
+ responses
48
+ end
49
+
50
+ private
51
+
52
+ def pack_events(encoded_events)
53
+ "[#{encoded_events.join(",")}]"
54
+ end
55
+
56
+ def event_too_large?(event, encoded_event)
57
+ return false unless encoded_event.size > max_payload_size
58
+
59
+ # This single event is too large, we can't flush it
60
+ Datadog.logger.debug(
61
+ "[#{self.class.name}] Dropping event for logs intake. Payload too large: '#{event.inspect}'"
62
+ )
63
+
64
+ true
65
+ end
66
+
67
+ def send_payload(encoded_payload)
68
+ @api.logs_intake_request(path: "/v1/input", payload: encoded_payload)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -25,6 +25,10 @@ module Datadog
25
25
  # Finishes the current test.
26
26
  # @return [void]
27
27
  def finish
28
+ if is_retry? && retry_reason.nil?
29
+ set_tag(Ext::Test::TAG_RETRY_REASON, Ext::Test::RetryReason::RETRY_EXTERNAL)
30
+ end
31
+
28
32
  test_visibility.deactivate_test
29
33
 
30
34
  super
@@ -68,6 +72,12 @@ module Datadog
68
72
  get_tag(Ext::Test::TAG_IS_RETRY) == "true"
69
73
  end
70
74
 
75
+ # Returns string with a reason why test was retried
76
+ # @return [String] retry reason
77
+ def retry_reason
78
+ get_tag(Ext::Test::TAG_RETRY_REASON)
79
+ end
80
+
71
81
  # Returns "true" if this span represents a test that wasn't known to Datadog before.
72
82
  # @return [Boolean] true if this test is a new one, false otherwise.
73
83
  def is_new?
@@ -36,7 +36,7 @@ module Datadog
36
36
  end
37
37
 
38
38
  def retry_reason
39
- Ext::Test::RetryReason::RETRY_NEW
39
+ Ext::Test::RetryReason::RETRY_DETECT_FLAKY
40
40
  end
41
41
  end
42
42
  end
@@ -8,7 +8,9 @@ module Datadog
8
8
  def configure(_, _)
9
9
  end
10
10
 
11
- def start_test_session(service: nil, tags: {}, estimated_total_tests_count: 0)
11
+ def start_test_session(
12
+ service: nil, tags: {}, estimated_total_tests_count: 0, distributed: false, local_test_suites_mode: true
13
+ )
12
14
  skip_tracing
13
15
  end
14
16
 
@@ -10,11 +10,12 @@ module Datadog
10
10
  class Agentless < Base
11
11
  attr_reader :api_key
12
12
 
13
- def initialize(api_key:, citestcycle_url:, api_url:, citestcov_url:)
13
+ def initialize(api_key:, citestcycle_url:, api_url:, citestcov_url:, logs_intake_url:)
14
14
  @api_key = api_key
15
15
  @citestcycle_http = build_http_client(citestcycle_url, compress: true)
16
16
  @api_http = build_http_client(api_url, compress: false)
17
17
  @citestcov_http = build_http_client(citestcov_url, compress: true)
18
+ @logs_intake_http = build_http_client(logs_intake_url, compress: true)
18
19
  end
19
20
 
20
21
  def citestcycle_request(path:, payload:, headers: {}, verb: "post")
@@ -42,6 +43,12 @@ module Datadog
42
43
  perform_request(@citestcov_http, path: path, payload: @citestcov_payload, headers: headers, verb: verb)
43
44
  end
44
45
 
46
+ def logs_intake_request(path:, payload:, headers: {}, verb: "post")
47
+ super
48
+
49
+ perform_request(@logs_intake_http, path: path, payload: payload, headers: headers, verb: verb)
50
+ end
51
+
45
52
  private
46
53
 
47
54
  def perform_request(http_client, path:, payload:, headers:, verb:, accept_compressed_response: false)
@@ -38,6 +38,10 @@ module Datadog
38
38
  ].join("\r\n")
39
39
  end
40
40
 
41
+ def logs_intake_request(path:, payload:, headers: {}, verb: "post")
42
+ headers[Ext::Transport::HEADER_CONTENT_TYPE] ||= Ext::Transport::CONTENT_TYPE_JSON
43
+ end
44
+
41
45
  def headers_with_default(headers)
42
46
  request_headers = default_headers
43
47
  request_headers.merge!(headers)
@@ -27,11 +27,15 @@ module Datadog
27
27
  citestcov_url = settings.ci.agentless_url ||
28
28
  "https://#{Ext::Transport::TEST_COVERAGE_INTAKE_HOST_PREFIX}.#{dd_site}:443"
29
29
 
30
+ logs_intake_url = settings.ci.agentless_url ||
31
+ "https://#{Ext::Transport::LOGS_INTAKE_HOST_PREFIX}.#{dd_site}:443"
32
+
30
33
  Agentless.new(
31
34
  api_key: settings.api_key,
32
35
  citestcycle_url: citestcycle_url,
33
36
  api_url: api_url,
34
- citestcov_url: citestcov_url
37
+ citestcov_url: citestcov_url,
38
+ logs_intake_url: logs_intake_url
35
39
  )
36
40
  end
37
41
 
@@ -46,6 +46,10 @@ module Datadog
46
46
  perform_request(@agent_intake_http, path: path, payload: @citestcov_payload, headers: headers, verb: verb)
47
47
  end
48
48
 
49
+ def logs_intake_request(path:, payload:, headers: {}, verb: "post")
50
+ raise NotImplementedError, "Logs intake is not supported in EVP proxy mode"
51
+ end
52
+
49
53
  private
50
54
 
51
55
  def perform_request(http_client, path:, payload:, headers:, verb:)
@@ -4,7 +4,7 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = 1
7
- MINOR = 15
7
+ MINOR = 16
8
8
  PATCH = 0
9
9
  PRE = nil
10
10
  BUILD = nil
data/lib/datadog/ci.rb CHANGED
@@ -429,6 +429,9 @@ require_relative "ci/contrib/parallel_tests/integration"
429
429
  require_relative "ci/contrib/selenium/integration"
430
430
  require_relative "ci/contrib/cuprite/integration"
431
431
  require_relative "ci/contrib/simplecov/integration"
432
+ require_relative "ci/contrib/activesupport/integration"
433
+ require_relative "ci/contrib/lograge/integration"
434
+ require_relative "ci/contrib/semantic_logger/integration"
432
435
 
433
436
  # Configuration extensions
434
437
  require_relative "ci/configuration/extensions"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog-ci
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.0
4
+ version: 1.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-25 00:00:00.000000000 Z
10
+ date: 2025-04-15 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: datadog
@@ -74,6 +74,7 @@ files:
74
74
  - ext/datadog_cov/datadog_cov.c
75
75
  - ext/datadog_cov/extconf.rb
76
76
  - lib/datadog/ci.rb
77
+ - lib/datadog/ci/async_writer.rb
77
78
  - lib/datadog/ci/auto_instrument.rb
78
79
  - lib/datadog/ci/cli/cli.rb
79
80
  - lib/datadog/ci/cli/command/base.rb
@@ -87,6 +88,11 @@ files:
87
88
  - lib/datadog/ci/configuration/components.rb
88
89
  - lib/datadog/ci/configuration/extensions.rb
89
90
  - lib/datadog/ci/configuration/settings.rb
91
+ - lib/datadog/ci/contrib/activesupport/configuration/settings.rb
92
+ - lib/datadog/ci/contrib/activesupport/ext.rb
93
+ - lib/datadog/ci/contrib/activesupport/integration.rb
94
+ - lib/datadog/ci/contrib/activesupport/logs_formatter.rb
95
+ - lib/datadog/ci/contrib/activesupport/patcher.rb
90
96
  - lib/datadog/ci/contrib/ciqueue/integration.rb
91
97
  - lib/datadog/ci/contrib/ciqueue/patcher.rb
92
98
  - lib/datadog/ci/contrib/cucumber/configuration/settings.rb
@@ -108,6 +114,11 @@ files:
108
114
  - lib/datadog/ci/contrib/knapsack/integration.rb
109
115
  - lib/datadog/ci/contrib/knapsack/patcher.rb
110
116
  - lib/datadog/ci/contrib/knapsack/runner.rb
117
+ - lib/datadog/ci/contrib/lograge/configuration/settings.rb
118
+ - lib/datadog/ci/contrib/lograge/ext.rb
119
+ - lib/datadog/ci/contrib/lograge/integration.rb
120
+ - lib/datadog/ci/contrib/lograge/log_subscriber.rb
121
+ - lib/datadog/ci/contrib/lograge/patcher.rb
111
122
  - lib/datadog/ci/contrib/minitest/configuration/settings.rb
112
123
  - lib/datadog/ci/contrib/minitest/ext.rb
113
124
  - lib/datadog/ci/contrib/minitest/helpers.rb
@@ -138,6 +149,11 @@ files:
138
149
  - lib/datadog/ci/contrib/selenium/integration.rb
139
150
  - lib/datadog/ci/contrib/selenium/navigation.rb
140
151
  - lib/datadog/ci/contrib/selenium/patcher.rb
152
+ - lib/datadog/ci/contrib/semantic_logger/configuration/settings.rb
153
+ - lib/datadog/ci/contrib/semantic_logger/ext.rb
154
+ - lib/datadog/ci/contrib/semantic_logger/integration.rb
155
+ - lib/datadog/ci/contrib/semantic_logger/logger.rb
156
+ - lib/datadog/ci/contrib/semantic_logger/patcher.rb
141
157
  - lib/datadog/ci/contrib/settings.rb
142
158
  - lib/datadog/ci/contrib/simplecov/configuration/settings.rb
143
159
  - lib/datadog/ci/contrib/simplecov/ext.rb
@@ -178,6 +194,8 @@ files:
178
194
  - lib/datadog/ci/git/tree_uploader.rb
179
195
  - lib/datadog/ci/git/upload_packfile.rb
180
196
  - lib/datadog/ci/git/user.rb
197
+ - lib/datadog/ci/logs/component.rb
198
+ - lib/datadog/ci/logs/transport.rb
181
199
  - lib/datadog/ci/readonly_test_module.rb
182
200
  - lib/datadog/ci/readonly_test_session.rb
183
201
  - lib/datadog/ci/remote/component.rb
@@ -194,7 +212,6 @@ files:
194
212
  - lib/datadog/ci/test_optimisation/coverage/ddcov.rb
195
213
  - lib/datadog/ci/test_optimisation/coverage/event.rb
196
214
  - lib/datadog/ci/test_optimisation/coverage/transport.rb
197
- - lib/datadog/ci/test_optimisation/coverage/writer.rb
198
215
  - lib/datadog/ci/test_optimisation/skippable.rb
199
216
  - lib/datadog/ci/test_optimisation/skippable_percentage/base.rb
200
217
  - lib/datadog/ci/test_optimisation/skippable_percentage/calculator.rb
@@ -1,116 +0,0 @@
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
- module TestOptimisation
15
- module Coverage
16
- class Writer
17
- include Core::Workers::Queue
18
- include Core::Workers::Polling
19
-
20
- attr_reader :transport
21
-
22
- DEFAULT_BUFFER_MAX_SIZE = 10_000
23
- DEFAULT_SHUTDOWN_TIMEOUT = 60
24
-
25
- DEFAULT_INTERVAL = 3
26
-
27
- def initialize(transport:, options: {})
28
- @transport = transport
29
-
30
- # Workers::Polling settings
31
- self.enabled = options.fetch(:enabled, true)
32
-
33
- # Workers::Async::Thread settings
34
- self.fork_policy = Core::Workers::Async::Thread::FORK_POLICY_RESTART
35
-
36
- # Workers::IntervalLoop settings
37
- self.loop_base_interval = options[:interval] || DEFAULT_INTERVAL
38
- self.loop_back_off_ratio = options[:back_off_ratio] if options.key?(:back_off_ratio)
39
- self.loop_back_off_max = options[:back_off_max] if options.key?(:back_off_max)
40
-
41
- @buffer_size = options.fetch(:buffer_size, DEFAULT_BUFFER_MAX_SIZE)
42
-
43
- self.buffer = buffer_klass.new(@buffer_size)
44
-
45
- @shutdown_timeout = options.fetch(:shutdown_timeout, DEFAULT_SHUTDOWN_TIMEOUT)
46
-
47
- @stopped = false
48
- end
49
-
50
- def write(event)
51
- return if @stopped
52
-
53
- # Start worker thread. If the process has forked, it will trigger #after_fork to
54
- # reconfigure the worker accordingly.
55
- perform
56
-
57
- enqueue(event)
58
- end
59
-
60
- def perform(*events)
61
- responses = transport.send_events(events)
62
-
63
- if responses.find(&:server_error?)
64
- loop_back_off!
65
- Datadog.logger.warn { "Encountered server error while sending coverage events" }
66
- end
67
-
68
- nil
69
- rescue => e
70
- Datadog.logger.warn { "Error while sending coverage events: #{e}" }
71
- loop_back_off!
72
- end
73
-
74
- def stop(force_stop = false, timeout = @shutdown_timeout)
75
- @stopped = true
76
-
77
- buffer.close if running?
78
-
79
- super
80
- end
81
-
82
- def enqueue(event)
83
- buffer.push(event)
84
- end
85
-
86
- def dequeue
87
- buffer.pop
88
- end
89
-
90
- def work_pending?
91
- !buffer.empty?
92
- end
93
-
94
- def async?
95
- true
96
- end
97
-
98
- def after_fork
99
- # In multiprocess environments, forks will share the same buffer until its written to.
100
- # A.K.A. copy-on-write. We don't want forks to write events generated from another process.
101
- # Instead, we reset it after the fork. (Make sure any enqueue operations happen after this.)
102
- self.buffer = buffer_klass.new(@buffer_size)
103
- end
104
-
105
- def buffer_klass
106
- if Core::Environment::Ext::RUBY_ENGINE == "ruby"
107
- Core::Buffer::CRuby
108
- else
109
- Core::Buffer::ThreadSafe
110
- end
111
- end
112
- end
113
- end
114
- end
115
- end
116
- end