semantic_logger 4.6.1 → 4.7.4

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +7 -7
  3. data/lib/semantic_logger.rb +23 -22
  4. data/lib/semantic_logger/appender.rb +32 -33
  5. data/lib/semantic_logger/appender/async.rb +9 -8
  6. data/lib/semantic_logger/appender/async_batch.rb +4 -2
  7. data/lib/semantic_logger/appender/bugsnag.rb +43 -30
  8. data/lib/semantic_logger/appender/elasticsearch.rb +10 -10
  9. data/lib/semantic_logger/appender/elasticsearch_http.rb +4 -4
  10. data/lib/semantic_logger/appender/file.rb +2 -1
  11. data/lib/semantic_logger/appender/graylog.rb +12 -10
  12. data/lib/semantic_logger/appender/honeybadger.rb +3 -3
  13. data/lib/semantic_logger/appender/http.rb +20 -18
  14. data/lib/semantic_logger/appender/kafka.rb +5 -5
  15. data/lib/semantic_logger/appender/mongodb.rb +6 -6
  16. data/lib/semantic_logger/appender/new_relic.rb +2 -2
  17. data/lib/semantic_logger/appender/rabbitmq.rb +5 -5
  18. data/lib/semantic_logger/appender/sentry.rb +7 -7
  19. data/lib/semantic_logger/appender/splunk.rb +5 -5
  20. data/lib/semantic_logger/appender/splunk_http.rb +4 -4
  21. data/lib/semantic_logger/appender/syslog.rb +20 -14
  22. data/lib/semantic_logger/appender/tcp.rb +5 -5
  23. data/lib/semantic_logger/appender/udp.rb +2 -2
  24. data/lib/semantic_logger/appenders.rb +11 -11
  25. data/lib/semantic_logger/base.rb +52 -23
  26. data/lib/semantic_logger/formatters.rb +11 -11
  27. data/lib/semantic_logger/formatters/base.rb +8 -3
  28. data/lib/semantic_logger/formatters/color.rb +10 -6
  29. data/lib/semantic_logger/formatters/default.rb +18 -5
  30. data/lib/semantic_logger/formatters/fluentd.rb +3 -3
  31. data/lib/semantic_logger/formatters/json.rb +1 -1
  32. data/lib/semantic_logger/formatters/raw.rb +31 -7
  33. data/lib/semantic_logger/formatters/signalfx.rb +10 -9
  34. data/lib/semantic_logger/formatters/syslog.rb +7 -6
  35. data/lib/semantic_logger/formatters/syslog_cee.rb +7 -6
  36. data/lib/semantic_logger/jruby/garbage_collection_logger.rb +4 -2
  37. data/lib/semantic_logger/levels.rb +9 -7
  38. data/lib/semantic_logger/log.rb +52 -60
  39. data/lib/semantic_logger/logger.rb +6 -8
  40. data/lib/semantic_logger/metric/new_relic.rb +3 -3
  41. data/lib/semantic_logger/metric/signalfx.rb +3 -3
  42. data/lib/semantic_logger/metric/statsd.rb +7 -7
  43. data/lib/semantic_logger/processor.rb +7 -5
  44. data/lib/semantic_logger/reporters/minitest.rb +4 -4
  45. data/lib/semantic_logger/semantic_logger.rb +24 -11
  46. data/lib/semantic_logger/subscriber.rb +6 -5
  47. data/lib/semantic_logger/sync.rb +12 -0
  48. data/lib/semantic_logger/sync_processor.rb +43 -0
  49. data/lib/semantic_logger/utils.rb +6 -6
  50. data/lib/semantic_logger/version.rb +1 -1
  51. metadata +9 -7
@@ -1,10 +1,10 @@
1
1
  begin
2
- require 'net/tcp_client'
2
+ require "net/tcp_client"
3
3
  rescue LoadError
4
- raise LoadError.new('Gem net_tcp_client is required for logging over TCP. Please add the gem "net_tcp_client" to your Gemfile.')
4
+ raise LoadError, 'Gem net_tcp_client is required for logging over TCP. Please add the gem "net_tcp_client" to your Gemfile.'
5
5
  end
