scout_apm_logging 0.0.13 → 1.0.1

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -4
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +6 -0
  5. data/NOTICE +4 -0
  6. data/lib/scout_apm/logging/config.rb +5 -131
  7. data/lib/scout_apm/logging/loggers/capture.rb +3 -2
  8. data/lib/scout_apm/logging/loggers/formatter.rb +21 -2
  9. data/lib/scout_apm/logging/loggers/opentelemetry/LICENSE +201 -0
  10. data/lib/scout_apm/logging/loggers/opentelemetry/NOTICE +9 -0
  11. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/log_record.rb +18 -0
  12. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger.rb +64 -0
  13. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger_provider.rb +31 -0
  14. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/severity_number.rb +43 -0
  15. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/version.rb +18 -0
  16. data/lib/scout_apm/logging/loggers/opentelemetry/api/logs.rb +28 -0
  17. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/logs_exporter.rb +389 -0
  18. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/version.rb +20 -0
  19. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/collector/logs/v1/logs_service_pb.rb +43 -0
  20. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/common/v1/common_pb.rb +58 -0
  21. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/logs/v1/logs_pb.rb +91 -0
  22. data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/resource/v1/resource_pb.rb +33 -0
  23. data/lib/scout_apm/logging/loggers/opentelemetry/opentelemetry.rb +62 -0
  24. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/batch_log_record_processor.rb +225 -0
  25. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/log_record_exporter.rb +64 -0
  26. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export.rb +34 -0
  27. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record.rb +115 -0
  28. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_data.rb +31 -0
  29. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_processor.rb +53 -0
  30. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger.rb +94 -0
  31. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger_provider.rb +158 -0
  32. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/version.rb +20 -0
  33. data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs.rb +28 -0
  34. data/lib/scout_apm/logging/utils.rb +0 -69
  35. data/lib/scout_apm/logging/version.rb +1 -1
  36. data/lib/scout_apm_logging.rb +2 -11
  37. data/scout_apm_logging.gemspec +7 -0
  38. data/spec/data/config_test_1.yml +0 -1
  39. data/spec/data/mock_config.yml +0 -3
  40. data/spec/integration/rails/lifecycle_spec.rb +57 -23
  41. data/spec/spec_helper.rb +0 -12
  42. data/spec/unit/config_spec.rb +0 -12
  43. data/spec/unit/loggers/capture_spec.rb +0 -6
  44. metadata +126 -39
  45. data/bin/scout_apm_logging_monitor +0 -6
  46. data/lib/scout_apm/logging/monitor/_rails.rb +0 -22
  47. data/lib/scout_apm/logging/monitor/collector/checksum.rb +0 -51
  48. data/lib/scout_apm/logging/monitor/collector/configuration.rb +0 -150
  49. data/lib/scout_apm/logging/monitor/collector/downloader.rb +0 -78
  50. data/lib/scout_apm/logging/monitor/collector/extractor.rb +0 -37
  51. data/lib/scout_apm/logging/monitor/collector/manager.rb +0 -57
  52. data/lib/scout_apm/logging/monitor/monitor.rb +0 -216
  53. data/lib/scout_apm/logging/monitor_manager/manager.rb +0 -162
  54. data/lib/scout_apm/logging/state.rb +0 -69
  55. data/spec/data/empty_logs_config.yml +0 -0
  56. data/spec/data/logs_config.yml +0 -3
  57. data/spec/data/state_file.json +0 -3
  58. data/spec/integration/loggers/capture_spec.rb +0 -68
  59. data/spec/integration/monitor/collector/downloader/will_verify_checksum.rb +0 -49
  60. data/spec/integration/monitor/collector_healthcheck_spec.rb +0 -29
  61. data/spec/integration/monitor/continuous_state_collector_spec.rb +0 -31
  62. data/spec/integration/monitor/previous_collector_setup_spec.rb +0 -45
  63. data/spec/integration/monitor_manager/disable_agent_spec.rb +0 -30
  64. data/spec/integration/monitor_manager/monitor_pid_file_spec.rb +0 -38
  65. data/spec/integration/monitor_manager/single_monitor_spec.rb +0 -53
  66. data/spec/unit/monitor/collector/configuration_spec.rb +0 -64
  67. data/spec/unit/state_spec.rb +0 -20
  68. data/tooling/checksums.rb +0 -106
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module ScoutApm
8
+ module Logging
9
+ module Loggers
10
+ module OpenTelemetry
11
+ module SDK
12
+ module Logs
13
+ # The SDK implementation of OpenTelemetry::Logs::Logger
14
+ class Logger < OpenTelemetry::Logs::Logger
15
+ # @api private
16
+ #
17
+ # Returns a new {OpenTelemetry::SDK::Logs::Logger} instance. This should
18
+ # not be called directly. New loggers should be created using
19
+ # {LoggerProvider#logger}.
20
+ #
21
+ # @param [String] name Instrumentation package name
22
+ # @param [String] version Instrumentation package version
23
+ # @param [LoggerProvider] logger_provider The {LoggerProvider} that
24
+ # initialized the logger
25
+ #
26
+ # @return [OpenTelemetry::SDK::Logs::Logger]
27
+ def initialize(name, version, logger_provider)
28
+ @instrumentation_scope = ::OpenTelemetry::SDK::InstrumentationScope.new(name, version)
29
+ @logger_provider = logger_provider
30
+ end
31
+
32
+ # Emit a {LogRecord} to the processing pipeline.
33
+ #
34
+ # @param [optional Time] timestamp Time when the event occurred.
35
+ # @param [optional Time] observed_timestamp Time when the event was
36
+ # observed by the collection system.
37
+ # @param [optional OpenTelemetry::Trace::SpanContext] span_context The
38
+ # OpenTelemetry::Trace::SpanContext to associate with the
39
+ # {LogRecord}.
40
+ # @param severity_number [optional Integer] Numerical value of the
41
+ # severity. Smaller numerical values correspond to less severe events
42
+ # (such as debug events), larger numerical values correspond to more
43
+ # severe events (such as errors and critical events).
44
+ # @param [optional String, Numeric, Boolean, Array<String, Numeric,
45
+ # Boolean>, Hash{String => String, Numeric, Boolean, Array<String,
46
+ # Numeric, Boolean>}] body A value containing the body of the log record.
47
+ # @param [optional Hash{String => String, Numeric, Boolean,
48
+ # Array<String, Numeric, Boolean>}] attributes Additional information
49
+ # about the event.
50
+ # @param [optional String (16-byte binary)] trace_id Request trace id as
51
+ # defined in {https://www.w3.org/TR/trace-context/#trace-id W3C Trace Context}.
52
+ # Can be set for logs that are part of request processing and have an
53
+ # assigned trace id.
54
+ # @param [optional String (8-byte binary)] span_id Span id. Can be set
55
+ # for logs that are part of a particular processing span. If span_id
56
+ # is present trace_id should also be present.
57
+ # @param [optional Integer (8-bit byte of bit flags)] trace_flags Trace
58
+ # flag as defined in {https://www.w3.org/TR/trace-context/#trace-flags W3C Trace Context}
59
+ # specification. At the time of writing the specification defines one
60
+ # flag - the SAMPLED flag.
61
+ # @param [optional OpenTelemetry::Context] context The OpenTelemetry::Context
62
+ # to associate with the {LogRecord}.
63
+ #
64
+ # @api public
65
+ def on_emit(timestamp: nil,
66
+ observed_timestamp: Time.now,
67
+ severity_text: nil,
68
+ severity_number: nil,
69
+ body: nil,
70
+ attributes: nil,
71
+ trace_id: nil,
72
+ span_id: nil,
73
+ trace_flags: nil,
74
+ context: ::OpenTelemetry::Context.current)
75
+
76
+ @logger_provider.on_emit(timestamp: timestamp,
77
+ observed_timestamp: observed_timestamp,
78
+ severity_text: severity_text,
79
+ severity_number: severity_number,
80
+ body: body,
81
+ attributes: attributes,
82
+ trace_id: nil,
83
+ span_id: nil,
84
+ trace_flags: nil,
85
+ instrumentation_scope: @instrumentation_scope,
86
+ context: context)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module ScoutApm
8
+ module Logging
9
+ module Loggers
10
+ module OpenTelemetry
11
+ module SDK
12
+ module Logs
13
+ # The SDK implementation of OpenTelemetry::Logs::LoggerProvider.
14
+ class LoggerProvider < OpenTelemetry::Logs::LoggerProvider
15
+ UNEXPECTED_ERROR_MESSAGE = 'unexpected error in ' \
16
+ 'OpenTelemetry::SDK::Logs::LoggerProvider#%s'
17
+
18
+ private_constant :UNEXPECTED_ERROR_MESSAGE
19
+
20
+ # Returns a new LoggerProvider instance.
21
+ #
22
+ # @param [optional Resource] resource The resource to associate with
23
+ # new LogRecords created by {Logger}s created by this LoggerProvider.
24
+ #
25
+ # @return [OpenTelemetry::SDK::Logs::LoggerProvider]
26
+ def initialize(resource: OpenTelemetry::SDK::Resources::Resource.create)
27
+ @log_record_processors = []
28
+ @mutex = Mutex.new
29
+ @resource = resource
30
+ @stopped = false
31
+ end
32
+
33
+ # Returns an {OpenTelemetry::SDK::Logs::Logger} instance.
34
+ #
35
+ # @param [String] name Instrumentation package name
36
+ # @param [optional String] version Instrumentation package version
37
+ #
38
+ # @return [OpenTelemetry::SDK::Logs::Logger]
39
+ def logger(name:, version: nil)
40
+ version ||= ''
41
+
42
+ if !name.is_a?(String) || name.empty?
43
+ OpenTelemetry.logger.warn('LoggerProvider#logger called with an ' \
44
+ "invalid name. Name provided: #{name.inspect}")
45
+ end
46
+
47
+ Logger.new(name, version, self)
48
+ end
49
+
50
+ # Adds a new log record processor to this LoggerProvider's
51
+ # log_record_processors.
52
+ #
53
+ # @param [LogRecordProcessor] log_record_processor The
54
+ # {LogRecordProcessor} to add to this LoggerProvider.
55
+ def add_log_record_processor(log_record_processor)
56
+ @mutex.synchronize do
57
+ if @stopped
58
+ OpenTelemetry.logger.warn('calling LoggerProvider#' \
59
+ 'add_log_record_processor after shutdown.')
60
+ return
61
+ end
62
+ @log_record_processors = @log_record_processors.dup.push(log_record_processor)
63
+ end
64
+ end
65
+
66
+ # Attempts to stop all the activity for this LoggerProvider. Calls
67
+ # {LogRecordProcessor#shutdown} for all registered {LogRecordProcessor}s.
68
+ #
69
+ # This operation may block until all log records are processed. Must
70
+ # be called before turning off the main application to ensure all data
71
+ # are processed and exported.
72
+ #
73
+ # After this is called all newly created {LogRecord}s will be no-op.
74
+ #
75
+ # @param [optional Numeric] timeout An optional timeout in seconds.
76
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
77
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
78
+ def shutdown(timeout: nil)
79
+ @mutex.synchronize do
80
+ if @stopped
81
+ OpenTelemetry.logger.warn('LoggerProvider#shutdown called multiple times.')
82
+ return Export::FAILURE
83
+ end
84
+
85
+ start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
86
+ results = @log_record_processors.map do |processor|
87
+ remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
88
+ break [Export::TIMEOUT] if remaining_timeout&.zero?
89
+
90
+ processor.shutdown(timeout: remaining_timeout)
91
+ end
92
+
93
+ @stopped = true
94
+ results.max || Export::SUCCESS
95
+ end
96
+ end
97
+
98
+ # Immediately export all {LogRecord}s that have not yet been exported
99
+ # for all the registered {LogRecordProcessor}s.
100
+ #
101
+ # This method should only be called in cases where it is absolutely
102
+ # necessary, such as when using some FaaS providers that may suspend
103
+ # the process after an invocation, but before the {LogRecordProcessor}
104
+ # exports the completed {LogRecord}s.
105
+ #
106
+ # @param [optional Numeric] timeout An optional timeout in seconds.
107
+ # @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
108
+ # a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
109
+ def force_flush(timeout: nil)
110
+ @mutex.synchronize do
111
+ return Export::SUCCESS if @stopped
112
+
113
+ start_time = OpenTelemetry::Common::Utilities.timeout_timestamp
114
+ results = @log_record_processors.map do |processor|
115
+ remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
116
+ return Export::TIMEOUT if remaining_timeout&.zero?
117
+
118
+ processor.force_flush(timeout: remaining_timeout)
119
+ end
120
+
121
+ results.max || Export::SUCCESS
122
+ end
123
+ end
124
+
125
+ # @api private
126
+ def on_emit(timestamp: nil,
127
+ observed_timestamp: nil,
128
+ severity_text: nil,
129
+ severity_number: nil,
130
+ body: nil,
131
+ attributes: nil,
132
+ trace_id: nil,
133
+ span_id: nil,
134
+ trace_flags: nil,
135
+ instrumentation_scope: nil,
136
+ context: nil)
137
+
138
+ log_record = LogRecord.new(timestamp: timestamp,
139
+ observed_timestamp: observed_timestamp,
140
+ severity_text: severity_text,
141
+ severity_number: severity_number,
142
+ body: body,
143
+ attributes: attributes,
144
+ trace_id: trace_id,
145
+ span_id: span_id,
146
+ trace_flags: trace_flags,
147
+ resource: @resource,
148
+ instrumentation_scope: instrumentation_scope)
149
+
150
+ @log_record_processors.each { |processor| processor.on_emit(log_record, context) }
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module ScoutApm
8
+ module Logging
9
+ module Loggers
10
+ module OpenTelemetry
11
+ module SDK
12
+ module Logs
13
+ # Current OpenTelemetry logs sdk version
14
+ VERSION = '0.1.0'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ require_relative 'logs/version'
8
+ require_relative 'logs/logger'
9
+ require_relative 'logs/logger_provider'
10
+ require_relative 'logs/log_record'
11
+ require_relative 'logs/log_record_data'
12
+ require_relative 'logs/log_record_processor'
13
+ require_relative 'logs/export'
14
+
15
+ module ScoutApm
16
+ module Logging
17
+ module Loggers
18
+ module OpenTelemetry
19
+ module SDK
20
+ # The Logs module contains the OpenTelemetry logs reference
21
+ # implementation.
22
+ module Logs
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -12,75 +12,6 @@ module ScoutApm
12
12
 
