scout_apm_logging 0.0.0.1 → 0.0.3

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 (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/Rakefile +2 -0
  4. data/lib/scout_apm/logging/config.rb +4 -1
  5. data/lib/scout_apm/logging/loggers/capture.rb +45 -16
  6. data/lib/scout_apm/logging/loggers/logger.rb +8 -9
  7. data/lib/scout_apm/logging/loggers/patches/tagged_logging.rb +93 -0
  8. data/lib/scout_apm/logging/loggers/proxy.rb +6 -2
  9. data/lib/scout_apm/logging/loggers/swaps/rails.rb +77 -0
  10. data/lib/scout_apm/logging/loggers/swaps/scout.rb +62 -0
  11. data/lib/scout_apm/logging/loggers/swaps/sidekiq.rb +64 -0
  12. data/lib/scout_apm/logging/monitor/monitor.rb +2 -0
  13. data/lib/scout_apm/logging/monitor_manager/manager.rb +18 -6
  14. data/lib/scout_apm/logging/state.rb +13 -14
  15. data/lib/scout_apm/logging/version.rb +1 -1
  16. data/lib/scout_apm_logging.rb +1 -1
  17. data/scout_apm_logging.gemspec +0 -2
  18. data/spec/integration/loggers/capture_spec.rb +5 -15
  19. data/spec/integration/monitor/collector/downloader/will_verify_checksum.rb +2 -0
  20. data/spec/integration/monitor/collector_healthcheck_spec.rb +2 -0
  21. data/spec/integration/monitor/continuous_state_collector_spec.rb +2 -0
  22. data/spec/integration/monitor/previous_collector_setup_spec.rb +3 -0
  23. data/spec/integration/monitor_manager/disable_agent_spec.rb +2 -0
  24. data/spec/integration/monitor_manager/monitor_pid_file_spec.rb +2 -0
  25. data/spec/integration/rails/lifecycle_spec.rb +32 -3
  26. data/spec/rails/app.rb +38 -0
  27. data/spec/spec_helper.rb +2 -25
  28. data/spec/unit/loggers/capture_spec.rb +1 -16
  29. data/spec/unit/monitor/collector/configuration_spec.rb +3 -3
  30. metadata +9 -3
  31. data/lib/scout_apm/logging/loggers/swap.rb +0 -82
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 198bf309d17f0abfcf2c33f820a2d44e1e92ef5af9e321ee9fbaacfec256f032
4
- data.tar.gz: 2a09b14a45e702fe1e4f4caee6ff89475e14971ba9edad41ae5cf3c72ab97850
3
+ metadata.gz: bb4dc1a11fe63b4c983636958676d8ca7e76bb04c5281bdabd272373deaf83e5
4
+ data.tar.gz: 70809502cbbfb93a9cc73e26329f4e52b57008f51f9e34b3769fdfb17b2d46f4
5
5
  SHA512:
6
- metadata.gz: ebd30ceac50e2f14f3693946e8dd883112cc502513678b3a9963e253f2622d1ea488c2a66bce01f3e20726d7c6f08f61392cde6f22f1d9d0412987780f6399fa
7
- data.tar.gz: c0cfeb3cfbed2628772550b18b1a2f7965a144fafea14846ed65936043ae283b48cef6ba0109a05dfe9df3b826080d0f24676c0957b3909311cae12098b1e2de
6
+ metadata.gz: b3a17d497a14d952294dd23ce5eac8605f7cee5da807ba53cc312acafbe314c33a303d75d97ac828f3ea1aba40e733da1104aa655866121e7f3c149afc9935cb
7
+ data.tar.gz: 3515ffc8593bc564318859e0fb7340f82c2c066509a82411091b8e5e21bb4abcb223e1318d83b76a12ac11986db22bf4abaec5f511d6c07bdcaa5cc32742b7fd
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## 0.0.3
2
+ * **Feature**: Add support for TaggedLogging.
3
+ * Add ability to customize file logger size. Increase default size to 10MiB.
4
+ * Fix an issue with removing of the monitor process when Rails workers exited, which was only intended for when the main process exits.
5
+ * Fix an issue with the known monitored logs state being removed on port flushing.
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
1
3
  task :default => :test
2
4
 
3
5
  task :test do
@@ -54,6 +54,7 @@ module ScoutApm
54
54
  logs_config
55
55
  logs_reporting_endpoint
56
56
  logs_proxy_log_dir
57
+ logs_log_file_size
57
58
  manager_lock_file
58
59
  monitor_pid_file
59
60
  monitor_state_file
@@ -72,6 +73,7 @@ module ScoutApm
72
73
  SETTING_COERCIONS = {
73
74
  'logs_monitor' => BooleanCoercion.new,
74
75
  'logs_monitored' => JsonCoercion.new,
76
+ 'logs_log_file_size' => IntegerCoercion.new,
75
77
  'monitor_interval' => IntegerCoercion.new,
76
78
  'monitor_interval_delay' => IntegerCoercion.new,
77
79
  'health_check_port' => IntegerCoercion.new
@@ -227,8 +229,9 @@ module ScoutApm
227
229
  'log_level' => 'info',
228
230
  'logs_monitored' => [],
229
231
  'logs_capture_level' => 'debug',
230
- 'logs_reporting_endpoint' => 'https://otlp.telemetryhub.com:4317',
232
+ 'logs_reporting_endpoint' => 'https://otlp.scoutotel.com:4317',
231
233
  'logs_proxy_log_dir' => '/tmp/scout_apm/logs/',
234
+ 'logs_log_file_size' => 1024 * 1024 * 10,
232
235
  'manager_lock_file' => '/tmp/scout_apm/monitor_lock_file.lock',
233
236
  'monitor_pid_file' => '/tmp/scout_apm/scout_apm_log_monitor.pid',
234
237
  'monitor_state_file' => '/tmp/scout_apm/scout_apm_log_monitor_state.json',
@@ -2,8 +2,13 @@
2
2
 
3
3
  require 'logger'
4
4
 
5
- require_relative './swap'
5
+ require_relative './formatter'
6
+ require_relative './logger'
6
7
  require_relative './proxy'
8
+ require_relative './swaps/rails'
9
+ require_relative './swaps/sidekiq'
10
+ require_relative './swaps/scout'
11
+ require_relative './patches/tagged_logging'
7
12
 
8
13
  module ScoutApm
9
14
  module Logging
@@ -12,33 +17,57 @@ module ScoutApm
12
17
  class Capture
13
18
  attr_reader :context
14
19
 
20
+ KNOWN_LOGGERS = [
21
+ Swaps::Rails,
22
+ Swaps::Sidekiq,
23
+ Swaps::Scout
24
+ ].freeze
25
+
15
26
  def initialize(context)
16
27
  @context = context
17
28
  end
18
29
 
19
- def capture_log_locations! # rubocop:disable Metrics/AbcSize
20
- logger_instances << Rails.logger if defined?(Rails)
21
- logger_instances << Sidekiq.logger if defined?(Sidekiq)
22
- logger_instances << ObjectSpace.each_object(::ScoutTestLogger).to_a if defined?(::ScoutTestLogger)
30
+ def setup!
31
+ return unless context.config.value('logs_monitor')
23
32
 
24
- # Swap in our logger for each logger instance, in conjunction with the original class.
25
- updated_log_locations = logger_instances.compact.flatten.map do |logger|
26
- swapped_in_location(logger)
27
- end
33
+ create_proxy_log_dir!
28
34
 
29
- context.config.state.add_log_locations!(updated_log_locations)
35
+ add_logging_patches!
36
+ capture_and_swap_log_locations!
30
37
  end
31
38
 
32
39
  private
33
40
 
34
- def logger_instances
35
- @logger_instances ||= []
41
+ def create_proxy_log_dir!
42
+ Utils.ensure_directory_exists(context.config.value('logs_proxy_log_dir'))
43
+ end
44
+
45
+ def add_logging_patches!
46
+ # We can't swap out the logger similar to that of Rails and Sidekiq, as
47
+ # the TaggedLogging logger is dynamically generated.
48
+ return unless Rails.logger.respond_to?(:tagged)
49
+
50
+ ::ActiveSupport::TaggedLogging.prepend(Patches::TaggedLogging)
51
+
52
+ # Re-extend TaggedLogging to verify the patch is be applied.
53
+ # This appears to be an issue in Ruby 2.7 with the broadcast logger.
54
+ ruby_version = Gem::Version.new(RUBY_VERSION)
55
+ isruby27 = (ruby_version >= Gem::Version.new('2.7') && ruby_version < Gem::Version.new('3.0'))
56
+ return unless isruby27 && Rails.logger.respond_to?(:broadcasts)
57
+
58
+ Rails.logger.broadcasts.each do |logger|
59
+ logger.extend ::ActiveSupport::TaggedLogging
60
+ end
36
61
  end
37
62
 
38
- def swapped_in_location(log_instance)
39
- swap = Swap.new(context, log_instance)
40
- swap.update_logger!
41
- swap.log_location
63
+ def capture_and_swap_log_locations!
64
+ # We can move this to filter_map when our lagging version is Ruby 2.7
65
+ updated_log_locations = KNOWN_LOGGERS.map do |logger|
66
+ logger.new(context).update_logger! if logger.present?
67
+ end
68
+ updated_log_locations.compact!
69
+
70
+ context.config.state.add_log_locations!(updated_log_locations)
42
71
  end
43
72
  end
44
73
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
4
-
5
3
  module ScoutApm
6
4
  module Logging
7
5
  module Loggers
@@ -12,8 +10,6 @@ module ScoutApm
12
10
  class Logger
13
11
  attr_reader :context, :log_instance
14
12
 
15
- # 1 MiB
16
- LOG_SIZE = 1024 * 1024
17
13
  # 1 log file
18
14
  LOG_AGE = 1
19
15
 
@@ -23,13 +19,16 @@ module ScoutApm
23
19
  end
24
20
 
25
21
  def create_logger!
26
- # Defaults are 7 files with 10 MiB.
27
22
  # We create the file in order to prevent a creation header log.
28
23
  File.new(determine_file_path, 'w+') unless File.exist?(determine_file_path)
29
- new_logger = FileLogger.new(determine_file_path, LOG_AGE, LOG_SIZE)
30
- # Ruby's Logger handles a lot of the coercion itself.
31
- new_logger.level = context.config.value('logs_capture_level')
32
- new_logger
24
+ log_size = context.config.value('logs_log_file_size')
25
+
26
+ FileLogger.new(determine_file_path, LOG_AGE, log_size).tap do |logger|
27
+ # Ruby's Logger handles a lot of the coercion itself.
28
+ logger.level = context.config.value('logs_capture_level')
29
+ # Add our custom formatter to the logger.
30
+ logger.formatter = Formatter.new
31
+ end
33
32
  end
34
33
 
35
34
  def determine_file_path # rubocop:disable Metrics/AbcSize
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../logger'
4
+ require_relative '../formatter'
5
+ require_relative '../proxy'
6
+
7
+ module ScoutApm
8
+ module Logging
9
+ module Loggers
10
+ module Patches
11
+ # Patches TaggedLogging to work with our loggers.
12
+ module TaggedLogging
13
+ def tagged(*tags) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
14
+ super(*tags) unless (self == ::Rails.logger && is_a?(ScoutApm::Logging::Loggers::Proxy)) ||
15
+ (::Rails.logger.respond_to?(:broadcasts) && ::Rails.logger.broadcasts.include?(self))
16
+
17
+ if is_a?(ScoutApm::Logging::Loggers::Proxy)
18
+ if block_given?
19
+ # We skip the first logger to prevent double tagging when calling formatter.tagged
20
+ loggers = @loggers[1..]
21
+ pushed_counts = extend_and_push_tags(loggers, *tags)
22
+
23
+ formatter.tagged(*tags) { yield self }.tap do
24
+ logger_pop_tags(loggers, pushed_counts)
25
+ end
26
+ else
27
+ loggers = instance_variable_get(:@loggers)
28
+
29
+ new_loggers = create_cloned_extended_loggers(loggers, nil, *tags)
30
+
31
+ self.clone.tap do |cp| # rubocop:disable Style/RedundantSelf
32
+ cp.instance_variable_set(:@loggers, new_loggers)
33
+ end
34
+ end
35
+ elsif block_given?
36
+ # We skip the first logger to prevent double tagging when calling formatter.tagged
37
+ loggers = ::Rails.logger.broadcasts[1..]
38
+ pushed_counts = extend_and_push_tags(loggers, *tags)
39
+
40
+ formatter.tagged(*tags) { yield self }.tap do
41
+ logger_pop_tags(loggers, pushed_counts)
42
+ end
43
+ else
44
+ broadcasts = ::Rails.logger.broadcasts
45
+
46
+ tagged_loggers = broadcasts.select { |logger| logger.respond_to?(:tagged) }
47
+ file_logger = broadcasts.find { |logger| logger.is_a?(Loggers::FileLogger) }
48
+ loggers = tagged_loggers << file_logger
49
+
50
+ current_tags = tagged_loggers.first.formatter.current_tags
51
+
52
+ new_loggers = create_cloned_extended_loggers(loggers, current_tags, *tags)
53
+ Proxy.create_with_loggers(*new_loggers)
54
+ end
55
+ end
56
+
57
+ def create_cloned_extended_loggers(loggers, current_tags = nil, *tags)
58
+ loggers.map do |logger|
59
+ logger_current_tags = if current_tags
60
+ current_tags
61
+ elsif logger.formatter.respond_to?(:current_tags)
62
+ logger.formatter.current_tags
63
+ else
64
+ []
65
+ end
66
+
67
+ ::ActiveSupport::TaggedLogging.new(logger).tap do |new_logger|
68
+ if defined?(::ActiveSupport::TaggedLogging::LocalTagStorage)
69
+ new_logger.formatter.extend ::ActiveSupport::TaggedLogging::LocalTagStorage
70
+ end
71
+ new_logger.push_tags(*logger_current_tags, *tags)
72
+ end
73
+ end
74
+ end
75
+
76
+ def extend_and_push_tags(loggers, *tags)
77
+ loggers.map do |logger|
78
+ logger.formatter.extend ::ActiveSupport::TaggedLogging::Formatter unless logger.formatter.respond_to?(:tagged)
79
+
80
+ logger.formatter.push_tags(tags).size
81
+ end
82
+ end
83
+
84
+ def logger_pop_tags(loggers, pushed_counts)
85
+ loggers.map.with_index do |logger, index|
86
+ logger.formatter.pop_tags(pushed_counts[index])
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -1,12 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
4
-
5
3
  module ScoutApm
6
4
  module Logging
7
5
  module Loggers
8
6
  # Holds both the original application logger and the new one. Relays commands to both.
9
7
  class Proxy
8
+ def self.create_with_loggers(*loggers)
9
+ new.tap do |proxy_logger|
10
+ loggers.each { |logger| proxy_logger.add(logger) }
11
+ end
12
+ end
13
+
10
14
  def initialize
11
15
  @loggers = []
12
16
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ScoutApm
4
+ module Logging
5
+ module Loggers
6
+ module Swaps
7
+ # Swaps in our logger for the Rails logger.
8
+ class Rails
9
+ attr_reader :context
10
+
11
+ def self.present?
12
+ defined?(::Rails) && ::Rails.logger
13
+ end
14
+
15
+ def initialize(context)
16
+ @context = context
17
+ end
18
+
19
+ def update_logger!
20
+ # In Rails 7.1, broadcast logger was added which allows sinking to multiple IO devices.
21
+ if defined?(::ActiveSupport::BroadcastLogger) && log_instance.is_a?(::ActiveSupport::BroadcastLogger)
22
+ add_logger_to_broadcast!
23
+ else
24
+ swap_in_proxy_logger!
25
+ end
26
+
27
+ new_log_location
28
+ end
29
+
30
+ private
31
+
32
+ def log_instance
33
+ ::Rails.logger
34
+ end
35
+
36
+ def new_file_logger
37
+ @new_file_logger ||= Loggers::Logger.new(context, log_instance).create_logger!
38
+ end
39
+
40
+ # Eseentially creates the original logger.
41
+ def original_logger
42
+ # We can use the previous logdev. log_device will continuously call write
43
+ # through the devices until the logdev (@dev) is an IO device other than logdev:
44
+ # https://github.com/ruby/ruby/blob/master/lib/logger/log_device.rb#L42
45
+ # Log device holds the configurations around shifting too.
46
+ original_logdevice = log_instance.instance_variable_get(:@logdev)
47
+
48
+ ::Logger.new(original_logdevice).tap do |logger|
49
+ logger.formatter = log_instance.formatter
50
+ end
51
+ end
52
+
53
+ def new_log_location
54
+ new_file_logger.instance_variable_get(:@logdev).filename
55
+ end
56
+
57
+ def add_logger_to_broadcast!
58
+ log_instance.broadcast_to(new_file_logger)
59
+ end
60
+
61
+ def swap_in_proxy_logger!
62
+ # First logger needs to be the original logger for the return value of relayed calls.
63
+ proxy_logger = Proxy.create_with_loggers(original_logger, new_file_logger)
64
+ proxy_logger.extend ::ActiveSupport::TaggedLogging if log_instance.respond_to?(:tagged)
65
+
66
+ ::Rails.logger = proxy_logger
67
+
68
+ # We also need to swap some of the Rails railtie loggers.
69
+ ::ActiveRecord::Base.logger = proxy_logger if defined?(::ActiveRecord::Base)
70
+ ::ActionController::Base.logger = proxy_logger if defined?(::ActionController::Base)
71
+ ::ActiveJob::Base.logger = proxy_logger if defined?(::ActiveJob::Base)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ScoutApm
4
+ module Logging
5
+ module Loggers
6
+ module Swaps
7
+ # Swaps in our logger for the test Scout logger.
8
+ class Scout
9
+ attr_reader :context
10
+
11
+ def self.present?
12
+ defined?(::TestLoggerWrapper) && ::TestLoggerWrapper.logger
13
+ end
14
+
15
+ def initialize(context)
16
+ @context = context
17
+ end
18
+
19
+ def update_logger!
20
+ swap_in_proxy_logger!
21
+
22
+ new_log_location
23
+ end
24
+
25
+ private
26
+
27
+ def log_instance
28
+ ::TestLoggerWrapper.logger
29
+ end
30
+
31
+ def new_file_logger
32
+ @new_file_logger ||= Loggers::Logger.new(context, log_instance).create_logger!
33
+ end
34
+
35
+ # Eseentially creates the original logger.
36
+ def original_logger
37
+ # We can use the previous logdev. log_device will continuously call write
38
+ # through the devices until the logdev (@dev) is an IO device other than logdev:
39
+ # https://github.com/ruby/ruby/blob/master/lib/logger/log_device.rb#L42
40
+ # Log device holds the configurations around shifting too.
41
+ original_logdevice = log_instance.instance_variable_get(:@logdev)
42
+
43
+ ::Logger.new(original_logdevice).tap do |logger|
44
+ logger.formatter = log_instance.formatter
45
+ end
46
+ end
47
+
48
+ def new_log_location
49
+ new_file_logger.instance_variable_get(:@logdev).filename
50
+ end
51
+
52
+ def swap_in_proxy_logger!
53
+ # First logger needs to be the original logger for the return value of relayed calls.
54
+ proxy_logger = Proxy.create_with_loggers(original_logger, new_file_logger)
55
+
56
+ ::TestLoggerWrapper.logger = proxy_logger
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ScoutApm
4
+ module Logging
5
+ module Loggers
6
+ module Swaps
7
+ # Swaps in our logger for the Sidekiq logger.
8
+ class Sidekiq
9
+ attr_reader :context
10
+
11
+ def self.present?
12
+ defined?(::Sidekiq) && ::Sidekiq.logger
13
+ end
14
+
15
+ def initialize(context)
16
+ @context = context
17
+ end
18
+
19
+ def update_logger!
20
+ swap_in_proxy_logger!
21
+
22
+ new_log_location
23
+ end
24
+
25
+ private
26
+
27
+ def log_instance
28
+ ::Sidekiq.logger
29
+ end
30
+
31
+ def new_file_logger
32
+ @new_file_logger ||= Loggers::Logger.new(context, log_instance).create_logger!
33
+ end
34
+
35
+ # Eseentially creates the original logger.
36
+ def original_logger
37
+ # We can use the previous logdev. log_device will continuously call write
38
+ # through the devices until the logdev (@dev) is an IO device other than logdev:
39
+ # https://github.com/ruby/ruby/blob/master/lib/logger/log_device.rb#L42
40
+ # Log device holds the configurations around shifting too.
41
+ original_logdevice = log_instance.instance_variable_get(:@logdev)
42
+
43
+ ::Logger.new(original_logdevice).tap do |logger|
44
+ logger.formatter = log_instance.formatter
45
+ end
46
+ end
47
+
48
+ def new_log_location
49
+ new_file_logger.instance_variable_get(:@logdev).filename
50
+ end
51
+
52
+ def swap_in_proxy_logger!
53
+ # First logger needs to be the original logger for the return value of relayed calls.
54
+ proxy_logger = Proxy.create_with_loggers(original_logger, new_file_logger)
55
+
56
+ ::Sidekiq.configure_server do |config|
57
+ config.logger = proxy_logger
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -29,6 +29,7 @@ module ScoutApm
29
29
 
30
30
  def initialize
31
31
  @context = Context.new
32
+ context.logger.debug('Monitor instance created')
32
33
 
33
34
  context.application_root = $stdin.gets&.chomp
34
35
 
@@ -83,6 +84,7 @@ module ScoutApm
83
84
  exit if fork
84
85
  $stdin.reopen '/dev/null'
85
86
 
87
+ context.logger.debug("Monitor process daemonized, PID: #{Process.pid}")
86
88
  File.write(context.config.value('monitor_pid_file'), Process.pid)
87
89
  end
88
90
 
@@ -24,9 +24,6 @@ module ScoutApm
24
24
  add_exit_handler!
25
25
 
26
26
  determine_configuration_state
27
-
28
- # Continue to hold the lock until we have written the PID file.
29
- ensure_monitor_pid_file_exists
30
27
  end
31
28
 
32
29
  def determine_configuration_state
@@ -35,6 +32,9 @@ module ScoutApm
35
32
  if monitoring_enabled
36
33
  context.logger.info('Log monitoring enabled')
37
34
  create_process
35
+
36
+ # Continue to hold the lock until we have written the PID file.
37
+ ensure_monitor_pid_file_exists
38
38
  else
39
39
  context.logger.info('Log monitoring disabled')
40
40
  remove_processes
@@ -47,10 +47,16 @@ module ScoutApm
47
47
  # treated as the same file as before.
48
48
  # If logs get rotated, the fingerprint changes, and the collector automatically detects this.
49
49
  def add_exit_handler!
50
+ # With the use of unicorn and puma worker killer, we want to ensure we only restart (exit and
51
+ # eventually start) the monitor and collector when the main process exits, and not the workers.
52
+ initialized_process_id = Process.pid
50
53
  at_exit do
51
54
  # Only remove/restart the monitor and collector if we are exiting from an app_server process.
52
55
  # We need to wait on this check, as the process command line changes at some point.
53
- remove_processes if Utils.current_process_is_app_server?
56
+ if Utils.current_process_is_app_server? && Process.pid == initialized_process_id
57
+ context.logger.debug('Exiting from app server process. Removing monitor and collector processes.')
58
+ remove_processes
59
+ end
54
60
  end
55
61
  end
56
62
 
@@ -64,12 +70,15 @@ module ScoutApm
64
70
  gem_directory = File.expand_path('../../../..', __dir__)
65
71
 
66
72
  # As we daemonize the process, we will write to the pid file within the process.
67
- Process.spawn("ruby #{gem_directory}/bin/scout_apm_logging_monitor", in: reader)
73
+ pid = Process.spawn("ruby #{gem_directory}/bin/scout_apm_logging_monitor", in: reader)
68
74
 
69
75
  reader.close
70
76
  # TODO: Add support for Sinatra.
71
77
  writer.puts Rails.root if defined?(Rails)
72
78
  writer.close
79
+ # Block until we have spawned the process and forked. This is to ensure
80
+ # we keep the exclusive lock until the process has written the PID file.
81
+ Process.wait(pid)
73
82
  end
74
83
 
75
84
  private
@@ -81,7 +90,10 @@ module ScoutApm
81
90
 
82
91
  # Naive benchmarks show this taking ~0.01 seconds.
83
92
  loop do
84
- break if File.exist?(context.config.value('monitor_pid_file'))
93
+ if File.exist?(context.config.value('monitor_pid_file'))
94
+ context.logger.debug('Monitor PID file exists. Releasing lock.')
95
+ break
96
+ end
85
97
 
86
98
  if Time.now - start_time > timeout_seconds
87
99
  context.logger.warn('Unable to verify monitor PID file write. Releasing lock.')
@@ -28,18 +28,16 @@ module ScoutApm
28
28
  memo[key] = context.config.value(key)
29
29
  end
30
30
 
31
- unless updated_log_locations.empty?
32
- contents = file.read
31
+ contents = file.read
32
+ old_log_state_files = if contents.empty?
33
+ []
34
+ else
35
+ current_data = JSON.parse(contents)
36
+ current_data['logs_monitored']
37
+ end
33
38
 
34
- olds_log_files = if contents.empty?
35
- []
36
- else
37
- current_data = JSON.parse(contents)
38
- current_data['logs_monitored']
39
- end
40
-
41
- data['logs_monitored'] = merge_and_dedup_log_locations(updated_log_locations, olds_log_files)
42
- end
39
+ data['logs_monitored'] =
40
+ merge_and_dedup_log_locations(updated_log_locations, old_log_state_files, data['logs_monitored'])
43
41
 
44
42
  file.rewind # Move cursor to beginning of the file
45
43
  file.truncate(0) # Truncate existing content
@@ -55,9 +53,10 @@ module ScoutApm
55
53
 
56
54
  # Should we add better detection for similar basenames but different paths?
57
55
  # May be a bit tricky with tools like capistrano and releases paths differentiated by time.
58
- def merge_and_dedup_log_locations(new_logs, old_logs)
59
- # Take the new logs if duplication, as we could be in a newer release.
60
- merged = (new_logs + old_logs).each_with_object({}) do |log_path, hash|
56
+ def merge_and_dedup_log_locations(*log_locations)
57
+ # Take the new logs if duplication (those first passed in the args) as we could be in a newer release.
58
+ logs = log_locations.reduce([], :concat)
59
+ merged = logs.each_with_object({}) do |log_path, hash|
61
60
  base_name = File.basename(log_path)
62
61
  hash[base_name] ||= log_path
63
62
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ScoutApm
4
4
  module Logging
5
- VERSION = '0.0.0.1'
5
+ VERSION = '0.0.3'
6
6
  end
7
7
  end
@@ -21,7 +21,7 @@ module ScoutApm
21
21
  initializer 'scout_apm_logging.monitor' do
22
22
  context = ScoutApm::Logging::MonitorManager.instance.context
23
23
 
24
- Loggers::Capture.new(context).capture_log_locations!
24
+ Loggers::Capture.new(context).setup!
25
25
 
26
26
  unless Utils.skip_setup?
27
27
  Utils.attempt_exclusive_lock(context) do
@@ -1,5 +1,3 @@
1
- require "bundler/gem_tasks"
2
-
3
1
  $LOAD_PATH.push File.expand_path('lib', __dir__)
4
2
  require 'scout_apm/logging/version'
5
3
 
@@ -2,6 +2,8 @@ require 'logger'
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
+ require_relative '../../../lib/scout_apm/logging/loggers/capture'
6
+
5
7
  describe ScoutApm::Logging::Loggers::Capture do
6
8
  it 'should find the logger, capture the log destination, and rotate collector configs' do
7
9
  ENV['SCOUT_MONITOR_INTERVAL'] = '10'
@@ -17,9 +19,7 @@ describe ScoutApm::Logging::Loggers::Capture do
17
19
  first_logger = ScoutTestLogger.new('/tmp/first_file.log')
18
20
  first_logger_basename = File.basename(first_logger.instance_variable_get(:@logdev).filename.to_s)
19
21
  first_logger_updated_path = File.join(context.config.value('logs_proxy_log_dir'), first_logger_basename)
20
-
21
- # While we only use the ObjectSpace for the test logger, we need to wait for it to be captured.
22
- wait_for_logger
22
+ TestLoggerWrapper.logger = first_logger
23
23
 
24
24
  similuate_railtie
25
25
 
@@ -36,6 +36,7 @@ describe ScoutApm::Logging::Loggers::Capture do
36
36
  second_logger = ScoutTestLogger.new('/tmp/second_file.log')
37
37
  second_logger_basename = File.basename(second_logger.instance_variable_get(:@logdev).filename.to_s)
38
38
  second_logger_updated_path = File.join(context.config.value('logs_proxy_log_dir'), second_logger_basename)
39
+ TestLoggerWrapper.logger = second_logger
39
40
 
40
41
  similuate_railtie
41
42
 
@@ -61,18 +62,7 @@ describe ScoutApm::Logging::Loggers::Capture do
61
62
  def similuate_railtie
62
63
  context = ScoutApm::Logging::MonitorManager.instance.context
63
64
 
64
- ScoutApm::Logging::Loggers::Capture.new(context).capture_log_locations!
65
+ ScoutApm::Logging::Loggers::Capture.new(context).setup!
65
66
  ScoutApm::Logging::MonitorManager.new.setup!
66
67
  end
67
-
68
- def wait_for_logger
69
- start_time = Time.now
70
- loop do
71
- break if ObjectSpace.each_object(ScoutTestLogger).count.positive?
72
-
73
- raise 'Timed out while waiting for logger in ObjectSpace' if Time.now - start_time > 10
74
-
75
- sleep 0.1
76
- end
77
- end
78
68
  end
@@ -12,7 +12,9 @@ describe ScoutApm::Logging::Collector::Downloader do
12
12
 
13
13
  File.write(otelcol_contrib_path, 'fake content')
14
14
 
15
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time start: #{Time.now}"
15
16
  ScoutApm::Logging::MonitorManager.instance.setup!
17
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time after setup: #{Time.now}"
16
18
 
17
19
  # Give the process time to initialize, download the collector, and start it
18
20
  wait_for_process_with_timeout!('otelcol-contrib', 20)
@@ -11,7 +11,9 @@ describe ScoutApm::Logging::Monitor do
11
11
 
12
12
  ScoutApm::Logging::Utils.ensure_directory_exists('/tmp/scout_apm/scout_apm_log_monitor.pid')
13
13
 
14
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time start: #{Time.now}"
14
15
  ScoutApm::Logging::MonitorManager.instance.setup!
16
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time after setup: #{Time.now}"
15
17
 
16
18
  # Give the process time to initialize, download the collector, and start it
17
19
  wait_for_process_with_timeout!('otelcol-contrib', 20)
@@ -11,7 +11,9 @@ describe ScoutApm::Logging::Monitor do
11
11
 
12
12
  context = ScoutApm::Logging::MonitorManager.instance.context
13
13
  collector_pid_location = context.config.value('collector_pid_file')
14
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time start: #{Time.now}"
14
15
  ScoutApm::Logging::MonitorManager.instance.setup!
16
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time after setup: #{Time.now}"
15
17
  # Give the process time to initialize, download the collector, and start it
16
18
  wait_for_process_with_timeout!('otelcol-contrib', 20)
17
19
 
@@ -11,7 +11,10 @@ describe ScoutApm::Logging::Monitor do
11
11
  collector_pid_location = ScoutApm::Logging::MonitorManager.instance.context.config.value('collector_pid_file')
12
12
  ScoutApm::Logging::Utils.ensure_directory_exists(monitor_pid_location)
13
13
 
14
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time start: #{Time.now}"
14
15
  ScoutApm::Logging::MonitorManager.instance.setup!
16
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time after setup: #{Time.now}"
17
+
15
18
  # Give the process time to initialize, download the collector, and start it
16
19
  wait_for_process_with_timeout!('otelcol-contrib', 20)
17
20
 
@@ -9,7 +9,9 @@ describe ScoutApm::Logging::Collector::Manager do
9
9
 
10
10
  expect(`pgrep otelcol-contrib --runstates D,R,S`).to be_empty
11
11
 
12
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time start: #{Time.now}"
12
13
  ScoutApm::Logging::MonitorManager.instance.setup!
14
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time after setup: #{Time.now}"
13
15
 
14
16
  wait_for_process_with_timeout!('otelcol-contrib', 20)
15
17
 
@@ -15,7 +15,9 @@ describe ScoutApm::Logging::Collector::Manager do
15
15
  file.write('123456')
16
16
  end
17
17
 
18
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time start: #{Time.now}"
18
19
  ScoutApm::Logging::MonitorManager.instance.setup!
20
+ ScoutApm::Logging::MonitorManager.instance.context.logger.info "Time after setup: #{Time.now}"
19
21
 
20
22
  # Give the process time to initialize, download the collector, and start it
21
23
  wait_for_process_with_timeout!('otelcol-contrib', 20)
@@ -1,14 +1,17 @@
1
1
  require 'spec_helper'
2
+ require_relative '../../rails/app'
2
3
 
3
4
  describe ScoutApm::Logging do
4
5
  it 'checks the Rails lifecycle for creating the daemon and collector processes' do
5
6
  ENV['SCOUT_LOGS_MONITOR'] = 'true'
6
- ENV['SCOUT_LOGS_MONITORED'] = '["/tmp/test.log"]'
7
7
 
8
- pid_file = ScoutApm::Logging::MonitorManager.instance.context.config.value('monitor_pid_file')
8
+ context = ScoutApm::Logging::MonitorManager.instance.context
9
+ pid_file = context.config.value('monitor_pid_file')
9
10
  expect(File.exist?(pid_file)).to be_falsey
10
11
 
11
- make_basic_app
12
+ rails_pid = fork do
13
+ initialize_app
14
+ end
12
15
 
13
16
  wait_for_process_with_timeout!('otelcol-contrib', 20)
14
17
 
@@ -21,6 +24,32 @@ describe ScoutApm::Logging do
21
24
  # Check if the process with the stored PID is running
22
25
  expect(ScoutApm::Logging::Utils.check_process_liveliness(pid, 'scout_apm_logging_monitor')).to be_truthy
23
26
 
27
+ # Call the app to generate the logs
28
+ `curl localhost:8080`
29
+
30
+ proxy_dir = context.config.value('logs_proxy_log_dir')
31
+ files = Dir.entries(proxy_dir) - ['.', '..']
32
+ log_file = File.join(proxy_dir, files[0])
33
+
34
+ lines = []
35
+ File.open(log_file, 'r') do |file|
36
+ file.each_line do |line|
37
+ # Parse each line as JSON
38
+ lines << JSON.parse(line)
39
+ rescue JSON::ParserError => e
40
+ puts e
41
+ end
42
+ end
43
+
44
+ messages = lines.map { |item| item['msg'] }
45
+
46
+ # Verify we have all the logs
47
+ expect(messages.count('[TEST] Some log')).to eq(1)
48
+ expect(messages.count('[YIELD] Yield Test')).to eq(1)
49
+ expect(messages.count('Another Log')).to eq(1)
50
+
51
+ # Kill the rails process. We use kill as using any other signal throws a long log line.
52
+ Process.kill('KILL', rails_pid)
24
53
  # Kill the process and ensure PID file clean up
25
54
  Process.kill('TERM', pid)
26
55
  sleep 1 # Give the process time to exit
data/spec/rails/app.rb ADDED
@@ -0,0 +1,38 @@
1
+ # https://github.com/rack/rack/pull/1937
2
+ begin
3
+ require 'rackup'
4
+ rescue LoadError # rubocop:disable Lint/SuppressedException
5
+ end
6
+
7
+ require 'action_controller/railtie'
8
+ require 'logger'
9
+ require 'scout_apm_logging'
10
+
11
+ Rails.logger = ActiveSupport::TaggedLogging.new(Logger.new($stdout))
12
+
13
+ class App < ::Rails::Application
14
+ config.eager_load = false
15
+
16
+ routes.append do
17
+ root to: 'root#index'
18
+ end
19
+ end
20
+
21
+ class RootController < ActionController::Base
22
+ def index
23
+ Rails.logger.tagged('TEST').info('Some log')
24
+ Rails.logger.tagged('YIELD') { logger.info('Yield Test') }
25
+ Rails.logger.info('Another Log')
26
+ render plain: Rails.version
27
+ end
28
+ end
29
+
30
+ def initialize_app
31
+ App.initialize!
32
+
33
+ if defined?(Rack::Server)
34
+ Rack::Server.start(app: App)
35
+ else
36
+ Rackup::Server.start(app: App)
37
+ end
38
+ end
data/spec/spec_helper.rb CHANGED
@@ -21,38 +21,15 @@ class ScoutTestLogger < ::Logger
21
21
  end
22
22
 
23
23
  RSpec.configure do |config|
24
+ ENV["SCOUT_LOG_FILE_PATH"] = "STDOUT"
24
25
  ENV["SCOUT_LOG_LEVEL"] = "debug"
25
- ENV["SCOUT_COLLECTOR_LOG_LEVEL"] = "debug"
26
+ ENV["SCOUT_COLLECTOR_LOG_LEVEL"] = "info"
26
27
 
27
28
  config.after(:each) do
28
29
  RSpec::Mocks.space.reset_all
29
30
  end
30
31
  end
31
32
 
32
- # Taken from:
33
- # https://github.com/rails/rails/blob/v7.1.3.2/railties/test/isolation/abstract_unit.rb#L252
34
- def make_basic_app
35
- @app = Class.new(Rails::Application) do
36
- def self.name; "RailtiesTestApp"; end
37
- end
38
- @app.config.hosts << proc { true }
39
- @app.config.eager_load = false
40
- @app.config.session_store :cookie_store, key: "_myapp_session"
41
- @app.config.active_support.deprecation = :log
42
- @app.config.log_level = :info
43
- @app.config.secret_key_base = "b3c631c314c0bbca50c1b2843150fe33"
44
-
45
- yield @app if block_given?
46
- @app.initialize!
47
-
48
- @app.routes.draw do
49
- get "/" => "omg#index"
50
- end
51
-
52
- require "rack/test"
53
- extend ::Rack::Test::Methods
54
- end
55
-
56
33
  def wait_for_process_with_timeout!(name, timeout_time)
57
34
  Timeout::timeout(timeout_time) do
58
35
  loop do
@@ -4,7 +4,6 @@ require 'stringio'
4
4
  require 'spec_helper'
5
5
 
6
6
  require_relative '../../../lib/scout_apm/logging/loggers/capture'
7
- require_relative '../../../lib/scout_apm/logging/loggers/proxy'
8
7
 
9
8
  def capture_stdout
10
9
  old_stdout = $stdout
@@ -29,11 +28,8 @@ describe ScoutApm::Logging::Loggers::Capture do
29
28
 
30
29
  TestLoggerWrapper.logger = ScoutTestLogger.new($stdout)
31
30
 
32
- # While we only use the ObjectSpace for the test logger, we need to wait for it to be captured.
33
- wait_for_logger
34
-
35
31
  capture = ScoutApm::Logging::Loggers::Capture.new(context)
36
- capture.capture_log_locations!
32
+ capture.setup!
37
33
 
38
34
  expect(TestLoggerWrapper.logger.class).to eq(ScoutApm::Logging::Loggers::Proxy)
39
35
 
@@ -50,15 +46,4 @@ describe ScoutApm::Logging::Loggers::Capture do
50
46
 
51
47
  expect(output_from_log).to include('TEST')
52
48
  end
53
-
54
- def wait_for_logger
55
- start_time = Time.now
56
- loop do
57
- break if ObjectSpace.each_object(::ScoutTestLogger).count.positive?
58
-
59
- raise 'Timed out while waiting for logger in ObjectSpace' if Time.now - start_time > 10
60
-
61
- sleep 0.1
62
- end
63
- end
64
49
  end
@@ -12,7 +12,7 @@ describe ScoutApm::Logging::Collector::Configuration do
12
12
  expect(File.exist?(context.config.value('collector_config_file'))).to be_truthy
13
13
  config = YAML.load_file(context.config.value('collector_config_file'))
14
14
 
15
- expect(config['exporters']['otlp']['endpoint']).to eq('https://otlp.telemetryhub.com:4317')
15
+ expect(config['exporters']['otlp']['endpoint']).to eq('https://otlp.scoutotel.com:4317')
16
16
  expect(config['exporters']['otlp']['headers']['x-telemetryhub-key']).to eq('00001000010000abc')
17
17
  expect(config['receivers']['filelog']['include']).to eq(['/tmp/fake_log_file.log'])
18
18
  end
@@ -26,7 +26,7 @@ describe ScoutApm::Logging::Collector::Configuration do
26
26
  expect(File.exist?(context.config.value('collector_config_file'))).to be_truthy
27
27
  config = YAML.load_file(context.config.value('collector_config_file'))
28
28
 
29
- expect(config['exporters']['otlp']['endpoint']).to eq('https://otlp.telemetryhub.com:4317')
29
+ expect(config['exporters']['otlp']['endpoint']).to eq('https://otlp.scoutotel.com:4317')
30
30
  expect(config['exporters']['otlp']['headers']['x-telemetryhub-key']).to eq('00001000010000abc')
31
31
  expect(config['receivers']['filelog']['include']).to eq(['/tmp/fake_log_file.log'])
32
32
 
@@ -44,7 +44,7 @@ describe ScoutApm::Logging::Collector::Configuration do
44
44
  expect(File.exist?(context.config.value('collector_config_file'))).to be_truthy
45
45
  config = YAML.load_file(context.config.value('collector_config_file'))
46
46
 
47
- expect(config['exporters']['otlp']['endpoint']).to eq('https://otlp.telemetryhub.com:4317')
47
+ expect(config['exporters']['otlp']['endpoint']).to eq('https://otlp.scoutotel.com:4317')
48
48
  expect(config['exporters']['otlp']['headers']['x-telemetryhub-key']).to eq('00001000010000abc')
49
49
  expect(config['receivers']['filelog']['include']).to eq(['/tmp/fake_log_file.log'])
50
50
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout_apm_logging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scout APM
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-16 00:00:00.000000000 Z
11
+ date: 2024-08-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: scout_apm
@@ -76,6 +76,7 @@ files:
76
76
  - ".github/workflows/test.yml"
77
77
  - ".gitignore"
78
78
  - ".rubocop.yml"
79
+ - CHANGELOG.md
79
80
  - Dockerfile
80
81
  - Gemfile
81
82
  - README.md
@@ -88,8 +89,11 @@ files:
88
89
  - lib/scout_apm/logging/loggers/capture.rb
89
90
  - lib/scout_apm/logging/loggers/formatter.rb
90
91
  - lib/scout_apm/logging/loggers/logger.rb
92
+ - lib/scout_apm/logging/loggers/patches/tagged_logging.rb
91
93
  - lib/scout_apm/logging/loggers/proxy.rb
92
- - lib/scout_apm/logging/loggers/swap.rb
94
+ - lib/scout_apm/logging/loggers/swaps/rails.rb
95
+ - lib/scout_apm/logging/loggers/swaps/scout.rb
96
+ - lib/scout_apm/logging/loggers/swaps/sidekiq.rb
93
97
  - lib/scout_apm/logging/monitor/collector/checksum.rb
94
98
  - lib/scout_apm/logging/monitor/collector/configuration.rb
95
99
  - lib/scout_apm/logging/monitor/collector/downloader.rb
@@ -116,6 +120,7 @@ files:
116
120
  - spec/integration/monitor_manager/monitor_pid_file_spec.rb
117
121
  - spec/integration/monitor_manager/single_monitor_spec.rb
118
122
  - spec/integration/rails/lifecycle_spec.rb
123
+ - spec/rails/app.rb
119
124
  - spec/spec_helper.rb
120
125
  - spec/unit/config_spec.rb
121
126
  - spec/unit/loggers/capture_spec.rb
@@ -160,6 +165,7 @@ test_files:
160
165
  - spec/integration/monitor_manager/monitor_pid_file_spec.rb
161
166
  - spec/integration/monitor_manager/single_monitor_spec.rb
162
167
  - spec/integration/rails/lifecycle_spec.rb
168
+ - spec/rails/app.rb
163
169
  - spec/spec_helper.rb
164
170
  - spec/unit/config_spec.rb
165
171
  - spec/unit/loggers/capture_spec.rb
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'logger'
4
-
5
- require_relative './formatter'
6
- require_relative './logger'
7
-
8
- module ScoutApm
9
- module Logging
10
- module Loggers
11
- # Swaps in our logger for the application's logger.
12
- class Swap
13
- attr_reader :context, :log_instance, :new_file_logger
14
-
15
- def initialize(context, log_instance)
16
- @context = context
17
- @log_instance = log_instance
18
- end
19
-
20
- def update_logger!
21
- create_proxy_log_dir!
22
-
23
- # In Rails 7.1, broadcast logger was added which allows sinking to multiple IO devices.
24
- if defined?(::ActiveSupport::BroadcastLogger) && log_instance.is_a?(::ActiveSupport::BroadcastLogger)
25
- add_logger_to_broadcast!
26
- else
27
- swap_in_proxy_logger!
28
- end
29
- end
30
-
31
- def log_location
32
- new_file_logger.instance_variable_get(:@logdev).filename
33
- end
34
-
35
- private
36
-
37
- def add_logger_to_broadcast!
38
- @new_file_logger = create_file_logger
39
- @new_file_logger.formatter = Loggers::Formatter.new
40
-
41
- log_instance.broadcast_to(new_file_logger)
42
- end
43
-
44
- def swap_in_proxy_logger! # rubocop:disable Metrics/AbcSize
45
- proxy_logger = Proxy.new
46
- # We can use the previous logdev. log_device will continuously call write
47
- # through the devices until the logdev (@dev) is an IO device other than logdev:
48
- # https://github.com/ruby/ruby/blob/master/lib/logger/log_device.rb#L42
49
- # Log device holds the configurations around shifting too.
50
- original_logdevice = log_instance.instance_variable_get(:@logdev)
51
- updated_original_logger = ::Logger.new(original_logdevice)
52
- updated_original_logger.formatter = log_instance.formatter
53
-
54
- @new_file_logger = create_file_logger
55
- @new_file_logger.formatter = Loggers::Formatter.new
56
-
57
- # First logger needs to be the original logger for the return value of relayed calls.
58
- proxy_logger.add(updated_original_logger)
59
- proxy_logger.add(new_file_logger)
60
-
61
- if defined?(::ActiveSupport::Logger) && log_instance.is_a?(::ActiveSupport::Logger)
62
- Rails.logger = proxy_logger
63
- elsif defined?(::Sidekiq::Logger) && log_instance.is_a?(::Sidekiq::Logger)
64
- Sidekiq.configure_server do |config|
65
- config.logger = proxy_logger
66
- end
67
- elsif defined?(::ScoutTestLogger) && log_instance.is_a?(::ScoutTestLogger)
68
- TestLoggerWrapper.logger = proxy_logger
69
- end
70
- end
71
-
72
- def create_file_logger
73
- Loggers::Logger.new(context, log_instance).create_logger!
74
- end
75
-
76
- def create_proxy_log_dir!
77
- Utils.ensure_directory_exists(context.config.value('logs_proxy_log_dir'))
78
- end
79
- end
80
- end
81
- end
82
- end