6
6
 
7
- raise 'Net::TCPClient v2.0 or greater is required to log over TCP' unless Net::TCPClient::VERSION.to_f >= 2.0
7
+ raise "Net::TCPClient v2.0 or greater is required to log over TCP" unless Net::TCPClient::VERSION.to_f >= 2.0
8
8
 
9
9
  module SemanticLogger
10
10
  module Appender
@@ -189,7 +189,7 @@ module SemanticLogger
189
189
 
190
190
  # Use the internal logger so that errors with remote logging are only written locally.
191
191
  Net::TCPClient.logger = logger
192
- Net::TCPClient.logger.name = 'Net::TCPClient'
192
+ Net::TCPClient.logger.name = "Net::TCPClient"
193
193
 
194
194
  super(level: level, formatter: formatter, filter: filter, application: application, environment: environment, host: host, &block)
195
195
  reopen
@@ -198,7 +198,7 @@ module SemanticLogger
198
198
  # After forking an active process call #reopen to re-open the handles to resources.
199
199
  def reopen
200
200
  close
201
- @tcp_client = Net::TCPClient.new(@tcp_client_args)
201
+ @tcp_client = Net::TCPClient.new(**@tcp_client_args)
202
202
  end
203
203
 
204
204
  # Write the log using the specified protocol and server.
@@ -1,4 +1,4 @@
1
- require 'socket'
1
+ require "socket"
2
2
  module SemanticLogger
3
3
  module Appender
4
4
  # UDP log appender.
@@ -74,7 +74,7 @@ module SemanticLogger
74
74
  def reopen
75
75
  close
76
76
  @socket = UDPSocket.new
77
- host, port = server.split(':')
77
+ host, port = server.split(":")
78
78
  @socket.connect(host, port.to_i)
79
79
  end
80
80
 
@@ -18,8 +18,8 @@ module SemanticLogger
18
18
  each do |appender|
19
19
  begin
20
20
  appender.log(log) if appender.should_log?(log)
21
- rescue Exception => exc
22
- logger.error "Failed to log to appender: #{appender.name}", exc
21
+ rescue Exception => e
22
+ logger.error "Failed to log to appender: #{appender.name}", e
23
23
  end
24
24
  end
25
25
  end
@@ -29,11 +29,11 @@ module SemanticLogger
29
29
  begin
30
30
  logger.trace "Flushing appender: #{appender.name}"
31
31
  appender.flush
32
- rescue Exception => exc
33
- logger.error "Failed to flush appender: #{appender.name}", exc
32
+ rescue Exception => e
33
+ logger.error "Failed to flush appender: #{appender.name}", e
34
34
  end
35
35
  end
36
- logger.trace 'All appenders flushed'
36
+ logger.trace "All appenders flushed"
37
37
  end
38
38
 
39
39
  def close
@@ -43,11 +43,11 @@ module SemanticLogger
43
43
  appender.flush
44
44
  appender.close
45
45
  delete(appender)
46
- rescue Exception => exc
47
- logger.error "Failed to close appender: #{appender.name}", exc
46
+ rescue Exception => e
47
+ logger.error "Failed to close appender: #{appender.name}", e
48
48
  end
49
49
  end
50
- logger.trace 'All appenders closed and removed from appender list'
50
+ logger.trace "All appenders closed and removed from appender list"
51
51
  end
52
52
 
53
53
  # After a fork the appender thread is not running, start it if it is not running.
@@ -58,11 +58,11 @@ module SemanticLogger
58
58
 
59
59
  logger.trace "Reopening appender: #{appender.name}"
60
60
  appender.reopen
61
- rescue Exception => exc
62
- logger.error "Failed to re-open appender: #{appender.name}", exc
61
+ rescue Exception => e
62
+ logger.error "Failed to re-open appender: #{appender.name}", e
63
63
  end
64
64
  end
65
- logger.trace 'All appenders re-opened'
65
+ logger.trace "All appenders re-opened"
66
66
  end
67
67
  end
