semantic_logger 4.5.0 → 4.12.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 +51 -21
- data/Rakefile +7 -7
- data/lib/semantic_logger/ansi_colors.rb +0 -10
- data/lib/semantic_logger/appender/async.rb +12 -10
- data/lib/semantic_logger/appender/async_batch.rb +7 -3
- data/lib/semantic_logger/appender/bugsnag.rb +43 -30
- data/lib/semantic_logger/appender/elasticsearch.rb +34 -15
- data/lib/semantic_logger/appender/elasticsearch_http.rb +4 -4
- data/lib/semantic_logger/appender/file.rb +249 -67
- data/lib/semantic_logger/appender/graylog.rb +15 -10
- data/lib/semantic_logger/appender/honeybadger.rb +3 -3
- data/lib/semantic_logger/appender/http.rb +41 -20
- data/lib/semantic_logger/appender/io.rb +68 -0
- data/lib/semantic_logger/appender/kafka.rb +46 -31
- data/lib/semantic_logger/appender/mongodb.rb +6 -6
- data/lib/semantic_logger/appender/new_relic.rb +2 -2
- data/lib/semantic_logger/appender/rabbitmq.rb +5 -5
- data/lib/semantic_logger/appender/sentry.rb +7 -7
- data/lib/semantic_logger/appender/sentry_ruby.rb +138 -0
- data/lib/semantic_logger/appender/splunk.rb +7 -5
- data/lib/semantic_logger/appender/splunk_http.rb +6 -5
- data/lib/semantic_logger/appender/syslog.rb +23 -15
- data/lib/semantic_logger/appender/tcp.rb +9 -9
- data/lib/semantic_logger/appender/udp.rb +2 -2
- data/lib/semantic_logger/appender/wrapper.rb +3 -2
- data/lib/semantic_logger/appender.rb +62 -65
- data/lib/semantic_logger/appenders.rb +36 -53
- data/lib/semantic_logger/base.rb +61 -39
- data/lib/semantic_logger/formatters/base.rb +16 -6
- data/lib/semantic_logger/formatters/color.rb +14 -15
- data/lib/semantic_logger/formatters/default.rb +18 -5
- data/lib/semantic_logger/formatters/fluentd.rb +7 -18
- data/lib/semantic_logger/formatters/json.rb +3 -5
- data/lib/semantic_logger/formatters/logfmt.rb +77 -0
- data/lib/semantic_logger/formatters/raw.rb +39 -10
- data/lib/semantic_logger/formatters/signalfx.rb +14 -21
- data/lib/semantic_logger/formatters/syslog.rb +8 -6
- data/lib/semantic_logger/formatters/syslog_cee.rb +9 -7
- data/lib/semantic_logger/formatters.rb +13 -13
- data/lib/semantic_logger/jruby/garbage_collection_logger.rb +4 -2
- data/lib/semantic_logger/levels.rb +9 -7
- data/lib/semantic_logger/log.rb +58 -73
- data/lib/semantic_logger/loggable.rb +8 -1
- data/lib/semantic_logger/logger.rb +19 -11
- data/lib/semantic_logger/metric/new_relic.rb +3 -3
- data/lib/semantic_logger/metric/signalfx.rb +3 -3
- data/lib/semantic_logger/metric/statsd.rb +7 -7
- data/lib/semantic_logger/processor.rb +9 -7
- data/lib/semantic_logger/reporters/minitest.rb +4 -4
- data/lib/semantic_logger/semantic_logger.rb +57 -23
- data/lib/semantic_logger/subscriber.rb +24 -7
- data/lib/semantic_logger/sync.rb +12 -0
- data/lib/semantic_logger/sync_processor.rb +58 -0
- data/lib/semantic_logger/test/capture_log_events.rb +34 -0
- data/lib/semantic_logger/utils.rb +32 -13
- data/lib/semantic_logger/version.rb +1 -1
- data/lib/semantic_logger.rb +27 -22
- metadata +15 -10
data/lib/semantic_logger/log.rb
CHANGED
@@ -47,6 +47,12 @@ module SemanticLogger
|
|
47
47
|
# context [Hash]
|
48
48
|
# Named contexts that were captured when the log entry was created.
|
49
49
|
class Log
|
50
|
+
# Keys passed in without a payload that will be extracted and the remainder passed into the payload.
|
51
|
+
NON_PAYLOAD_KEYS = %i[message exception backtrace exception
|
52
|
+
duration min_duration
|
53
|
+
log_exception on_exception_level
|
54
|
+
metric metric_amount dimensions].freeze
|
55
|
+
|
50
56
|
attr_accessor :level, :level_index, :name, :message, :time, :duration,
|
51
57
|
:payload, :exception, :thread_name, :backtrace,
|
52
58
|
:tags, :named_tags, :context,
|
@@ -79,20 +85,13 @@ module SemanticLogger
|
|
79
85
|
log_exception: :full,
|
80
86
|
on_exception_level: nil,
|
81
87
|
dimensions: nil)
|
82
|
-
# Elastic logging: Log when :duration exceeds :min_duration
|
83
|
-
# Except if there is an exception when it will always be logged
|
84
|
-
if duration
|
85
|
-
self.duration = duration
|
86
|
-
return false if (duration < min_duration) && exception.nil?
|
87
|
-
end
|
88
88
|
|
89
|
-
self.message
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
89
|
+
self.message = message
|
90
|
+
self.payload = payload
|
91
|
+
self.duration = duration
|
92
|
+
self.metric = metric
|
93
|
+
self.metric_amount = metric_amount
|
94
|
+
self.dimensions = dimensions
|
96
95
|
|
97
96
|
if exception
|
98
97
|
case log_exception
|
@@ -113,57 +112,54 @@ module SemanticLogger
|
|
113
112
|
end
|
114
113
|
end
|
115
114
|
|
115
|
+
# Elastic logging: Log when :duration exceeds :min_duration
|
116
|
+
# Except if there is an exception when it will always be logged
|
117
|
+
return false if duration && ((duration < min_duration) && exception.nil?)
|
118
|
+
|
116
119
|
if backtrace
|
117
120
|
self.backtrace = Utils.extract_backtrace(backtrace)
|
118
121
|
elsif level_index >= SemanticLogger.backtrace_level_index
|
119
|
-
self.backtrace = Utils.extract_backtrace
|
120
|
-
end
|
121
|
-
|
122
|
-
if metric
|
123
|
-
self.metric = metric
|
124
|
-
self.metric_amount = metric_amount
|
125
|
-
self.dimensions = dimensions
|
122
|
+
self.backtrace = Utils.extract_backtrace(caller)
|
126
123
|
end
|
127
124
|
|
128
125
|
true
|
129
126
|
end
|
130
127
|
|
131
|
-
# Assign
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
# Java::JavaLang::ClassCastException.new.is_a?(Exception) => false
|
141
|
-
if exception.nil? && payload.nil? && message.respond_to?(:backtrace) && message.respond_to?(:message)
|
142
|
-
exception = message
|
143
|
-
message = nil
|
144
|
-
elsif exception.nil? && payload && payload.respond_to?(:backtrace) && payload.respond_to?(:message)
|
145
|
-
exception = payload
|
146
|
-
payload = nil
|
147
|
-
elsif payload && !payload.is_a?(Hash)
|
148
|
-
message = message.nil? ? payload : "#{message} -- #{payload}"
|
149
|
-
payload = nil
|
128
|
+
# Assign known keys to self, all other keys to the payload.
|
129
|
+
def assign_hash(hash)
|
130
|
+
self.payload ||= {}
|
131
|
+
hash.each_pair do |key, value|
|
132
|
+
if respond_to?("#{key}=".to_sym)
|
133
|
+
public_send("#{key}=".to_sym, value)
|
134
|
+
else
|
135
|
+
payload[key] = value
|
136
|
+
end
|
150
137
|
end
|
138
|
+
self.payload = nil if payload.empty?
|
139
|
+
self
|
140
|
+
end
|
151
141
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
142
|
+
# Extract the arguments from a Hash Payload
|
143
|
+
def extract_arguments(payload, message = nil)
|
144
|
+
raise(ArgumentError, "payload must be a Hash") unless payload.is_a?(Hash)
|
145
|
+
|
146
|
+
message = nil if message == ""
|
147
|
+
return payload if payload.key?(:payload)
|
148
|
+
|
149
|
+
new_payload = {}
|
150
|
+
args = {}
|
151
|
+
payload.each_pair do |key, value|
|
152
|
+
# Supplied message takes precedence
|
153
|
+
if (key == :message) && !message.nil?
|
154
|
+
new_payload[key] = value
|
155
|
+
next
|
163
156
|
end
|
164
|
-
|
165
|
-
|
157
|
+
|
158
|
+
NON_PAYLOAD_KEYS.include?(key) ? args[key] = value : new_payload[key] = value
|
166
159
|
end
|
160
|
+
args[:payload] = new_payload unless new_payload.empty?
|
161
|
+
args[:message] = message if message
|
162
|
+
args
|
167
163
|
end
|
168
164
|
|
169
165
|
MAX_EXCEPTIONS_TO_UNWRAP = 5
|
@@ -191,7 +187,7 @@ module SemanticLogger
|
|
191
187
|
|
192
188
|
# Returns [String] the exception backtrace including all of the child / caused by exceptions
|
193
189
|
def backtrace_to_s
|
194
|
-
trace =
|
190
|
+
trace = ""
|
195
191
|
each_exception do |exception, i|
|
196
192
|
if i.zero?
|
197
193
|
trace = (exception.backtrace || []).join("\n")
|
@@ -212,6 +208,7 @@ module SemanticLogger
|
|
212
208
|
else
|
213
209
|
def duration_to_s
|
214
210
|
return unless duration
|
211
|
+
|
215
212
|
duration < 10.0 ? "#{format('%.3f', duration)}ms" : "#{format('%.1f', duration)}ms"
|
216
213
|
end
|
217
214
|
end
|
@@ -219,13 +216,14 @@ module SemanticLogger
|
|
219
216
|
# Returns [String] the duration in human readable form
|
220
217
|
def duration_human
|
221
218
|
return nil unless duration
|
219
|
+
|
222
220
|
seconds = duration / 1000
|
223
221
|
if seconds >= 86_400.0 # 1 day
|
224
222
|
"#{(seconds / 86_400).to_i}d #{Time.at(seconds).strftime('%-Hh %-Mm')}"
|
225
223
|
elsif seconds >= 3600.0 # 1 hour
|
226
|
-
Time.at(seconds).strftime(
|
224
|
+
Time.at(seconds).strftime("%-Hh %-Mm")
|
227
225
|
elsif seconds >= 60.0 # 1 minute
|
228
|
-
Time.at(seconds).strftime(
|
226
|
+
Time.at(seconds).strftime("%-Mm %-Ss")
|
229
227
|
elsif seconds >= 1.0 # 1 second
|
230
228
|
"#{format('%.3f', seconds)}s"
|
231
229
|
else
|
@@ -238,9 +236,7 @@ module SemanticLogger
|
|
238
236
|
level.to_s[0..0].upcase
|
239
237
|
end
|
240
238
|
|
241
|
-
#
|
242
|
-
# Example:
|
243
|
-
# 18934:thread 23 test_logging.rb:51
|
239
|
+
# DEPRECATED
|
244
240
|
def process_info(thread_name_length = 30)
|
245
241
|
file, line = file_name_and_line(true)
|
246
242
|
file_name = " #{file}:#{line}" if file
|
@@ -248,7 +244,7 @@ module SemanticLogger
|
|
248
244
|
"#{$$}:#{format("%.#{thread_name_length}s", thread_name)}#{file_name}"
|
249
245
|
end
|
250
246
|
|
251
|
-
CALLER_REGEXP = /^(.*):(\d+)
|
247
|
+
CALLER_REGEXP = /^(.*):(\d+).*/.freeze
|
252
248
|
|
253
249
|
# Extract the filename and line number from the last entry in the supplied backtrace
|
254
250
|
def extract_file_and_line(stack, short_name = false)
|
@@ -265,7 +261,7 @@ module SemanticLogger
|
|
265
261
|
|
266
262
|
# Strip the standard Rails colorizing from the logged message
|
267
263
|
def cleansed_message
|
268
|
-
message.to_s.gsub(/(\e(\[([\d;]*[mz]?))?)?/,
|
264
|
+
message.to_s.gsub(/(\e(\[([\d;]*[mz]?))?)?/, "").strip
|
269
265
|
end
|
270
266
|
|
271
267
|
# Return the payload in text form
|
@@ -279,19 +275,8 @@ module SemanticLogger
|
|
279
275
|
!(payload.nil? || (payload.respond_to?(:empty?) && payload.empty?))
|
280
276
|
end
|
281
277
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
# DEPRECATED
|
286
|
-
def formatted_time
|
287
|
-
time.strftime(Formatters::Base.build_time_format)
|
288
|
-
end
|
289
|
-
|
290
|
-
DeprecatedLogger = Struct.new(:host, :application)
|
291
|
-
|
292
|
-
# DEPRECATED: Use SemanticLogger::Formatters::Raw
|
293
|
-
def to_h(host = SemanticLogger.host, application = SemanticLogger.application)
|
294
|
-
logger = DeprecatedLogger.new(host, application)
|
278
|
+
def to_h(host = SemanticLogger.host, application = SemanticLogger.application, environment = SemanticLogger.environment)
|
279
|
+
logger = Struct.new(:host, :application, :environment).new(host, application, environment)
|
295
280
|
SemanticLogger::Formatters::Raw.new.call(self, logger)
|
296
281
|
end
|
297
282
|
|
@@ -8,7 +8,7 @@
|
|
8
8
|
# Example:
|
9
9
|
# require 'semantic_logger'
|
10
10
|
# SemanticLogger.default_level = :debug
|
11
|
-
# SemanticLogger.add_appender(io:
|
11
|
+
# SemanticLogger.add_appender(io: $stdout, formatter: :color)
|
12
12
|
#
|
13
13
|
# class ExternalSupplier
|
14
14
|
# # Create class and instance logger methods
|
@@ -32,7 +32,14 @@ module SemanticLogger
|
|
32
32
|
module Loggable
|
33
33
|
def self.included(base)
|
34
34
|
base.extend ClassMethods
|
35
|
+
base.singleton_class.class_eval do
|
36
|
+
undef_method :logger if method_defined?(:logger)
|
37
|
+
undef_method :logger= if method_defined?(:logger=)
|
38
|
+
end
|
35
39
|
base.class_eval do
|
40
|
+
undef_method :logger if method_defined?(:logger)
|
41
|
+
undef_method :logger= if method_defined?(:logger=)
|
42
|
+
|
36
43
|
# Returns [SemanticLogger::Logger] class level logger
|
37
44
|
def self.logger
|
38
45
|
@semantic_logger ||= SemanticLogger[self]
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "concurrent"
|
2
2
|
module SemanticLogger
|
3
3
|
# Logger stores the class name to be used for all log messages so that every
|
4
4
|
# log message written by this instance will include the class name
|
@@ -9,7 +9,7 @@ module SemanticLogger
|
|
9
9
|
subscriber = block || object
|
10
10
|
|
11
11
|
unless subscriber.is_a?(Proc) || subscriber.respond_to?(:call)
|
12
|
-
raise(
|
12
|
+
raise("When supplying an on_log subscriber, it must support the #call method")
|
13
13
|
end
|
14
14
|
|
15
15
|
subscribers = (@subscribers ||= Concurrent::Array.new)
|
@@ -21,7 +21,19 @@ module SemanticLogger
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.processor
|
24
|
-
@processor
|
24
|
+
@processor ||= Processor.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# Switch to the synchronous processor
|
28
|
+
def self.sync!
|
29
|
+
return if @processor.is_a?(SyncProcessor)
|
30
|
+
|
31
|
+
@processor = SyncProcessor.new(@processor&.appenders)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Running without the background logging thread?
|
35
|
+
def self.sync?
|
36
|
+
processor.is_a?(SyncProcessor)
|
25
37
|
end
|
26
38
|
|
27
39
|
# Returns a Logger instance
|
@@ -63,20 +75,16 @@ module SemanticLogger
|
|
63
75
|
Logger.processor.log(log)
|
64
76
|
end
|
65
77
|
|
66
|
-
|
67
|
-
|
68
|
-
@processor = Processor.new
|
78
|
+
@processor = nil
|
69
79
|
@subscribers = nil
|
70
80
|
|
71
81
|
def self.call_subscribers(log)
|
72
82
|
return unless @subscribers
|
73
83
|
|
74
84
|
@subscribers.each do |subscriber|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
self.class.processor.logger.error('Exception calling :on_log subscriber', exc)
|
79
|
-
end
|
85
|
+
subscriber.call(log)
|
86
|
+
rescue Exception => e
|
87
|
+
processor.logger.error("Exception calling :on_log subscriber", e)
|
80
88
|
end
|
81
89
|
end
|
82
90
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
begin
|
2
|
-
require
|
2
|
+
require "newrelic_rpm"
|
3
3
|
rescue LoadError
|
4
|
-
raise 'Gem newrelic_rpm is required for logging to New Relic. Please add the gem "newrelic_rpm" to your Gemfile.'
|
4
|
+
raise LoadError, 'Gem newrelic_rpm is required for logging to New Relic. Please add the gem "newrelic_rpm" to your Gemfile.'
|
5
5
|
end
|
6
6
|
|
7
7
|
# Send Metrics to NewRelic
|
@@ -37,7 +37,7 @@ module SemanticLogger
|
|
37
37
|
# regular expression. All other messages will be ignored.
|
38
38
|
# Proc: Only include log messages where the supplied Proc returns true
|
39
39
|
# The Proc must return true or false.
|
40
|
-
def initialize(prefix:
|
40
|
+
def initialize(prefix: "Custom", **args, &block)
|
41
41
|
@prefix = prefix
|
42
42
|
super(**args, &block)
|
43
43
|
end
|
@@ -10,7 +10,7 @@ module SemanticLogger
|
|
10
10
|
class Signalfx < SemanticLogger::Appender::Http
|
11
11
|
attr_reader :full_url
|
12
12
|
|
13
|
-
END_POINT =
|
13
|
+
END_POINT = "v2/datapoint".freeze
|
14
14
|
|
15
15
|
# Create SignalFx metrics appender.
|
16
16
|
#
|
@@ -75,7 +75,7 @@ module SemanticLogger
|
|
75
75
|
# end
|
76
76
|
def initialize(token:,
|
77
77
|
dimensions: nil,
|
78
|
-
url:
|
78
|
+
url: "https://ingest.signalfx.com",
|
79
79
|
formatter: nil,
|
80
80
|
**args,
|
81
81
|
&block)
|
@@ -84,7 +84,7 @@ module SemanticLogger
|
|
84
84
|
|
85
85
|
super(url: url, formatter: formatter, **args, &block)
|
86
86
|
|
87
|
-
@header[
|
87
|
+
@header["X-SF-TOKEN"] = token
|
88
88
|
@full_url = "#{url}/#{END_POINT}"
|
89
89
|
end
|
90
90
|
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require "uri"
|
2
2
|
begin
|
3
|
-
require
|
3
|
+
require "statsd-ruby"
|
4
4
|
rescue LoadError
|
5
|
-
raise 'Gem statsd-ruby is required for logging metrics. Please add the gem "statsd-ruby" to your Gemfile.'
|
5
|
+
raise LoadError, 'Gem statsd-ruby is required for logging metrics. Please add the gem "statsd-ruby" to your Gemfile.'
|
6
6
|
end
|
7
7
|
|
8
8
|
module SemanticLogger
|
@@ -26,17 +26,17 @@ module SemanticLogger
|
|
26
26
|
# metric: :statsd,
|
27
27
|
# url: 'localhost:8125'
|
28
28
|
# )
|
29
|
-
def initialize(url:
|
29
|
+
def initialize(url: "udp://localhost:8125")
|
30
30
|
@url = url
|
31
31
|
end
|
32
32
|
|
33
33
|
def reopen
|
34
34
|
uri = URI.parse(@url)
|
35
|
-
raise('Statsd only supports udp. Example: "udp://localhost:8125"') if uri.scheme !=
|
35
|
+
raise('Statsd only supports udp. Example: "udp://localhost:8125"') if uri.scheme != "udp"
|
36
36
|
|
37
37
|
@statsd = ::Statsd.new(uri.host, uri.port)
|
38
|
-
path = uri.path.chomp(
|
39
|
-
@statsd.namespace = path.sub(
|
38
|
+
path = uri.path.chomp("/")
|
39
|
+
@statsd.namespace = path.sub("/", "") if path != ""
|
40
40
|
end
|
41
41
|
|
42
42
|
def log(log)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module SemanticLogger
|
2
2
|
# Thread that submits and processes log requests
|
3
3
|
class Processor < Appender::Async
|
4
|
-
# Allow the internal logger to be overridden from its default of
|
4
|
+
# Allow the internal logger to be overridden from its default of $stderr
|
5
5
|
# Can be replaced with another Ruby logger or Rails logger, but never to
|
6
6
|
# SemanticLogger::Logger itself since it is for reporting problems
|
7
7
|
# while trying to log to the various appenders
|
@@ -11,13 +11,14 @@ module SemanticLogger
|
|
11
11
|
|
12
12
|
# Internal logger for SemanticLogger
|
13
13
|
# For example when an appender is not working etc..
|
14
|
-
# By default logs to
|
14
|
+
# By default logs to $stderr
|
15
15
|
def self.logger
|
16
|
-
@logger ||=
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
@logger ||=
|
17
|
+
begin
|
18
|
+
l = SemanticLogger::Appender::IO.new($stderr, level: :warn)
|
19
|
+
l.name = name
|
20
|
+
l
|
21
|
+
end
|
21
22
|
end
|
22
23
|
|
23
24
|
attr_reader :appenders
|
@@ -30,6 +31,7 @@ module SemanticLogger
|
|
30
31
|
# Start the appender thread
|
31
32
|
def start
|
32
33
|
return false if active?
|
34
|
+
|
33
35
|
thread
|
34
36
|
true
|
35
37
|
end
|
@@ -23,7 +23,7 @@ module SemanticLogger
|
|
23
23
|
class Minitest < ::Minitest::AbstractReporter
|
24
24
|
include SemanticLogger::Loggable
|
25
25
|
|
26
|
-
logger.name =
|
26
|
+
logger.name = "Minitest"
|
27
27
|
|
28
28
|
attr_accessor :io
|
29
29
|
|
@@ -33,11 +33,11 @@ module SemanticLogger
|
|
33
33
|
|
34
34
|
def after_test(test)
|
35
35
|
if test.error?
|
36
|
-
logger.benchmark_error("FAIL #{test.class_name} #{test.name}", duration: test.time * 1_000, metric:
|
36
|
+
logger.benchmark_error("FAIL #{test.class_name} #{test.name}", duration: test.time * 1_000, metric: "minitest/fail")
|
37
37
|
elsif test.skipped?
|
38
|
-
logger.benchmark_warn("SKIP #{test.class_name} #{test.name}", duration: test.time * 1_000, metric:
|
38
|
+
logger.benchmark_warn("SKIP #{test.class_name} #{test.name}", duration: test.time * 1_000, metric: "minitest/skip")
|
39
39
|
else
|
40
|
-
logger.benchmark_info("PASS #{test.class_name} #{test.name}", duration: test.time * 1_000, metric:
|
40
|
+
logger.benchmark_info("PASS #{test.class_name} #{test.name}", duration: test.time * 1_000, metric: "minitest/pass")
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "concurrent"
|
2
|
+
require "socket"
|
3
3
|
|
4
4
|
module SemanticLogger
|
5
5
|
# Logging levels in order of most detailed to most severe
|
@@ -52,7 +52,7 @@ module SemanticLogger
|
|
52
52
|
# Returns [String] name of this host for logging purposes
|
53
53
|
# Note: Not all appenders use `host`
|
54
54
|
def self.host
|
55
|
-
@host ||= Socket.gethostname.force_encoding(
|
55
|
+
@host ||= Socket.gethostname.force_encoding("UTF-8")
|
56
56
|
end
|
57
57
|
|
58
58
|
# Override the default host name
|
@@ -71,7 +71,19 @@ module SemanticLogger
|
|
71
71
|
@application = application
|
72
72
|
end
|
73
73
|
|
74
|
-
|
74
|
+
# Returns [String] name of this environment for logging purposes
|
75
|
+
# Note: Not all appenders use `environment`
|
76
|
+
def self.environment
|
77
|
+
@environment
|
78
|
+
end
|
79
|
+
|
80
|
+
# Override the default environment
|
81
|
+
def self.environment=(environment)
|
82
|
+
@environment = environment
|
83
|
+
end
|
84
|
+
|
85
|
+
@application = ENV["SEMANTIC_LOGGER_APP"] || "Semantic Logger"
|
86
|
+
@environment = ENV["SEMANTIC_LOGGER_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"]
|
75
87
|
|
76
88
|
# Add a new logging appender as a new destination for all log messages
|
77
89
|
# emitted from Semantic Logger
|
@@ -89,7 +101,7 @@ module SemanticLogger
|
|
89
101
|
# Or,
|
90
102
|
# io: [IO]
|
91
103
|
# An IO Stream to log to.
|
92
|
-
# For example
|
104
|
+
# For example $stdout, $stderr, etc.
|
93
105
|
#
|
94
106
|
# Or,
|
95
107
|
# appender: [Symbol|SemanticLogger::Subscriber]
|
@@ -110,7 +122,7 @@ module SemanticLogger
|
|
110
122
|
# Default: SemanticLogger.default_level
|
111
123
|
#
|
112
124
|
# formatter: [Symbol|Object|Proc]
|
113
|
-
# Any of the following symbol values: :default, :color, :json
|
125
|
+
# Any of the following symbol values: :default, :color, :json, :logfmt, etc...
|
114
126
|
# Or,
|
115
127
|
# An instance of a class that implements #call
|
116
128
|
# Or,
|
@@ -126,14 +138,14 @@ module SemanticLogger
|
|
126
138
|
# Examples:
|
127
139
|
#
|
128
140
|
# # Send all logging output to Standard Out (Screen)
|
129
|
-
# SemanticLogger.add_appender(io:
|
141
|
+
# SemanticLogger.add_appender(io: $stdout)
|
130
142
|
#
|
131
143
|
# # Send all logging output to a file
|
132
144
|
# SemanticLogger.add_appender(file_name: 'logfile.log')
|
133
145
|
#
|
134
146
|
# # Send all logging output to a file and only :info and above to standard output
|
135
147
|
# SemanticLogger.add_appender(file_name: 'logfile.log')
|
136
|
-
# SemanticLogger.add_appender(io:
|
148
|
+
# SemanticLogger.add_appender(io: $stdout, level: :info)
|
137
149
|
#
|
138
150
|
# Log to log4r, Logger, etc.:
|
139
151
|
#
|
@@ -142,7 +154,7 @@ module SemanticLogger
|
|
142
154
|
# require 'semantic_logger'
|
143
155
|
#
|
144
156
|
# # Built-in Ruby logger
|
145
|
-
# log = Logger.new(
|
157
|
+
# log = Logger.new($stdout)
|
146
158
|
# log.level = Logger::DEBUG
|
147
159
|
#
|
148
160
|
# SemanticLogger.default_level = :debug
|
@@ -151,8 +163,8 @@ module SemanticLogger
|
|
151
163
|
# logger = SemanticLogger['Example']
|
152
164
|
# logger.info "Hello World"
|
153
165
|
# logger.debug("Login time", user: 'Joe', duration: 100, ip_address: '127.0.0.1')
|
154
|
-
def self.add_appender(
|
155
|
-
appender =
|
166
|
+
def self.add_appender(**args, &block)
|
167
|
+
appender = appenders.add(**args, &block)
|
156
168
|
# Start appender thread if it is not already running
|
157
169
|
Logger.processor.start
|
158
170
|
appender
|
@@ -161,7 +173,15 @@ module SemanticLogger
|
|
161
173
|
# Remove an existing appender
|
162
174
|
# Currently only supports appender instances
|
163
175
|
def self.remove_appender(appender)
|
164
|
-
|
176
|
+
return unless appender
|
177
|
+
|
178
|
+
appenders.delete(appender)
|
179
|
+
appender.close
|
180
|
+
end
|
181
|
+
|
182
|
+
# Clear out all previously registered appenders
|
183
|
+
def self.clear_appenders!
|
184
|
+
Logger.processor.close
|
165
185
|
end
|
166
186
|
|
167
187
|
# Returns [SemanticLogger::Subscriber] a copy of the list of active
|
@@ -169,7 +189,7 @@ module SemanticLogger
|
|
169
189
|
# Use SemanticLogger.add_appender and SemanticLogger.remove_appender
|
170
190
|
# to manipulate the active appenders list
|
171
191
|
def self.appenders
|
172
|
-
Logger.processor.appenders
|
192
|
+
Logger.processor.appenders
|
173
193
|
end
|
174
194
|
|
175
195
|
# Flush all queued log entries disk, database, etc.
|
@@ -233,9 +253,9 @@ module SemanticLogger
|
|
233
253
|
# When the log_level_signal is raised on this process, the global default log level
|
234
254
|
# rotates through the following log levels in the following order, starting
|
235
255
|
# from the current global default level:
|
236
|
-
# :warn, :info, :debug, :trace
|
256
|
+
# :fatal, :error, :warn, :info, :debug, :trace
|
237
257
|
#
|
238
|
-
# If the current level is :trace it wraps around back to :
|
258
|
+
# If the current level is :trace it wraps around back to :fatal
|
239
259
|
#
|
240
260
|
# 2. Logging a Ruby thread dump
|
241
261
|
#
|
@@ -256,22 +276,24 @@ module SemanticLogger
|
|
256
276
|
# Note:
|
257
277
|
# To only register one of the signal handlers, set the other to nil
|
258
278
|
# Set gc_log_microseconds to nil to not enable JRuby Garbage collections
|
259
|
-
def self.add_signal_handler(log_level_signal =
|
279
|
+
def self.add_signal_handler(log_level_signal = "USR2", thread_dump_signal = "TTIN", gc_log_microseconds = 100_000)
|
260
280
|
if log_level_signal
|
261
281
|
Signal.trap(log_level_signal) do
|
262
|
-
|
263
|
-
|
264
|
-
|
282
|
+
current_level_index = LEVELS.find_index(default_level)
|
283
|
+
new_level_index = current_level_index == 0 ? LEVELS.size - 1 : current_level_index - 1
|
284
|
+
new_level = LEVELS[new_level_index]
|
265
285
|
self.default_level = new_level
|
286
|
+
self["SemanticLogger"].warn "Changed global default log level to #{new_level.inspect}"
|
266
287
|
end
|
267
288
|
end
|
268
289
|
|
269
290
|
if thread_dump_signal
|
270
291
|
Signal.trap(thread_dump_signal) do
|
271
|
-
logger = SemanticLogger[
|
292
|
+
logger = SemanticLogger["Thread Dump"]
|
272
293
|
Thread.list.each do |thread|
|
273
294
|
# MRI re-uses the main thread for signals, JRuby uses `SIGTTIN handler` thread.
|
274
295
|
next if defined?(JRuby) && (thread == Thread.current)
|
296
|
+
|
275
297
|
logger.backtrace(thread: thread)
|
276
298
|
end
|
277
299
|
end
|
@@ -290,7 +312,7 @@ module SemanticLogger
|
|
290
312
|
# If the tag being supplied is definitely a string then this fast
|
291
313
|
# tag api can be used for short lived tags
|
292
314
|
def self.fast_tag(tag)
|
293
|
-
return yield if tag.nil? || tag ==
|
315
|
+
return yield if tag.nil? || tag == ""
|
294
316
|
|
295
317
|
t = Thread.current[:semantic_logger_tags] ||= []
|
296
318
|
begin
|
@@ -367,7 +389,7 @@ module SemanticLogger
|
|
367
389
|
# :nodoc
|
368
390
|
def self.named_tagged(hash)
|
369
391
|
return yield if hash.nil? || hash.empty?
|
370
|
-
raise(ArgumentError,
|
392
|
+
raise(ArgumentError, "#named_tagged only accepts named parameters (Hash)") unless hash.is_a?(Hash)
|
371
393
|
|
372
394
|
begin
|
373
395
|
push_named_tags(hash)
|
@@ -476,11 +498,23 @@ module SemanticLogger
|
|
476
498
|
Thread.current[:semantic_logger_silence] || @default_level_index
|
477
499
|
end
|
478
500
|
|
479
|
-
|
501
|
+
# Run Semantic Logger in Synchronous mode.
|
502
|
+
#
|
503
|
+
# I.e. Instead of logging messages in a separate thread for better performance,
|
504
|
+
# log them using the current thread.
|
505
|
+
def self.sync!
|
506
|
+
Logger.sync!
|
507
|
+
end
|
508
|
+
|
509
|
+
# Running in synchronous mode?
|
510
|
+
def self.sync?
|
511
|
+
Logger.sync?
|
512
|
+
end
|
480
513
|
|
481
514
|
# Initial default Level for all new instances of SemanticLogger::Logger
|
482
515
|
@default_level = :info
|
483
516
|
@default_level_index = Levels.index(@default_level)
|
484
517
|
@backtrace_level = :error
|
485
518
|
@backtrace_level_index = Levels.index(@backtrace_level)
|
519
|
+
@sync = false
|
486
520
|
end
|