semantic_logger 3.4.1 → 4.0.0.beta1
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 +10 -0
- data/Rakefile +4 -8
- data/lib/semantic_logger.rb +2 -31
- data/lib/semantic_logger/appender.rb +76 -0
- data/lib/semantic_logger/appender/bugsnag.rb +3 -8
- data/lib/semantic_logger/appender/file.rb +1 -1
- data/lib/semantic_logger/appender/honeybadger.rb +1 -1
- data/lib/semantic_logger/appender/http.rb +1 -1
- data/lib/semantic_logger/appender/mongodb.rb +30 -28
- data/lib/semantic_logger/appender/sentry.rb +2 -2
- data/lib/semantic_logger/appender/splunk_http.rb +4 -4
- data/lib/semantic_logger/appender/syslog.rb +2 -2
- data/lib/semantic_logger/appender/tcp.rb +9 -5
- data/lib/semantic_logger/appender/udp.rb +1 -0
- data/lib/semantic_logger/base.rb +73 -140
- data/lib/semantic_logger/core_ext/thread.rb +4 -1
- data/lib/semantic_logger/formatters/color.rb +7 -0
- data/lib/semantic_logger/formatters/default.rb +7 -0
- data/lib/semantic_logger/formatters/syslog.rb +1 -1
- data/lib/semantic_logger/log.rb +115 -12
- data/lib/semantic_logger/logger.rb +6 -215
- data/lib/semantic_logger/metrics/new_relic.rb +1 -1
- data/lib/semantic_logger/metrics/statsd.rb +5 -1
- data/lib/semantic_logger/metrics/udp.rb +80 -0
- data/lib/semantic_logger/processor.rb +235 -0
- data/lib/semantic_logger/semantic_logger.rb +36 -65
- data/lib/semantic_logger/subscriber.rb +2 -2
- data/lib/semantic_logger/version.rb +1 -1
- data/test/appender/bugsnag_test.rb +10 -9
- data/test/appender/elasticsearch_test.rb +3 -2
- data/test/appender/graylog_test.rb +4 -3
- data/test/appender/honeybadger_test.rb +2 -2
- data/test/appender/http_test.rb +3 -2
- data/test/appender/mongodb_test.rb +24 -23
- data/test/appender/new_relic_test.rb +15 -8
- data/test/appender/sentry_test.rb +2 -2
- data/test/appender/splunk_http_test.rb +8 -7
- data/test/appender/splunk_test.rb +6 -5
- data/test/appender/tcp_test.rb +3 -4
- data/test/appender/udp_test.rb +4 -5
- data/test/appender/wrapper_test.rb +37 -38
- data/test/concerns/compatibility_test.rb +2 -2
- data/test/loggable_test.rb +1 -1
- data/test/logger_test.rb +149 -528
- data/test/measure_test.rb +249 -0
- data/test/semantic_logger_test.rb +257 -0
- metadata +24 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0753c0265adc4668e64539c5014d6ea98a9f5659
|
4
|
+
data.tar.gz: 4af0ca018bd158bccc8506985c84f8e29dad6d1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eba4d620e6930c556912f8fc089326d3dbfca5bc8224e2949487509c70a37f332580ce96c78d06ae1249a15169930395a1697a012c687b2bbcf6aa58ce4d6138
|
7
|
+
data.tar.gz: 0206b4fedff5b5850d9f8541588263643f8a21a7c732a3845a12c6f4f94272ddc2042a613159fe8030e9f3855740d7461dc10885b24cbf2bd8071ce613361651
|
data/README.md
CHANGED
@@ -50,6 +50,16 @@ and are therefore not automatically included by this gem:
|
|
50
50
|
- Syslog Appender to a remote syslogng server over TCP or UDP: gem 'net_tcp_client'
|
51
51
|
- Splunk Appender: gem 'splunk-sdk-ruby'
|
52
52
|
|
53
|
+
## V4 Upgrade notes
|
54
|
+
|
55
|
+
The following changes need to be made when upgrading to V4:
|
56
|
+
- Ruby V2.1 / JRuby V9.1 is now the minimum runtime version.
|
57
|
+
- Replace calls to Logger#with_payload with SemanticLogger.named_tagged.
|
58
|
+
- Replace calls to Logger#payload with SemanticLogger.named_tags.
|
59
|
+
- Appenders now write payload data in a seperate :payload tag instead of mixing them.
|
60
|
+
directly into the root elements to avoid name clashes.
|
61
|
+
- MongoDB Appender requires Mongo Ruby Client V2 or greater.
|
62
|
+
|
53
63
|
## Install
|
54
64
|
|
55
65
|
gem install semantic_logger
|
data/Rakefile
CHANGED
@@ -15,14 +15,10 @@ task publish: :gem do
|
|
15
15
|
system "rm semantic_logger-#{SemanticLogger::VERSION}.gem"
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
t.verbose = true
|
23
|
-
end
|
24
|
-
|
25
|
-
Rake::Task['functional'].invoke
|
18
|
+
Rake::TestTask.new(:test) do |t|
|
19
|
+
t.pattern = 'test/**/*_test.rb'
|
20
|
+
t.verbose = true
|
21
|
+
t.warning = false
|
26
22
|
end
|
27
23
|
|
28
24
|
task default: :test
|
data/lib/semantic_logger.rb
CHANGED
@@ -5,44 +5,15 @@ require 'semantic_logger/semantic_logger'
|
|
5
5
|
# @formatter:off
|
6
6
|
module SemanticLogger
|
7
7
|
autoload :AnsiColors, 'semantic_logger/ansi_colors'
|
8
|
+
autoload :Appender, 'semantic_logger/appender'
|
8
9
|
autoload :Base, 'semantic_logger/base'
|
9
10
|
autoload :DebugAsTraceLogger, 'semantic_logger/debug_as_trace_logger'
|
10
11
|
autoload :Log, 'semantic_logger/log'
|
11
12
|
autoload :Logger, 'semantic_logger/logger'
|
12
13
|
autoload :Loggable, 'semantic_logger/loggable'
|
14
|
+
autoload :Processor, 'semantic_logger/processor'
|
13
15
|
autoload :Subscriber, 'semantic_logger/subscriber'
|
14
16
|
|
15
|
-
module Appender
|
16
|
-
# DEPRECATED, use SemanticLogger::AnsiColors
|
17
|
-
AnsiColors = SemanticLogger::AnsiColors
|
18
|
-
|
19
|
-
# DEPRECATED: use SemanticLogger::Formatters::Color.new
|
20
|
-
def self.colorized_formatter
|
21
|
-
SemanticLogger::Formatters::Color.new
|
22
|
-
end
|
23
|
-
|
24
|
-
# DEPRECATED: use SemanticLogger::Formatters::Json.new
|
25
|
-
def self.json_formatter
|
26
|
-
SemanticLogger::Formatters::Json.new
|
27
|
-
end
|
28
|
-
|
29
|
-
autoload :Bugsnag, 'semantic_logger/appender/bugsnag'
|
30
|
-
autoload :Elasticsearch, 'semantic_logger/appender/elasticsearch'
|
31
|
-
autoload :File, 'semantic_logger/appender/file'
|
32
|
-
autoload :Graylog, 'semantic_logger/appender/graylog'
|
33
|
-
autoload :Honeybadger, 'semantic_logger/appender/honeybadger'
|
34
|
-
autoload :Sentry, 'semantic_logger/appender/sentry'
|
35
|
-
autoload :Http, 'semantic_logger/appender/http'
|
36
|
-
autoload :MongoDB, 'semantic_logger/appender/mongodb'
|
37
|
-
autoload :NewRelic, 'semantic_logger/appender/new_relic'
|
38
|
-
autoload :Splunk, 'semantic_logger/appender/splunk'
|
39
|
-
autoload :SplunkHttp, 'semantic_logger/appender/splunk_http'
|
40
|
-
autoload :Syslog, 'semantic_logger/appender/syslog'
|
41
|
-
autoload :Tcp, 'semantic_logger/appender/tcp'
|
42
|
-
autoload :Udp, 'semantic_logger/appender/udp'
|
43
|
-
autoload :Wrapper, 'semantic_logger/appender/wrapper'
|
44
|
-
end
|
45
|
-
|
46
17
|
module Concerns
|
47
18
|
autoload :Compatibility, 'semantic_logger/concerns/compatibility'
|
48
19
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module SemanticLogger
|
2
|
+
module Appender
|
3
|
+
# @formatter:off
|
4
|
+
autoload :Bugsnag, 'semantic_logger/appender/bugsnag'
|
5
|
+
autoload :Elasticsearch, 'semantic_logger/appender/elasticsearch'
|
6
|
+
autoload :File, 'semantic_logger/appender/file'
|
7
|
+
autoload :Graylog, 'semantic_logger/appender/graylog'
|
8
|
+
autoload :Honeybadger, 'semantic_logger/appender/honeybadger'
|
9
|
+
autoload :Sentry, 'semantic_logger/appender/sentry'
|
10
|
+
autoload :Http, 'semantic_logger/appender/http'
|
11
|
+
autoload :MongoDB, 'semantic_logger/appender/mongodb'
|
12
|
+
autoload :NewRelic, 'semantic_logger/appender/new_relic'
|
13
|
+
autoload :Splunk, 'semantic_logger/appender/splunk'
|
14
|
+
autoload :SplunkHttp, 'semantic_logger/appender/splunk_http'
|
15
|
+
autoload :Syslog, 'semantic_logger/appender/syslog'
|
16
|
+
autoload :Tcp, 'semantic_logger/appender/tcp'
|
17
|
+
autoload :Udp, 'semantic_logger/appender/udp'
|
18
|
+
autoload :Wrapper, 'semantic_logger/appender/wrapper'
|
19
|
+
# @formatter:on
|
20
|
+
|
21
|
+
# DEPRECATED, use SemanticLogger::AnsiColors
|
22
|
+
AnsiColors = SemanticLogger::AnsiColors
|
23
|
+
|
24
|
+
# DEPRECATED: use SemanticLogger::Formatters::Color.new
|
25
|
+
def self.colorized_formatter
|
26
|
+
SemanticLogger::Formatters::Color.new
|
27
|
+
end
|
28
|
+
|
29
|
+
# DEPRECATED: use SemanticLogger::Formatters::Json.new
|
30
|
+
def self.json_formatter
|
31
|
+
SemanticLogger::Formatters::Json.new
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns [SemanticLogger::Subscriber] appender for the supplied options
|
35
|
+
def self.create(options, &block)
|
36
|
+
if options[:io] || options[:file_name]
|
37
|
+
SemanticLogger::Appender::File.new(options, &block)
|
38
|
+
elsif appender = options.delete(:appender)
|
39
|
+
if appender.is_a?(Symbol)
|
40
|
+
constantize_symbol(appender).new(options)
|
41
|
+
elsif appender.is_a?(Subscriber)
|
42
|
+
appender
|
43
|
+
else
|
44
|
+
raise(ArgumentError, "Parameter :appender must be either a Symbol or an object derived from SemanticLogger::Subscriber, not: #{appender.inspect}")
|
45
|
+
end
|
46
|
+
elsif options[:logger]
|
47
|
+
SemanticLogger::Appender::Wrapper.new(options, &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.constantize_symbol(symbol, namespace = 'SemanticLogger::Appender')
|
52
|
+
klass = "#{namespace}::#{camelize(symbol.to_s)}"
|
53
|
+
begin
|
54
|
+
if RUBY_VERSION.to_i >= 2
|
55
|
+
Object.const_get(klass)
|
56
|
+
else
|
57
|
+
klass.split('::').inject(Object) { |o, name| o.const_get(name) }
|
58
|
+
end
|
59
|
+
rescue NameError
|
60
|
+
raise(ArgumentError, "Could not convert symbol: #{symbol} to a class in: #{namespace}. Looking for: #{klass}")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# Borrow from Rails, when not running Rails
|
67
|
+
def self.camelize(term)
|
68
|
+
string = term.to_s
|
69
|
+
string = string.sub(/^[a-z\d]*/) { |match| match.capitalize }
|
70
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
71
|
+
string.gsub!('/'.freeze, '::'.freeze)
|
72
|
+
string
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -27,18 +27,13 @@ class SemanticLogger::Appender::Bugsnag < SemanticLogger::Subscriber
|
|
27
27
|
# regular expression. All other messages will be ignored.
|
28
28
|
# Proc: Only include log messages where the supplied Proc returns true
|
29
29
|
# The Proc must return true or false.
|
30
|
-
def initialize(
|
31
|
-
|
32
|
-
options = {level: options} unless options.is_a?(Hash)
|
33
|
-
options = options.dup
|
34
|
-
options[:level] = :error unless options.has_key?(:level)
|
35
|
-
|
36
|
-
raise 'Bugsnag only supports :info, :warn, or :error log levels' unless [:info, :warn, :error].include?(options[:level])
|
30
|
+
def initialize(level: :error, formatter: nil, filter: nil, host: SemanticLogger.host, application: SemanticLogger.application, &block)
|
31
|
+
raise 'Bugsnag only supports :info, :warn, or :error log levels' unless [:info, :warn, :error].include?(level)
|
37
32
|
|
38
33
|
# Replace the Bugsnag logger so that we can identify its log messages and not forward them to Bugsnag
|
39
34
|
Bugsnag.configure { |config| config.logger = SemanticLogger[Bugsnag] }
|
40
35
|
|
41
|
-
super(
|
36
|
+
super(level: level, formatter: formatter, filter: filter, host: host, application: application, &block)
|
42
37
|
end
|
43
38
|
|
44
39
|
# Returns [Hash] of parameters to send to Bugsnag.
|
@@ -38,7 +38,7 @@ module SemanticLogger
|
|
38
38
|
# SemanticLogger.add_appender(io: STDOUT, formatter: :color)
|
39
39
|
#
|
40
40
|
# # And log to a file at the same time
|
41
|
-
# SemanticLogger
|
41
|
+
# SemanticLogger.add_appender(file_name: 'application.log', formatter: :color)
|
42
42
|
#
|
43
43
|
# logger = SemanticLogger['test']
|
44
44
|
# logger.info 'Hello World'
|
@@ -50,7 +50,7 @@ class SemanticLogger::Appender::Honeybadger < SemanticLogger::Subscriber
|
|
50
50
|
context.delete(:exception)
|
51
51
|
Honeybadger.notify(log.exception, context)
|
52
52
|
else
|
53
|
-
message
|
53
|
+
message = {
|
54
54
|
error_class: context.delete(:name),
|
55
55
|
error_message: context.delete(:message),
|
56
56
|
context: context
|
@@ -199,7 +199,7 @@ class SemanticLogger::Appender::Http < SemanticLogger::Subscriber
|
|
199
199
|
true
|
200
200
|
else
|
201
201
|
# Failures are logged to the global semantic logger failsafe logger (Usually stderr or file)
|
202
|
-
SemanticLogger::
|
202
|
+
SemanticLogger::Processor.logger.error("Bad HTTP response from: #{url} code: #{response.code}, #{response.body}")
|
203
203
|
false
|
204
204
|
end
|
205
205
|
end
|
@@ -2,7 +2,7 @@ require 'socket'
|
|
2
2
|
begin
|
3
3
|
require 'mongo'
|
4
4
|
rescue LoadError
|
5
|
-
raise 'Gem mongo is required for logging to MongoDB. Please add the gem "mongo" to your Gemfile.'
|
5
|
+
raise 'Gem mongo is required for logging to MongoDB. Please add the gem "mongo" v2.0 or greater to your Gemfile.'
|
6
6
|
end
|
7
7
|
|
8
8
|
module SemanticLogger
|
@@ -49,14 +49,15 @@ module SemanticLogger
|
|
49
49
|
# # Log some messages
|
50
50
|
# logger.info 'This message is written to mongo as a document'
|
51
51
|
class MongoDB < SemanticLogger::Subscriber
|
52
|
-
attr_reader :
|
53
|
-
attr_accessor :write_concern
|
52
|
+
attr_reader :client, :collection
|
54
53
|
|
55
54
|
# Create a MongoDB Appender instance
|
56
55
|
#
|
57
56
|
# Parameters:
|
58
|
-
#
|
59
|
-
#
|
57
|
+
# uri: [String]
|
58
|
+
# Mongo connection string.
|
59
|
+
# Example:
|
60
|
+
# mongodb://127.0.0.1:27017/test
|
60
61
|
#
|
61
62
|
# collection_name: [String]
|
62
63
|
# Name of the collection to store log data in
|
@@ -78,6 +79,7 @@ module SemanticLogger
|
|
78
79
|
#
|
79
80
|
# collection_max: [Integer]
|
80
81
|
# Maximum number of log entries that the capped collection will hold.
|
82
|
+
# Default: no max limit
|
81
83
|
#
|
82
84
|
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
83
85
|
# Override the log level for this appender.
|
@@ -101,28 +103,30 @@ module SemanticLogger
|
|
101
103
|
# application: [String]
|
102
104
|
# Name of this application to appear in log messages.
|
103
105
|
# Default: SemanticLogger.application
|
104
|
-
def initialize(
|
105
|
-
|
106
|
-
@
|
107
|
-
@collection_name =
|
108
|
-
@
|
106
|
+
def initialize(uri:, collection_name: 'semantic_logger', write_concern: 0, collection_size: 1024**3, collection_max: nil,
|
107
|
+
level: nil, formatter: nil, filter: nil, host: SemanticLogger.host, application: SemanticLogger.application, &block)
|
108
|
+
@client = Mongo::Client.new(uri, logger: SemanticLogger::Processor.logger.clone)
|
109
|
+
@collection_name = collection_name
|
110
|
+
@options = {
|
111
|
+
capped: true,
|
112
|
+
size: collection_size,
|
113
|
+
write: {w: write_concern}
|
114
|
+
}
|
115
|
+
@options[:max] = collection_max if collection_max
|
109
116
|
|
110
|
-
|
111
|
-
@collection_size = options.delete(:collection_size) || 1024**3
|
112
|
-
@collection_max = options.delete(:collection_max)
|
117
|
+
reopen
|
113
118
|
|
114
119
|
# Create the collection and necessary indexes
|
115
120
|
create_indexes
|
116
121
|
|
117
122
|
# Set the log level and formatter
|
118
|
-
super(
|
119
|
-
reopen
|
123
|
+
super(level: level, formatter: formatter, filter: filter, host: host, application: application, &block)
|
120
124
|
end
|
121
125
|
|
122
126
|
# After forking an active process call #reopen to re-open
|
123
127
|
# open the handles to resources
|
124
128
|
def reopen
|
125
|
-
@collection =
|
129
|
+
@collection = client[@collection_name, @options]
|
126
130
|
end
|
127
131
|
|
128
132
|
# Create the required capped collection.
|
@@ -136,10 +140,14 @@ module SemanticLogger
|
|
136
140
|
#
|
137
141
|
# Creates an index based on tags to support faster searches.
|
138
142
|
def create_indexes
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
+
# Create Capped collection
|
144
|
+
begin
|
145
|
+
@collection.create
|
146
|
+
rescue Mongo::Error::OperationFailure
|
147
|
+
# Already exists
|
148
|
+
end
|
149
|
+
|
150
|
+
@collection.indexes.create_one({tags: 1})
|
143
151
|
end
|
144
152
|
|
145
153
|
# Purge all data from the capped collection by dropping the collection
|
@@ -147,22 +155,16 @@ module SemanticLogger
|
|
147
155
|
# Also useful when the size of the capped collection needs to be changed
|
148
156
|
def purge_all
|
149
157
|
collection.drop
|
150
|
-
|
158
|
+
reopen
|
151
159
|
create_indexes
|
152
160
|
end
|
153
161
|
|
154
|
-
# Flush all pending logs to disk.
|
155
|
-
# Waits for all sent documents to be written to disk
|
156
|
-
def flush
|
157
|
-
db.get_last_error
|
158
|
-
end
|
159
|
-
|
160
162
|
# Log the message to MongoDB
|
161
163
|
def log(log)
|
162
164
|
return false unless should_log?(log)
|
163
165
|
|
164
166
|
# Insert log entry into Mongo
|
165
|
-
collection.
|
167
|
+
collection.insert_one(formatter.call(log, self))
|
166
168
|
true
|
167
169
|
end
|
168
170
|
|
@@ -51,10 +51,10 @@ class SemanticLogger::Appender::Sentry < SemanticLogger::Subscriber
|
|
51
51
|
context.delete(:exception)
|
52
52
|
Raven.capture_exception(log.exception, context)
|
53
53
|
else
|
54
|
-
message
|
54
|
+
message = {
|
55
55
|
error_class: context.delete(:name),
|
56
56
|
error_message: context.delete(:message),
|
57
|
-
extra:
|
57
|
+
extra: context
|
58
58
|
}
|
59
59
|
message[:backtrace] = log.backtrace if log.backtrace
|
60
60
|
Raven.capture_message(message[:error_message], message)
|
@@ -65,10 +65,10 @@ class SemanticLogger::Appender::SplunkHttp < SemanticLogger::Appender::Http
|
|
65
65
|
# Proc: Only include log messages where the supplied Proc returns true
|
66
66
|
# The Proc must return true or false.
|
67
67
|
def initialize(options, &block)
|
68
|
-
options
|
69
|
-
@source_type
|
70
|
-
@index
|
71
|
-
token
|
68
|
+
options = options.dup
|
69
|
+
@source_type = options.delete(:source_type)
|
70
|
+
@index = options.delete(:index)
|
71
|
+
token = options.delete(:token)
|
72
72
|
raise(ArgumentError, 'Missing mandatory parameter :token') unless token
|
73
73
|
|
74
74
|
# Splunk supports HTTP Compression, enable by default
|
@@ -66,7 +66,7 @@ module SemanticLogger
|
|
66
66
|
# Only used with the TCP protocol.
|
67
67
|
# Specify custom parameters to pass into Net::TCPClient.new
|
68
68
|
# For a list of options see the net_tcp_client documentation:
|
69
|
-
# https://
|
69
|
+
# https://github.com/rocketjob/net_tcp_client/blob/master/lib/net/tcp_client/tcp_client.rb
|
70
70
|
#
|
71
71
|
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
72
72
|
# Override the log level for this appender.
|
@@ -196,7 +196,7 @@ module SemanticLogger
|
|
196
196
|
::Syslog.open(application, @options, @facility)
|
197
197
|
when :tcp
|
198
198
|
# Use the local logger for @remote_syslog so errors with the remote logger can be recorded locally.
|
199
|
-
@tcp_client_options[:logger] = SemanticLogger::
|
199
|
+
@tcp_client_options[:logger] = SemanticLogger::Processor.logger.clone
|
200
200
|
@remote_syslog = Net::TCPClient.new(@tcp_client_options)
|
201
201
|
when :udp
|
202
202
|
@remote_syslog = UDPSocket.new
|
@@ -182,12 +182,13 @@ module SemanticLogger
|
|
182
182
|
# connect_retry_count: 5
|
183
183
|
# )
|
184
184
|
def initialize(options = {}, &block)
|
185
|
-
@
|
186
|
-
@
|
185
|
+
@tcp_client = nil
|
186
|
+
@options = options.dup
|
187
|
+
@separator = @options.delete(:separator) || "\n"
|
187
188
|
|
188
189
|
# Use the internal logger so that errors with remote logging are only written locally.
|
189
|
-
Net::TCPClient.logger
|
190
|
-
Net::TCPClient.logger.name
|
190
|
+
Net::TCPClient.logger = SemanticLogger::Processor.logger.clone
|
191
|
+
Net::TCPClient.logger.name = 'Net::TCPClient'
|
191
192
|
|
192
193
|
options = extract_subscriber_options!(@options)
|
193
194
|
super(options, &block)
|
@@ -205,7 +206,10 @@ module SemanticLogger
|
|
205
206
|
def log(log)
|
206
207
|
return false unless should_log?(log)
|
207
208
|
|
208
|
-
|
209
|
+
message = formatter.call(log, self)
|
210
|
+
@tcp_client.retry_on_connection_failure do
|
211
|
+
@tcp_client.write("#{message}#{separator}")
|
212
|
+
end
|
209
213
|
true
|
210
214
|
end
|
211
215
|
|
data/lib/semantic_logger/base.rb
CHANGED
@@ -4,8 +4,6 @@
|
|
4
4
|
#
|
5
5
|
# Implements common behavior such as log level, default text formatter etc
|
6
6
|
#
|
7
|
-
# Note: Do not create instances of this class directly
|
8
|
-
#
|
9
7
|
module SemanticLogger
|
10
8
|
class Base
|
11
9
|
# Class name to be logged
|
@@ -116,8 +114,33 @@ module SemanticLogger
|
|
116
114
|
end
|
117
115
|
end
|
118
116
|
|
117
|
+
# Backward compatibility
|
119
118
|
alias_method :benchmark, :measure
|
120
119
|
|
120
|
+
# Log a thread backtrace
|
121
|
+
def backtrace(thread: Thread.current, level: :warn, message: 'Backtrace:', payload: nil, metric: nil, metric_amount: 1)
|
122
|
+
log = Log.new(name, level)
|
123
|
+
backtrace =
|
124
|
+
if thread == Thread.current
|
125
|
+
self.class.cleanse_backtrace
|
126
|
+
else
|
127
|
+
log.thread_name = thread.name
|
128
|
+
log.tags = thread[:semantic_logger_tags].clone
|
129
|
+
log.named_tags = thread[:semantic_logger_named_tags].clone
|
130
|
+
thread.backtrace
|
131
|
+
end
|
132
|
+
# TODO: Keep backtrace instead of transforming into a text message at this point
|
133
|
+
# Maybe log_backtrace: true
|
134
|
+
if backtrace
|
135
|
+
message += "\n"
|
136
|
+
message << backtrace.join("\n")
|
137
|
+
end
|
138
|
+
|
139
|
+
if log.assign(message: message, backtrace: backtrace, payload: payload, metric: metric, metric_amount: metric_amount) && should_log?(log)
|
140
|
+
self.log(log)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
121
144
|
# :nodoc:
|
122
145
|
def tagged(*tags, &block)
|
123
146
|
SemanticLogger.tagged(*tags, &block)
|
@@ -151,33 +174,16 @@ module SemanticLogger
|
|
151
174
|
SemanticLogger.fast_tag(tag, &block)
|
152
175
|
end
|
153
176
|
|
154
|
-
#
|
155
|
-
#
|
156
|
-
# Add a payload to all log calls on This Thread within the supplied block
|
157
|
-
#
|
158
|
-
# logger.with_payload(tracking_number: 12345) do
|
159
|
-
# logger.debug('Hello World')
|
160
|
-
# end
|
161
|
-
#
|
162
|
-
# If a log call already includes a pyload, this payload will be merged with
|
163
|
-
# the supplied payload, with the supplied payload taking precedence
|
164
|
-
#
|
165
|
-
# logger.with_payload(tracking_number: 12345) do
|
166
|
-
# logger.debug('Hello World', result: 'blah')
|
167
|
-
# end
|
177
|
+
# :nodoc:
|
168
178
|
def with_payload(payload)
|
169
|
-
|
170
|
-
|
171
|
-
yield
|
172
|
-
ensure
|
173
|
-
Thread.current[:semantic_logger_payload] = current_payload
|
179
|
+
warn '#with_payload is deprecated, use SemanticLogger.named_tagged'
|
180
|
+
SemanticLogger.named_tagged(payload)
|
174
181
|
end
|
175
182
|
|
176
|
-
#
|
177
|
-
# on this thread.
|
178
|
-
# Returns nil if no payload is currently set
|
183
|
+
# :nodoc:
|
179
184
|
def payload
|
180
|
-
|
185
|
+
warn '#payload is deprecated, use SemanticLogger.named_tags'
|
186
|
+
SemanticLogger.named_tags
|
181
187
|
end
|
182
188
|
|
183
189
|
protected
|
@@ -206,9 +212,8 @@ module SemanticLogger
|
|
206
212
|
# regular expression. All other messages will be ignored
|
207
213
|
# Proc: Only include log messages where the supplied Proc returns true
|
208
214
|
# The Proc must return true or false
|
209
|
-
def initialize(klass, level=nil, filter=nil)
|
210
|
-
# Support filtering all messages to this logger using a Regular Expression
|
211
|
-
# or Proc
|
215
|
+
def initialize(klass, level = nil, filter = nil)
|
216
|
+
# Support filtering all messages to this logger using a Regular Expression or Proc
|
212
217
|
raise ':filter must be a Regexp or Proc' unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc)
|
213
218
|
|
214
219
|
@filter = filter.is_a?(Regexp) ? filter.freeze : filter
|
@@ -247,78 +252,31 @@ module SemanticLogger
|
|
247
252
|
end
|
248
253
|
|
249
254
|
# Log message at the specified level
|
250
|
-
def log_internal(level, index, message=nil, payload=nil, exception=nil)
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
exception = message
|
256
|
-
message = nil
|
257
|
-
elsif exception.nil? && payload && payload.respond_to?(:backtrace) && payload.respond_to?(:message)
|
258
|
-
exception = payload
|
259
|
-
payload = nil
|
260
|
-
end
|
261
|
-
|
262
|
-
# Add result of block as message or payload if not nil
|
263
|
-
if block_given? && (result = yield)
|
264
|
-
if result.is_a?(String)
|
265
|
-
message = message.nil? ? result : "#{message} -- #{result}"
|
266
|
-
elsif message.nil? && result.is_a?(Hash)
|
267
|
-
message = result
|
268
|
-
elsif payload && payload.respond_to?(:merge)
|
269
|
-
payload.merge(result)
|
255
|
+
def log_internal(level, index, message = nil, payload = nil, exception = nil, &block)
|
256
|
+
log = Log.new(name, level, index)
|
257
|
+
should_log =
|
258
|
+
if payload.nil? && exception.nil? && message.is_a?(Hash)
|
259
|
+
log.assign(message)
|
270
260
|
else
|
271
|
-
payload
|
261
|
+
log.assign_positional(message, payload, exception, &block)
|
272
262
|
end
|
273
|
-
end
|
274
263
|
|
275
|
-
|
276
|
-
if self.payload
|
277
|
-
payload = payload.nil? ? self.payload : self.payload.merge(payload)
|
278
|
-
end
|
279
|
-
|
280
|
-
# Add caller stack trace
|
281
|
-
backtrace = extract_backtrace if index >= SemanticLogger.backtrace_level_index
|
282
|
-
|
283
|
-
log = Log.new(level, Thread.current.name, name, message, payload, Time.now, nil, tags, index, exception, nil, backtrace)
|
284
|
-
|
285
|
-
# Logging Hash only?
|
286
|
-
# logger.info(name: 'value')
|
287
|
-
if payload.nil? && exception.nil? && message.is_a?(Hash)
|
288
|
-
payload = message.dup
|
289
|
-
min_duration = payload.delete(:min_duration) || 0.0
|
290
|
-
log.exception = payload.delete(:exception)
|
291
|
-
log.message = payload.delete(:message)
|
292
|
-
log.metric = payload.delete(:metric)
|
293
|
-
log.metric_amount = payload.delete(:metric_amount) || 1
|
294
|
-
if duration = payload.delete(:duration)
|
295
|
-
return false if duration <= min_duration
|
296
|
-
log.duration = duration
|
297
|
-
end
|
298
|
-
log.payload = payload if payload.size > 0
|
299
|
-
end
|
300
|
-
|
301
|
-
self.log(log) if include_message?(log)
|
302
|
-
end
|
303
|
-
|
304
|
-
SELF_PATTERN = File.join('lib', 'semantic_logger')
|
305
|
-
|
306
|
-
# Extract the callers backtrace leaving out Semantic Logger
|
307
|
-
def extract_backtrace
|
308
|
-
stack = caller
|
309
|
-
while (first = stack.first) && first.include?(SELF_PATTERN)
|
310
|
-
stack.shift
|
311
|
-
end
|
312
|
-
stack
|
264
|
+
self.log(log) if should_log && include_message?(log)
|
313
265
|
end
|
314
266
|
|
315
267
|
# Measure the supplied block and log the message
|
316
268
|
def measure_internal(level, index, message, params)
|
317
|
-
start = Time.now
|
318
269
|
exception = nil
|
270
|
+
result = nil
|
271
|
+
# Single parameter is a hash
|
272
|
+
if params.empty? && message.is_a?(Hash)
|
273
|
+
params = message
|
274
|
+
message = nil
|
275
|
+
end
|
276
|
+
start = Time.now
|
319
277
|
begin
|
320
278
|
if block_given?
|
321
|
-
result
|
279
|
+
result =
|
322
280
|
if silence_level = params[:silence]
|
323
281
|
# In case someone accidentally sets `silence: true` instead of `silence: :error`
|
324
282
|
silence_level = :error if silence_level == true
|
@@ -326,65 +284,40 @@ module SemanticLogger
|
|
326
284
|
else
|
327
285
|
yield(params)
|
328
286
|
end
|
329
|
-
exception = params[:exception]
|
330
|
-
result
|
331
287
|
end
|
332
288
|
rescue Exception => exc
|
333
289
|
exception = exc
|
334
290
|
ensure
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
payload = params[:payload]
|
341
|
-
metric = params[:metric]
|
342
|
-
duration =
|
291
|
+
# Must use ensure block otherwise a `return` in the yield above will skip the log entry
|
292
|
+
log = Log.new(name, level, index)
|
293
|
+
exception ||= params[:exception]
|
294
|
+
message = params[:message] if params[:message]
|
295
|
+
duration =
|
343
296
|
if block_given?
|
344
|
-
1000.0 * (
|
297
|
+
1000.0 * (Time.now - start)
|
345
298
|
else
|
346
299
|
params[:duration] || raise('Mandatory block missing when :duration option is not supplied')
|
347
300
|
end
|
348
301
|
|
349
|
-
#
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
end
|
369
|
-
message = "#{message} -- Exception: #{exception.class}: #{exception.message}"
|
370
|
-
logged_exception = nil
|
371
|
-
backtrace = exception.backtrace
|
372
|
-
else
|
373
|
-
# Log the message with its duration but leave out the exception that was raised
|
374
|
-
logged_exception = nil
|
375
|
-
backtrace = exception.backtrace
|
376
|
-
end
|
377
|
-
log = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, logged_exception, metric, backtrace)
|
378
|
-
self.log(log) if include_message?(log)
|
379
|
-
raise exception
|
380
|
-
elsif duration >= min_duration
|
381
|
-
# Only log if the block took longer than 'min_duration' to complete
|
382
|
-
# Add caller stack trace
|
383
|
-
backtrace = extract_backtrace if index >= SemanticLogger.backtrace_level_index
|
384
|
-
|
385
|
-
log = Log.new(level, Thread.current.name, name, message, payload, end_time, duration, tags, index, nil, metric, backtrace)
|
386
|
-
self.log(log) if include_message?(log)
|
387
|
-
end
|
302
|
+
# Extract options after block completes so that block can modify any of the options
|
303
|
+
payload = params[:payload]
|
304
|
+
|
305
|
+
should_log = log.assign(
|
306
|
+
message: message,
|
307
|
+
payload: payload,
|
308
|
+
min_duration: params[:min_duration] || 0.0,
|
309
|
+
exception: exception,
|
310
|
+
metric: params[:metric],
|
311
|
+
metric_amount: 1,
|
312
|
+
duration: duration,
|
313
|
+
backtrace: nil,
|
314
|
+
log_exception: params[:log_exception] || :partial,
|
315
|
+
on_exception_level: params[:on_exception_level]
|
316
|
+
)
|
317
|
+
|
318
|
+
self.log(log) if should_log && include_message?(log)
|
319
|
+
raise exception if exception
|
320
|
+
result
|
388
321
|
end
|
389
322
|
end
|
390
323
|
|