68
68
  end
@@ -126,7 +126,7 @@ module SemanticLogger
126
126
  # Log a thread backtrace
127
127
  def backtrace(thread: Thread.current,
128
128
  level: :warn,
129
- message: 'Backtrace:',
129
+ message: "Backtrace:",
130
130
  payload: nil,
131
131
  metric: nil,
132
132
  metric_amount: nil)
@@ -190,7 +190,8 @@ module SemanticLogger
190
190
  # Allow named tags to be passed into the logger
191
191
  if tags.size == 1
192
192
  tag = tags[0]
193
- return yield if tag.nil? || tag == ''
193
+ return yield if tag.nil? || tag == ""
194
+
194
195
  return tag.is_a?(Hash) ? SemanticLogger.named_tagged(tag, &block) : SemanticLogger.fast_tag(tag.to_s, &block)
195
196
  end
196
197
 
@@ -240,7 +241,7 @@ module SemanticLogger
240
241
 
241
242
  # Write log data to underlying data storage
242
243
  def log(_log_)
243
- raise NotImplementedError, 'Logging Appender must implement #log(log)'
244
+ raise NotImplementedError, "Logging Appender must implement #log(log)"
244
245
  end
245
246
 
246
247
  # Whether this log entry meets the criteria to be logged by this appender.
@@ -262,14 +263,22 @@ module SemanticLogger
262
263
  # For example if set to :warn, this appender would only log :warn and :fatal
263
264
  # log messages when other appenders could be logging :info and lower
264
265
  #
265
- # filter [Regexp|Proc]
266
+ # filter [Regexp|Proc|Module]
266
267
  # RegExp: Only include log messages where the class name matches the supplied
267
268
  # regular expression. All other messages will be ignored
268
269
  # Proc: Only include log messages where the supplied Proc returns true
269
270
  # The Proc must return true or false
271
+ # Module: A module that implements `.call`. For example:
272
+ # module ComplexFilter
273
+ # def self.call(log)
274
+ # (/\AExclude/ =~ log.message).nil?
275
+ # end
276
+ # end
270
277
  def initialize(klass, level = nil, filter = nil)
271
- # Support filtering all messages to this logger using a Regular Expression or Proc
272
- raise ':filter must be a Regexp or Proc' unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc)
278
+ # Support filtering all messages to this logger instance.
279
+ unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc) || filter.respond_to?(:call)
280
+ raise ":filter must be a Regexp, Proc, or implement :call"
281
+ end
273
282
 
274
283
  @filter = filter.is_a?(Regexp) ? filter.freeze : filter
275
284
  @name = klass.is_a?(String) ? klass : klass.name
@@ -302,23 +311,42 @@ module SemanticLogger
302
311
  end
303
312
 
304
313
  # Log message at the specified level
305
- def log_internal(level, index, message = nil, payload = nil, exception = nil, &block)
306
- log = Log.new(name, level, index)
314
+ def log_internal(level, index, message = nil, payload = nil, exception = nil)
315
+ # Handle variable number of arguments by detecting exception object and payload hash.
316
+ if exception.nil? && payload.nil? && message.respond_to?(:backtrace) && message.respond_to?(:message)
317
+ exception = message
318
+ message = nil
319
+ elsif exception.nil? && payload && payload.respond_to?(:backtrace) && payload.respond_to?(:message)
320
+ exception = payload
321
+ payload = nil
322
+ elsif payload && !payload.is_a?(Hash)
323
+ message = message.nil? ? payload : "#{message} -- #{payload}"
324
+ payload = nil
325
+ end
326
+
327
+ log = Log.new(name, level, index)
307
328
  should_log =
308
329
  if payload.nil? && exception.nil? && message.is_a?(Hash)