13
13
  FileUtils.mkdir_p(file_path) unless File.directory?(file_path)
14
14
  end
15
-
16
- # TODO: Add support for other platforms
17
- def self.get_architecture
18
- if /arm/ =~ RbConfig::CONFIG['arch']
19
- 'arm64'
20
- else
21
- 'amd64'
22
- end
23
- end
24
-
25
- def self.get_host_os
26
- if /darwin|mac os/ =~ RbConfig::CONFIG['host_os']
27
- 'darwin'
28
- else
29
- 'linux'
30
- end
31
- end
32
-
33
- def self.check_process_liveliness(pid, name)
34
- # Pipe to cat to prevent truncation of the output
35
- process_information = `ps -p #{pid} -o pid=,stat=,command= | cat`
36
- return false if process_information.empty?
37
-
38
- process_information_parts = process_information.split(' ')
39
- process_information_status = process_information_parts[1]
40
-
41
- return false if process_information_status == 'Z'
42
- return false unless process_information.include?(name)
43
-
44
- true
45
- end
46
-
47
- def self.current_process_is_app_server?
48
- # TODO: Add more app servers.
49
- process_command = `ps -p #{Process.pid} -o command= | cat`.downcase
50
- [
51
- process_command.include?('puma'),
52
- process_command.include?('unicorn'),
53
- process_command.include?('passenger')
54
- ].any?
55
- end
56
-
57
- def self.skip_setup?
58
- [
59
- ARGV.include?('assets:precompile'),
60
- ARGV.include?('assets:clean'),
61
- (defined?(::Rails::Console) && $stdout.isatty && $stdin.isatty)
62
- ].any?
63
- end
64
-
65
- def self.attempt_exclusive_lock(context)
66
- lock_file = context.config.value('manager_lock_file')
67
- ensure_directory_exists(lock_file)
68
-
69
- begin
70
- file = File.open(lock_file, File::RDWR | File::CREAT | File::EXCL)
71
- rescue Errno::EEXIST
72
- context.logger.info('Manager lock file held, continuing.')
73
- return
74
- end
75
-
76
- # Ensure the lock file is deleted when the block completes
77
- begin
78
- yield
79
- ensure
80
- file.close
81
- File.delete(lock_file) if File.exist?(lock_file)
82
- end
83
- end
84
15
  end
