semantic_logger 3.4.1 → 4.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|