309
- # Check if someone just logged a hash payload instead of meaning to call semantic logger
310
- if message.key?(:message) || message.key?(:payload) || message.key?(:exception) || message.key?(:metric)
311
- log.assign(message)
312
- else
313
- log.assign_positional(nil, message, nil, &block)
314
- end
315
- elsif exception.nil? && message && payload && payload.is_a?(Hash) &&
316
- (payload.key?(:payload) || payload.key?(:exception) || payload.key?(:metric))
317
- log.assign(message: message, **payload)
330
+ # Everything as keyword arguments.
331
+ log.assign(**log.extract_arguments(message))
332
+ elsif exception.nil? && message && payload && payload.is_a?(Hash)
333
+ # Message with keyword arguments as the rest.
334
+ log.assign(message: message, **log.extract_arguments(payload))
318
335
  else
319
- log.assign_positional(message, payload, exception, &block)
336
+ # No keyword arguments.
337
+ log.assign(message: message, payload: payload, exception: exception)
320
338
  end
321
339
 
340
+ # Add result of block to message or payload if not nil
341
+ if block_given?
342
+ result = yield(log)
343
+ if result.is_a?(String)
344
+ log.message = log.message.nil? ? result : "#{log.message} -- #{result}"
345
+ elsif result.is_a?(Hash)
346
+ log.assign_hash(result)
347
+ end
348
+ end
349
+
322
350
  # Log level may change during assign due to :on_exception_level
323
351
  self.log(log) if should_log && should_log?(log)
324
352
  end
@@ -344,8 +372,8 @@ module SemanticLogger
344
372
  yield(params)
345
373
  end
346
374
  end
347
- rescue Exception => exc
348
- exception = exc
375
+ rescue Exception => e
376
+ exception = e
349
377
  ensure
350
378
  # Must use ensure block otherwise a `return` in the yield above will skip the log entry
351
379
  log = Log.new(name, level, index)
@@ -355,7 +383,7 @@ module SemanticLogger
355
383
  if block_given?
356
384
  1_000.0 * (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start)
357
385
  else
358
- params[:duration] || raise('Mandatory block missing when :duration option is not supplied')
386
+ params[:duration] || raise("Mandatory block missing when :duration option is not supplied")
359
387
  end
360
388
 
361
389
  # Extract options after block completes so that block can modify any of the options
@@ -377,6 +405,7 @@ module SemanticLogger
377
405
  # Log level may change during assign due to :on_exception_level
378
406
  self.log(log) if should_log && should_log?(log)
379
407
  raise exception if exception
408
+
380
409
  result
381
410
  end
382
411
  end
@@ -395,8 +424,8 @@ module SemanticLogger
395
424
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
396
425
  begin
397
426
  yield
398
- rescue Exception => exc
399
- exception = exc
427
+ rescue Exception => e
428
+ exception = e
400
429
  ensure
401
430
  log = Log.new(name, level, index)
402
431
  # May return false due to elastic logging
@@ -1,15 +1,15 @@
1
1
  module SemanticLogger
2
2
  module Formatters
3
3
  # @formatter:off
4
- autoload :Base, 'semantic_logger/formatters/base'
5
- autoload :Color, 'semantic_logger/formatters/color'
6
- autoload :Default, 'semantic_logger/formatters/default'
7
- autoload :Json, 'semantic_logger/formatters/json'
8
- autoload :Raw, 'semantic_logger/formatters/raw'
9
- autoload :OneLine, 'semantic_logger/formatters/one_line'
10
- autoload :Signalfx, 'semantic_logger/formatters/signalfx'
11
- autoload :Syslog, 'semantic_logger/formatters/syslog'
12
- autoload :Fluentd, 'semantic_logger/formatters/fluentd'
4
+ autoload :Base, "semantic_logger/formatters/base"
5
+ autoload :Color, "semantic_logger/formatters/color"
6
+ autoload :Default, "semantic_logger/formatters/default"
7
+ autoload :Json, "semantic_logger/formatters/json"
8
+ autoload :Raw, "semantic_logger/formatters/raw"
9
+ autoload :OneLine, "semantic_logger/formatters/one_line"
10
+ autoload :Signalfx, "semantic_logger/formatters/signalfx"
11
+ autoload :Syslog, "semantic_logger/formatters/syslog"
12
+ autoload :Fluentd, "semantic_logger/formatters/fluentd"
13
13
  # @formatter:on