85
16
  end
86
17
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ScoutApm
4
4
  module Logging
5
- VERSION = '0.0.13'
5
+ VERSION = '1.0.1'
6
6
  end
7
7
  end
@@ -6,12 +6,8 @@ require 'scout_apm/logging/config'
6
6
  require 'scout_apm/logging/logger'
7
7
  require 'scout_apm/logging/context'
8
8
  require 'scout_apm/logging/utils'
9
- require 'scout_apm/logging/state'
10
-
11
9
  require 'scout_apm/logging/loggers/capture'
12
10
 
13
- require 'scout_apm/logging/monitor_manager/manager'
14
-
15
11
  module ScoutApm
16
12
  ## This module is responsible for setting up monitoring of the application's logs.
17
13
  module Logging
@@ -19,15 +15,10 @@ module ScoutApm
19
15
  # If we are in a Rails environment, setup the monitor daemon manager.
20
16
  class RailTie < ::Rails::Railtie
21
17
  initializer 'scout_apm_logging.monitor', after: :initialize_logger, before: :initialize_cache do
22
- context = ScoutApm::Logging::MonitorManager.instance.context
18
+ context = Context.new
19
+ context.config = Config.with_file(context, context.config.value('config_file'))
23
20
 
24
21
  Loggers::Capture.new(context).setup!
