semantic_logger 4.5.0 → 4.7.1

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +7 -7
  4. data/lib/semantic_logger.rb +23 -22
  5. data/lib/semantic_logger/ansi_colors.rb +0 -10
  6. data/lib/semantic_logger/appender.rb +54 -64
  7. data/lib/semantic_logger/appender/async.rb +10 -8
  8. data/lib/semantic_logger/appender/async_batch.rb +4 -2
  9. data/lib/semantic_logger/appender/bugsnag.rb +7 -7
  10. data/lib/semantic_logger/appender/elasticsearch.rb +12 -11
  11. data/lib/semantic_logger/appender/elasticsearch_http.rb +4 -4
  12. data/lib/semantic_logger/appender/file.rb +2 -1
  13. data/lib/semantic_logger/appender/graylog.rb +15 -10
  14. data/lib/semantic_logger/appender/honeybadger.rb +3 -3
  15. data/lib/semantic_logger/appender/http.rb +20 -18
  16. data/lib/semantic_logger/appender/kafka.rb +5 -5
  17. data/lib/semantic_logger/appender/mongodb.rb +6 -6
  18. data/lib/semantic_logger/appender/new_relic.rb +2 -2
  19. data/lib/semantic_logger/appender/rabbitmq.rb +5 -5
  20. data/lib/semantic_logger/appender/sentry.rb +7 -7
  21. data/lib/semantic_logger/appender/splunk.rb +6 -5
  22. data/lib/semantic_logger/appender/splunk_http.rb +3 -3
  23. data/lib/semantic_logger/appender/syslog.rb +12 -12
  24. data/lib/semantic_logger/appender/tcp.rb +9 -9
  25. data/lib/semantic_logger/appender/udp.rb +2 -2
  26. data/lib/semantic_logger/appenders.rb +13 -34
  27. data/lib/semantic_logger/base.rb +43 -31
  28. data/lib/semantic_logger/formatters.rb +11 -11
  29. data/lib/semantic_logger/formatters/base.rb +15 -6
  30. data/lib/semantic_logger/formatters/color.rb +12 -13
  31. data/lib/semantic_logger/formatters/default.rb +18 -5
  32. data/lib/semantic_logger/formatters/fluentd.rb +7 -18
  33. data/lib/semantic_logger/formatters/json.rb +3 -5
  34. data/lib/semantic_logger/formatters/raw.rb +39 -10
  35. data/lib/semantic_logger/formatters/signalfx.rb +14 -21
  36. data/lib/semantic_logger/formatters/syslog.rb +3 -3
  37. data/lib/semantic_logger/formatters/syslog_cee.rb +3 -3
  38. data/lib/semantic_logger/jruby/garbage_collection_logger.rb +4 -2
  39. data/lib/semantic_logger/levels.rb +9 -7
  40. data/lib/semantic_logger/log.rb +49 -73
  41. data/lib/semantic_logger/logger.rb +6 -8
  42. data/lib/semantic_logger/metric/new_relic.rb +3 -3
  43. data/lib/semantic_logger/metric/signalfx.rb +3 -3
  44. data/lib/semantic_logger/metric/statsd.rb +7 -7
  45. data/lib/semantic_logger/processor.rb +7 -5
  46. data/lib/semantic_logger/reporters/minitest.rb +4 -4
  47. data/lib/semantic_logger/semantic_logger.rb +37 -12
  48. data/lib/semantic_logger/subscriber.rb +14 -7
  49. data/lib/semantic_logger/sync.rb +12 -0
  50. data/lib/semantic_logger/sync_processor.rb +43 -0
  51. data/lib/semantic_logger/utils.rb +6 -6
  52. data/lib/semantic_logger/version.rb +1 -1
  53. metadata +5 -3
@@ -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
 
@@ -8,9 +8,8 @@ module SemanticLogger
8
8
  @logger.name = self.class.name
9
9
  end
10
10
 
11
- def add(options, deprecated_level = nil, &block)
12
- options = options.is_a?(Hash) ? options.dup : convert_old_appender_args(options, deprecated_level)
13
- appender = SemanticLogger::Appender.factory(options, &block)
11
+ def add(**args, &block)
12
+ appender = SemanticLogger::Appender.factory(**args, &block)
14
13
  self << appender
15
14
  appender
16
15
  end
@@ -19,8 +18,8 @@ module SemanticLogger
19
18
  each do |appender|