14
14
 
15
15
  # Return formatter that responds to call.
@@ -22,10 +22,10 @@ module SemanticLogger
22
22
  # - Any object that responds to :call
23
23
  def self.factory(formatter)
24
24
  if formatter.is_a?(Symbol)
25
- SemanticLogger::Utils.constantize_symbol(formatter, 'SemanticLogger::Formatters').new
25
+ SemanticLogger::Utils.constantize_symbol(formatter, "SemanticLogger::Formatters").new
26
26
  elsif formatter.is_a?(Hash) && formatter.size.positive?
27
27
  fmt, options = formatter.first
28
- SemanticLogger::Utils.constantize_symbol(fmt.to_sym, 'SemanticLogger::Formatters').new(options)
28
+ SemanticLogger::Utils.constantize_symbol(fmt.to_sym, "SemanticLogger::Formatters").new(**options)
29
29
  elsif formatter.respond_to?(:call)
30
30
  formatter
31
31
  else
@@ -1,8 +1,8 @@
1
- require 'time'
1
+ require "time"
2
2
  module SemanticLogger
3
3
  module Formatters
4
4
  class Base
5
- attr_accessor :time_format, :log_host, :log_application, :log_environment, :precision
5
+ attr_accessor :log, :logger, :time_format, :log_host, :log_application, :log_environment, :precision
6
6
 
7
7
  # Time precision varies by Ruby interpreter
8
8
  # JRuby 9.1.8.0 supports microseconds
@@ -61,6 +61,11 @@ module SemanticLogger
61
61
  format_time(log.time) if time_format
62
62
  end
63
63
 
64
+ # Process ID
65
+ def pid
66
+ $$
67
+ end
68
+
64
69
  private
65
70
 
66
71
  # Return the Time as a formatted string
@@ -77,7 +82,7 @@ module SemanticLogger
77
82
  when :seconds
78
83
  time.to_f
79
84
  when nil
80
- ''
85
+ ""
81
86
  else
82
87
  time.strftime(time_format)
83
88
  end
@@ -1,8 +1,12 @@
1
- # Load AwesomePrint if available
1
+ # Load Amazing Print, or Awesome Print if available
2
2
  begin
3
- require 'awesome_print'
3
+ require "amazing_print"
4
4
  rescue LoadError
5
- nil
5
+ begin
6
+ require "awesome_print"
7
+ rescue LoadError
8
+ nil
9
+ end
6
10
  end
7
11
 
8
12
  module SemanticLogger
@@ -61,9 +65,9 @@ module SemanticLogger
61
65
  #
62
66
  # Parameters:
63
67
  # ap: [Hash]
64
- # Any valid AwesomePrint option for rendering data.
68
+ # Any valid Amazing Print option for rendering data.
65
69
  # These options can also be changed be creating a `~/.aprc` file.
66
- # See: https://github.com/michaeldv/awesome_print
70
+ # See: https://github.com/amazing-print/amazing_print
67
71
  #
68
72
  # Note: The option :multiline is set to false if not supplied.
69
73
  # Note: Has no effect if Awesome Print is not installed.
@@ -105,7 +109,7 @@ module SemanticLogger
105
109
  def payload
106
110
  return unless log.payload?
107
111
 
108
- if !defined?(AwesomePrint) || !log.payload.respond_to?(:ai)
112
+ if !log.payload.respond_to?(:ai)
109
113
  super
110
114
  else
111
115
  begin
@@ -2,8 +2,6 @@ module SemanticLogger
2
2
  module Formatters
3
3
  # Default non-colored text log output
4
4
  class Default < Base
5
- attr_accessor :log, :logger
6
-
7
5
  # Formatting methods, must return nil, or a string
8
6
  # Nil values are ignored
9
7
 
@@ -12,9 +10,24 @@ module SemanticLogger
12
10
  log.level_to_s
13
11
  end
14
12
 