25
-
26
- unless Utils.skip_setup?
27
- Utils.attempt_exclusive_lock(context) do
28
- ScoutApm::Logging::MonitorManager.instance.setup!
29
- end
30
- end
31
22
  end
32
23
  end
33
24
  end
@@ -17,9 +17,16 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.required_ruby_version = '>= 2.6'
19
19
 
20
+ s.add_dependency 'googleapis-common-protos-types'
21
+ s.add_dependency 'google-protobuf', '~> 3.0'
22
+ s.add_dependency 'opentelemetry-api'
23
+ s.add_dependency 'opentelemetry-common'
24
+ s.add_dependency 'opentelemetry-instrumentation-base'
25
+ s.add_dependency 'opentelemetry-sdk', '>= 1.2'
20
26
  s.add_dependency 'scout_apm'
21
27
 
22
28
  s.add_development_dependency 'rspec'
23
29
  s.add_development_dependency 'rubocop', '1.50.2'
24
30
  s.add_development_dependency 'rubocop-ast', '1.30.0'
31
+ s.add_development_dependency 'webmock'
25
32
  end
@@ -9,7 +9,6 @@ common: &defaults
9
9
  ###
10
10
  logs_monitor: true
11
11
  logs_ingest_key: "00001000010000abc"
12
- logs_monitored: ["/tmp/fake_log_file.log"]
13
12
 
