scout_apm_logging 0.0.12 → 1.0.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.
- checksums.yaml +4 -4
- data/.gitignore +0 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +8 -0
- data/NOTICE +4 -0
- data/lib/scout_apm/logging/config.rb +5 -131
- data/lib/scout_apm/logging/loggers/capture.rb +8 -6
- data/lib/scout_apm/logging/loggers/formatter.rb +21 -2
- data/lib/scout_apm/logging/loggers/opentelemetry/LICENSE +201 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/NOTICE +9 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/log_record.rb +18 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger.rb +64 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/logger_provider.rb +31 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/severity_number.rb +43 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs/version.rb +18 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/api/logs.rb +28 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/logs_exporter.rb +389 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/exporter/otlp/version.rb +20 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/collector/logs/v1/logs_service_pb.rb +43 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/common/v1/common_pb.rb +58 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/logs/v1/logs_pb.rb +91 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/exporter/proto/resource/v1/resource_pb.rb +33 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/opentelemetry.rb +62 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/batch_log_record_processor.rb +225 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export/log_record_exporter.rb +64 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/export.rb +34 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record.rb +115 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_data.rb +31 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/log_record_processor.rb +53 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger.rb +94 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/logger_provider.rb +158 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs/version.rb +20 -0
- data/lib/scout_apm/logging/loggers/opentelemetry/sdk/logs.rb +28 -0
- data/lib/scout_apm/logging/loggers/patches/rails_logger.rb +17 -0
- data/lib/scout_apm/logging/loggers/proxy.rb +22 -5
- data/lib/scout_apm/logging/loggers/swaps/rails.rb +4 -12
- data/lib/scout_apm/logging/loggers/swaps/scout.rb +2 -10
- data/lib/scout_apm/logging/loggers/swaps/sidekiq.rb +2 -6
- data/lib/scout_apm/logging/utils.rb +0 -69
- data/lib/scout_apm/logging/version.rb +1 -1
- data/lib/scout_apm_logging.rb +3 -12
- data/scout_apm_logging.gemspec +7 -0
- data/spec/data/config_test_1.yml +0 -1
- data/spec/data/mock_config.yml +0 -3
- data/spec/integration/rails/lifecycle_spec.rb +57 -23
- data/spec/spec_helper.rb +0 -12
- data/spec/unit/config_spec.rb +0 -12
- data/spec/unit/loggers/capture_spec.rb +0 -6
- metadata +127 -39
- data/bin/scout_apm_logging_monitor +0 -6
- data/lib/scout_apm/logging/monitor/_rails.rb +0 -22
- data/lib/scout_apm/logging/monitor/collector/checksum.rb +0 -51
- data/lib/scout_apm/logging/monitor/collector/configuration.rb +0 -150
- data/lib/scout_apm/logging/monitor/collector/downloader.rb +0 -78
- data/lib/scout_apm/logging/monitor/collector/extractor.rb +0 -37
- data/lib/scout_apm/logging/monitor/collector/manager.rb +0 -57
- data/lib/scout_apm/logging/monitor/monitor.rb +0 -216
- data/lib/scout_apm/logging/monitor_manager/manager.rb +0 -162
- data/lib/scout_apm/logging/state.rb +0 -69
- data/spec/data/empty_logs_config.yml +0 -0
- data/spec/data/logs_config.yml +0 -3
- data/spec/data/state_file.json +0 -3
- data/spec/integration/loggers/capture_spec.rb +0 -68
- data/spec/integration/monitor/collector/downloader/will_verify_checksum.rb +0 -49
- data/spec/integration/monitor/collector_healthcheck_spec.rb +0 -29
- data/spec/integration/monitor/continuous_state_collector_spec.rb +0 -31
- data/spec/integration/monitor/previous_collector_setup_spec.rb +0 -45
- data/spec/integration/monitor_manager/disable_agent_spec.rb +0 -30
- data/spec/integration/monitor_manager/monitor_pid_file_spec.rb +0 -38
- data/spec/integration/monitor_manager/single_monitor_spec.rb +0 -53
- data/spec/unit/monitor/collector/configuration_spec.rb +0 -64
- data/spec/unit/state_spec.rb +0 -20
- data/tooling/checksums.rb +0 -106
@@ -0,0 +1,53 @@
|
|
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
|
+
# LogRecordProcessor describes a duck type and provides a synchronous no-op hook for when a
|
14
|
+
# {LogRecord} is emitted. It is not required to subclass this
|
15
|
+
# class to provide an implementation of LogRecordProcessor, provided the interface is
|
16
|
+
# satisfied.
|
17
|
+
class LogRecordProcessor
|
18
|
+
# Called when a {LogRecord} is emitted. Subsequent calls are not
|
19
|
+
# permitted after shutdown is called.
|
20
|
+
# @param [LogRecord] log_record The emitted {LogRecord}
|
21
|
+
# @param [Context] context The {Context}
|
22
|
+
def on_emit(log_record, context); end
|
23
|
+
|
24
|
+
# Export all log records to the configured `Exporter` that have not yet
|
25
|
+
# been exported.
|
26
|
+
#
|
27
|
+
# This method should only be called in cases where it is absolutely
|
28
|
+
# necessary, such as when using some FaaS providers that may suspend
|
29
|
+
# the process after an invocation, but before the `Processor` exports
|
30
|
+
# the completed spans.
|
31
|
+
#
|
32
|
+
# @param [Numeric] timeout An optional timeout in seconds.
|
33
|
+
# @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
|
34
|
+
# a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
|
35
|
+
def force_flush(timeout: nil)
|
36
|
+
Export::SUCCESS
|
37
|
+
end
|
38
|
+
|
39
|
+
# Called when {LoggerProvider#shutdown} is called.
|
40
|
+
#
|
41
|
+
# @param [Numeric] timeout An optional timeout in seconds.
|
42
|
+
# @return [Integer] Export::SUCCESS if no error occurred, Export::FAILURE if
|
43
|
+
# a non-specific failure occurred, Export::TIMEOUT if a timeout occurred.
|
44
|
+
def shutdown(timeout: nil)
|
45
|
+
Export::SUCCESS
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -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
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# A patch to Rails to allow swapping out the logger for the held logger in the proxy.
|
4
|
+
module Rails
|
5
|
+
class << self
|
6
|
+
def logger=(new_logger)
|
7
|
+
@logger.tap do |rails_logger|
|
8
|
+
if rails_logger.respond_to?(:is_scout_proxy_logger?)
|
9
|
+
old_logger = rails_logger.instance_variable_get(:@loggers).first
|
10
|
+
rails_logger.swap_scout_loggers!(old_logger, new_logger)
|
11
|
+
else
|
12
|
+
@logger = new_logger
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -4,9 +4,7 @@ module ScoutApm
|
|
4
4
|
module Logging
|
5
5
|
module Loggers
|
6
6
|
# Holds both the original application logger and the new one. Relays commands to both.
|
7
|
-
class Proxy
|
8
|
-
include ::Kernel
|
9
|
-
|
7
|
+
class Proxy
|
10
8
|
def self.create_with_loggers(*loggers)
|
11
9
|
new.tap do |proxy_logger|
|
12
10
|
loggers.each { |logger| proxy_logger.add_scout_loggers(logger) }
|
@@ -21,12 +19,19 @@ module ScoutApm
|
|
21
19
|
@loggers << logger
|
22
20
|
end
|
23
21
|
|
24
|
-
def remove_scout_loggers(logger)
|
22
|
+
def remove_scout_loggers!(logger)
|
25
23
|
@loggers.reject! { |inst_log| inst_log == logger }
|
26
24
|
|
27
25
|
@loggers
|
28
26
|
end
|
29
27
|
|
28
|
+
def swap_scout_loggers!(old_logger, new_logger)
|
29
|
+
logger_index = @loggers.index(old_logger)
|
30
|
+
return unless logger_index
|
31
|
+
|
32
|
+
@loggers[logger_index] = new_logger
|
33
|
+
end
|
34
|
+
|
30
35
|
# We don't want other libraries to change the formatter of the logger we create.
|
31
36
|
def formatter=(formatter)
|
32
37
|
@loggers.first.formatter = formatter
|
@@ -38,8 +43,20 @@ module ScoutApm
|
|
38
43
|
@loggers.first.level = level
|
39
44
|
end
|
40
45
|
|
46
|
+
def is_a?(klass)
|
47
|
+
@loggers.first.is_a?(klass)
|
48
|
+
end
|
49
|
+
|
50
|
+
def kind_of?(klass)
|
51
|
+
@loggers.first.is_a?(klass)
|
52
|
+
end
|
53
|
+
|
54
|
+
def instance_of?(klass)
|
55
|
+
@loggers.first.instance_of?(klass)
|
56
|
+
end
|
57
|
+
|
41
58
|
def class
|
42
|
-
|
59
|
+
@loggers.first.class
|
43
60
|
end
|
44
61
|
|
45
62
|
def is_scout_proxy_logger?
|
@@ -19,8 +19,10 @@ module ScoutApm
|
|
19
19
|
def update_logger!
|
20
20
|
# In Rails 7.1, broadcast logger was added which allows sinking to multiple IO devices.
|
21
21
|
if defined?(::ActiveSupport::BroadcastLogger) && log_instance.is_a?(::ActiveSupport::BroadcastLogger)
|
22
|
+
context.logger.debug('Rails Broadcast logger detected. Adding new logger to broadcast.')
|
22
23
|
add_logger_to_broadcast!
|
23
24
|
else
|
25
|
+
context.logger.debug("Swapping in Proxy for current Rails logger: #{log_instance.class}.")
|
24
26
|
swap_in_proxy_logger!
|
25
27
|
end
|
26
28
|
|
@@ -37,18 +39,8 @@ module ScoutApm
|
|
37
39
|
@new_file_logger ||= Loggers::Logger.new(context, log_instance).create_logger!
|
38
40
|
end
|
39
41
|
|
40
|
-
|
41
|
-
|
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.level = log_instance.level
|
50
|
-
logger.formatter = log_instance.formatter
|
51
|
-
|
42
|
+
def original_logger
|
43
|
+
@original_logger = log_instance.clone.tap do |logger|
|
52
44
|
if ::Rails.env.development? && $stdout.tty? && $stderr.tty?
|
53
45
|
next if ::ActiveSupport::Logger.respond_to?(:logger_outputs_to?) && ::ActiveSupport::Logger.logger_outputs_to?(
|
54
46
|
logger, $stdout, $stderr
|
@@ -17,6 +17,7 @@ module ScoutApm
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def update_logger!
|
20
|
+
context.logger.debug('Swapping in Proxy for Test logger.')
|
20
21
|
swap_in_proxy_logger!
|
21
22
|
|
22
23
|
new_log_location
|
@@ -34,16 +35,7 @@ module ScoutApm
|
|
34
35
|
|
35
36
|
# Eseentially creates the original logger.
|
36
37
|
def original_logger
|
37
|
-
|
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.level = log_instance.level
|
45
|
-
logger.formatter = log_instance.formatter
|
46
|
-
end
|
38
|
+
@original_logger = log_instance.clone
|
47
39
|
end
|
48
40
|
|
49
41
|
def new_log_location
|
@@ -17,6 +17,7 @@ module ScoutApm
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def update_logger!
|
20
|
+
context.logger.debug("Swapping in Proxy for current Sidekiq logger: #{log_instance.class}.")
|
20
21
|
swap_in_proxy_logger!
|
21
22
|
|
22
23
|
new_log_location
|
@@ -38,12 +39,7 @@ module ScoutApm
|
|
38
39
|
# through the devices until the logdev (@dev) is an IO device other than logdev:
|
39
40
|
# https://github.com/ruby/ruby/blob/master/lib/logger/log_device.rb#L42
|
40
41
|
# Log device holds the configurations around shifting too.
|
41
|
-
|
42
|
-
|
43
|
-
::Logger.new(original_logdevice).tap do |logger|
|
44
|
-
logger.level = log_instance.level
|
45
|
-
logger.formatter = log_instance.formatter
|
46
|
-
end
|
42
|
+
@original_logger = log_instance.clone
|
47
43
|
end
|
48
44
|
|
49
45
|
def new_log_location
|
@@ -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
|
data/lib/scout_apm_logging.rb
CHANGED
@@ -6,28 +6,19 @@ 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
|
18
14
|
if defined?(Rails) && defined?(Rails::Railtie)
|
19
15
|
# If we are in a Rails environment, setup the monitor daemon manager.
|
20
16
|
class RailTie < ::Rails::Railtie
|
21
|
-
initializer 'scout_apm_logging.monitor' do
|
22
|
-
context =
|
17
|
+
initializer 'scout_apm_logging.monitor', after: :initialize_logger, before: :initialize_cache do
|
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
|
data/scout_apm_logging.gemspec
CHANGED
@@ -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.18'
|
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
|
data/spec/data/config_test_1.yml
CHANGED
data/spec/data/mock_config.yml
CHANGED
@@ -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
|