15
- # Process info
13
+ # Name of the thread that logged the message.
14
+ def thread_name
15
+ format("%.30s", log.thread_name)
16
+ end
17
+
18
+ # Ruby file name and line number that logged the message.
19
+ def file_name_and_line
20
+ file, line = log.file_name_and_line(true)
21
+ "#{file}:#{line}" if file
22
+ end
23
+
24
+ # Returns [String] the available process info
25
+ # Example:
26
+ # [18934:thread_name test_logging.rb:51]
16
27
  def process_info
17
- "[#{log.process_info}]"
28
+ process_id = "#{pid}:" if pid
29
+ fname = file_name_and_line
30
+ fname ? "[#{process_id}#{thread_name} #{fname}]" : "[#{process_id}#{thread_name}]"
18
31
  end
19
32
 
20
33
  # Tags
@@ -67,7 +80,7 @@ module SemanticLogger
67
80
  self.log = log
68
81
  self.logger = logger
69
82
 
70
- [time, level, process_info, tags, named_tags, duration, name, message, payload, exception].compact.join(' ')
83
+ [time, level, process_info, tags, named_tags, duration, name, message, payload, exception].compact.join(" ")
71
84
  end
72
85
  end
73
86
  end
@@ -1,4 +1,4 @@
1
- require 'json'
1
+ require "json"
2
2
 
3
3
  module SemanticLogger
4
4
  module Formatters
@@ -13,8 +13,8 @@ module SemanticLogger
13
13
  end
14
14
 
15
15
  def level
16
- hash['severity'] = log.level
17
- hash['severity_index'] = log.level_index
16
+ hash["severity"] = log.level
17
+ hash["severity_index"] = log.level_index
18
18
  end
19
19
 
20
20
  def process_info
@@ -1,4 +1,4 @@
1
- require 'json'
1
+ require "json"
2
2
  module SemanticLogger
3
3
  module Formatters
4
4
  class Json < Raw
@@ -1,9 +1,9 @@
1
- require 'json'
1
+ require "json"
2
2
  module SemanticLogger
3
3
  module Formatters
4
4
  class Raw < Base
5
5
  # Fields are added by populating this hash.
6
- attr_accessor :hash, :log, :logger, :time_key
6
+ attr_accessor :hash, :time_key
7
7
 
8
8
  # By default Raw formatter does not reformat the time
9
9
  def initialize(time_format: :none, time_key: :time, **args)
@@ -37,11 +37,18 @@ module SemanticLogger
37
37
  hash[:level_index] = log.level_index
38
38
  end
39
39
 
40
- # Process info
41
- def process_info
42
- hash[:pid] = $$
40
+ # Process ID
41
+ def pid
42
+ hash[:pid] = super
43
+ end
44
+
45
+ # Name of the thread that logged the message.
46
+ def thread_name
43
47
  hash[:thread] = log.thread_name
48
+ end
44
49
 
50
+ # Ruby file name and line number that logged the message.
51
+ def file_name_and_line
45
52
  file, line = log.file_name_and_line
46
53
  return unless file
47
54
 
@@ -85,6 +92,7 @@ module SemanticLogger
85
92
  # Exception
86
93
  def exception
87
94
  return unless log.exception
95
+
88
96
  root = hash
89
97
  log.each_exception do |exception, i|
90
98
  name = i.zero? ? :exception : :cause
@@ -93,7 +101,7 @@ module SemanticLogger
93
101
  message: exception.message,
94
102
  stack_trace: exception.backtrace
95
103
  }
96
- root = root[name]
104
+ root = root[name]
97
105
  end
98
106
  end
99
107
 
@@ -109,7 +117,23 @@ module SemanticLogger
109
117
  self.log = log
110
118
  self.logger = logger
111
119
 
112
- host; application; environment; time; level; process_info; duration; tags; named_tags; name; message; payload; exception; metric
120
+ host
121
+ application
122
+ environment
123
+ time
124
+ level
125
+ pid
126
+ thread_name
127
+ file_name_and_line
128
+ duration
129
+ tags
130
+ named_tags
131
+ name
132
+ message
133
+ payload
134
+ exception
135
+ metric
136
+
113
137
  hash
114
138
  end
115
139
  end