14
13
  production:
15
14
  <<: *defaults
@@ -9,9 +9,6 @@ common: &defaults
9
9
  ###
10
10
  logs_monitor: true
11
11
  logs_ingest_key: "00001000010000abc"
12
- logs_monitored: ["/tmp/fake_log_file.log"]
13
- # Need to give a high enough number for the original health check to pass
14
- monitor_interval: 10
15
12
 
16
13
  production:
17
14
  <<: *defaults
@@ -1,32 +1,45 @@
1
+ require 'webmock/rspec'
2
+
1
3
  require 'spec_helper'
4
+ require 'zlib'
5
+ require 'stringio'
2
6
  require_relative '../../rails/app'
3
7
 
4
8
  describe ScoutApm::Logging do
9
+ before do
10
+ @file_path = '/app/response_body.txt'
11
+ # Capture the outgoing HTTP request to inspect its values
12
+ stub_request(:post, 'https://otlp-devel.scoutotel.com:4318/v1/logs')
13
+ .to_return do |request|
14
+ # We have to write to the file, as we are applying the patch in the fork, and
15
+ # need to run the expectations in the main process.
16
+ File.open(@file_path, 'a+') do |file|
17
+ msgs = transform_body_to_msgs(request.body)
18
+ file.puts(msgs)
19
+ end
20
+ { body: '', headers: {}, status: 200 }
21
+ end
22
+ end
23
+
5
24
  it 'checks the Rails lifecycle for creating the daemon and collector processes' do
