semantic_logger 4.18.0 → 5.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/README.md +42 -81
- data/Rakefile +10 -3
- data/lib/semantic_logger/appender/async.rb +86 -173
- data/lib/semantic_logger/appender/cloudwatch_logs.rb +4 -4
- data/lib/semantic_logger/appender/elasticsearch.rb +6 -182
- data/lib/semantic_logger/appender/elasticsearch_base.rb +212 -0
- data/lib/semantic_logger/appender/elasticsearch_http.rb +2 -2
- data/lib/semantic_logger/appender/file.rb +20 -4
- data/lib/semantic_logger/appender/graylog.rb +2 -2
- data/lib/semantic_logger/appender/http.rb +27 -2
- data/lib/semantic_logger/appender/io.rb +8 -4
- data/lib/semantic_logger/appender/kafka.rb +2 -2
- data/lib/semantic_logger/appender/loki.rb +2 -4
- data/lib/semantic_logger/appender/mongodb.rb +3 -6
- data/lib/semantic_logger/appender/new_relic_logs.rb +2 -2
- data/lib/semantic_logger/appender/open_telemetry.rb +8 -6
- data/lib/semantic_logger/appender/opensearch.rb +35 -0
- data/lib/semantic_logger/appender/rabbitmq.rb +3 -3
- data/lib/semantic_logger/appender/sentry_ruby.rb +2 -2
- data/lib/semantic_logger/appender/splunk.rb +2 -2
- data/lib/semantic_logger/appender/splunk_http.rb +3 -3
- data/lib/semantic_logger/appender/syslog.rb +5 -4
- data/lib/semantic_logger/appender/tcp.rb +2 -2
- data/lib/semantic_logger/appender/udp.rb +2 -2
- data/lib/semantic_logger/appender/wrapper.rb +4 -4
- data/lib/semantic_logger/appender.rb +30 -19
- data/lib/semantic_logger/appenders.rb +26 -5
- data/lib/semantic_logger/base.rb +100 -21
- data/lib/semantic_logger/concerns/compatibility.rb +2 -2
- data/lib/semantic_logger/core_ext/process.rb +34 -0
- data/lib/semantic_logger/formatters/base.rb +46 -7
- data/lib/semantic_logger/formatters/color.rb +6 -3
- data/lib/semantic_logger/formatters/default.rb +6 -4
- data/lib/semantic_logger/formatters/ecs.rb +151 -0
- data/lib/semantic_logger/formatters/fluentd.rb +15 -4
- data/lib/semantic_logger/formatters/json.rb +6 -1
- data/lib/semantic_logger/formatters/logfmt.rb +2 -2
- data/lib/semantic_logger/formatters/loki.rb +4 -4
- data/lib/semantic_logger/formatters/open_telemetry.rb +15 -5
- data/lib/semantic_logger/formatters/pattern.rb +235 -0
- data/lib/semantic_logger/formatters/raw.rb +2 -2
- data/lib/semantic_logger/formatters/signalfx.rb +2 -2
- data/lib/semantic_logger/formatters/syslog.rb +14 -3
- data/lib/semantic_logger/formatters/syslog_cee.rb +1 -1
- data/lib/semantic_logger/formatters.rb +2 -0
- data/lib/semantic_logger/log.rb +18 -4
- data/lib/semantic_logger/logger.rb +2 -2
- data/lib/semantic_logger/metric/new_relic.rb +2 -2
- data/lib/semantic_logger/metric/signalfx.rb +2 -2
- data/lib/semantic_logger/metric/statsd.rb +2 -2
- data/lib/semantic_logger/processor.rb +21 -0
- data/lib/semantic_logger/queue_processor.rb +369 -0
- data/lib/semantic_logger/reporters/minitest.rb +4 -4
- data/lib/semantic_logger/semantic_logger.rb +103 -11
- data/lib/semantic_logger/subscriber.rb +15 -2
- data/lib/semantic_logger/sync_processor.rb +25 -3
- data/lib/semantic_logger/test/capture_log_events.rb +2 -2
- data/lib/semantic_logger/test/minitest.rb +8 -4
- data/lib/semantic_logger/test/rspec.rb +249 -0
- data/lib/semantic_logger/utils.rb +83 -4
- data/lib/semantic_logger/version.rb +1 -1
- data/lib/semantic_logger.rb +9 -0
- metadata +17 -8
- data/lib/semantic_logger/appender/async_batch.rb +0 -93
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff43a3438164b6bf70367a7b2806350e65da8762fc6fb4e333a769cdf200e95b
|
|
4
|
+
data.tar.gz: 3d12647aaed6e22b7abc7a4c377c0d0470f00ffee3401d2db6043aece3ce09c1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2893b8e69a4d246c1346e5fc6b20ca6a8fcdc3a29e78a44e4e1c8dae5466971298d9cfcabd736080beef17c2eb68914cb90ddef844bf6afd3ede388850232a90
|
|
7
|
+
data.tar.gz: 944f2cbf7232a4cae3ecee1f67d770d4b6a9306fae810b6045710c6920cc5876a5d56246d0a2605c7e066722df4abba1d8dccc29b43964c677a1bd33296dac73
|
data/README.md
CHANGED
|
@@ -1,13 +1,41 @@
|
|
|
1
1
|
# Semantic Logger
|
|
2
2
|
[](https://rubygems.org/gems/semantic_logger) [](https://github.com/reidmorrison/semantic_logger/actions?query=workflow%3Abuild) [](https://rubygems.org/gems/semantic_logger) [](http://opensource.org/licenses/Apache-2.0) 
|
|
3
3
|
|
|
4
|
-
Semantic Logger is a
|
|
4
|
+
Semantic Logger is a high-performance, asynchronous structured logging framework for Ruby
|
|
5
|
+
and Rails.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
It differs from ordinary loggers in two important ways:
|
|
8
|
+
|
|
9
|
+
1. **It logs structured data, not just strings.** Along with the text message, each log entry can
|
|
10
|
+
carry a payload (any Hash), an exception, a duration, metrics, and tags. That data is preserved
|
|
11
|
+
all the way to the destination, so it stays searchable instead of being flattened into text.
|
|
12
|
+
2. **It logs asynchronously.** Log events are pushed onto an in-memory queue and written to their
|
|
13
|
+
destinations by a separate background thread, so your application is not blocked while logs are
|
|
14
|
+
written. Semantic Logger can log thousands of lines per second without slowing the application
|
|
15
|
+
down.
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
require "semantic_logger"
|
|
19
|
+
|
|
20
|
+
SemanticLogger.default_level = :info
|
|
21
|
+
SemanticLogger.add_appender(io: $stdout, formatter: :color)
|
|
22
|
+
|
|
23
|
+
logger = SemanticLogger["MyApp"]
|
|
24
|
+
|
|
25
|
+
# A plain message, plus structured data that stays searchable
|
|
26
|
+
logger.info("Queried users table", duration: 54, result: :ok, table: "users")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
When running Rails, use
|
|
30
|
+
[rails_semantic_logger](https://github.com/reidmorrison/rails_semantic_logger) instead, since it
|
|
31
|
+
replaces the Rails default logger with Semantic Logger automatically.
|
|
7
32
|
|
|
8
33
|
## Documentation
|
|
9
34
|
|
|
10
|
-
|
|
35
|
+
Start with the [Introduction](https://logger.rocketjob.io/), then the
|
|
36
|
+
[Programmer's Guide](https://logger.rocketjob.io/api.html).
|
|
37
|
+
|
|
38
|
+
* Full guide: [https://logger.rocketjob.io/](https://logger.rocketjob.io/)
|
|
11
39
|
|
|
12
40
|
## Logging Destinations
|
|
13
41
|
|
|
@@ -28,6 +56,7 @@ Logging to the following destinations are all supported "out-of-the-box":
|
|
|
28
56
|
* UDP
|
|
29
57
|
* Syslog
|
|
30
58
|
* CloudWatch Logs
|
|
59
|
+
* OpenTelemetry
|
|
31
60
|
* Add any existing Ruby logger as another destination.
|
|
32
61
|
* Roll-your-own
|
|
33
62
|
|
|
@@ -63,89 +92,16 @@ and are therefore not automatically included by this gem:
|
|
|
63
92
|
- Syslog Appender to a remote syslogng server over TCP or UDP: gem 'net_tcp_client'
|
|
64
93
|
- Splunk Appender: gem 'splunk-sdk-ruby'
|
|
65
94
|
- Elasticsearch Appender: gem 'elasticsearch'
|
|
95
|
+
- OpenSearch Appender: gem 'opensearch-ruby'
|
|
66
96
|
- Kafka Appender: gem 'ruby-kafka'
|
|
67
97
|
- Legacy Sentry Appender: gem 'sentry-raven' (deprecated)
|
|
68
98
|
- Sentry Appender: gem 'sentry-ruby'
|
|
99
|
+
- OpenTelemetry Appender: gem 'opentelemetry-logs-sdk' (plus an exporter, e.g. 'opentelemetry-exporter-otlp-logs')
|
|
69
100
|
|
|
70
|
-
## Upgrading
|
|
101
|
+
## Upgrading
|
|
71
102
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
API's directly.
|
|
75
|
-
|
|
76
|
-
This does not affect any calls to the public api `SemanticLogger.add_appender`.
|
|
77
|
-
|
|
78
|
-
File and IO are now separate appenders. When creating the File appender explicitly, its arguments
|
|
79
|
-
have changed. For example, when requesting an IO stream, it needs to be changed from:
|
|
80
|
-
|
|
81
|
-
~~~ruby
|
|
82
|
-
SemanticLogger::Appender::File.new(io: $stderr)
|
|
83
|
-
~~~
|
|
84
|
-
to:
|
|
85
|
-
~~~ruby
|
|
86
|
-
SemanticLogger::Appender::IO.new($stderr)
|
|
87
|
-
~~~
|
|
88
|
-
|
|
89
|
-
Additionally, this needs to be changed from:
|
|
90
|
-
~~~ruby
|
|
91
|
-
SemanticLogger::Appender::File.new(file_name: "file.log")
|
|
92
|
-
~~~
|
|
93
|
-
to:
|
|
94
|
-
~~~ruby
|
|
95
|
-
SemanticLogger::Appender::File.new("file.log")
|
|
96
|
-
~~~
|
|
97
|
-
|
|
98
|
-
Rails Semantic Logger, if used, needs to be upgraded to v4.9 when upgrading to Semantic Logger v4.9.
|
|
99
|
-
|
|
100
|
-
## Upgrading to Semantic Logger v4.4
|
|
101
|
-
|
|
102
|
-
With some forking frameworks it is necessary to call `reopen` after the fork. With v4.4 the
|
|
103
|
-
workaround for Ruby 2.5 crashes is no longer needed.
|
|
104
|
-
I.e. Please remove the following line if being called anywhere:
|
|
105
|
-
|
|
106
|
-
~~~ruby
|
|
107
|
-
SemanticLogger::Processor.instance.instance_variable_set(:@queue, Queue.new)
|
|
108
|
-
~~~
|
|
109
|
-
|
|
110
|
-
## Upgrading to Semantic Logger v4.0
|
|
111
|
-
|
|
112
|
-
The following changes need to be made when upgrading to V4:
|
|
113
|
-
- Ruby V2.3 / JRuby V9.1 is now the minimum runtime version.
|
|
114
|
-
- Replace calls to Logger#with_payload with SemanticLogger.named_tagged.
|
|
115
|
-
- Replace calls to Logger#payload with SemanticLogger.named_tags.
|
|
116
|
-
- MongoDB Appender requires Mongo Ruby Client V2 or greater.
|
|
117
|
-
- Appenders now write payload data in a seperate :payload tag instead of mixing them
|
|
118
|
-
directly into the root elements to avoid name clashes.
|
|
119
|
-
|
|
120
|
-
As a result any calls like the following:
|
|
121
|
-
|
|
122
|
-
~~~ruby
|
|
123
|
-
logger.debug foo: 'foo', bar: 'bar'
|
|
124
|
-
~~~
|
|
125
|
-
|
|
126
|
-
Must be replaced with the following in v4:
|
|
127
|
-
|
|
128
|
-
~~~ruby
|
|
129
|
-
logger.debug payload: {foo: 'foo', bar: 'bar'}
|
|
130
|
-
~~~
|
|
131
|
-
|
|
132
|
-
Similarly, for measure blocks:
|
|
133
|
-
|
|
134
|
-
~~~ruby
|
|
135
|
-
logger.measure_info('How long is the sleep', foo: 'foo', bar: 'bar') { sleep 1 }
|
|
136
|
-
~~~
|
|
137
|
-
|
|
138
|
-
Must be replaced with the following in v4:
|
|
139
|
-
|
|
140
|
-
~~~ruby
|
|
141
|
-
logger.measure_info('How long is the sleep', payload: {foo: 'foo', bar: 'bar'}) { sleep 1 }
|
|
142
|
-
~~~
|
|
143
|
-
|
|
144
|
-
The common log call has not changed, and the payload is still logged directly:
|
|
145
|
-
|
|
146
|
-
~~~ruby
|
|
147
|
-
logger.debug('log this', foo: 'foo', bar: 'bar')
|
|
148
|
-
~~~
|
|
103
|
+
See the [Upgrading Guide](https://logger.rocketjob.io/upgrading.html) for instructions on
|
|
104
|
+
upgrading between major versions.
|
|
149
105
|
|
|
150
106
|
## Install
|
|
151
107
|
|
|
@@ -165,6 +121,11 @@ SemanticLogger.add_appender(file_name: 'development.log', formatter: :color)
|
|
|
165
121
|
|
|
166
122
|
If running rails, see: [Semantic Logger Rails](https://logger.rocketjob.io/rails.html)
|
|
167
123
|
|
|
124
|
+
## Contributing
|
|
125
|
+
|
|
126
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for how to set up the project, run the
|
|
127
|
+
tests, and an overview of the architecture, including a class diagram.
|
|
128
|
+
|
|
168
129
|
## Author
|
|
169
130
|
|
|
170
131
|
[Reid Morrison](https://github.com/reidmorrison)
|
data/Rakefile
CHANGED
|
@@ -9,8 +9,8 @@ task :gem do
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
task publish: :gem do
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
system "git tag -a v#{SemanticLogger::VERSION} -m 'Tagging #{SemanticLogger::VERSION}'"
|
|
13
|
+
system "git push --tags"
|
|
14
14
|
system "gem push semantic_logger-#{SemanticLogger::VERSION}.gem"
|
|
15
15
|
system "rm semantic_logger-#{SemanticLogger::VERSION}.gem"
|
|
16
16
|
end
|
|
@@ -21,4 +21,11 @@ Rake::TestTask.new(:test) do |t|
|
|
|
21
21
|
t.warning = false
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
begin
|
|
25
|
+
require "rspec/core/rake_task"
|
|
26
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
27
|
+
rescue LoadError
|
|
28
|
+
# RSpec is only available in the test/development environment.
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
task default: %i[test spec]
|
|
@@ -2,28 +2,39 @@ require "forwardable"
|
|
|
2
2
|
|
|
3
3
|
module SemanticLogger
|
|
4
4
|
module Appender
|
|
5
|
-
#
|
|
5
|
+
# Proxy that allows any appender to run asynchronously in a separate thread.
|
|
6
|
+
#
|
|
7
|
+
# The worker thread and the in-memory queue are owned by an internal
|
|
8
|
+
# SemanticLogger::QueueProcessor. This proxy forwards log/flush/close/reopen on to the
|
|
9
|
+
# processor, and forwards the remaining appender methods (name, level, ...) directly to
|
|
10
|
+
# the wrapped appender so they keep executing on the caller's thread.
|
|
6
11
|
class Async
|
|
7
12
|
extend Forwardable
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
attr_reader :queue, :appender, :max_queue_size
|
|
14
|
+
attr_reader :appender, :processor
|
|
11
15
|
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
# Methods forwarded directly to the wrapped appender (run on the caller's thread).
|
|
17
|
+
def_delegators :@appender,
|
|
18
|
+
:name, :should_log?, :filter, :host, :application, :environment,
|
|
19
|
+
:level, :level=, :logger, :logger=, :console_stream, :console_output?
|
|
20
|
+
|
|
21
|
+
# Methods forwarded to the queue processor that owns the thread and queue.
|
|
22
|
+
# Tuning options (max_queue_size, batch_size, non_blocking, ...) are set once at
|
|
23
|
+
# construction via SemanticLogger.add_appender, so only the values that callers actually
|
|
24
|
+
# read back are re-exposed here. lag_* backs the public SemanticLogger.lag_* API.
|
|
25
|
+
def_delegators :@processor,
|
|
26
|
+
:log, :flush, :close, :thread, :active?, :queue, :max_queue_size,
|
|
27
|
+
:capped?, :non_blocking?, :batch?,
|
|
28
|
+
:lag_check_interval, :lag_check_interval=,
|
|
29
|
+
:lag_threshold_s, :lag_threshold_s=,
|
|
30
|
+
:processed_count, :dropped_count
|
|
23
31
|
|
|
24
32
|
# Appender proxy to allow an existing appender to run asynchronously in a separate thread.
|
|
25
33
|
#
|
|
26
34
|
# Parameters:
|
|
35
|
+
# appender: [SemanticLogger::Subscriber]
|
|
36
|
+
# The appender to log to in a separate thread.
|
|
37
|
+
#
|
|
27
38
|
# max_queue_size: [Integer]
|
|
28
39
|
# The maximum number of log messages to hold on the queue before blocking attempts to add to the queue.
|
|
29
40
|
# -1: The queue size is uncapped and will never block no matter how long the queue is.
|
|
@@ -36,172 +47,74 @@ module SemanticLogger
|
|
|
36
47
|
# lag_check_interval: [Integer]
|
|
37
48
|
# Number of messages to process before checking for slow logging.
|
|
38
49
|
# Default: 1,000
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
# Note: Not applicable when batch: true.
|
|
51
|
+
#
|
|
52
|
+
# batch: [true|false]
|
|
53
|
+
# Process log messages in batches via the appender's #batch method, instead of one at a time.
|
|
54
|
+
# The appender must implement #batch.
|
|
55
|
+
# Default: false
|
|
56
|
+
#
|
|
57
|
+
# batch_size: [Integer]
|
|
58
|
+
# Maximum number of messages to batch up before sending.
|
|
59
|
+
# Default: 300
|
|
60
|
+
# Note: Only applicable when batch: true.
|
|
61
|
+
#
|
|
62
|
+
# batch_seconds: [Integer]
|
|
63
|
+
# Maximum number of seconds between sending batches.
|
|
64
|
+
# Default: 5
|
|
65
|
+
# Note: Only applicable when batch: true.
|
|
66
|
+
#
|
|
67
|
+
# non_blocking: [true|false]
|
|
68
|
+
# Whether to drop log messages instead of blocking the calling thread when the queue is full.
|
|
69
|
+
# When true and the queue is capped, attempts to add to a full queue return immediately and
|
|
70
|
+
# the message is dropped. The number of dropped messages is logged to the internal logger
|
|
71
|
+
# periodically (see dropped_message_report_seconds). Only applies to a capped queue.
|
|
72
|
+
# Default: false
|
|
73
|
+
#
|
|
74
|
+
# dropped_message_report_seconds: [Integer]
|
|
75
|
+
# When non_blocking is enabled, log the count of dropped messages to the internal logger
|
|
76
|
+
# at most once every this number of seconds.
|
|
77
|
+
# Default: 30
|
|
78
|
+
#
|
|
79
|
+
# async_max_retries: [Integer]
|
|
80
|
+
# Maximum number of consecutive times to restart the worker thread (with a back-off)
|
|
81
|
+
# after it raises an exception while processing messages, before giving up and stopping
|
|
82
|
+
# the thread. The counter resets after any message is processed successfully.
|
|
83
|
+
# -1: Retry indefinitely and never stop the thread (the pre-v5 behaviour).
|
|
84
|
+
# Default: 100
|
|
85
|
+
def initialize(appender:, **args)
|
|
86
|
+
@appender = appender
|
|
87
|
+
@processor = QueueProcessor.start(appender: appender, **args)
|
|
50
88
|
end
|
|
51
89
|
|
|
52
|
-
# Re-open appender after a fork
|
|
90
|
+
# Re-open appender after a fork.
|
|
53
91
|
def reopen
|
|
54
|
-
# Workaround CRuby crash on fork by recreating queue on reopen
|
|
55
|
-
# https://github.com/reidmorrison/semantic_logger/issues/103
|
|
56
|
-
@queue&.close
|
|
57
|
-
create_queue
|
|
58
|
-
|
|
59
92
|
appender.reopen if appender.respond_to?(:reopen)
|
|
60
|
-
|
|
61
|
-
@thread&.kill if @thread&.alive?
|
|
62
|
-
@thread = Thread.new { process }
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
# Returns [true|false] if the queue has a capped size.
|
|
66
|
-
def capped?
|
|
67
|
-
@capped
|
|
93
|
+
processor.reopen
|
|
68
94
|
end
|
|
69
95
|
|
|
70
|
-
# Returns [
|
|
96
|
+
# Returns [Hash] operational statistics for this appender.
|
|
71
97
|
#
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
#
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
submit_request(:flush)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# Close all appenders and flush any outstanding messages.
|
|
96
|
-
def close
|
|
97
|
-
# TODO: Prevent new close requests once this appender has been closed.
|
|
98
|
-
submit_request(:close)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
private
|
|
102
|
-
|
|
103
|
-
def create_queue
|
|
104
|
-
if max_queue_size == -1
|
|
105
|
-
@queue = Queue.new
|
|
106
|
-
@capped = false
|
|
107
|
-
else
|
|
108
|
-
@queue = SizedQueue.new(max_queue_size)
|
|
109
|
-
@capped = true
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Separate thread for batching up log messages before writing.
|
|
114
|
-
def process
|
|
115
|
-
# This thread is designed to never go down unless the main thread terminates
|
|
116
|
-
# or the appender is closed.
|
|
117
|
-
Thread.current.name = logger.name
|
|
118
|
-
logger.trace "Async: Appender thread active"
|
|
119
|
-
begin
|
|
120
|
-
process_messages
|
|
121
|
-
rescue StandardError => e
|
|
122
|
-
# This block may be called after the file handles have been released by Ruby
|
|
123
|
-
begin
|
|
124
|
-
logger.error("Async: Restarting due to exception", e)
|
|
125
|
-
rescue StandardError
|
|
126
|
-
nil
|
|
127
|
-
end
|
|
128
|
-
retry
|
|
129
|
-
rescue Exception => e
|
|
130
|
-
# This block may be called after the file handles have been released by Ruby
|
|
131
|
-
begin
|
|
132
|
-
logger.error("Async: Stopping due to fatal exception", e)
|
|
133
|
-
rescue StandardError
|
|
134
|
-
nil
|
|
135
|
-
end
|
|
136
|
-
ensure
|
|
137
|
-
@thread = nil
|
|
138
|
-
# This block may be called after the file handles have been released by Ruby
|
|
139
|
-
begin
|
|
140
|
-
logger.trace("Async: Thread has stopped")
|
|
141
|
-
rescue StandardError
|
|
142
|
-
nil
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def process_messages
|
|
148
|
-
count = 0
|
|
149
|
-
while (message = queue.pop)
|
|
150
|
-
if message.is_a?(Log)
|
|
151
|
-
appender.log(message)
|
|
152
|
-
count += 1
|
|
153
|
-
# Check every few log messages whether this appender thread is falling behind
|
|
154
|
-
if count > lag_check_interval
|
|
155
|
-
check_lag(message)
|
|
156
|
-
count = 0
|
|
157
|
-
end
|
|
158
|
-
else
|
|
159
|
-
break unless process_message(message)
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
logger.trace "Async: Queue Closed"
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# Returns false when message processing should be stopped
|
|
166
|
-
def process_message(message)
|
|
167
|
-
case message[:command]
|
|
168
|
-
when :flush
|
|
169
|
-
appender.flush
|
|
170
|
-
message[:reply_queue] << true if message[:reply_queue]
|
|
171
|
-
when :close
|
|
172
|
-
appender.close
|
|
173
|
-
message[:reply_queue] << true if message[:reply_queue]
|
|
174
|
-
return false
|
|
175
|
-
else
|
|
176
|
-
logger.warn "Async: Appender thread: Ignoring unknown command: #{message[:command]}"
|
|
177
|
-
end
|
|
178
|
-
true
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
def check_lag(log)
|
|
182
|
-
diff = Time.now - log.time
|
|
183
|
-
return unless diff > lag_threshold_s
|
|
184
|
-
|
|
185
|
-
logger.warn "Async: Appender thread has fallen behind by #{diff} seconds with #{queue.size} messages queued up. Consider reducing the log level or changing the appenders"
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
# Submit command and wait for reply
|
|
189
|
-
def submit_request(command)
|
|
190
|
-
return false unless active?
|
|
191
|
-
|
|
192
|
-
queue_size = queue.size
|
|
193
|
-
msg = "Async: Queued log messages: #{queue_size}, running command: #{command}"
|
|
194
|
-
if queue_size > 1_000
|
|
195
|
-
logger.warn msg
|
|
196
|
-
elsif queue_size > 100
|
|
197
|
-
logger.info msg
|
|
198
|
-
elsif queue_size.positive?
|
|
199
|
-
logger.trace msg
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
reply_queue = Queue.new
|
|
203
|
-
queue << {command: command, reply_queue: reply_queue}
|
|
204
|
-
reply_queue.pop
|
|
98
|
+
# name: [String] Name of the wrapped appender.
|
|
99
|
+
# async: [true] This appender logs asynchronously via a separate thread.
|
|
100
|
+
# thread_active: [Boolean] Whether the worker thread is currently running.
|
|
101
|
+
# queue_size: [Integer] Number of log messages currently waiting to be written.
|
|
102
|
+
# capped: [Boolean] Whether the queue has a maximum size.
|
|
103
|
+
# max_queue_size: [Integer] Maximum queue size, or nil when uncapped.
|
|
104
|
+
# processed: [Integer] Cumulative number of log messages written since startup.
|
|
105
|
+
# dropped: [Integer] Cumulative number of log messages dropped because the queue
|
|
106
|
+
# was full (only possible when non_blocking is enabled).
|
|
107
|
+
def stats
|
|
108
|
+
{
|
|
109
|
+
name: name,
|
|
110
|
+
async: true,
|
|
111
|
+
thread_active: active? || false,
|
|
112
|
+
queue_size: queue.size,
|
|
113
|
+
capped: capped?,
|
|
114
|
+
max_queue_size: capped? ? max_queue_size : nil,
|
|
115
|
+
processed: processed_count,
|
|
116
|
+
dropped: dropped_count
|
|
117
|
+
}
|
|
205
118
|
end
|
|
206
119
|
end
|
|
207
120
|
end
|
|
@@ -54,7 +54,7 @@ module SemanticLogger
|
|
|
54
54
|
# Note that currently CloudWatch Logs has 10000 hard limit.
|
|
55
55
|
# Default: 4000
|
|
56
56
|
def initialize(
|
|
57
|
-
|
|
57
|
+
*,
|
|
58
58
|
group:,
|
|
59
59
|
client_kwargs: {},
|
|
60
60
|
stream: nil,
|
|
@@ -62,8 +62,8 @@ module SemanticLogger
|
|
|
62
62
|
create_stream: true,
|
|
63
63
|
force_flush_interval_seconds: 5,
|
|
64
64
|
max_buffered_events: 4_000,
|
|
65
|
-
|
|
66
|
-
&
|
|
65
|
+
**,
|
|
66
|
+
&
|
|
67
67
|
)
|
|
68
68
|
@group = group
|
|
69
69
|
@client_kwargs = client_kwargs
|
|
@@ -73,7 +73,7 @@ module SemanticLogger
|
|
|
73
73
|
@force_flush_interval_seconds = force_flush_interval_seconds
|
|
74
74
|
@max_buffered_events = max_buffered_events
|
|
75
75
|
|
|
76
|
-
super(
|
|
76
|
+
super(*, **, &)
|
|
77
77
|
reopen
|
|
78
78
|
end
|
|
79
79
|
|