20
19
  begin
21
20
  appender.log(log) if appender.should_log?(log)
22
- rescue Exception => exc
23
- logger.error "Failed to log to appender: #{appender.inspect}", exc
21
+ rescue Exception => e
22
+ logger.error "Failed to log to appender: #{appender.name}", e
24
23
  end
25
24
  end
26
25
  end
@@ -30,11 +29,11 @@ module SemanticLogger
30
29
  begin
31
30
  logger.trace "Flushing appender: #{appender.name}"
32
31
  appender.flush
33
- rescue Exception => exc
34
- logger.error "Failed to flush appender: #{appender.inspect}", exc
32
+ rescue Exception => e
33
+ logger.error "Failed to flush appender: #{appender.name}", e
35
34
  end
36
35
  end
37
- logger.trace 'All appenders flushed'
36
+ logger.trace "All appenders flushed"
38
37
  end
39
38
 
40
39
  def close
@@ -44,11 +43,11 @@ module SemanticLogger
44
43
  appender.flush
45
44
  appender.close
46
45
  delete(appender)
47
- rescue Exception => exc
48
- logger.error "Failed to close appender: #{appender.inspect}", exc
46
+ rescue Exception => e
47
+ logger.error "Failed to close appender: #{appender.name}", e
49
48
  end
50
49
  end
51
- logger.trace 'All appenders closed and removed from appender list'
50
+ logger.trace "All appenders closed and removed from appender list"
52
51
  end
53
52
 
54
53
  # After a fork the appender thread is not running, start it if it is not running.
@@ -59,31 +58,11 @@ module SemanticLogger
59
58
 
60
59
  logger.trace "Reopening appender: #{appender.name}"
61
60
  appender.reopen
62
- rescue Exception => exc
63
- logger.error "Failed to re-open appender: #{appender.inspect}", exc
61
+ rescue Exception => e
62
+ logger.error "Failed to re-open appender: #{appender.name}", e
64
63
  end
65
64
  end
66
- logger.trace 'All appenders re-opened'
67
- end
68
-
69
- private
70
-
71
- # Backward compatibility
72
- def convert_old_appender_args(appender, level)
73
- options = {}
74
- options[:level] = level if level
75
-
76
- if appender.is_a?(String)
77
- options[:file_name] = appender
78
- elsif appender.is_a?(IO)
79
- options[:io] = appender
80
- elsif appender.is_a?(Symbol) || appender.is_a?(Subscriber)
81
- options[:appender] = appender
82
- else
83
- options[:logger] = appender
84
- end
85
- warn "[DEPRECATED] SemanticLogger.add_appender parameters have changed. Please use: #{options.inspect}"
86
- options
65
+ logger.trace "All appenders re-opened"
87
66
  end
88
67
  end
89
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
 
@@ -233,26 +234,14 @@ module SemanticLogger
233
234
  SemanticLogger.silence(new_level, &block)
234
235
  end
235
236
 
236
- # Deprecated. Use `SemanticLogger.tagged`
237
+ # :nodoc:
237
238
  def fast_tag(tag, &block)
238
239
  SemanticLogger.fast_tag(tag, &block)
239
240
  end
240
241
 
241
- # :nodoc:
242
- def with_payload(payload, &block)
243
- warn '#with_payload is deprecated, use SemanticLogger.named_tagged'
244
- SemanticLogger.named_tagged(payload, &block)
245
- end
246
-
247
- # :nodoc:
248
- def payload
249
- warn '#payload is deprecated, use SemanticLogger.named_tags'
250
- SemanticLogger.named_tags
251
- end
252
-
253
242
  # Write log data to underlying data storage
254
243
  def log(_log_)
255
- raise NotImplementedError, 'Logging Appender must implement #log(log)'
244
+ raise NotImplementedError, "Logging Appender must implement #log(log)"
256
245
  end
257
246
 
258
247
  # Whether this log entry meets the criteria to be logged by this appender.
@@ -281,7 +270,7 @@ module SemanticLogger
281
270
  # The Proc must return true or false
282
271
  def initialize(klass, level = nil, filter = nil)
283
272
  # Support filtering all messages to this logger using a Regular Expression or Proc
284
- raise ':filter must be a Regexp or Proc' unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc)
273
+ raise ":filter must be a Regexp or Proc" unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc)
285
274
 