6
25
  ENV['SCOUT_LOGS_MONITOR'] = 'true'
26
+ ENV['SCOUT_LOGS_REPORTING_ENDPOINT_HTTP'] = 'https://otlp-devel.scoutotel.com:4318/v1/logs'
7
27
 
8
- context = ScoutApm::Logging::MonitorManager.instance.context
9
- pid_file = context.config.value('monitor_pid_file')
10
- expect(File.exist?(pid_file)).to be_falsey
28
+ context = ScoutApm::Logging::Context.new
29
+ context.config = ScoutApm::Logging::Config.with_file(context, context.config.value('config_file'))
11
30
 
12
31
  rails_pid = fork do
13
32
  initialize_app
14
33
  end
15
34
 
16
- wait_for_process_with_timeout!('otelcol-contrib', 20)
17
-
18
- # Check if the monitor PID file exists
19
- expect(File.exist?(pid_file)).to be_truthy
20
-
21
- # Read the PID from the PID file
22
- pid = File.read(pid_file).to_i
23
-
24
- # Check if the process with the stored PID is running
25
- expect(ScoutApm::Logging::Utils.check_process_liveliness(pid, 'scout_apm_logging_monitor')).to be_truthy
35
+ # TODO: Improve check to wait for Rails initialization.
36
+ sleep 5
26
37
 
27
38
  # Call the app to generate the logs
28
39
  `curl localhost:8080`
29
40
 
41
+ sleep 5
42
+
30
43
  proxy_dir = context.config.value('logs_proxy_log_dir')
31
44
  files = Dir.entries(proxy_dir) - ['.', '..']
32
45
  log_file = File.join(proxy_dir, files[0])
@@ -41,24 +54,45 @@ describe ScoutApm::Logging do
41
54
  end
42
55
  end
43
56
 
44
- messages = lines.map { |item| item['msg'] }
57
+ local_messages = lines.map { |item| item['msg'] }
45
58
 
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
- expect(messages.count('Should not be captured')).to eq(0)
59
+ # Verify we have all the logs in the local log file
60
+ expect(local_messages.count('[TEST] Some log')).to eq(1)
61
+ expect(local_messages.count('[YIELD] Yield Test')).to eq(1)
62
+ expect(local_messages.count('Another Log')).to eq(1)
63
+ expect(local_messages.count('Should not be captured')).to eq(0)
51
64
 
52
65
  log_locations = lines.map { |item| item['log_location'] }.compact
53
66
 
54
67
  # Verify that log attributes aren't persisted
55
68
  expect(log_locations.size).to eq(1)
56
69
 
70
+ # Verify the logs are sent to the receiver
71
+ receiver_contents = File.readlines(@file_path, chomp: true)
72
+ expect(receiver_contents.count('[TEST] Some log')).to eq(1)
73
+ expect(receiver_contents.count('[YIELD] Yield Test')).to eq(1)
74
+ expect(receiver_contents.count('Another Log')).to eq(1)
75
+ expect(receiver_contents.count('Should not be captured')).to eq(0)
76
+
57
77
  # Kill the rails process. We use kill as using any other signal throws a long log line.
