semantic_logger 4.7.4 → 4.9.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 +47 -19
- data/lib/semantic_logger/appender/async.rb +1 -1
- data/lib/semantic_logger/appender/elasticsearch.rb +24 -6
- data/lib/semantic_logger/appender/file.rb +249 -68
- data/lib/semantic_logger/appender/io.rb +68 -0
- data/lib/semantic_logger/appender/kafka.rb +4 -0
- data/lib/semantic_logger/appender/splunk.rb +2 -1
- data/lib/semantic_logger/appender/splunk_http.rb +2 -2
- data/lib/semantic_logger/appender/syslog.rb +5 -3
- data/lib/semantic_logger/appender/wrapper.rb +3 -2
- data/lib/semantic_logger/appender.rb +12 -6
- data/lib/semantic_logger/appenders.rb +31 -27
- data/lib/semantic_logger/base.rb +5 -4
- data/lib/semantic_logger/formatters/base.rb +1 -0
- data/lib/semantic_logger/formatters/color.rb +3 -3
- data/lib/semantic_logger/formatters/logfmt.rb +72 -0
- data/lib/semantic_logger/formatters/syslog.rb +2 -1
- data/lib/semantic_logger/formatters/syslog_cee.rb +2 -1
- data/lib/semantic_logger/formatters.rb +10 -11
- data/lib/semantic_logger/log.rb +2 -4
- data/lib/semantic_logger/loggable.rb +8 -1
- data/lib/semantic_logger/logger.rb +16 -6
- data/lib/semantic_logger/processor.rb +3 -3
- data/lib/semantic_logger/semantic_logger.rb +18 -10
- data/lib/semantic_logger/subscriber.rb +10 -0
- data/lib/semantic_logger/sync_processor.rb +5 -5
- data/lib/semantic_logger/test/capture_log_events.rb +34 -0
- data/lib/semantic_logger/utils.rb +29 -10
- data/lib/semantic_logger/version.rb +1 -1
- data/lib/semantic_logger.rb +4 -0
- metadata +8 -6
@@ -57,7 +57,7 @@ module SemanticLogger
|
|
57
57
|
# Only used with the TCP protocol.
|
58
58
|
# Specify custom parameters to pass into Net::TCPClient.new
|
59
59
|
# For a list of options see the net_tcp_client documentation:
|
60
|
-
# https://github.com/
|
60
|
+
# https://github.com/reidmorrison/net_tcp_client/blob/master/lib/net/tcp_client/tcp_client.rb
|
61
61
|
#
|
62
62
|
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
63
63
|
# Override the log level for this appender.
|
@@ -151,7 +151,8 @@ module SemanticLogger
|
|
151
151
|
begin
|
152
152
|
require "syslog_protocol"
|
153
153
|
rescue LoadError
|
154
|
-
raise LoadError,
|
154
|
+
raise LoadError,
|
155
|
+
"Missing gem: syslog_protocol. This gem is required when logging over TCP or UDP. To fix this error: gem install syslog_protocol"
|
155
156
|
end
|
156
157
|
|
157
158
|
# The net_tcp_client gem is required when logging over TCP.
|
@@ -159,7 +160,8 @@ module SemanticLogger
|
|
159
160
|
begin
|
160
161
|
require "net/tcp_client"
|
161
162
|
rescue LoadError
|
162
|
-
raise LoadError,
|
163
|
+
raise LoadError,
|
164
|
+
"Missing gem: net_tcp_client. This gem is required when logging over TCP. To fix this error: gem install net_tcp_client"
|
163
165
|
end
|
164
166
|
end
|
165
167
|
end
|
@@ -32,7 +32,7 @@ module SemanticLogger
|
|
32
32
|
# require 'logger'
|
33
33
|
# require 'semantic_logger'
|
34
34
|
#
|
35
|
-
# ruby_logger = Logger.new(
|
35
|
+
# ruby_logger = Logger.new($stdout)
|
36
36
|
# SemanticLogger.add_appender(logger: ruby_logger)
|
37
37
|
#
|
38
38
|
# logger = SemanticLogger['test']
|
@@ -45,7 +45,8 @@ module SemanticLogger
|
|
45
45
|
# Check if the custom appender responds to all the log levels. For example Ruby ::Logger
|
46
46
|
does_not_implement = LEVELS[1..-1].find { |i| !@logger.respond_to?(i) }
|
47
47
|
if does_not_implement
|
48
|
-
raise(ArgumentError,
|
48
|
+
raise(ArgumentError,
|
49
|
+
"Supplied logger does not implement:#{does_not_implement}. It must implement all of #{LEVELS[1..-1].inspect}")
|
49
50
|
end
|
50
51
|
|
51
52
|
super(**args, &block)
|
@@ -9,6 +9,7 @@ module SemanticLogger
|
|
9
9
|
autoload :File, "semantic_logger/appender/file"
|
10
10
|
autoload :Graylog, "semantic_logger/appender/graylog"
|
11
11
|
autoload :Honeybadger, "semantic_logger/appender/honeybadger"
|
12
|
+
autoload :IO, "semantic_logger/appender/io"
|
12
13
|
autoload :Kafka, "semantic_logger/appender/kafka"
|
13
14
|
autoload :Sentry, "semantic_logger/appender/sentry"
|
14
15
|
autoload :Http, "semantic_logger/appender/http"
|
@@ -32,7 +33,7 @@ module SemanticLogger
|
|
32
33
|
appender = build(**args, &block)
|
33
34
|
|
34
35
|
# If appender implements #batch, then it should use the batch proxy by default.
|
35
|
-
batch
|
36
|
+
batch = true if batch.nil? && appender.respond_to?(:batch)
|
36
37
|
|
37
38
|
if batch == true
|
38
39
|
Appender::AsyncBatch.new(
|
@@ -56,8 +57,10 @@ module SemanticLogger
|
|
56
57
|
|
57
58
|
# Returns [Subscriber] instance from the supplied options.
|
58
59
|
def self.build(io: nil, file_name: nil, appender: nil, metric: nil, logger: nil, **args, &block)
|
59
|
-
if
|
60
|
-
SemanticLogger::Appender::File.new(
|
60
|
+
if file_name
|
61
|
+
SemanticLogger::Appender::File.new(file_name, **args, &block)
|
62
|
+
elsif io
|
63
|
+
SemanticLogger::Appender::IO.new(io, **args, &block)
|
61
64
|
elsif logger
|
62
65
|
SemanticLogger::Appender::Wrapper.new(logger: logger, **args, &block)
|
63
66
|
elsif appender
|
@@ -66,7 +69,8 @@ module SemanticLogger
|
|
66
69
|
elsif appender.is_a?(Subscriber)
|
67
70
|
appender
|
68
71
|
else
|
69
|
-
raise(ArgumentError,
|
72
|
+
raise(ArgumentError,
|
73
|
+
"Parameter :appender must be either a Symbol or an object derived from SemanticLogger::Subscriber, not: #{appender.inspect}")
|
70
74
|
end
|
71
75
|
elsif metric
|
72
76
|
if metric.is_a?(Symbol)
|
@@ -74,10 +78,12 @@ module SemanticLogger
|
|
74
78
|
elsif metric.is_a?(Subscriber)
|
75
79
|
metric
|
76
80
|
else
|
77
|
-
raise(ArgumentError,
|
81
|
+
raise(ArgumentError,
|
82
|
+
"Parameter :metric must be either a Symbol or an object derived from SemanticLogger::Subscriber, not: #{appender.inspect}")
|
78
83
|
end
|
79
84
|
else
|
80
|
-
raise(ArgumentError,
|
85
|
+
raise(ArgumentError,
|
86
|
+
"To create an appender it must supply one of the following: :io, :file_name, :appender, :metric, or :logger")
|
81
87
|
end
|
82
88
|
end
|
83
89
|
|
@@ -10,42 +10,48 @@ module SemanticLogger
|
|
10
10
|
|
11
11
|
def add(**args, &block)
|
12
12
|
appender = SemanticLogger::Appender.factory(**args, &block)
|
13
|
+
|
14
|
+
if appender.respond_to?(:console_output?) && appender.console_output? && console_output?
|
15
|
+
logger.warn "Ignoring attempt to add a second console appender: #{appender.class.name} since it would result in duplicate console output."
|
16
|
+
return
|
17
|
+
end
|
18
|
+
|
13
19
|
self << appender
|
14
20
|
appender
|
15
21
|
end
|
16
22
|
|
23
|
+
# Whether any of the existing appenders already output to the console?
|
24
|
+
# I.e. Writes to stdout or stderr.
|
25
|
+
def console_output?
|
26
|
+
any? { |appender| appender.respond_to?(:console_output?) && appender.console_output? }
|
27
|
+
end
|
28
|
+
|
17
29
|
def log(log)
|
18
30
|
each do |appender|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
logger.error "Failed to log to appender: #{appender.name}", e
|
23
|
-
end
|
31
|
+
appender.log(log) if appender.should_log?(log)
|
32
|
+
rescue Exception => e
|
33
|
+
logger.error "Failed to log to appender: #{appender.name}", e
|
24
34
|
end
|
25
35
|
end
|
26
36
|
|
27
37
|
def flush
|
28
38
|
each do |appender|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
logger.error "Failed to flush appender: #{appender.name}", e
|
34
|
-
end
|
39
|
+
logger.trace "Flushing appender: #{appender.name}"
|
40
|
+
appender.flush
|
41
|
+
rescue Exception => e
|
42
|
+
logger.error "Failed to flush appender: #{appender.name}", e
|
35
43
|
end
|
36
44
|
logger.trace "All appenders flushed"
|
37
45
|
end
|
38
46
|
|
39
47
|
def close
|
40
|
-
each do |appender|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
logger.error "Failed to close appender: #{appender.name}", e
|
48
|
-
end
|
48
|
+
to_a.each do |appender|
|
49
|
+
logger.trace "Closing appender: #{appender.name}"
|
50
|
+
delete(appender)
|
51
|
+
appender.flush
|
52
|
+
appender.close
|
53
|
+
rescue Exception => e
|
54
|
+
logger.error "Failed to close appender: #{appender.name}", e
|
49
55
|
end
|
50
56
|
logger.trace "All appenders closed and removed from appender list"
|
51
57
|
end
|
@@ -53,14 +59,12 @@ module SemanticLogger
|
|
53
59
|
# After a fork the appender thread is not running, start it if it is not running.
|
54
60
|
def reopen
|
55
61
|
each do |appender|
|
56
|
-
|
57
|
-
next unless appender.respond_to?(:reopen)
|
62
|
+
next unless appender.respond_to?(:reopen)
|
58
63
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
+
logger.trace "Reopening appender: #{appender.name}"
|
65
|
+
appender.reopen
|
66
|
+
rescue Exception => e
|
67
|
+
logger.error "Failed to re-open appender: #{appender.name}", e
|
64
68
|
end
|
65
69
|
logger.trace "All appenders re-opened"
|
66
70
|
end
|
data/lib/semantic_logger/base.rb
CHANGED
@@ -63,7 +63,7 @@ module SemanticLogger
|
|
63
63
|
# SemanticLogger.default_level = :info
|
64
64
|
#
|
65
65
|
# # Log to screen
|
66
|
-
# SemanticLogger.add_appender(io:
|
66
|
+
# SemanticLogger.add_appender(io: $stdout, formatter: :color)
|
67
67
|
#
|
68
68
|
# # And log to a file at the same time
|
69
69
|
# SemanticLogger.add_appender(file_name: 'application.log', formatter: :color)
|
@@ -136,7 +136,7 @@ module SemanticLogger
|
|
136
136
|
|
137
137
|
backtrace =
|
138
138
|
if thread == Thread.current
|
139
|
-
Utils.extract_backtrace
|
139
|
+
Utils.extract_backtrace(caller)
|
140
140
|
else
|
141
141
|
log.thread_name = thread.name
|
142
142
|
log.tags = (thread[:semantic_logger_tags] || []).clone
|
@@ -188,7 +188,8 @@ module SemanticLogger
|
|
188
188
|
# - For better performance with clean tags, see `SemanticLogger.tagged`.
|
189
189
|
def tagged(*tags, &block)
|
190
190
|
# Allow named tags to be passed into the logger
|
191
|
-
|
191
|
+
# Rails::Rack::Logger passes logs as an array with a single argument
|
192
|
+
if tags.size == 1 && !tags.first.is_a?(Array)
|
192
193
|
tag = tags[0]
|
193
194
|
return yield if tag.nil? || tag == ""
|
194
195
|
|
@@ -376,7 +377,7 @@ module SemanticLogger
|
|
376
377
|
exception = e
|
377
378
|
ensure
|
378
379
|
# Must use ensure block otherwise a `return` in the yield above will skip the log entry
|
379
|
-
log
|
380
|
+
log = Log.new(name, level, index)
|
380
381
|
exception ||= params[:exception]
|
381
382
|
message = params[:message] if params[:message]
|
382
383
|
duration =
|
@@ -109,14 +109,14 @@ module SemanticLogger
|
|
109
109
|
def payload
|
110
110
|
return unless log.payload?
|
111
111
|
|
112
|
-
if
|
113
|
-
super
|
114
|
-
else
|
112
|
+
if log.payload.respond_to?(:ai)
|
115
113
|
begin
|
116
114
|
"-- #{log.payload.ai(@ai_options)}"
|
117
115
|
rescue StandardError
|
118
116
|
super
|
119
117
|
end
|
118
|
+
else
|
119
|
+
super
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module SemanticLogger
|
4
|
+
module Formatters
|
5
|
+
# Produces logfmt formatted messages
|
6
|
+
#
|
7
|
+
# The following fields are extracted from the raw log and included in the formatted message:
|
8
|
+
# :timestamp, :level, :name, :message, :duration, :tags, :named_tags
|
9
|
+
#
|
10
|
+
# E.g.
|
11
|
+
# timestamp="2020-07-20T08:32:05.375276Z" level=info name="DefaultTest" base="breakfast" spaces="second breakfast" double_quotes="\"elevensies\"" single_quotes="'lunch'" tag="success"
|
12
|
+
#
|
13
|
+
# All timestamps are ISO8601 formatteed
|
14
|
+
# All user supplied values are escaped and surrounded by double quotes to avoid ambiguious message delimeters
|
15
|
+
# `tags` are treated as keys with boolean values. Tag names are not formatted or validated, ensure you use valid logfmt format for tag names.
|
16
|
+
# `named_tags` are flattened are merged into the top level message field. Any conflicting fields are overridden.
|
17
|
+
# `payload` values take precedence over `tags` and `named_tags`. Any conflicting fields are overridden.
|
18
|
+
#
|
19
|
+
# Futher Reading https://brandur.org/logfmt
|
20
|
+
class Logfmt < Raw
|
21
|
+
def initialize(time_format: :iso_8601, time_key: :timestamp, **args)
|
22
|
+
super(time_format: time_format, time_key: time_key, **args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def call(log, logger)
|
26
|
+
@raw = super(log, logger)
|
27
|
+
|
28
|
+
raw_to_logfmt
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def raw_to_logfmt
|
34
|
+
@parsed = @raw.slice(time_key, :level, :name, :message, :duration).merge(tag: "success")
|
35
|
+
handle_tags
|
36
|
+
handle_payload
|
37
|
+
handle_exception
|
38
|
+
|
39
|
+
flatten_log
|
40
|
+
end
|
41
|
+
|
42
|
+
def handle_tags
|
43
|
+
tags = @raw.fetch(:tags){ [] }
|
44
|
+
.each_with_object({}){ |tag, accum| accum[tag] = true }
|
45
|
+
|
46
|
+
@parsed = @parsed.merge(tags)
|
47
|
+
.merge(@raw.fetch(:named_tags){ {} })
|
48
|
+
end
|
49
|
+
|
50
|
+
def handle_payload
|
51
|
+
return unless @raw.key? :payload
|
52
|
+
|
53
|
+
@parsed = @parsed.merge(@raw[:payload])
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_exception
|
57
|
+
return unless @raw.key? :exception
|
58
|
+
|
59
|
+
@parsed[:tag] = "exception"
|
60
|
+
@parsed = @parsed.merge(@raw[:exception])
|
61
|
+
end
|
62
|
+
|
63
|
+
def flatten_log
|
64
|
+
flattened = @parsed.map do |key, value|
|
65
|
+
"#{key}=#{value.to_json}"
|
66
|
+
end
|
67
|
+
|
68
|
+
flattened.join(" ")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
begin
|
2
2
|
require "syslog_protocol"
|
3
3
|
rescue LoadError
|
4
|
-
raise LoadError,
|
4
|
+
raise LoadError,
|
5
|
+
'Gem syslog_protocol is required for remote logging using the Syslog protocol. Please add the gem "syslog_protocol" to your Gemfile.'
|
5
6
|
end
|
6
7
|
|
7
8
|
module SemanticLogger
|
@@ -1,7 +1,8 @@
|
|
1
1
|
begin
|
2
2
|
require "syslog_protocol"
|
3
3
|
rescue LoadError
|
4
|
-
raise LoadError,
|
4
|
+
raise LoadError,
|
5
|
+
'Gem syslog_protocol is required for remote logging using the Syslog protocol. Please add the gem "syslog_protocol" to your Gemfile.'
|
5
6
|
end
|
6
7
|
|
7
8
|
module SemanticLogger
|
@@ -1,16 +1,15 @@
|
|
1
1
|
module SemanticLogger
|
2
2
|
module Formatters
|
3
|
-
|
4
|
-
autoload :
|
5
|
-
autoload :
|
6
|
-
autoload :
|
7
|
-
autoload :
|
8
|
-
autoload :
|
9
|
-
autoload :
|
10
|
-
autoload :
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
# @formatter:on
|
3
|
+
autoload :Base, "semantic_logger/formatters/base"
|
4
|
+
autoload :Color, "semantic_logger/formatters/color"
|
5
|
+
autoload :Default, "semantic_logger/formatters/default"
|
6
|
+
autoload :Json, "semantic_logger/formatters/json"
|
7
|
+
autoload :Raw, "semantic_logger/formatters/raw"
|
8
|
+
autoload :OneLine, "semantic_logger/formatters/one_line"
|
9
|
+
autoload :Signalfx, "semantic_logger/formatters/signalfx"
|
10
|
+
autoload :Syslog, "semantic_logger/formatters/syslog"
|
11
|
+
autoload :Fluentd, "semantic_logger/formatters/fluentd"
|
12
|
+
autoload :Logfmt, "semantic_logger/formatters/logfmt"
|
14
13
|
|
15
14
|
# Return formatter that responds to call.
|
16
15
|
#
|
data/lib/semantic_logger/log.rb
CHANGED
@@ -114,14 +114,12 @@ module SemanticLogger
|
|
114
114
|
|
115
115
|
# Elastic logging: Log when :duration exceeds :min_duration
|
116
116
|
# Except if there is an exception when it will always be logged
|
117
|
-
if duration
|
118
|
-
return false if (duration < min_duration) && exception.nil?
|
119
|
-
end
|
117
|
+
return false if duration && ((duration < min_duration) && exception.nil?)
|
120
118
|
|
121
119
|
if backtrace
|
122
120
|
self.backtrace = Utils.extract_backtrace(backtrace)
|
123
121
|
elsif level_index >= SemanticLogger.backtrace_level_index
|
124
|
-
self.backtrace = Utils.extract_backtrace
|
122
|
+
self.backtrace = Utils.extract_backtrace(caller)
|
125
123
|
end
|
126
124
|
|
127
125
|
true
|
@@ -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]
|
@@ -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
|
@@ -70,11 +82,9 @@ module SemanticLogger
|
|
70
82
|
return unless @subscribers
|
71
83
|
|
72
84
|
@subscribers.each do |subscriber|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
processor.logger.error("Exception calling :on_log subscriber", e)
|
77
|
-
end
|
85
|
+
subscriber.call(log)
|
86
|
+
rescue Exception => e
|
87
|
+
processor.logger.error("Exception calling :on_log subscriber", e)
|
78
88
|
end
|
79
89
|
end
|
80
90
|
end
|
@@ -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,11 +11,11 @@ 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
16
|
@logger ||=
|
17
17
|
begin
|
18
|
-
l = SemanticLogger::Appender::
|
18
|
+
l = SemanticLogger::Appender::IO.new($stderr, level: :warn)
|
19
19
|
l.name = name
|
20
20
|
l
|
21
21
|
end
|
@@ -101,7 +101,7 @@ module SemanticLogger
|
|
101
101
|
# Or,
|
102
102
|
# io: [IO]
|
103
103
|
# An IO Stream to log to.
|
104
|
-
# For example
|
104
|
+
# For example $stdout, $stderr, etc.
|
105
105
|
#
|
106
106
|
# Or,
|
107
107
|
# appender: [Symbol|SemanticLogger::Subscriber]
|
@@ -122,7 +122,7 @@ module SemanticLogger
|
|
122
122
|
# Default: SemanticLogger.default_level
|
123
123
|
#
|
124
124
|
# formatter: [Symbol|Object|Proc]
|
125
|
-
# Any of the following symbol values: :default, :color, :json
|
125
|
+
# Any of the following symbol values: :default, :color, :json, :logfmt, etc...
|
126
126
|
# Or,
|
127
127
|
# An instance of a class that implements #call
|
128
128
|
# Or,
|
@@ -138,14 +138,14 @@ module SemanticLogger
|
|
138
138
|
# Examples:
|
139
139
|
#
|
140
140
|
# # Send all logging output to Standard Out (Screen)
|
141
|
-
# SemanticLogger.add_appender(io:
|
141
|
+
# SemanticLogger.add_appender(io: $stdout)
|
142
142
|
#
|
143
143
|
# # Send all logging output to a file
|
144
144
|
# SemanticLogger.add_appender(file_name: 'logfile.log')
|
145
145
|
#
|
146
146
|
# # Send all logging output to a file and only :info and above to standard output
|
147
147
|
# SemanticLogger.add_appender(file_name: 'logfile.log')
|
148
|
-
# SemanticLogger.add_appender(io:
|
148
|
+
# SemanticLogger.add_appender(io: $stdout, level: :info)
|
149
149
|
#
|
150
150
|
# Log to log4r, Logger, etc.:
|
151
151
|
#
|
@@ -154,7 +154,7 @@ module SemanticLogger
|
|
154
154
|
# require 'semantic_logger'
|
155
155
|
#
|
156
156
|
# # Built-in Ruby logger
|
157
|
-
# log = Logger.new(
|
157
|
+
# log = Logger.new($stdout)
|
158
158
|
# log.level = Logger::DEBUG
|
159
159
|
#
|
160
160
|
# SemanticLogger.default_level = :debug
|
@@ -164,7 +164,7 @@ module SemanticLogger
|
|
164
164
|
# logger.info "Hello World"
|
165
165
|
# logger.debug("Login time", user: 'Joe', duration: 100, ip_address: '127.0.0.1')
|
166
166
|
def self.add_appender(**args, &block)
|
167
|
-
appender =
|
167
|
+
appender = appenders.add(**args, &block)
|
168
168
|
# Start appender thread if it is not already running
|
169
169
|
Logger.processor.start
|
170
170
|
appender
|
@@ -173,7 +173,15 @@ module SemanticLogger
|
|
173
173
|
# Remove an existing appender
|
174
174
|
# Currently only supports appender instances
|
175
175
|
def self.remove_appender(appender)
|
176
|
-
|
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
|
177
185
|
end
|
178
186
|
|
179
187
|
# Returns [SemanticLogger::Subscriber] a copy of the list of active
|
@@ -181,7 +189,7 @@ module SemanticLogger
|
|
181
189
|
# Use SemanticLogger.add_appender and SemanticLogger.remove_appender
|
182
190
|
# to manipulate the active appenders list
|
183
191
|
def self.appenders
|
184
|
-
Logger.processor.appenders
|
192
|
+
Logger.processor.appenders
|
185
193
|
end
|
186
194
|
|
187
195
|
# Flush all queued log entries disk, database, etc.
|
@@ -494,12 +502,12 @@ module SemanticLogger
|
|
494
502
|
# I.e. Instead of logging messages in a separate thread for better performance,
|
495
503
|
# log them using the current thread.
|
496
504
|
def self.sync!
|
497
|
-
|
505
|
+
Logger.sync!
|
498
506
|
end
|
499
507
|
|
500
508
|
# Running in synchronous mode?
|
501
509
|
def self.sync?
|
502
|
-
|
510
|
+
Logger.sync?
|
503
511
|
end
|
504
512
|
|
505
513
|
# Initial default Level for all new instances of SemanticLogger::Logger
|
@@ -22,6 +22,11 @@ module SemanticLogger
|
|
22
22
|
# NOOP
|
23
23
|
end
|
24
24
|
|
25
|
+
# Method called to log an event
|
26
|
+
def log(log)
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
|
25
30
|
# Returns [SemanticLogger::Formatters::Default] default formatter for this subscriber.
|
26
31
|
def default_formatter
|
27
32
|
SemanticLogger::Formatters::Default.new
|
@@ -68,6 +73,11 @@ module SemanticLogger
|
|
68
73
|
super(log) && (log.metric_only? ? metrics? : true)
|
69
74
|
end
|
70
75
|
|
76
|
+
# Whether this appender is logging to stdout or stderror
|
77
|
+
def console_output?
|
78
|
+
false
|
79
|
+
end
|
80
|
+
|
71
81
|
private
|
72
82
|
|
73
83
|
# Initializer for Abstract Class SemanticLogger::Subscriber
|
@@ -10,7 +10,7 @@ module SemanticLogger
|
|
10
10
|
def_delegator :@appenders, :close
|
11
11
|
def_delegator :@appenders, :reopen
|
12
12
|
|
13
|
-
# Allow the internal logger to be overridden from its default of
|
13
|
+
# Allow the internal logger to be overridden from its default of $stderr
|
14
14
|
# Can be replaced with another Ruby logger or Rails logger, but never to
|
15
15
|
# SemanticLogger::Logger itself since it is for reporting problems
|
16
16
|
# while trying to log to the various appenders
|
@@ -20,11 +20,11 @@ module SemanticLogger
|
|
20
20
|
|
21
21
|
# Internal logger for SemanticLogger
|
22
22
|
# For example when an appender is not working etc..
|
23
|
-
# By default logs to
|
23
|
+
# By default logs to $stderr
|
24
24
|
def self.logger
|
25
25
|
@logger ||=
|
26
26
|
begin
|
27
|
-
l = SemanticLogger::Appender::
|
27
|
+
l = SemanticLogger::Appender::IO.new($stderr, level: :warn)
|
28
28
|
l.name = name
|
29
29
|
l
|
30
30
|
end
|
@@ -32,8 +32,8 @@ module SemanticLogger
|
|
32
32
|
|
33
33
|
attr_reader :appenders
|
34
34
|
|
35
|
-
def initialize
|
36
|
-
@appenders = Appenders.new(self.class.logger.dup)
|
35
|
+
def initialize(appenders = nil)
|
36
|
+
@appenders = appenders || Appenders.new(self.class.logger.dup)
|
37
37
|
end
|
38
38
|
|
39
39
|
def start
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module SemanticLogger
|
2
|
+
module Test
|
3
|
+
# Logging class to captures all logging events in memory.
|
4
|
+
#
|
5
|
+
# Example:
|
6
|
+
#
|
7
|
+
# class UserTest < ActiveSupport::TestCase
|
8
|
+
# describe User do
|
9
|
+
# let(:capture_logger) { SemanticLogger::Test::CaptureLogEvents.new }
|
10
|
+
# let(:user) { User.new }
|
11
|
+
#
|
12
|
+
# it "logs message" do
|
13
|
+
# user.stub(:logger, capture_logger) do
|
14
|
+
# user.enable!
|
15
|
+
# end
|
16
|
+
# assert_equal "Hello World", capture_logger.events.last.message
|
17
|
+
# assert_equal :info, capture_logger.events.last.level
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
class CaptureLogEvents < SemanticLogger::Subscriber
|
22
|
+
attr_accessor :events
|
23
|
+
|
24
|
+
# By default collect all log levels, and collect metric only log events.
|
25
|
+
def initialize(level: :trace, metrics: true)
|
26
|
+
super(level: level, metrics: true)
|
27
|
+
end
|
28
|
+
|
29
|
+
def log(log)
|
30
|
+
(@events ||= []) << log
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|