286
275
  @filter = filter.is_a?(Regexp) ? filter.freeze : filter
287
276
  @name = klass.is_a?(String) ? klass : klass.name
@@ -314,20 +303,42 @@ module SemanticLogger
314
303
  end
315
304
 
316
305
  # Log message at the specified level
317
- def log_internal(level, index, message = nil, payload = nil, exception = nil, &block)
318
- log = Log.new(name, level, index)
306
+ def log_internal(level, index, message = nil, payload = nil, exception = nil)
307
+ # Handle variable number of arguments by detecting exception object and payload hash.
308
+ if exception.nil? && payload.nil? && message.respond_to?(:backtrace) && message.respond_to?(:message)
309
+ exception = message
310
+ message = nil
311
+ elsif exception.nil? && payload && payload.respond_to?(:backtrace) && payload.respond_to?(:message)
312
+ exception = payload
313
+ payload = nil
314
+ elsif payload && !payload.is_a?(Hash)
315
+ message = message.nil? ? payload : "#{message} -- #{payload}"
316
+ payload = nil
317
+ end
318
+
319
+ log = Log.new(name, level, index)
319
320
  should_log =
320
321
  if payload.nil? && exception.nil? && message.is_a?(Hash)
321
- # Check if someone just logged a hash payload instead of meaning to call semantic logger
322
- if message.key?(:message) || message.key?(:payload) || message.key?(:exception) || message.key?(:metric)
323
- log.assign(message)
324
- else
325
- log.assign_positional(nil, message, nil, &block)
326
- end
322
+ # Everything as keyword arguments.
323
+ log.assign(**log.extract_arguments(message))
324
+ elsif exception.nil? && message && payload && payload.is_a?(Hash)
325
+ # Message with keyword arguments as the rest.
326
+ log.assign(message: message, **log.extract_arguments(payload))
327
327
  else
328
- log.assign_positional(message, payload, exception, &block)
328
+ # No keyword arguments.
329
+ log.assign(message: message, payload: payload, exception: exception)
329
330
  end
330
331
 
332
+ # Add result of block to message or payload if not nil
333
+ if block_given?
334
+ result = yield(log)
335
+ if result.is_a?(String)
336
+ log.message = log.message.nil? ? result : "#{log.message} -- #{result}"
337
+ elsif result.is_a?(Hash)
338
+ log.assign_hash(result)
339
+ end
340
+ end
341
+
331
342
  # Log level may change during assign due to :on_exception_level
332
343
  self.log(log) if should_log && should_log?(log)
333
344
  end
@@ -353,8 +364,8 @@ module SemanticLogger
353
364
  yield(params)
354
365
  end
355
366
  end
356
- rescue Exception => exc
357
- exception = exc
367
+ rescue Exception => e
368
+ exception = e
358
369
  ensure
359
370
  # Must use ensure block otherwise a `return` in the yield above will skip the log entry
360
371
  log = Log.new(name, level, index)
@@ -364,7 +375,7 @@ module SemanticLogger
364
375
  if block_given?
365
376
  1_000.0 * (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start)
366
377
  else
367
- params[:duration] || raise('Mandatory block missing when :duration option is not supplied')
378
+ params[:duration] || raise("Mandatory block missing when :duration option is not supplied")
368
379
  end
369
380
 
370
381
  # Extract options after block completes so that block can modify any of the options
@@ -386,6 +397,7 @@ module SemanticLogger
386
397
  # Log level may change during assign due to :on_exception_level
387
398
  self.log(log) if should_log && should_log?(log)
388
399
  raise exception if exception
400
+
389
401
  result
390
402
  end
391
403
  end
@@ -404,8 +416,8 @@ module SemanticLogger
404
416
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
405
417
  begin
406
418
  yield
407
- rescue Exception => exc
408
- exception = exc
419
+ rescue Exception => e
420
+ exception = e
409
421
  ensure
410
422
  log = Log.new(name, level, index)
411
423
  # 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,12 +1,12 @@
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, :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
9
- PRECISION =
9
+ PRECISION =
10
10
  if defined?(JRuby)
11
11
  if JRUBY_VERSION.to_f >= 9.1
12
12
  maint = JRUBY_VERSION.match(/\A\d+\.\d+\.(\d+)\./)[1].to_i
@@ -34,11 +34,15 @@ module SemanticLogger
34
34
  # precision: [Integer]