58
78
  Process.kill('KILL', rails_pid)
59
- # Kill the process and ensure PID file clean up
60
- Process.kill('TERM', pid)
61
- sleep 1 # Give the process time to exit
62
- expect(File.exist?(pid_file)).to be_falsey
79
+ end
80
+
81
+ private
82
+
83
+ def transform_body_to_msgs(body)
84
+ gz = Zlib::GzipReader.new(StringIO.new(body))
85
+ uncompressed = gz.read
86
+
87
+ value = ScoutApm::Logging::Loggers::Opentelemetry::Proto::Collector::Logs::V1::ExportLogsServiceRequest.decode(uncompressed)
88
+ value_hash = value.to_h
89
+
90
+ value_hash[:resource_logs].map do |item|
91
+ item[:scope_logs].map do |sl|
92
+ sl[:log_records].map do |log|
93
+ log[:body][:string_value]
94
+ end
95
+ end
96
+ end.flatten
63
97
  end
64
98
  end
data/spec/spec_helper.rb CHANGED
@@ -23,20 +23,8 @@ end
23
23
  RSpec.configure do |config|
24
24
  ENV["SCOUT_LOG_FILE_PATH"] = "STDOUT"
25
25
  ENV["SCOUT_LOG_LEVEL"] = "debug"
26
- ENV["SCOUT_COLLECTOR_LOG_LEVEL"] = "info"
27
26
 
28
27
  config.after(:each) do
29
28
  RSpec::Mocks.space.reset_all
30
29
  end
31
30
  end
32
-
33
- def wait_for_process_with_timeout!(name, timeout_time)
34
- Timeout::timeout(timeout_time) do
35
- loop do
36
- break if `pgrep #{name} --runstates D,R,S`.strip != ""
37
- sleep 0.1
38
- end
39
- end
40
-
41
- sleep 1
42
- end
@@ -8,18 +8,6 @@ describe ScoutApm::Logging::Config do
8
8
 
9
9
  expect(conf.value('log_level')).to eq('debug')
10
10
  expect(conf.value('logs_monitor')).to eq(true)
11
- expect(conf.value('monitor_pid_file')).to eq('/tmp/scout_apm/scout_apm_log_monitor.pid')
12
11
  expect(conf.value('logs_ingest_key')).to eq('00001000010000abc')
13
- expect(conf.value('logs_monitored')).to eq(['/tmp/fake_log_file.log'])
14
- end
15
-
16
- it 'loads the state file into the config' do
17
- ENV['SCOUT_MONITOR_STATE_FILE'] = File.expand_path('../data/state_file.json', __dir__)
18
-
19
- context = ScoutApm::Logging::Context.new
20
- conf_file = File.expand_path('../data/config_test_1.yml', __dir__)
21
- conf = ScoutApm::Logging::Config.with_file(context, conf_file)
22
-
23
- expect(conf.value('health_check_port')).to eq(1234)
24
12
  end
25
13
  end
@@ -16,8 +16,6 @@ end
16
16
 
17
17
  describe ScoutApm::Logging::Loggers::Capture do
18
18
  it 'should swap the STDOUT logger and create a proxy logger' do
19
- ENV['SCOUT_MONITOR_INTERVAL'] = '10'
20
- ENV['SCOUT_MONITOR_INTERVAL_DELAY'] = '10'
21
19
  ENV['SCOUT_LOGS_MONITOR'] = 'true'
22
20
  ENV['SCOUT_LOGS_CAPTURE_LEVEL'] = 'debug'
23
21
 
@@ -47,10 +45,6 @@ describe ScoutApm::Logging::Loggers::Capture do
47
45
  # Shouldn't capture. While the log_capture_level was set to debug,
48
46
  # the original logger instance had a higher log level of info.
49
47
  expect(content).not_to include('SHOULD NOT CAPTURE')
50
-
51
- state_file = File.read(context.config.value('monitor_state_file'))
52
- state_data = JSON.parse(state_file)
53
- expect(state_data['logs_monitored']).to eq([log_path])
54
48
  end
55
49
 
56
50
  expect(output_from_log).to include('TEST')