35
35
  # How many fractional digits to log times with.
36
36
  # Default: PRECISION (6, except on older JRuby, where 3)
37
- def initialize(time_format: nil, log_host: true, log_application: true,
37
+ def initialize(time_format: nil,
38
+ log_host: true,
39
+ log_application: true,
40
+ log_environment: true,
38
41
  precision: PRECISION)
39
42
  @time_format = time_format || self.class.build_time_format(precision)
40
43
  @log_host = log_host
41
44
  @log_application = log_application
45
+ @log_environment = log_environment
42
46
  @precision = precision
43
47
  end
44
48
 
@@ -48,7 +52,7 @@ module SemanticLogger
48
52
  # precision: [Integer]
49
53
  # How many fractional digits to log times with.
50
54
  # Default: PRECISION (6, except on older JRuby, where 3)
51
- def self.build_time_format(precision=PRECISION)
55
+ def self.build_time_format(precision = PRECISION)
52
56
  "%Y-%m-%d %H:%M:%S.%#{precision}N"
53
57
  end
54
58
 
@@ -57,6 +61,11 @@ module SemanticLogger
57
61
  format_time(log.time) if time_format
58
62
  end
59
63
 
64
+ # Process ID
65
+ def pid
66
+ $$
67
+ end
68
+
60
69
  private
61
70
 
62
71
  # Return the Time as a formatted string
@@ -73,7 +82,7 @@ module SemanticLogger
73
82
  when :seconds
74
83
  time.to_f
75
84
  when nil
76
- ''
85
+ ""
77
86
  else
78
87
  time.strftime(time_format)
79
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,24 +65,19 @@ 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.
70
74
  #
71
75
  # color_map: [Hash | SemanticLogger::Formatters::Color::ColorMap]
72
76
  # ColorMaps each of the log levels to a color
73
- def initialize(ap: {multiline: false},
74
- color_map: ColorMap.new,
75
- time_format: nil,
76
- log_host: false,
77
- log_application: false,
78
- precision: PRECISION)
77
+ def initialize(ap: {multiline: false}, color_map: ColorMap.new, **args)
79
78
  @ai_options = ap
80
79
  @color_map = color_map.is_a?(ColorMap) ? color_map : ColorMap.new(color_map)
81
- super(time_format: time_format, log_host: log_host, log_application: log_application, precision: precision)
80
+ super(**args)
82
81
  end
83
82
 
84
83
  def level
@@ -110,7 +109,7 @@ module SemanticLogger
110
109
  def payload
111
110
  return unless log.payload?
112
111
 
113
- if !defined?(AwesomePrint) || !log.payload.respond_to?(:ai)
112
+ if !log.payload.respond_to?(:ai)
114
113
  super
115
114
  else
116
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,37 +1,26 @@
1
- require 'json'
1
+ require "json"
2
2
 
3
3
  module SemanticLogger
4
4
  module Formatters
5
- # Fluentd is similar to SemanticLogger::Formatters::Json but with log level that are recongnized
5
+ # Fluentd is similar to SemanticLogger::Formatters::Json but with log levels that are recognized
6
6
  # by kubernetes fluentd.
7
7
  class Fluentd < Json
8
8
  attr_reader :need_process_info
9
9
 
10
- def initialize(log_host: true, log_application: true, need_process_info: false)
10
+ def initialize(time_format: :rfc_3339, time_key: :time, need_process_info: false, **args)
11
11
  @need_process_info = need_process_info
12
- super(log_host: log_host, log_application: log_application, time_key: 'time', time_format: :rfc_3339)
12
+ super(time_format: time_format, time_key: time_key, **args)
13
13
  end
14
14
 
15
- def severity
16
- hash['severity'] = log.level
17
- hash['severity_index'] = log.level_index
15
+ def level
16
+ hash["severity"] = log.level
17
+ hash["severity_index"] = log.level_index
18
18
  end
19
19
 
20
20
  def process_info
21
21
  # Ignore fields: pid, thread, file and line by default
22
22
  super() if need_process_info
23
23
  end
24
-
25
- def call(log, logger)
26
- self.hash = {}
27
- self.log = log
28
- self.logger = logger
29
-
30
- host; application; time; severity; process_info; duration; tags; named_tags; name; message; payload; exception; metric
31
- hash
32
-
33
- hash.to_json
34
- end
35
24
  end
36
25
  end
37
26
  end